bookmark_borderINDIP/CRYFH: having legacy Lotus Script code do your work!

In our company we do have a wonderful, flexible, proven, stable own-built workflow engine, but it is written in Lotus Script code. baah..

I didn’t want to rewrite the whole thing in Java…

But you may now think: hey why does he not run an agent?

I tried, and I failed, how else!!! Always the way I understand things, they will never really work!

Luckily I then I found Kathy Browns article how to do it and it works!!!

Solution:

  • put some value into the NotesDocument to “control” your logic in the LS agent
  • run the agent with the document as parameter
  • write some field in the agent into your document: NO NEED TO SAVE THE DOCUMENT!!!
  • read the result from you NotesDocument in your xPage code and process it
My mistake was: I tried to update a field which was visible on the xPage, and here my approach failed. 
Or could I manually “refresh” the xPage after the agent has run? Seems to be maybe a “timing” issue, cause the value is there, it’s only just not displayed in the field on the xPage. Anyone?

How we use this technique with our workflow engine:
The engine can require a comment to be given for certain target state. But the target state I don’t know yet in the xPage, cause this logic is handled in LS. But with the technique above I can create an agent provide the target action (reject/approve or something else), calculate the target state and find out if for that state a comment is required. If so I can then call a dialog in the xPage where the user can enter his comment. In the agent which runs then, to process the workflow, I then simply read this comment field and process it. In our case it’s written to a workflow log and also included in the notification to the approver of the next state
Nathan: did you read my comment to your comment? I bow to you..

bookmark_borderunQUINDIPping QUINDIP and other accronyms

according to Tim Tripcony (read the comment on this blog) quindip means confusion, I am now trying to unConfuse you about the confusion I created with my accronyms I use 
  • INDIP: INDispensabletIP (those ones which I deem very important in any xPages developers knowledge bag)
  • QUINDIP: QUickINDIP (those ones I deem quickly explained, 2min to read,  understand and implement)
  • FRULE: FRUstratedLearningExpierence (things I learned the hard way (shall I repeat how hard?), ie. it took me hours/days to get the hang of it and mostly in the end it was so obvious only I lacked some very basic knowledge in the first place)
  • CRYFH: CRYForHelp (when I have no clue anymore how to proceed and I need your input)
  • YOUFEB: YOUrFEedBack required (please gimme comments, ask questions what you want me to blog about etc)
  • DYHOP: DoYouHaveOtherProposals for accronyms? 😉
ups.. something very important I almost forgot…

let the game begin (provide your ideas in the comments): any idea what the anagram of in-mood is?

well.. a hint: in-mood is the anagram of the actual word. When I had my own company few years ago, I was so in (good) mood about stuff I was doing that time.. that I figured: great this will be my company name!

Unfortunately I cannot offer anything as a price to the winner besides maybe some special mentioning in a blog entry or my personal effort trying to help to solve an interesting xPage problem!

bookmark_borderBIG THANK YOU to all my readers

A big “thank you” to all of you. 

You helped raise attention to my blog (as of 2013-04-03 this blog is just under the top 50 of the past 5 days in this list) and it seems some important people in the xPages community do read my blog (at least once in a while 😉 )

I can only assume that the content combined with my, hopefully funny, style to write are responsible for the hits I get.

I don’t know why, but somehow my blog seems to hit some pain points out there.

Maybe some of you might now already why I created this blog:
xPages are a great technology, BUT it’s really hard to find decent documentation.
Everything is POORLY documented and you need to collect bits and pieces all over the web to get some stuff going properly and this is frustrating and takes literally ages!

The xPages TOP CRACKS out there doing some interesting blogging: they know their stuff, too good actually. Sometimes they miss the important little things, the little things which drive us newbies crazy because we don’t get the stuff working.

Example:
The repeat control. Has anyone of you ever wondered why the “Collection name” is called collection name?
I always thought in Lotus Script terms of a collection.
It took me a while to understand that the actual “meaning” of this property was a handle to the single record/data/document within the collection! So why not call this stupid property something like “entity handle” or “entity name” or “single data entry handle”.. or something we newbies can understand well at once!

Take this example video which I think is great, but it has a minor glitch and no-one seems to care 😉
Check out min 1:13. He says: we add a collection name “rows” (plural!) and then he enters anyway “row” (singular). If you don’t pay attention you will never get it to work. I had to zoom in (ie. fullscreen until I figured out where I made the mistake!)

