203 Lotus blogs updated hourly. Who will post next? Home | Blogs | Search | About 
 
Latest 7 Posts
A more direct way of creating an Outlook mail item from the Notes client
Wed, Nov 1st 2017 5
Sending an automated mail using Outlook from a Notes agent
Tue, Sep 12th 2017 5
Breweries and tap rooms for #MWLUG
Sat, Jul 29th 2017 3
So where can I go for dinner near #MWLUG?
Thu, Jul 27th 2017 2
Creating a meeting notice in Outlook from the Notes client
Fri, Jun 23rd 2017 3
Getting email addresses from the Notes address book
Wed, Jun 21st 2017 2
Progammatically opening a mailto link from the Notes client
Fri, Jun 2nd 2017 9
Top 10
Exporting from #XPages to Excel without Excel, Part 2
Thu, Sep 26th 2013 9
Progammatically opening a mailto link from the Notes client
Fri, Jun 2nd 2017 9
Java still not refreshing correctly in #XPages 8.5.3 UP 1
Mon, Nov 4th 2013 8
Dirty pages and keeping users on them in #XPages
Wed, Apr 16th 2014 8
Simple dialog returning a value to your #XPages
Wed, Jul 16th 2014 8
Copying property definitions for custom controls in #XPages
Thu, Mar 10th 2016 8
Austin, Texas hosts #MWLUG2016 in August
Wed, Apr 6th 2016 8
Exception avoided in FTSearchSorted in #XPages
Mon, Aug 25th 2014 7
Are you sure? Asking for confirmation in #XPages
Wed, Sep 17th 2014 7
Sample database for #Excel exporting from #XPages
Mon, Feb 24th 2014 6


Configurable notification agent in #OldNotes
Twitter Google+ Facebook LinkedIn Addthis Email Gmail Flipboard Reddit Tumblr WhatsApp StumbleUpon Yammer Evernote Delicious
David Navarre    

Shockingly, when I arrived at my current company, they had basically NO scheduled agents at all. Apparently, someone had decided long ago that scheduled agents were dangerous, that they would overwhelm and crash the servers. So, whenever anything was done, it was done manually. This even extended to user notifications. That is, if I submitted a document for approval, there was some formula language that would populate a new notification message in the client and the user would fill in any extra details before clicking send. I was shocked. As I’ve modified designs, I’ve been adding background notifications and also scheduled agents. Our main project management database, which our field offices use copies of to manage their projects, hasn’t been mine to modify, since it’s already working and there is a team that customizes the design for each field office.

As we’ve been delving further into XPages and as I’ve been spreading the good word about scheduled agents and notifications, we’re now finally putting them into those project management databases. One hurdle though. Our admin team has, quite rightly, limited who can sign agents that will run on production servers.

Concept

Now, I’ve designed dozens or even hundreds of notification and reminder agents in many databases over the decades, but I always designed them from scratch, customizing it to the particular database and the particular recipients. I’d created a basic one and Ariwan Susey, who’s really coming up to speed on LotusScript and XPages, modified it for use in that project management database. This was nice, and Virginia Tauss had started creating copies of it, customized for each notice type. However, every time someone made a change to the half-dozen agents, I had to sign them. Since they were customized for their particular database and the particular recipients, this meant that eventually, I might spend all day signing agents instead of writing code.

Since the agents were almost the same, except for what view they used and who received the message, I realized that if I created a basic agent, they could use configuration documents to customize as many notices as they wanted and I’d never have to sign that configurable agent again!

Configuration Choices

There were a few basic things I knew would be different between each notification: the view, the recipients, the subject, the server to run on and the time to run. After creating some tests, I also realized that I wanted to emulate the scheduling choices of agents themselves and allow the user to select weekly or monthly notifications instead of just daily. I also remembered that sometimes, they would want to mark the document after they sent the notice, so I made that a configuration choice as well. Based on my recent experience in my Excel series (part 1, part 2, and the sample database) and with full-text queries, I realized we could use those full-text queries in these notifications as well.

So, here’s my form:

AutoNotify Configuration

