Subscribe via Feed

Writing a Managed Bean to Automate Server Side Functionality in XPages

Jeremy Hodge, Jul 4, 2010 11:46:10 PM

In recent articles I've discussed how to create a client side controller using JavaScript and Dojo to enhance and automate your XPages application UI, but that is really only one-half of the story. The automation and control of the server-side application logic is also a very important piece, and critical to the proper implementation of an MVC design pattern.

With this article I am going to kick off a series of articles discussing how to create managed beans that you can use (and re-use) throughout your XPages application, in very powerful ways. To do this we are going to start to look at the underlying structure of XPages, Java Server Faces (or JSF) and how we can utilize the JSF framework to enhance our applications.

Before we get started, I should mention I am going to only scratch the surface of JSF and its capabilities. For more indepth review, I suggest you read Java Server Faces: The Complete Reference, originally suggested by Karsten Lehmann, who wrote an excellent series on XPages and the JSF. While the book is not about XPages, and there is no discussion of XPages in it, it serves as a very strong foundation for understanding the underpinnings of XPages.

Ok, so lets get the basics covered. First, lets talk in general about a "managed bean," or more generically a "bean."  If you are not familiar yet with Java, you may heard about beans, but wondered what exactly it is. All a bean is, is a single Java object that has been integrated into your XPages (or JSF) application. Its a simple class that has public and private properties, methods, etc. There is no magic, or special construction to a Bean. It is a simple, basic, plain Java Object. The Java class follows this basic construction:

package com.ZetaOne.myFirstManagedBeans;

public class HelloWorld {

    private String SomeVariable;
    private String AnotherVariable;

    // Class Constructor...
    public HelloWorld() {

    }

    // Property getters/setters
    public String getSomeVariable() {
        return SomeVariable;
    }

    public String getAnotherVariable() {
        return AnotherVariable;
    }

    public void setSomeVariable(String someVariable) {
        SomeVariable = someVariable;
    }

    public void setAnotherVariable(String anotherVariable) {
        AnotherVariable = anotherVariable;
    }

}

The full name of this class is com.ZetaOne.myFirstManagedBeans.HelloWorld. This simple class holds two "Properties": SomeVariable, and AnotherVariable. Because the properties are declares as private, they are not publically available to be modified by external objects or functions, but must use the respective getXXX, and setXXX functions to access or change the properties' value.

Later on, when we plug this object into our XPages application as a managed bean, those two variables become available to us to use within our application, just like the properties of other objects we regularly utilize, like fields on a notes document.

For example, given a defined NotesDocument named myDataDoc, if we wanted to access the field myDataField on that document, we could use the expression #{myDataDoc.myDataField} to bind a UI Component to that value. This is called a value binding, and is also available with our managed bean. for example, to access the AnotherVariable property of our managed bean (which for discussion we have given the name myFirstBeanie) we would use the value binding #{myFirstBeanie.anotherVariable}. The proper use of case on the variable is important.  When we use that value binding, the JSF will look at the myFirstBeanie object, and will convert "anotherVariable" into a function call to "getAnotherVariable" to see if it exists. [ NOTE: JSF will actually go through a list of other possibilities if getAnotherVariable() doesn't exist, but we'll discuss those later ].

Now, you can see how we can connect the object in the backend to UI elements on the front end. But it doesn't end there.  In SSJS, you can also access the object globally, like any other defined element.  To get or set a value on the object you can call the getter/setter functions directly, like this:

var x = "This is some text that I am going to put into another variable";
myFirstBeanie.setAnotherVariable(x);

You can do the same thing with methods and functions, which is called a method binding to connect events in the UI to the backend java class. We'll go over that more in detail later.

If all of this sounds familiar, its because it should be. This is 100% how XPages work. Every XPage you create is actually "compiled" down to Java source code that performs these same actions based on what you have created in in your XPages application. The only difference is that the java object that is created is called a backing bean and there is one controlling backing bean for every XPage you create. A managed bean is just another bean that can be integrated into other backing beans as a reusable object.

Ok, so lets get a little dirty here and actually learn how to integrate this bean into your XPages application. To add a managed bean, you have to switch perspectives in Domino Designer to the Java Perspective. After you do that, you have to create the actual Java source code for your bean. Doing so is easy, first we need to create a folder inside the NSF to hold the source code files. These files need to be within the folder /WebContent/WEB-INF:

Open Your NSF in the Package Explorer, and right click the WEB-INF folder, and select "New > Folder", and name it src.

After we create our folder, we need to tell domino designer to include the files that we put into it in the build process, so our source code gets compiled and included when DDE compiles our XPages. To do this, right click the new src folder, and select "Build Path > Add To Build Path". If you do not see "Add To Build Path," you can also click "Configure Build Path..." and in the dialog that opens, click the Add Folder... button, find the src folder, and click Add.

Now, let's create our source code. When we added the src folder to the build path, you will see a new entry appear in the outline called "WebContent/WEB-INF/src" towards the top of the items in the application. This is where we want to create our source code.

Right click this folder, and select New Package, give the package a name, like your reverse domain, and myFirstBeans, like com.ZetaOne.MyFirstBeans, and click finish. This will add a "package" to your src folder, which is basically just a collection of Java classes.

Right Click this package, and select "New > Class", name it HelloWorld, and click Finish. Don't worry about all the other options for now.

Now you should have the start of your bean.  Go ahead and copy in the innards from my class above and save your class.

Now, we have to expose this new bean to our XPages application. To do that, we need to edit the faces.config file found in the WEB-INF folder. Scroll back down in your NSF outline until you see the WebContent folder, and expand it so you can see the WEB-INF folder, and expand it. In there, you should see a faces-config.xml file. Double click it to edit.

