Use script library from another database - lotus-notes

Is it possible to call script libraries from another database?

Not directly. About the only thing you can do is have one database inherit from the other, and set only the lotusscript libraries to be inherited. Then you could make changes on the parent, and have them carry over to the child (or children) databases.
You can, however, run agents on another database. Agents in turn can make calls to script libraries in their own databases. Depending on your goals, you may be able to get what you need from that.

From your comments, it seems that you are calling an agent within an agent. Not really the best way to go about it.
You may get the result you want if you merely call the "TextExternalUse" agent directly from the button. This means creating a regular action button rather than a shared action and calling the agent directly.
UPDATE:
I think I know what your problem is. If you're using formula to call the agent in the other database, it won't work, because formula can only call agents in the current database. So if you're using "ToolsRunMacro" it has no parameter for specifying a different database.
Try calling the agent with LotusScript. Here is an example.
I created 2 databases one with an agent called "clickme", which simply displays a "notesUIWorkspace.prompt", and another database with a view that has an action button with the following code that calls the agent from db1
Sub Click(Source As Button)
Dim agnt As notesAgent
Dim db2 As notesDatabase
Set db2 = New notesDatabase("","test2.nsf")
Set agnt = db2.GetAgent("clickme")
Call agnt.Run
End Sub
Can you test something like the above ?

Related

Lotus Notes - Script or formula to create multiple new documents within a database

I have the following situation:
currently an end user needs to create several documents using a step by step process, but with some new features that was created, the user will need to create more required documents.
I am afraid they will forget to create an important one that will mess the process at the end.
Based on this I was thinking to create a script, since the Compose #Command (Formula Language) allows me to create only one form.
Note that these documents will have computed fields, so no need to fill any data on these new forms.
Here is what I got so far, it is working but I think someone could give a better idea. Thanks.
Dim session As New notessession
Dim db As notesdatabase
Dim newdoc As notesdocument
Dim i%
Set db=session.currentdatabase
For i%=1 To 1 'or however many slots you want
Set newdoc=db.createdocument
newdoc.form= "Form1"
Call newdoc.save(True,True)
Set newdoc=db.createdocument
newdoc.form="Form2"
Call newdoc.save(True,True)
Set newdoc=db.createdocument
newdoc.form="Form3"
Call newdoc.save(True,True)
Next i%
End Sub
If you want to make the documents compute as if they were opened in frontend, then you need to tell the code to do that: simple saving a document does NOT do frontend calculations. You need to add a ComputeWithForm before every save to do exactly that: compute the document with the assigned form. That will look like this:
Set newdoc=db.createdocument
newdoc.form= "Form1"
Call newdoc.ComputeWithForm( True, True )
Call newdoc.save(True,True)
Take care: if there is any error in the formulas of your form because you forgot to fill some essential field, then the compute will not complete and only fields above the one that had the error will be calculated. In addition this funcion may throw an Error if something goes wrong that you have to catch in your code (depends of parameters, check documentation)

Xpages only passes first character to Agent

I have created an Xpage to allow the administrator to input a single Notes Document (They are Contracts) ID into an edit box and press a button to delete the Contract. The delete calls an Agent passing the Contract ID. Below is the button script and then the relevant part of the Agent. What is happening is only the first character is being passed to the Agent, i.e if the Contract ID is 9MXCB4 only "9" is being passed as the Agent message box prints this to the log. What am I doing wrong here? If I hard code a Contract ID after the message box the Contract is processed correctly.
Button code
ag = database.getAgent("DeleteOneContract");
noteid = getComponent("ContractIDDelete").getValue()
ag.run(noteid)
Part of Agent code
Dim runAgent As NotesAgent
Dim deleteID As Variant
deleteID = runAgent.Parameterdocid
MsgBox "Input is " & deleteID
'If line below is uncommented it processes the Contract correctly
'deleteID = "9MXCB4"
' Rest of agent process
....
Note that I have also tried runAgent.Target and runAgent.Query
Just tested that and when I pass it a valid NoteID, the agent reads it just fine. I don't think you can pass any other value than a NoteID to the agent this way.
An alternative might be to use the agent.runWithDocumentContext(doc) method and retrieve the document before sending it to the agent.
I believe that the note ID parameter has to actually be a hexidecimal number in string form. It doesn't have to line up with an actual note ID in the database, but it can only contain 0-9 and A-F (with presumably a cap on size).
To add an extra thought on Jesse's and Mark's correct answers: from AJF's question we cannot tell whether the Xpage is bound to an actual NotesDocument object, or whether it is a (temporary) stand-alone page. In that case, of course, agent.runWithDocumentContext won't work.
But unless you have a good reason to perform the rest of your task using a LotusScript coding: why use an agent in the first place? Why not perform the deletion directly using SSJS code? On the Xpages side of the process you most probably will have to start with SSJS code very similar to Mark's example, but then why not go ahead and finish it off with two or three more lines?
In fact I try to avoid calling agents directly from my Xpages driven applications, due to performance issues, and because I don't like my code to be scattered all over the place.

Lotus notes - error accessing shared private on first use view from LotusScript

