bookmark_borderquindip: make accessing events/properties faster

Are you annoyed having to click x-times to get to your properties/events?

I am…

but how about this:

Detach the properties and events views and place them on a separate monitor so that you always have them available. I use an external screen and have the properties/events views detached on my internal LCD.

right click header of the view in designer and select “Detached”

This way I don’t bother resizing the panel on the bottom every 10 seconds. I click a field or any other element and then I turn my head to look at my secondary screen and have immediate access to all my properties/events I need…

this would be even cooler if it would work with <alt><tab> but it doesn’t! (->IBM: do you listen/read?)

bookmark_borderquindip: more mysteries about scoped variables solved

I don’t know about you.. I was for quite some time not quite getting the hang on “requestScope” and “viewScope” variables.

I did understand the “sessionScope” and the “applicationScope” variables.

after a few weeks of playing around with xPages, getting quite deep into JSF  framework etc, I had today finally (maybe only to me) a stupid revelation:

why a requestScope and a viewScope variable is called this way, and thus understand properly how it works

requestScope
Say you have a webpage open and you now click a button (ie. to save a document). The page (or parts of it) are sent back to the server (mostly via post, sometimes via a get HTTP request). When you in this button now set a requestScope variable you can actually use this value in the next page to be opened. I personally will use this to detect which view is most likely to be opened after a document has been submitted.

There is a little tweek to be made to get this working properly, see my other post.

viewScope
the viewScope is only valid as long as you stay on the same page! and if you know that an xPage is essentially (in JSF terms) a “view” you now also know the reason why it’s called a “viewScope” variable.

Use case why I would use  viewScope variable I don’t really have, but you could use it example to track how many times a user has refreshed the current webpage, say to switch between tabs etc. This could help you to track down bottlenecks in your layout.

bookmark_borderyour turn!

What are your most urgent issues regarding development with XPages?

let me know and write a comment.

Why I would like to know?

Well in the past few weeks when I tried to get the XPages framework for our company up and running, I spent countless hours doing research on the internet. And mostly I either didn’t find the information I was looking for at all, or it took me too long and I had to “syndicate” bits and pieces from various sources into a model which would work for me…

just take the example of “scoped variables”. In every XPage session/training I attended so far they tell you about the application/session/view/request scope variables.

No-one can really tell you exactly what the difference between view and request scope variable is.

and No-one can actually tell you how you get the request scope variables to work! Most XPage developers think they don’t work at all.

The reason for this is: we (yes, I include myself as well into that group of people) lack a good amount of necessary background knowledge how HTTP and JSF really work.

As soon as you get the chance to talk to certain people who know more about those topics, you start to realize things and suddenly the puzzle pieces fit together and form a quite nice image.

yours

Michael

bookmark_borderindip: inject JS into xPage dynamically

wow…

so… as you can see.. I was struggling lately a lot with how I could my validation work the way I want it…

I would like to setup some configuration documents where I can define certain criteria upon which my documents (ie. xPages) are validated….

so the simple (required/threshold/regex pattern) ones I got (at least as a prototype) working…

what was still missing was a way to inject “logic” into my validation via setup document..

With LotusScript you could simply use “Evaluate” and the code provided in the setup document would be “evaluated” (ie executed)..

But how the hell can you achieve something similar in xPages? Well working with JavaScript it would be a breeze… as there exists also an “eval” statement.

But as I was/am trying to get our framework working based as much as I can on Java language some other mechanism should be applied.

As I cannot just simply inject some code into a running (already compiled Java class) this would not be so easy. A colleague mentioned 3 methods.
One method I forgot, the other were: use an own class loader and load a full class on the fly. Might work, but I am 100% sure the Notes JVM security model would cough on it.
The third was to use EL expressions with an ExpressionFactory. Would have been a way to go…

But lazy as I was I was trying to figure out a way how I could inject JavaScript into running Java code.

and guess what.. I was lucky and figured it out:

here’s the code:

FacesContext facesContext = FacesContext.getCurrentInstance();
PageExpressionEvaluator eval = new ExpressionEvaluatorImpl(facesContext);

MethodBinding method = eval.createMethodBinding(
facesContext.getViewRoot(),
“#{javascript:var c = getComponent(“field1”);document1.replaceItemValue(“test”,c.getValue()); document1.save()}”,
null, null, null);

// other examples of JavaScript code to “experiment”
// “#{javascript:print(“hello world”)}”
// “#{javascript:return true}”

method.invoke(facesContext, null);

As you can see the interesting stuff is going on in the second parameter of the method createMethodBinding. There you can inject JavaScript code. Just enter your code into a button and then copy the relevant piece out of your xPage XML source code! In our framework this code will be read from the configuration document!

I admit.. the solution is “semi-optimal” cause I wanted to get rid of JavaScript as much as I can. But then hey: I don’t use those “formulas” very often, and for those rare cases I think I can accept the performance dip.

dip? indip? INDispensabletIP!

a side-dip: any ideas how I got the idea of how to get this working?

check this out:

in the package explorer view under Localxsp you will find the source code for all your xPages and custom controls! Just create a simple xPage with a button, add some JavaScript to the button and you basically get the code I posted above!

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!