Don’t get me wrong:
I’m not accusing anyone of anything here! I just noticed on my learning way that I was over and over and over and over (how many times shall I repeat?) not really happy with the information I was looking for.

I just think that the beginner xPages developer needs to know also the little details. An attribute wrongly activated/selected etc.. and nothing works. And the error messages you do get, com’on.. you all know it: THEY ARE USELESS!!! It takes you again (shall I repeat?) HOURS to figure out where the actual problem is. Thankfully I did figure out how to debug Java code and this makes my life a whole lot easier.
But again: why does IBM not propagate this great feature more openly??? I would expect it even in the help of the designer!

Summary:
I think I had a great, difficult and bumpy but yet steep, learning curve in the past 6 months, way more to go I assume. But the knowledge I have now is quite sufficient to be a decent xPages developer.

What I expect from you guys out there:
Give me feedback!!!!! Write comments! Ask me questions and I will try to blog about more interesting things.

THANKS FOR YOUR ATTENTION

bookmark_borderQUINDIP: Solved! accessing fields before page is being displayed with Java!

Use the beforeRenderResponse event to modify fields before they are rendered and displayed on the browser!

Thanks to the phase listener implementation in our framework I could also solve the following issue:

Modify fields (set value, set read only, set hide) before the page is displayed in the browser, ie. it should arrive “properly” displayed (what else 😉 )

Up until now I didn’t quite now when to call my Bean to do all the stuff above. Sometimes the fields were not available in the view hierarchy yet, sometimes it was too late and the page already rendered.

If you use it this way you can apply all those changes (even for new documents!):

Result:

The “read” only fields are only read only for employees of our company, as is the GEID (which is otherwise completely hidden)


bookmark_borderQUINDIP: SOLVED!!! that damn DominoDocument IS a WILD AND MAGICAL thing!!!

Wow…

So here’s what I learned:

notes objects usually can’t be serialized. For some stupid reason I came accross the DominoDocument.wrap method and thought: let’s give it a try!! You bet: You create a “manual” DominoDocument with it and it can be serialized.

Exactly this technique now helps me to dynamically display RT fields (actually MIME entities to be correct so far, but I think it’ll work for RT as well) as tooltips:

Resulting code:

<xe:tooltip id=”tooltip4″ dynamicContent=”true” for=”someLabel”>
<xp:inputRichText id=”inputRichText1″
readonly=”true”>
<xp:this.value><![CDATA[#{javascript:doc = database.getDocumentByUNID(‘someUNIDToADocumentContainingTheBodyField’); 
dominoDoc = com.ibm.xsp.model.domino.wrapped.DominoDocument.wrap(null, doc, null, null, false, null, null);
dominoDoc.getValue(‘Body’)}]]></xp:this.value>
</xp:inputRichText>
</xe:tooltip>


bookmark_borderCRYFH: how can I bind a richtext field with javascript?

Maybe it helps to have some knowledgeable readers, let’s see.

What I would like to achieve:
Have tooltips displaying RichText fields (defined as “help documents”).

This works for just 1 tooltip: I define a document data source and simply bind the RT field on the xPage to the docSource.Body, voilà!

Now:
Of course I do have multiple places where I would like to display such a fantastic tooltip!

Tooltips indeed are “dynamic”.

Using this code I get the subject from the help document back no problem:

database.getDocumentByUNID(‘someUNID’).getItemValue(‘Subject’)

using the same code (trying to retrieve the RT item) I simply get back the item’s name!!

What do I miss?


What I tried, but also didn’t work: to change the docSource dynamically, ie. having the tooltip change the UNID of the docSource and then simply bind as described above with docSource.Body. But I couldn’t manage to get the dynamic tooltip to “refresh” the docSource.


Any ideas?


CRYForHelp

bookmark_borderQUINDIP: format your custom type aheads properly

Did you read my blogs about cool type ahead features? really cool type-ahead and making type-ahead easy as pie.

Here’s the sequel on how to make the “custom” type-ahead also look really nice.

Java code to create custom type-ahead:

StringBuffer sb = new StringBuffer(“”);
StringBuffer sbNames = new StringBuffer(“”);
Session session = (Session)DominoUtils.getCurrentSession();
Database db = (Database) DominoUtils.getCurrentDatabase();
View view = db.getView(“lupCountriesByUNID”);

// apply the search, this can be anything, looking up by key and NOT forcing a match
// or an FT search, we use for different amount of characters different fields to search in
// 2 characters = ISO language code, 3 characters = ISO currency code etc.
view.FTSearch(“*” + searchValue + “*”, 0);

