bookmark_borderindispensable tip: how to bind domino form to a xPage

if you want to keep your design straightforward use as Form in the data binding section the same name as the xPage name:

this will allow you to open a document created with this xPage without knowing it’s corresponding xPage with the following URL command:

/path/to/your/db.nsf/$$OpenDominoDocument.xsp?documentId=UNIVERSALID

If you do it this way you do not even need to bind a notes form to the corresponding xPage:


Drawbacks?

there is… you cannot use the Data view to drag&drop the fields from the Domino form onto the xPage:

there are no fields defined the data view could provide you with.
and you have to set all the data binding yourself: add the fieldName of the field where you want to store the value of this “component” manually (just type it in!`)

bookmark_borderfinal solution preventing validators to kick-in when not required

remember? it was first days, then hours, okay, today hours as well.. but I think with some help of you guys out there blogging also I found the final solution, and the times do get better and better, as I get more and more knowledge about the whole thing.

summary:

  • use the PhaseListener to catch the phase: PROCESS_VALIDATIONS
  • add some code to the beforePhase event (to disable the validators for all but the required events)
  • add some code to the afterPhase event (to enable the validators again)
  • add a recursive method which will enable/disable (ie toggle) all available validators
  • add event parameters to your buttons where you DO WANT TO trigger the validators

PhaseListener updates:

  • add this code in the beforePhase method, it will disable the validators if no event parameters (name=requireValidation, value=true) are present

FacesContext facesContext = event.getFacesContext();
try {
    // handle validators
    if (event.getPhaseId().equals(PhaseId.PROCESS_VALIDATIONS)) {
// add validators if required
// i use:    
//CustomValidator v = new CustomValidator();
//v.handleValidators();

        // if not submitted via save button disable validators
        // get eventHandlerClientId
        String eventHandlerClientId = (String) facesContext
                .getExternalContext().getRequestParameterMap().get(
                        “$$xspsubmitid”);
        // extract eventHandlerId
        String eventHandlerId = eventHandlerClientId.substring(
                eventHandlerClientId.lastIndexOf(“:”) + 1,
                eventHandlerClientId.length());
        // get eventHandler “component”
        UIEventHandler eventHandler = (UIEventHandler) Util
                .findComponent(facesContext.getViewRoot(),
                        eventHandlerId);

        // find the parameters set via Edit Event parameters on the
        // Events page
        boolean skipValidation = true;
        List<Parameter> parameters = eventHandler.getParameters();
        if (null != parameters) {
            Iterator<Parameter> iterator = parameters.iterator();

            while (iterator.hasNext()) {
                Parameter par = iterator.next();
                if (par.getName().equals(“requireValidation”)
                        && par.getValue().equals(“true”)) {
                    skipValidation = false;
                    break;
                }
            }
        }
        if (skipValidation) {
            toggleValidators(facesContext.getViewRoot(), true);
        }

    }
} catch (Exception e) {
    // default disable validations for all other events which are not
    // “requireValidation=true” and which might throw an error while trying to get their event handler
    toggleValidators(facesContext.getViewRoot(), true);
}

  • add this code to the afterPhase, it will enable the validators again:

if (event.getPhaseId().equals(PhaseId.PROCESS_VALIDATIONS)) {
    FacesContext facesContext = event.getFacesContext();
    toggleValidators(facesContext.getViewRoot(), false);
}

  • add this method, it will recursively find all components where validators might be existing and enables/disables them. This method is most likely candidate for speed improvements: You could use as parent component the actual tab (for tabbed panels) being displayed, but then you would have to track which one is selected, I prefer to just run it on the whole tree to make it simple for now
private void toggleValidators(UIComponent parent, boolean toggle) {

    List<UIComponent> children = parent.getChildren();
    Iterator<UIComponent> iterator = children.iterator();
    while (iterator.hasNext()) {
        UIComponent child = iterator.next();
        if (child instanceof javax.faces.component.UIInput) {
            if (child instanceof com.ibm.xsp.component.UIInputEx) {
                UIInputEx input = (UIInputEx) child;
                input.setDisableValidators(toggle);
                if (0 < child.getChildCount()) {
                    toggleValidators(child, toggle);
                }
            } else if (child instanceof com.ibm.xsp.component.UISelectOneEx) {
                // radio/checkbox/combobox etc.
                UISelectOneEx input = (UISelectOneEx) child;
                input.setDisableValidators(toggle);
                if (0 < child.getChildCount()) {
                    toggleValidators(child, toggle);
                }
            }
        } else {
            if (0 < child.getChildCount()) {
                toggleValidators(child, toggle);
            }
        }
    }
}

  • add an event parameter to all your buttons where you do want to trigger the validation

et voilà.. you have a nice working form where validators are only triggered when really required (ie. upon save)!
no more stupid validations kicking-in when switching tabs, clicking buttons, refreshing via combo boxes panels etc…
as for the “Save as draft” button: I would recommend that you add a field on the form “flagIsDraft” so that you can take care of not postprocessing such documents
Kudos go to Tommy Valand and weihang chen, their “blogs” helped me get my way through!

bookmark_borderspeeding up XPages execution AND development

to speed up execution you should native Java code whereever possible!!!!!!!!! (should I add some more explanation marks???????) DID YOU GET THIS

okay.. fun aside… let’s get down to the hardcore stuff:

let’s assume you created a helper class doing some nice stuff for you on your XPage (such as logging to another place than is possible with DebugToolbar)
let’s assume your Logger is in the package com.yourcompanyname.xpages.utilities

now if you want to log the action of a button within an XPage you would need to add this code:

var Logger:com.yourcompanyname.xpages.utilities.Logger = new com.yourcompanyname.xpages.utilities.Logger()
Logger.log(“your message”)

what you might have forgotten though (actually you didn’t cause you just used it: JavaScript!)

so simply create a SSJS library which you include on every page you create.

add this line:
var Logger: com.yourcompanyname.xpages.utilities.Logger  = new  com.yourcompanyname.xpages.utilities.Logger();

you can then in your button simply log the message like this:

Logger.log(“your message”)

doesn’t that save you endless typing/correcting/testing etc?

think of the SSJS Library as a “proxy” to your native Java classes!

bookmark_bordersick of adding hundres of standard validators in a huge XPage?

I am!

do they, who the hell are they anyway?, really expect you to add on 50 to 100 fields with all those clumsy interface buttons the normal validators?
examples? let’s count the steps it takes me to add a validator:
1. select the field in the XPage
2. open properties view
3. “enlarge” (or drag it upwards) the properties view (cause it’s always to slim in height)
4. click “All properties”
5. scroll down to data or click these on the first to sections:

6. click on the “validators” which makes some equally small buttons visible
7. click the plus button to add a validator:

8. select the validator you want to apply
9.-x. add the required property values

Now repeat that for about 50 or more fields on an XPage!!! I don’t think your customer is happy to pay your for this stupid/error prone clumsy work.

well I don’t know about you.. but I want to keep as much code centralized as I can. I am such a lazy person. So I tried to follow up on our method we had in our plain old Notes framework: field validation configured via setup documents!

So I had to figure out how custom validators work. This journey also took some hours, but within a day I got all working. And this included getting the JSF phases to understand (see my other post about that topic)

Here the result:

The display will be handled by the errorMessage/errorMessages control: I tend to think of the one which is connected to the field as the “summary” message (reason is it should no distract the look and feel of your input form too much), and the ones collecting all messages as the “detail” messages, but I think its actually the other way around

Code your validator:

public class CustomValidator implements Validator {

public void validate(FacesContext facesContext, UIComponent field,
Object arg) throws ValidatorException {
String value = arg.toString();

// add here your validation conditions for which a message should be
// displayed and then
// create a FacesMessage which then will show up next to your field in
// the
String m1 = “ups something went wrong: summary”;
String m2 = “ups something went wrong: detail”;
FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, m1, m2);

throw new ValidatorException(msg);
}
}

DO NOT HANDLE THE EXCEPTION!!! 
first I had a try/catch block installed.. but what happened? the messages showed up and yet the document could be save anyway!!! what a disaster… so get rid of the try/catch and let the ValidatorException be thrown and handled by the servlet engine.

faces-config.xml:

  <validator>
    <validator-id>idOfYourOwnValidator</validator-id>
    <validator-class>com.abb.xpages.framework.CustomValidator</validator-class>
  </validator>

we are done! wait!!! and how do you get this validator applied? wasn’t that the whole point? not having to repeat all those 10 steps over and over again?

well… please read this post about the phase-listener:
http://in-mood.blogspot.ch/2012/09/jsf-phases-in-xpages.html

there you add a condition which will in the beforeValidations phase add all the required validators:

add this to your phase-listener:

if (event.getPhaseId().equals(PhaseId.PROCESS_VALIDATIONS)) { CustomValidator v = new CustomValidator(); v.addValidators(); }

add this to your CustomValidator:
public void addValidators(){
// repeat this step (maybe in a proper loop for all fields which require the validator
// Util is a class I created with an abstract method “findComponent”, abstract such that I don’t
// have to always instantiate it whereever I use it

field = (UIInput) Util.findComponent(FacesContext
.getCurrentInstance().getViewRoot(),
“fieldNameOnTheXPage”);

// add your validator
Validator[] validators = field.getValidators();
// make sure you only add the validator once, otherwise the
// messages control will display one
// message for every roundtrip the page has done to the server!
if (0 == validators.length) {
field.addValidator(facesContext.getApplication()
.createValidator(“idOfYourOwnValidator“));
}

for single instances you can of course add it manually as well (such as for testing if it actually works:)

now there is one minor drawback in this whole process:
on my local machine the “createValidator” won’t work due to security issues.
on our test server it works, I assume it has to do with a grant * something statement I once added to the java.policy in the jvmlibsecurity directory of the program directory

update:
Add this to the grant section:
permission java.lang.RuntimePermission “getClassLoader”;

I am actually now “finetuning” the “addValidators” as I could not yet figure out how to create the “required” Validator myself such that it adds the message to the control instead of alerting it in the client!

bookmark_borderJSF phases in XPages

I was trying to setup a system to handle “validation” via setup documents
the normal validators which can be set up directly on each field would not help much (or be too much work to implement)

I first tried a simple method: isDocValid returning true/false and adding JSF Messages like following:

String m1 = “summary: ups something went wrong”;
String m2 = “detail: ups something went wrong”;
msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, m1, m2);
facesContext.addMessage(field.getClientId(facesContext), msg);

I would call this methid in the querySaveEvent of the XPage, and it seemed (at least for new documents) to work well.. until I opened a document from a view, and oh wonder (maybe it’s a feature and not a bug) the querySaveDocument event was not even triggered…

That was bad news: I also had a “save as draft” button which would let the user return to the document, but if the validation then would fail?

nope.. I started looking for another way…

so I talked to a guy who has a LOT, I mean a LOOOOOOOOOOOOOT, of JSF experience.
With his help and some from my best friend (google) I did the following:

created a phase listener which logged all events (great for debugging, see those “immediate” events)
a very good article about the JSF phases can be found here:
http://www.ibm.com/developerworks/library/j-jsf3/
a MUST read for any serious XPages developer with little or no JSF experience!!

so then thanks to the phase listener I could see the how all phases process.

and now I immediately had also a way to “plugin” my custom validators properly (more on that in another post)

so here what I did for the phase listener:
Java class:

public class PhaseListener implements javax.faces.event.PhaseListener {

public void beforePhase(PhaseEvent event) {
// log your beforePhase with event.getPhaseId()
}

public void afterPhase(PhaseEvent event) {
// log your afterPhase with event.getPhaseId()
}
}

faces-config.xml:
  <lifecycle>
    <phase-listener>package.of.your.PhaseListener</phase-listener>
  </lifecycle>

now you can add simple additional code in any phase (before or after)
just use something like:

if (event.getPhaseId().equals(PhaseId.PROCESS_VALIDATIONS)) {
// run your code
}

PhaseId. (dot control space) will list all the CONSTANTS to check for any of the phases

bookmark_borderdon’t use “finally” in your Java code for XPages

since I have no started digging deeper into the XPages mysteries I want to share some of my learnings.

As most of you know: if you use Java in Lotus Notes/Domino you have to take care that you recycle the Notes objects you instantiated (session, database, document etc.)

Java has a nice feature called “finally”. If you use a try/catch block (which I do to log all errors happening, so that I can follow up and fix them) you can also add the “finally” block at the end..

It could serve pretty well for incinerating (I bought that term form some other blogger) the Notes objects…

But beware: I created a class which should be called upon the querySaveDocument event. As soon as I added the finally block the page would crash, most of the times so bad that my whole Notes/Designer went down too…

After hours (again hours!!! can you imagine what my week looks like???) putting log code moving it down one by one… until I reached the try block, nothing worked anymore…

but luck I figured: why not remove the finally block.. and miraculously the XPage could be displayed again

I don’t know what/why exactly it crashed and if you always should not use the finally block, try it.. if your system crashes, remove it and handle it in another way

bookmark_borderrequestScope mystery solved

again RTFM!!!! but hey… the FM not always tells you what you want to know!

Might that be the reason why we developers tend to NRTFM?

dunno..

anyhow… after DAYS of testing / searching (is it called googling nowadays?) / changing code and iterating a (felt) thousand times…

I finally came accross the solution how to “persist” the requestScope from one xPage to another…

First (I hope I am not wrong with this) a bit of background:

The parameters set in the requestScope would (normally) get submitted via the URL (in a GET request). As those JSF (and xPages) mostly work via POST request we (unless we use nice tools, such as the TCP Monitor in the designer!) never really see them. That’s one of the reasons so many Domino developers struggle to get the requestScope working. We cannot really debug it properly.

Thanks to TCP Monitor and a friend helping me, we finally figured:

After an xPage has been submitted and the navigation rule would redirect it to another page this redirection was a request to the client browser!

Imagine: The server tells the browser: please ask now for page xyz.xsp

And with the little background above you can understand that the server didn’t tell the browser which requestParameters it should transmit as well, alas they would be (ARE!!!) lost.

But as i said.. I did a lot of research on this and I found the following setting: (You find it under the “Package explorer” view in the designer

if you turn this feature off the server does not ask the browser for asking the new page but the server actually redirects himself to the new page and hence will preserve the requestScope values….

So you can actually have the dimmwitted example of two xPages where on one page you enter the name and submit it, and the second page will greet you with “Hello yourname” works!

I for myself will use this feature to tell my xpView.xsp (the one which handles all views in my db) will know which view it has to display after a document has been submitted (at least if nothing else has been defined)

bookmark_borderhave you ever wondered if i might be possible to make a custom control look nicer in the xPage design view?

It can be done! And it’s actually not even that complicated.

Find the instructions here:
http://www-10.lotus.com/ldd/ddwiki.nsf/dx/16102009115724SCAEXA.htm

or read on…

there is this nice Design Definition property on all custom controls (starting 8.5.3 I think):

if you add some xPage source code to it (tip: create a new xpage the way you would like to look this custom control in the design view and copy & paste its source code here)

it will later on in the actual xPage look like this:

in this example i used is as a way to “document” some settings required to make it work properly.

But of course you could, if you have, for a company framework, also paste in a picture of a standard menu, the footer or the header of your pages.

then while designing the xPage you get a better feeling on how the page will look like later.

and it gets even better.. just read an article, that this design definition is “dynamic”, means you can actually have the custom control look different, ie. depending on custom properties you set.
Read this article: http://dontpanic82.blogspot.ch/2010/01/xpages-using-powerful-design-definition.html

bookmark_borderExtension Library installation pains

okay okay.. I know.. RTFM

but hey.. we are developers, we know what we are doing, right? 😉

How it all began:
I was first trying to install the Extension Library on my desktop manually. and of course I installed the Domino part instead of the Designer part 🙁

I then considered following those instructions here:
http://www-10.lotus.com/ldd/ddwiki.nsf/dx/Installing_the_upgrade_pack_on_Domino_Designer_and_Notes_ddxl853

but again RTFM…

I mean c’mon… can’t be that complicated.

It can!!! After 2 days of trying (installing/uninstalling both LN/FP/UpgradePack)  to get this upgrade pack installed I almost gave up.

But then I took a quiet moment and told me: one last time.

Interestingly the modules had been installed in previous attemps, only I could not load any xPage with modules from the extension library as something didn’t install 100% correctly! I always got the Error 500 command not handled exception.

With those features installed… I could finally figure out the exact filenames to check and remove manually any directory/file which was still in the mentioned (see link above) directories. If Windows 7 search would have done a better job I wouldn’t have needed those exact filenames though, maybe some of my anger goes to MS.

so here is how I found the exact names:

Files searched:
  • org.apache.wink…
  • com.ibm.domino.das…
  • com.ibm.wink…
  • com.ibm.xsp.extlib…

directories searched:

  • frameworksharedeclipsefeatures
  • frameworksharedeclipseplugins
  • datadominoworkspaceapplicationseclipsefeatures
  • datadominoworkspaceapplicationseclipseplugins
  • dataworkspaceapplicationseclipsefeatures
  • dataworkspaceapplicationseclipseplugins

So after I had figured out the names I had to look for and manually deleted them (also in the DataWorkspace and DataDominoWorkspace directory), the upgrade pack installed just fine…
yours
Michael