Since I’ve been fiddling with DXL editing of forms lately, let me include the DXL for that third row for your review. The right cell contains a table for displaying the weekday or day of the month choices, with the hide-whens appropriately.

<tablerow>
<tablecell>
<par def='4'>Day(s) to run:</par></tablecell>
<tablecell>
<par def='5'><field borderstyle='none' lookupeachchar='false' lookupaddressonrefresh='false'
type='keyword' kind='editable' name='frequency'><keywords helperbutton='false'
recalconchange='true' columns='3' ui='radiobutton'><textlist><text>Daily</text><text
>Weekly</text><text>Monthly</text></textlist></keywords></field></par>
<table leftmargin='0' widthtype='fixedleft' refwidth='2.5000in'><tablecolumn
width='1in'/><tablecolumn width='1.5000in'/>
<tablerow>
<tablecell valign='center' borderwidth='0px'>
<pardef id='6' spacebefore='1.5' keepwithnext='true' keeptogether='true'><code
event='hidewhen'><formula>frequency != "Weekly"</formula></code></pardef>
<par def='6'>Day of week: </par></tablecell>
<tablecell valign='center' borderwidth='0px'>
<pardef id='7' spacebefore='1.5' keepwithnext='true' keeptogether='true'><code
event='hidewhen'><formula>frequency != "Weekly"</formula></code></pardef>
<par def='7'><field usenotesstyle='false' height='0.2500in' width='1in' multiline='true'
borderstyle='none' lookupeachchar='false' lookupaddressonrefresh='false'
type='keyword' kind='editable' name='weekdayToRun'><keywords helperbutton='false'
columns='1' ui='combobox'><textlist><text>Sunday|1</text><text>Monday|2</text><text
>Tuesday|3</text><text>Wednesday|4</text><text>Thursday|5</text><text>Friday|6</text><text
>Saturday|7</text></textlist></keywords></field></par></tablecell></tablerow>
<tablerow>
<tablecell valign='center' borderwidth='0px'>
<pardef id='8' keepwithnext='true' keeptogether='true'><code event='hidewhen'><formula
>frequency != "Monthly"</formula></code></pardef>
<par def='8'>Day of month:</par></tablecell>
<tablecell valign='center' borderwidth='0px'>
<pardef id='9' keepwithnext='true' keeptogether='true'><code event='hidewhen'><formula
>frequency != "Monthly"</formula></code></pardef>
<par def='9'><field type='number' kind='editable' name='monthdayToRun'><numberformat
format='general' digits='2' punctuated='false' parens='false' percent='false'
bytes='false'/><code event='defaultvalue'><formula>1</formula></code><code
event='inputvalidation'><formula>@If ( frequency != "Monthly"; @Success; @ThisValue > 1 & @ThisValue < 29; @Success; @Failure ( "Must be in the first 28 days of the month" ))</formula></code></field></par></tablecell></tablerow></table>
<pardef id='10' keepwithnext='true' keeptogether='true'><code event='hidewhen'><formula
>frequency != "Monthly"</formula></code></pardef>
<par def='10'><run><font size='1pt'/></run></par></tablecell>
</tablerow>

As I use the source view more in XPages, I get more and more comfortable with just editing code, and checking appearances occasionally. While I have only done a little of that in forms, I have used it several times in views. When I created this form, my initial design of it was done by creating a single in the normal designer form, then saving it, and re-opening it in DXL. Then I added several fields to a form with cut-and-paste for field names. Using the properties boxes just seemed like it would take so much longer – after all, I had the field names in my notepad already.

The Agent

Our agent is set to run hourly, on every server. If there are no autoNotify documents, it doesn’t do anything, but if there are, it checks each one for whether it runs on that server, on that day and at that hour.

Sub Initialize
Dim session As New NotesSession
' thisdb is declared in my utilities library, so not declared here '
Dim autoNotifyView As NotesView
Dim autoNotifyDoc As NotesDocument
Dim serverToRunOn As Variant
Dim hourToRun As Variant
Dim frequency As Variant
Dim weekdayToRun As Variant
Dim monthdayToRun As Variant
Dim hourNow As Integer
Dim weekdayToday As Integer
Dim monthdayToday As Integer
Dim reason As String