That file should look like this:



 
 

We are going to add lines to this file, outside the block to define our bean.  Here's what we are going to add:


    HelloWorld
    com.ZetaOne.MyFirstBeans.HelloWorld
    session

The managed-bean-name gives a name to the bean, and defines how we will access it in our XPages application; managed-bean-class is the fully qualified Java class name that we created earler; and managed-bean-scope defines in which scope our bean will be stored. This can be request, session or application, and just like the scope variables requestScope or sessionScope, it determines how long that object will be cached. For now, we'll use session.  Your final faces-config.xml should look like this:



 
 
 
    HelloWorld
    com.ZetaOne.MyFirstBeans.HellowWorld
    session
 

Now we are ready to use our bean in an XPage. Create a new XPage, and put a field and a computed field on the page; the field with a label of "Some" and the computed field with "Another". Value bind the two fields to your HelloWorld bean by using #{HelloWorld.someVariable} (to the field) and #{HelloWorld.anotherVariable} (to the computed field).

Also add a button that does a full refresh, and uses server side JavaScript to set the value of AnotherVariable to "Hello World!".

Your source code should look similar to this:




    
    
    


    
    
    


    
        
                            HelloWorld.setAnotherVariable("Hello World!");
            }]]>

        

    

    

Now, you can enter text in the field, and click the button, and you should see the page retain the value you entered (its now cached in the HelloWorld object), and you should see the Hello World! appear in the computed field, like this:

And there you go, your first real-world implementation of a managed bean.  The next few articles will expand upon the capability of the managed bean, and show you how you can perform complex functions and transformations on data easily, without getting your controller all mixed up in your view.

Happy Coding!



9 responses to Writing a Managed Bean to Automate Server Side Functionality in XPages

vayasin, October 4, 2010 8:57 PM

Hi,

i have a library of custom java classes in my WebContent, working together nicely with my xpages. :)
but now i want to use these same classes inside my java agents and webservice providers.
im still unable to refference my namespace from the databases WebContent.
is this even possible? it seems java agents run in an isolated enviroment.


tye, July 20, 2010 6:03 AM

good,do you have any xpages data,please shared it,thank you


mort, July 8, 2010 2:13 AM

Thanks for that Jeremy :-) Thats given me a few things to try. I'll post back here if I discover a good way to get it working


Jeremy Hodge, July 7, 2010 12:57 PM

@mort - I have actually been doing some work with web services and managed beans lately ... There are a couple of issues you could be running into .. one is the java policy ... depending on the classes used, and what is(n't) allowed to do, you may have issues. Take a look at that file, temporarily grant wide-open permissions and see if it works, and if it does, you know you have a policy issue.

If it doesn't, I have had problems with other classes that will fail to load for whatever reasons (dependencies, version issues, security policy, etc) ... In my case I ended up building my own transport class to handle the communication between the webservice and my objects ... it was a name-value pair webservice, and not soap, which made it easier.

@Demha - The bean is accessed via the name you give it in the faces-config.xml file, in the <managed-bean-name> parameter. Then in EL, or SSJS, you can access it directly via that name. To access it in other code (like other managed beans) you have to do a little bit more to get to it. I'll post more on that soon, or you can read Karsten's blog (linked in the article) and he shows you how.

As for the instance per user, that depends on what you specify in the faces-config.xml for <managed-bean-scope>, if you specify request or session, it is one instance per user, however, if you specify application, there is one instance for the entire application. it is not store in the sessionScope or applicationScope however, those are seperate object, pretty much on an equal level as your managed bean.

I'll have more posted soon that will delve deeper in to real world uses and how to utilize this, along with some other added functionality I have not yet covered.


Demha, July 7, 2010 10:38 AM

Hi,

How can I access this bean from the serverside?
I will have one instance of HellowWorld per user, this instance is stored in the sessionScope?
I'm working in a PureMVC implementation for Xpage, and I'm looking for the best way to make reusable component.


mort, July 7, 2010 3:12 AM

I have a web service on another service that returns a 'cost to date' figure from an SQL table. The input parameter is a job number. I've added a web service consumer to my Xpage database and this works fine when calling from an agent. I was thinking it would be great if I could make calls to the webservice in this back-end java bean. I followed your instructions to create the bean then I tried referencing the consumer classes so I could make calls to the web service. But the consumer classes are not visible to the bean. Do you have any suggestions as to how I could consume a web service in the bean? Is this approach a bad idea? I have also been struggling to work out how to consume a web services using clientside Dojo but no luck so far.


Jeremy Hodge, July 6, 2010 11:03 AM

@Nick ... Yes, I see SSJS libraries under a managed bean implementation at least having much less significance, however, its "the best tool for the job" ... so depending on the need/code re-usability, etc, I don't know if they are are redundant.


Nick Wall, July 6, 2010 7:28 AM

Great article. A few days ago I found a couple of similar articles over at www.mindoo.com

http://www.mindoo.com/web/blog.nsf/dx/16.07.2009095816KLEBCY.htm?opendocument
http://www.mindoo.com/web/blog.nsf/dx/18.07.2009191738KLENAL.htm?opendocument

Just starting quite an XPage app and this is all really useful as I am trying to implement proper MVC.

A random thought came into my head: if we can set up our Model and Controller packages in the beans, these can be accessed from pretty much anywhere through EL or SSJS (think am right on this point), does it make SSJS libraries redundant? I have not played with accessing the UIComponent (the article above), but if you can also access the Ui then all I need is a Client side JS Controller and my beans?

Look forward to any other articles you do on this.


Eric Mack, July 5, 2010 1:38 AM

Had to smile, wondering what my wife would guess the article would be about from subject alone...