Document doc = view.getFirstDocument();
sb.append(“<UL>”);
boolean found = false;
while(null != doc ){
found = true;
sb.append(“<LI><TABLE class=”receivingCountry“><TR class=”level” + doc.getItemValueString(“Level”) + “”>”);
sb.append(“<TD class=”recCountryLevel“><span class=”informal”>Level: ” + doc.getItemValueString(“Level”) + “</span></TD>” );
sb.append(“<TD class=”recCountryName“>” + doc.getItemValueString(“R_CountryName”)+ “</TD>”);
sb.append(“<TD class=”recCountryDesc“><span class=”informal”>” + doc.getItemValueString(“R_CountryDesc”)+ “</span></TD>”); 
sb.append(“</TR></TABLE></LI>”);

doc = view.getNextDocument(doc);
}

if( !found){
sb.append(“<LI><span class=”informal”>no result</span></LI>” );
}
sb.append(“</UL>”);
return sb.toString();

CSS applied:

.receivingCountry{
table-layout: fixed; /* in my case important to make the sugguestions fit */
width: 380px; /* in my case important to make the sugguestions fit */
border-collapse: collapse; /* needed to make the space go away */
border: 1px solid #DDDDDD;
padding: 0;
margin: 0;
white-space: normal; /* in my case very important to make the table cells wrap */
}

.tundra .dijitMenuItem {
border: 0;
margin: 0;
padding: 0; /* needed to get rid of the space between items */
background-color: transparent; /* needed to get rid of the gray oneUITheme background */
}

.level1 {
background-color: #FFCC66;
}
.level2 {
background-color: #66CCFF;
}

.recCountryName{
vertical-align: top;
width: 200px;
}

.recCountryLevel{
vertical-align: top;
width: 80px;
}

.recCountryDesc{
vertical-align: top;
width: 200px;
}

Result:


bookmark_borderQUINDIP: how to set field values with java (or DominoDocument the magic animal)

Old approach:

   XspInputText field = (XspInputText) StandardUtil.findComponent(facesContext .getViewRoot(), “countryName”);

The annoying thing about this approach: You never know exactly which class the component has, ie. a “read only” field is not XspInputText etc., and thus you cannot just use this approach really transparently.

New approach:

DominoDocument dominoDoc = StandardUtil.getDominoDocument();
dominoDoc.replaceItemValue(“editableField”, new Date().toString());

It works for editable/hidden/disabled/readOnly fields!!!

And the best thing is: you do not even need to know the fields xPage name anymore! 

You only care about set in the binding property. This in effect speeds up development a lot, cause I do not need to check/modify field names in 2 places anymore.

addendum:
the getDominoDocument works like this:

DominoDocument dominoDoc = (DominoDocument) JSFConnector
.getVariableValue(“currentDocument”);
return dominoDoc;

and the JSFConnector you will find here (kudos to Karsten Lehmann)

bookmark_borderFRULE: DominoDocument is a wild animal

Here’s the story:

We needed multiple “dynamic tables” in our projects. Thanks to Russel Maher I had something to start off with.

Too bad his solution worked on the “backend” document. After I had managed to get a “container” around his solution another problem popped up: Save conflicts.

I couldn’t figure out why this happened. I could only imagine it was some sort of “timing issue”. In his solution upon a save a cleaning of the table is done. This merely renames the fields such that they order properly (in case some rows had been deleted). In this process the document was saved in the end. Cause I had several such “tables” to handle the saves of each of those kind of interfered and created those save conflicts.

But how could I solve this?

After a LOT, you should by the time now (if you followed my blog for a while) know what a LOT means!!! Enough to almost give up! Luckily I didn’t.

I figured: if I could only “reorder/rename” those items in the DominoDocument, then those changes would “magically” be transferred to the document upon the actual save. This is all thanks to the architecture of JSF, the data store etc.. (don’t ask me details, I am just about to get a hang on this one!)

So while I tried to get this working I always came accross this thing here.

As I mentioned in that other blog: that guy reporting this error on the Lotus forum had mentioned it happened when trying to put a NULL value vector somewhere.

After a LOT of testing I found: this is exactly what happened in my case!!! I was trying to copy values from date fields over (in order to rename them). But date fields which have no date simply have a NULL in them.

So the final solution was pretty simple: Just check if that item is available or has a NULL value.

Now my solution works smooothly: no more save conflicts, just the way I imagined!

Here’s how it could look like: