Did you know that you can drag&drop in the applications view design elements from one application to the other?
you can actually “drop” them anywhere on the target application and they are put in the proper place.
Did you know that you can drag&drop in the applications view design elements from one application to the other?
you can actually “drop” them anywhere on the target application and they are put in the proper place.
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?)
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.
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
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!
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:
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:
PhaseListener updates:
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);
}
if (event.getPhaseId().equals(PhaseId.PROCESS_VALIDATIONS)) {
FacesContext facesContext = event.getFacesContext();
toggleValidators(facesContext.getViewRoot(), false);
}
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!
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!