On Error GoTo errorhandler

Set thisdb = session.Currentdatabase
Call StartAgentLogging ( session )

Dim serverName As New NotesName ( thisdb.Server )

' get view of autonotify documents '
Set autoNotifyView = thisdb.Getview("AutoNotify")
Set autoNotifyDoc = autoNotifyView.Getfirstdocument()

While Not autoNotifyDoc Is Nothing
	' check server to run on '
	serverToRunOn = autoNotifyDoc.Getitemvalue("serverToRunOn")
	If ( serverToRunOn (0) = serverName.Common ) Then
		' check frequency & day '
		frequency = autoNotifyDoc.Getitemvalue("frequency")
		weekdayToRun = autoNotifyDoc.Getitemvalue("weekdayToRun")
		If ( weekdayToRun (0) = "" ) Then
			weekdayToRun (0) = "0"
		End If
		weekdayToday = Weekday ( Today )
		monthdayToRun = autoNotifyDoc.Getitemvalue("monthdayToRun")
		monthdayToday = Day ( Today )
		If ( frequency (0) = "Daily" or ( frequency (0) = "Weekly" & CInt (weekdayToRun (0)) = weekdayToday ) Or ( frequency (0) = "Weekly" & CInt ( monthdayToRun (0) ) = monthdayToday ) ) Then
			' check hour to run '
			hourToRun = autoNotifyDoc.Getitemvalue("schedule")
			hourNow = Hour (Now)
			If ( CInt ( hourToRun (0) ) = hourNow ) Then
				' run '
				If ( sendNotices ( autoNotifyDoc ) ) Then
					Call agentLog.LogAction ( autoNotifyDoc.Getitemvalue("NoticeName") & " sent")
				Else
					Call agentLog.LogAction ( autoNotifyDoc.Getitemvalue("NoticeName") & " FAILED")
				End If
			End If
		End If
	End If

	Set autoNotifyDoc = autoNotifyView.Getnextdocument(autoNotifyDoc)
Wend
Call agentLog.LogAction ( "Completed" )

exiting:
	Exit Sub
errorhandler:' report all errors in a messagebox '
	reason = "Error #" & CStr (Err) & " (" &amp; Error & ") on line " & CStr (Erl)
	MessageBox reason, 16, "Error"
	Call agentLog.LogAction ( reason )
	Resume exiting ' transfers control to the exiting label

End Sub

The actual notification builds off the values from the configuration document. At MWLUG, speakers recommended making sure to use functions instead of subroutines, partly because functions return a value and partly for forward compatible with other programming languages. So, my sendNotices function is a boolean, indicating success or failure.

The simplest, yet most powerful part of the script is the application of the querystring. By using that, I could create dozens of notifications from a single view, saving myself disk space by avoiding unnecessary view indices.

Ariwan’s great contribution to the basic agent that made it so useful in this configurable design was the use of columnvalues. The agent simply spits out the contents of the view, populating the message with the details of the document regardless of which fields are used. I’d never thought of doing that!

You’ll notice that in the loop, we get a handle to the nextdoc before processing. If the document would be removed from the view by marking one of the fields “Yes” and saving the document, we need to already have a handle to the next document. If we don’t do that, the view won’t be able to find the next document by referring to the current document, as it has no position in the view any more.

Now, since I want each notification to be processed even if I encounter some errors, I added error-handling in the function as well. If I had not, an error would bubble up to the Initialize routine and stop my agent. This way, it only stops that particular notification, but continues to the next one.

Function sendNotices ( autoNotifyDoc As NotesDocument ) As Boolean
Dim viewName As Variant
Dim recipientGroup As Variant
Dim subjectLine As Variant
Dim introText As Variant
Dim queryString As Variant
Dim flagField As Variant

Dim workingView As NotesView
Dim workingCollection As NotesDocumentCollection
Dim doc As NotesDocument
Dim nextdoc As NotesDocument
Dim memo As NotesDocument
Dim body As NotesRichTextItem
Dim reason As String
Dim count As Integer