Good morning,
I have develop a note application which is used to make a booking. This application is used by multiple user at the same time.
I am quiet new to this development and now I would like to develop a functionality so that user can print a export data to excel.
I have created a view (Shared) where its Selection Formula is base on critical each user specify in a search form. I have problem when a user is being printing and yet finished, the other users is also clicking printing same time, the result of export data on the sides are the same to the one who created first.
I was thought may be using the kind of (Shared, Private on first Use View) but it generated an error [Notes error: Index is not to be generated on server ("view name") ] at the points where I called
view.Clear
view.SelectionFormula = formula
uiw.ViewRebuild
I have no idea how to solve this problem. Could you please advice how this problem could be solved?
Thanks your in advance for your great help.
Best regards,
Veasna
There are different ways to do this. One possibility is to use a "shared, private on first use" (spofu) view: then every user gets his own copy of the view, and they don't impact each other. But I think it is not a good idea to do it like that, as every user needs designer rights to change the selection formula of the view. This is something you do not want.
A better way would be to use a spofu folder for each user and put the documents in it like this:
Dim ses as New NotesSession
Dim db as NotesDatabase
Dim dc as NotesDocumentCollection
Dim folder As NotesView
Dim formula as String
Set db = ses.currentDatabase
Set folder = db.GetView("NameOfTheSpofuFolder" )
'Make it empty
Call folder.AllEntries.RemoveFromFolder("NameOfTheSpofuFolder")
'Search documents based on the formula
Formula = "Field1 = 2 & Field2 = 5"
Set dc = db.Search( formula, Nothing, 0)
Call dc.PutInFolder("NameOfTheSpofuFolder")
Spofu folders need a little "care" but usually they work quite nicely.
This code is not tested and just written down without syntax check etc. It might contain typos, but should give you an idea how to start.
You could create a Lotusscript agent to export the data the users specify.
Get the search criteria from the form, then use db.Search or (preferably) db.FTSearch to get the documents to export.
Now you can export the data of those documents to Excel, using one of the techniques described here:
http://blog.texasswede.com/export-from-notes-to-excel-3-different-ways/
If you want to export as CSV, you can use this code as a start: http://blog.texasswede.com/export-notes-view-to-excel-with-multi-value-fields/
According to this thread on the Notes 6/7 forum, there may be a workaround for this problem. You haven't shown enough code to know for sure. If you are using getView() to access the Shared - Private On First Use (SPOFU) view, that doesn't work. The workaround is to loop through the db.Views() array, checking both the Name and Readers properties in order to make sure that you get a handle on the private instance of the view instead of the shared instance.

How to handle entity creation/editing in a master-detail

I'm wondering what strategies people are using to handle the creation and editing of an entity in a master-detail setup. (Our app is an internet-enabled desktop app.)
Here's how we currently handle this: a form is created in a popup for the entity that needs to be edited, which we give a copy of the object. When the user clicks the "Cancel" button, we close the window and ignore the object completely. When the user clicks the "OK" button, the master view is notified and receives the edited entity. It then copies the properties of the modified entity into the original entity using originalEntity.copyFrom(modifiedEntity). In case we want to create a new entity, we pass an empty entity to the popup which the user can then edit as if it was an existing entity. The master view needs to decide whether to "insert" or "update" the entities it receives into the collection it manages.
I have some questions and observations on the above workflow:
who should handle the creation of the copy of the entity? (master or detail)
we use copyFrom() to prevent having to replace entities in a collection which could cause references to break. Is there a better way to do this? (implementing copyFrom() can be tricky)
new entities receive an id of -1 (which the server tier/hibernate uses to differentiate between an insert or an update). This could potentially cause problems when looking up (cached) entities by id before they are saved. Should we use a temporary unique id for each new entity instead?
Can anyone share tips & tricks or experiences? Thanks!
Edit: I know there is no absolute wrong or right answer to this question, so I'm just looking for people to share thoughts and pros/cons on the way they handle master/details situations.
There are a number of ways you could alter this approach. Keep in mind that no solution can really be "wrong" per se. It all depends on the details of your situation. Here's one way to skin the cat.
who should handle the creation of the copy of the entity? (master or detail)
I see the master as an in-memory list representation of a subset of persisted entities. I would allow the master to handle any changes to its list. The list itself could be a custom collection. Use an ItemChanged event to fire a notification to the master that an item has been updated and needs to be persisted. Fire a NewItem event to notify the master of an insert.
we use copyFrom() to prevent having to replace entities in a collection which could cause references to break. Is there a better way to do this? (implementing copyFrom() can be tricky)
Instead of using copyFrom(), I would pass the existing reference to the details popup. If you're using an enumerable collection to store the master list, you can pass the object returned from list[index] to the details window. The reference itself will be altered so there's no need to use any kind of Replace method on the list. When OK is pressed, fire that ItemChanged event. You can even pass the index so it knows which object to update.
new entities receive an id of -1 (which the server tier/hibernate uses to differentiate between an insert or an update). This could potentially cause problems when looking up (cached) entities by id before they are saved. Should we use a temporary unique id for each new entity instead?
Are changes not immediately persisted? Use a Hibernate Session with the Unit of Work pattern to determine what's being inserted and what's being updated. There are more examples of Unit of Work out there. You might have to check out some blog posts by the .NET community if there's not much on the Java end. The concept is the same animal either way.
Hope this helps!
The CSLA library can help with this situation a lot.
However, if you want to self implement :
You have a master object, the master object contains a list of child objects.
The detail form can edit a child object directly. Since everything is reference types, the master object is automatically updated.
The issue is knowing that the master object is dirty, and therefore should be persisted to your database or whatnot.
CSLA handles this with an IsDirty() property. In the master object you would query each child object to see if it is dirty, and if so persist everything (as well as tracking if the master object itself is dirty)
You can also handle this is the INotifyPropertyChanged interface.
As for some of your other questions :
You want to separate your logic. The entity can handle storage of its own properties, and integrity rules for itself, but logic for how different object interact with each other should be separate. Look into patterns such as MVC or MVP.
In this case, creation of a new child object should either be in the master object, or should be in a separate business logic object that creates the child and then adds it to the parent.
For IDs, using GUIDs as the ID can save you quite a bit of problems, because then you don't have to talk to the database to determine a correct ID. You can keep a flag on the object for if it is new or not (and therefore should be inserted or updated).
Again, CSLA handles all of this for you, but does have quite a bit of overhead.
regarding undo on cancel : CSLA has n-level undo implemented, but if you are trying to do it by hand, I would either use your CopyFrom function, or refresh the object's data from the persistance layer on cancel (re-fetch).
i just implemented such a model.but not using NH, i am using my own code to persist objects in Oracle Db.
i have used the master detail concept in the same web form.
like i have master entity grid and on detail action command i open a penal just below the clicked master record row.
On Detail Add mode, i just populate an empty entity whose id were generated in negative numbers by a static field.and on Save Detail button i saved that entity in the details list of the Master Record in Asp.NET Session.
On Detail Edit,View i populated the Detail Panel with selected Detail through ajax calls using Jquery and appended that penal just below the clicked row.
On Save Button i persisted the Master Session (containing list of Details) in database.
and i worked good for me as if multiple details a master need to fill.
also if you like you can use Jquery Modal to Popup that Panel instead of appending below the row.
Hope it helps :)
Thanks,

