Test to see if bean is instantiated? - xpages

I wanted to test to see if a session scope bean was in fact valid in a beforePageLoad event using SSJS. If I clear the session scopes using the Debug toolbar I get an error when trying to test the bean to see if it is null.
if (registrationBean == null){
The error is:
Error while executing JavaScript action expression
Script interpreter error, line=2, col=22: [ReferenceError] 'registrationBean' not found
Question is how to test the bean to see if it is instantiated??? If not, then I want to go to another XPage (redirect) to allow the user to enter the values that are used to populate the bean.
Or, is this only an issue because I used the Debug Toolbar to clear ALL session and application scopes?
Howard

Use a try/catch block. If you get the error, it's null.
I suspect it's only a problem because the applicationScope has been cleared. Usually the first attempt to reference the variable instantiates the object. However, clearing the whole of applicationScope can break a lot of XPages code in your application and should be avoided.

First, make sure that the bean is set up in faces_config.xml (but it seems this is the case). Then you should not be able to reference the bean before it is instantiated...
An easy way to see when the bean is instantiated is to put a System.out.println("....") in the constructor of the bean. That should bring you on the track. You could (should!) use the OpenNTF LogReader to see what is going on - this will show you any errors thrown by the page and bean.
And then of course clearing all the data via the debug toolbar may put the system in an "unknown" state - and you should probably try to reload the page subsequently to ensure it is well-defined/-instantiated.
/John

Related

Xpages equivalent to Database Script initialize

I am running Xpages in XPiNC.
My usual pattern for an Xpages app is to have a xpHome.xsp page that is set to be the first page that is opened. In this I page I set any scope variables that are at the application level, then head to the "real" first page.
Now I have run into a problem. My current database will send out emails when a status changes, and this will include a doc link to the document, which points to the correct Xpage to open. However, because the user is not going through the home page, then my applicationScope vars are being set.
I thought I could fix this by setting a semaphore in the initApp function - the last thing it would do is to place a "Y" in an applicationScope.semaphore field. So when I open my Xpage the first thing it does is check for that, and if it is null, then I call the initApp function.
For some reason this is not working. But even so I would like to find the equivalent of the old database script "Initialize" event. Something I can call whenever the db is opened for the first time.
How do others handle this problem?
Create a managed Java bean "app" which
works on application scope
sets all application parameters
offers all application parameters
Access the bean with app.xxx in EL or Javascript or call methods directly like app.getXxx() or app.doWhatEverYouWant() in JavaScript.
The bean "app" gets initalized automatically when one of the methods gets called first time.
You can find an example here for start or google for "XPages managed beans" for more Information.
Yes, you have to switch your current code partly to Java but it should be worth it in the long run.
If you want to or have to stay with JavaScript then initialize your application scope variables in a custom control which is included in every XPage like layout.xsp in beforePageLoad event.
Use an additional variable applicationScope.initialized. Check if applicationScope variables aren't initialized yet in JavaScript with
if (!applicationScope.initialized) {
... initialize your applicationScope variables ...
applicationScope.initialized = "yes";
}

XPages sometimes refresh and lose content

I hope someone can help me solve a very serious problem we face at the moment with a business critical application losing data when a user works in it.
This happens randomly - I have never reproduced this but the users are in the system a lot more than me.
A document is created with a load of fields on it, and there are 2 rich text fields. We're using Domino 8.5.3 - there are no extension lib controls in use. The document has workflow built in, and all validation is done by a SSJS function called from the data query save event. There is an insane amount of logging to the sessionscope.log and also this is (now) captured for each user in a notes document so I can review what they are doing.
Sometimes, a user gets to a workflow step where they have to fill in a Rich Text field and make a choice in a dropdown field, then they submit the document with a workflow button. When the workflow button is pressed (does a Full Update) some client side JS runs first
// Process any autogenerated submit listeners
if( XSP._processListeners ){ // Not sure if this is valid in all versions of XPages
XSP._processListeners( XSP.querySubmitListeners, document.forms[0].id );
}
(I added this to try and prevent the RTF fields losing their values after reading a blog but so far it's not working)
then the Server-side event runs and calls view.save() to trigger QS code (for validation) and PS code to run the workflow agent on the server.
95% of the time, this works fine.
5% of the time however, the page refreshes all the changes made, both to the RFT field (CKEditor) and the dropdown field are reloaded as they were previously, with no content. It's like the save hasn't happened, and the Full Update button has decided to work like a page refresh instead of a submit.
Under normal circumstances, the log shows that when a workflow button is pressed, the QuerySave code starts and returns True. Then the ID of the workflow button pressed is logged (so I can see which ones are being used when I am reviewing problems), then the PostSave code starts and finally returns true.
When there is a problem, The QuerySave event runs, returns true if the validation has passed, or false if it's failed, and then it stops. The ID of the workflow button is also logged. But the code should continue by calling the PostSave function if the QuerySave returns true - it doesn't even log that it's starting the PostSave function.
And to make matters worse, after the failure to call the PostSave code, the next thing that is logged is the beforePageLoad event running and this apparently reloads the page, which hasn't got the recent edits on it, and so the users loses all the information they have typed!
This has to be the most annoying problem I've ever encountered with XPages as I can find no reason why a successful QuerySave (or even a failure because mandatory fields weren't filled in) would cause the page to refresh like this and lose the content. Please please can someone help point me in the right direction??
It sounds as if in the 5% use cases, the document open for > 30mins and the XSP session is timing out - the submit causes the component tree to be re-created, and the now empty page returned back to the user. Try increasing the time out for the application to see if the issue goes away.
I would design the flow slightly different. In JSF/XPages validation belongs into validators, not into a QuerySave event. Also I'd rather use a submit for the buttons, so you don't need to trigger a view.save() in code. This does not interfere with JSF's sequence of things - but that's style not necessarily source of your problem.... idea about that:
As Jeremy I would as a first stop suspect a timeout, then the next stop is a fatal issue in your QuerySave event, that derails the runtime (for whatever reason). You can try something like this:
var qsResult = false;
// your code goes here, no return statements
// please and if you are happy
qsResult = true;
return qsResult;
The pessimistic approach would eventually tell you if something is wrong. Also: if there is an abort and your querySave just returns, then you might run in this trap
function noReturn() {return; } //nothing comes back!
noReturn() == true; --> false
noReturn() == false; --> false
noReturn() != false; --> true!!!!
What you need to check: what is your performance setting: serialize to disk, keep in memory or keep latest in memory? It could be you running foul of the way JavaScript libraries work.
A SSJS library is loaded whenever it is needed. Variables inside are initialized. A library is unloaded when memory conditions require it and all related variables are discarded. so if you rely on any variable in a JS Function that sits inside a SSJS library between calls you might or might not get the value back, which could describe your error condition. Stuff you want to keep should go into a scope (viewScope seems right here).
To make it a little more trickier:
When you use closures and first class functions these functions have access to the variables from the parent function, unless the library had been unloaded. Also functions (you could park them in a scope too) don't serialize (open flaw) so you need to be careful when putting them into a scope.
If your stuff is really complex you might be better off with a backing bean.
Did that help?
To create a managed bean (or more) check Per's article. Your validator would sit in a application bean:
<faces-config>
<managed-bean>
<managed-bean-name>workflowvalidator</managed-bean-name>
<managed-bean-class>com.company.WfValidator</managed-bean-class>
<managed-bean-scope>application</managed-bean-scope>
</managed-bean>
</faces-config>
Inside you would use a map for the error messages
public Map<String,String> getErrorMessages() {
if (this.errorStrings == null) { // errorStrings implements the MAP interface
this.loadErrorDefinitions(); //Private method, loads from Domino
}
return this.errorStrings;
}
then you can use EL in the Error message string of your validators:
workflowvalidator.errorMessage("some-id");
this allows XPages to pick the right one directly in EL, which is faster than SSJS. You could then go and implement your own custom Java validator that talks to that bean (this would allow you bypass SSJS here). Other than the example I wouldn't put the notes code in it, but talk to your WfValidator class. To do that you need to get a handle to it in Java:
private WfValidator getValidatorBean() {
FacesContext fc = FacesContext.getCurrentInstance();
return (WfValidator) fc.getApplication()
.getVariableResolver()
.resolveVariable(fc, "workflowvalidator");
}
Using the resolver you get access to the loaded bean. Hope that helps!
My experience is that this problem is due to keeping page in memory. Sometimes for some reason the page gets wiped out of memory. I'm seeing this when there is a lot of partial refreshes with rather complex backend Java processing. This processing somehow seems to take the space from memory that is used by the XPage.
The problem might have been fixed in later releases but I'm seeing it at least in 8.5.2.
In your case I would figure out some other workaround for the CKEditor bug and use "Keep pages on disk" option. Or if you can upgrade to 9.0.1 it might fix both problems.

JSF page navigation failing with NullPointerException

I wrote two pages...one a form where data submitted and second just to confirm the transaction actually carried out some calculation.
I have a managed bean i.e. FormDataBean and a class Reservation.java from which i instantiate for each booking made. Now I have at the end of a form a submit button:
<h:commandButton value="Submit" action="confirmation"/>
in the bean I have setters and getters as usual. in a method i defined I create an instance of Reservation, then set the beans variables to the instance variabels, like
reservation.startDate = startDate;
reservation.endDate = endDate;
reservation.checkRange();
The last method, i.e. checkRange() will use the assigned values to instance variables to carry calculation. it should return a string successful or failure.
Now when I enter data in the form, and press submit, it just refreshes the page but nothing is submitted. because it doesn't go to next page :(
Any idea what is happening? I don't need to define a navigation rule, because in other project, I carry out simple calculation and display result in next page and it worsks! Please advice
Thanks,
Your are missing to tell us some of the more important details so the answer is a kind of guesswork.
As you don't use navigation rules I assume you are using JSF 2, aren't you?
With JSF 2 you can directly set the new navigation target, without navigation rules. A forward to "confirmation" should work if your outcome file is named confirmation.xhtml. Check that. With a navigation rule you could forward it do a different file.
This part should work regardless of the rest.
For the bean not getting any values make sure that you are using the correct scope either through annotation or entry in your faces-config.xml. As you have a quite unusal validation mechanism you probably have to use the session scope.
The correct way would be using an actionlistener that does your checks and then sets the navigation depending on your checks. The bean scope could be more restrictive then.
Did you try action="confirmation?faces-redirect=true"?

resetProperty() in session scoped managed bean called by default?

I have a session scoped managed bean, with a property current. If I have a method
public void resetCurrent() {
current = new Configuration();
}
in the bean, it gets called automatically every time I navigate to a new page in the application. Is this normal behavior? I am not calling the method anywhere in the code.
Considering that this approach to reset the session bean properties is, to say the least, less than ideal, which would be the right way to accomplish it?
Thank you.
JSF doesn't do that. It's your code which does that. Your view or another bean or maybe the bean itself is calling it. Putting a debug breakpoint on that line or adding Thread.dumpStack() should give you insights in who's calling it by reading the call stack. Or just rename the method to something else and check if you don't see compilation errors during build or get EL exceptions during runtime which should pinpoint the callers.
Considering that this approach to reset the session bean properties is, to say the least, less than ideal, which would be the right way to accomplish it?
Depends on the functional requirements. For example, if the bean is supposed to hold view scoped data, then put it in the view scope instead. Or if it is supposed to hold session scoped data (e.g. logged-in user) and you're basically logging out, then rather invalidate the session.

CDI/Weld - how to handle browser page refresh after ending conversation?

In the very early days of using CDI I'm navigating to a page with a long running
conversation active using faces-redirect=true, so I have a URL like ..myPage.xhtml?cid=1.
At some point I end the conversation, I mean this has to be a reasonable thing to do
or you might as well use session scope? Anyway, I end the conversation and then the
user hits F5, and then of course this causes a 'conversation not found' error as cid=1
doesn't exist.
Can anyone suggest how to get around this problem? I'm using the Steven Verborgh
ViewScoped implementation and simply using a conversation scoped bean to pass parameters
between pages. So I have for example 2 #ViewScoped beans each of which back page 1 & 2.
I #Inject the #ConversationScoped ParameterBean into both view scoped beans. I start the
conversation (parameterBean.getConversation().begin()) in the action method called from
page 1. In the preRenderView event for page 2 I take a reference to the properties of
the parameterBean into a page 2 backing bean instance variable and end the conversation,
it's done it's job and no longer required.
Except for the F5 problem it works fine. If anyone has any suggestions I'd appreciate it,
hopefully I'm not missing something really obvious. I kind of assuming there's no getting
away from a redirect.
Thanks.
There is no workaround for it. The default #ConversationScoped is utterly broken. I'm using the #ConversationScoped from MyFaces CODI instead. It solves all problems you can get with the standard scope.

Resources