sendNotices = false

' get viewName '
viewName = autoNotifyDoc.Getitemvalue("viewName" )
Set workingView = thisdb.Getview ( viewName (0) )
' apply query string, if there is one '
queryString = autoNotifyDoc.Getitemvalue("queryString" )
If ( queryString (0) <> "" ) Then
	Call workingView.Ftsearch(queryString(0), 0)
End If

Set doc = workingView.Getfirstdocument()

count = 0

Set memo = thisdb.Createdocument()
Set body = memo.Createrichtextitem("Body")
memo.Principal = thisdb.Title

' copy the introductory text from the autoNotify document into the email '
introText = autoNotifyDoc.Getitemvalue("introText" )
Call body.Appendtext ( introText(0) )
Call body.Addnewline(2)

While Not doc Is Nothing
	Set nextdoc = workingView.Getnextdocument(doc)
	count = count + 1
	Call body.Appendtext( CStr ( count ) & ".")
	Call body.Addtab(1)
	ForAll thing In doc.Columnvalues
		Call body.Appendtext( thing )
		Call body.Addtab(1)
	End ForAll
	Call body.Appenddoclink(doc, "Open the doc", "Link")
	Call body.Addnewline(1)

	' if field to mark, then modify field and save doc '
	flagField = autoNotifyDoc.Getitemvalue("flagField" )
	If ( Trim ( flagField (0) ) <> "" ) Then
		Call agentLog.LogAction ( flagField (0) & " field #" & CStr ( count ) )
		Call doc.ReplaceItemValue ( flagField (0), "Yes" )
		Call doc.Save ( True, False )
	End If

	Set doc = nextdoc

Wend

subjectLine = autoNotifyDoc.Getitemvalue("subjectLine" )
memo.Subject = CStr (count) & " " & subjectLine (0)
recipientGroup = autoNotifyDoc.Getitemvalue("recipientGroup" )
Call memo.Send(False, DetermineKeyword ( recipientGroup(0)) )

sendNotices = True

exiting:
	Exit Function
errorhandler:' report all errors in a messagebox '
	reason = "Error #" & CStr (Err) & " (" & Error & ") on line " & CStr (Erl)
	MessageBox reason, 16, "Error"
	Call agentLog.LogAction ( reason )
	Resume exiting ' transfers control to the exiting label '

End Function

It’s not quite perfect because if the server is down, it won’t run the notification later. I might take that into account in a future version, since many our project servers are in locations where power may not always be 24×7. Similarly, if someone puts too many notifications to run at the same time, the agent could time out, failing to run all of them.

Hopefully, this exercise proves useful to someone else. I can’t believe I spent more than a decade constantly re-writing the same code when I could have saved myself considerable time by just creating a customizable, reusable piece of code back in the day. Live and learn!




---------------------
http://lostinxpages.com/2014/09/25/configurable-notification-agent-in-oldnotes/
Sep 25, 2014
6 hits



Recent Blog Posts
5
A more direct way of creating an Outlook mail item from the Notes client
Wed, Nov 1st 2017 3:54p   David Navarre
A
5
Sending an automated mail using Outlook from a Notes agent
Tue, Sep 12th 2017 11:14p   David Navarre
A
3
Breweries and tap rooms for #MWLUG
Sat, Jul 29th 2017 4:49p   David Navarre
A
2
So where can I go for dinner near #MWLUG?
Thu, Jul 27th 2017 10:02p   David Navarre
A
3
Creating a meeting notice in Outlook from the Notes client
Fri, Jun 23rd 2017 5:23p   David Navarre
A
2
Getting email addresses from the Notes address book
Wed, Jun 21st 2017 5:50p   David Navarre
A
9
Progammatically opening a mailto link from the Notes client
Fri, Jun 2nd 2017 9:35p   David Navarre
A
3
What good is the internet of things to people who don’t have internet?
Tue, Feb 21st 2017 8:36p   David Navarre
A




Created and Maintained by Yancy Lent - About - Planet Lotus Blog - Advertising - Mobile Edition