How can I export a list of databases resident on a given Domino server?

I have a Lotus Domino server with a truly astounding number of Domino databases on it, arranged in various folders.
Is there some means of exporting a list of all these databases, with their titles and creators' names, in a spreadsheet format of some kind? I have the Domino Admin and Domino Designer software, and I have or can get whatever access rights I'd need.
Actually, you can use a very simple Lotuscript agent to connect to a server and walk through all databases on the server, using the NotesDbDirectory class. Here is some code, modified slightly from what's in the 6.5 Help files - this dumps the title and path of all databases to a csv file. Note: the one argument to the GetFirstDatabase method let's you specify which objects on the server you want to scan - 1247 is the constant for "Databases" - basically, all NSF files. There are other constants for finding templates only (NTF's), only database with replication enabled, etc.
Sub Initialize
Dim db As NotesDatabase
Dim f As Integer
f = Freefile
Open "c:\dbExport.csv" For Output As #f
Dim dbdir As New NotesDbDirectory("") ' opens LOCAL - put a server name here
Set db = dbdir.GetFirstDatabase(1247) ' all databases - NSF, NSG and NSH (no templates)
While Not(db Is Nothing)
Print #f, """" + db.Title + """, """ + db.FileName + """"
Set db = dbdir.GetNextDatabase
Wend
Close #f
End Sub
You'd think there'd be a way in the Domino Admin, but there's no way to export the list. So, your best bet I think is to use the Domain Catalog database. To build it, go into the server configuration doc > Server Tasks > and turn on the Domain Catalog. Then the catalog.nsf database will be built and will contain all the databases in your domain. You can customize the views to include the information you need.
Then finally, you can go into a view, select all the documents and click Edit > Copy Selected As Table. Then paste that into a spreadsheet.
It is a little known fact that you can "select all" in the Admin client and paste into Excel. There is also an option for a flat view of databases instead of a folder view.
The creator of the database is not listed but there is a lot of other useful information
Inherited some legacy server, didn't we ?
If the server was sensibly maintained in the past, you already have the following things :
a catalog.nsf database, which is exactly what you want, only better
the catalog server task up and running.
The catalog task is the task that automatically builds and maintain the catalog.nsf database. If it is not already running, you can launch it once at teh server console in Domino admin :
load catalog
and even better, add it to the server tasks in the server's notes.ini
Now, the catalog tasks only cover the databases whose properties have been set such as to allow cataloging. A well behaved Domino admin would not allow a database to reach production without those properties properly set (and I believe it is the default anyway) but it seems you are not exactly in a nominal situation.
If this is not enough and if you have time to tinker around, I was in a similar situation once, and I built a database with some rather advanced scripts to conduct a thourough census, including agents and their schedules etc. If you want, I'd be happy to pass it to you.
Have fun with your new toy !

Resources