Subscribe via Feed

Getting Deeper into the Managed Bean - Creating a Cached Master/Detail Recordset

Jeremy Hodge, Aug 9, 2010 12:10:36 PM

In my first article in the JSF series, I covered the concept of the Managed Bean, and gave you a brief example on how to implement one. I thought for today's post, I would dig a bit deeper and give you an example of a more-fully fleshed out managed bean example.

Let's continue to work with the HelloWorld class from the first post in the series and build upon that. The first example I would like to show you is how to build a managed bean to work with a set of master / detail records. This is the same concept as a parent document, and its immediate child documents in Lotus Notes. However, with the managed bean we can create and add muliple records to our recordset, then act on them globally to commit them to the database all at once, increasing our application's performance as we do not have to perform as many read/write operations to the disk.

Before we get started, I would suggest that you read Tim Tripcony's blog post "Keeping Things in Perspective" on customizing DDE for java/XPages development. It's a great post and really makes working with DDE easier. Throughout this article, I am going to reference how I have customized the environment, which is pretty much like he suggests, and I highly recommend you do the same.

To facilitate the detail recordset, we are going to add another class to our package. To add the class, in the Package Explorer right click your package (in this example, its "com.ZetaOne.myFirstBeans") and select "New > Class."

Name the new class "HelloCountry" and click finish. Now double click and edit the HelloCountry class, and let's add a few private class member variables:

package com.ZetaOne.myFirstBeans;

public class HelloCountry {

     private String CountryName;
     private String CapitalCity;
     private String GoodFood;

}

These private variables are going to represent the three pieces of information the HelloCountry class is going to store. Now we need to create our getter/setter functions for these class members. Remember we use getters/setters to retreive and store the values of these properties.

New Java Programmer's Note: The 'private' keyword prevents code from outside the scope of the class from seeing and modifying the properties directly. We create the getters/setters as public methods that modify those properties so we can do validation and additional processing based on those the new values getting assigned. This allows us to maintain the integrity of our class because member variables can't get set without us knowing about it.

Now, to create the getters/setters, there is a quick source code short cut we can utilize thanks to the E(clipse) in DDE. Right click in the source code window, select Source and Generate Getters/Setters.

In the dialog that appears, select each of the three properties (or click the Select All button) and click Ok, and you should now see six new methods added to your code, a getter and a setter for each property. Let's go ahead and save the Class and re-open our HelloWorld class.

Now, we are going to add a property to the HelloWorld class that will allow us to add a detail recordset of HelloCountry records to our HellowWorld class. To do this, we are going to utilize a java.util.Vector to hold our HelloCountry instances. Add the following lines to our HelloWorld class (new lines in bold):

package com.ZetaOne.myFirstBeans;

import java.util.Vector;
import com.ZetaOne.myFirstBeans.HelloCountry;

public class HelloWorld {

     private Vector myCountries;

     .... // rest of the class is here

}

This adds a new vector (which is similar to an Array) of objects of the type HelloCountry. In this vector we can add/remove/update HelloCountry objects until our hearts are content.

Now that we have our vector myCountries declared, we have to actually initialize that vector. To do that, we need to modify the constructor of the HelloWorld class. The constructor is the method that has the same name as the class itself, HelloWorld. Let's update that method now to initialize the myCountries memeber.

public HelloWorld() {

     myCountries = new Vector();

}

Now we have to figure out how to get Countries in to and out of our object. To do that, let's add a constructor to our HelloCountry class that can take parameters to fill out the HelloCountry class:

public HelloCountry(String country, String capital, String goodFood) {

    CountryName = country;
    CapitalCity = capital;
    GoodFood = goodFood;

}

Now, let's another public method to our HelloWorld class called AddCountry, that takes the same three parameters, and creates the entry in our Vector:

public void AddCountry(String country, String capital, String goodFood) {

    myCountries.add(new HelloCountry(country, capital, goodFood));

}

Now, we may want the ability to directly interact with Vector of HelloCountrys, so let's create a method to retrieve the vector from the HelloWorld class:

public java.util.Vector getCountries() {

    return myCountries;

}

Ok, there is one last thing we want to do before we get into the fun of applying this in our XPages application. We've added a constructor to the HelloCountry class that allows us to pass in the three pieces of data the class wants. BUT, what if we want to create a new instance of HelloCountry that is empty, so the user can provide the data? We can add a constructor for that as well. This introduces the concept of method overloading. We can create different types of methods that accomplish the (relative) same task, but pass them different parameters. The compiler automatically matches up which method to call based on the parameters you send it. So let's add one more constructor to our HelloCountry class, and not pass it any parameters. That will allow us to create a new HelloCountry class with blank values:

public HelloCountry() {

    CountryName = "";
    CapitalCity = "";
    GoodFood = "";

}

Then, to have the HelloWorld class add an empty country, let's add another public AddCountry method as well, again overloading the method with no parameters, and have it call create the new HelloCountry using the constructor without parameters:

public void AddCountry() {

    myCountries.add(new HelloCountry());

}

Ok ... let's get started with the fun. I am assuming you are using the same database to work with this example as you did with the last. If you are starting from scratch, remember to add the managed bean to the faces-config.xml file now.  Otherwise, let's create a new XPage, and get this implemented.

I created an XPage called HelloWorldDetail. Let's start by adding a button to our XPage that adds a country to our HelloWorld myCountries object. To do that we create the button, label it "Add USA", and on the server side onclick event we add the following SSJS code:

HelloWorld.AddCountry('United States', 'Washington, D.C.', 'Apple Pie');

Just to add some variety, let's add another button, labeled 'Add Germany', and use the following code for the onclick

HelloWorld.AddCountry('Germany', 'Berlin', 'Beer');

And, let's add one more button to add an empty country as well:

HelloWorld.AddCountry();

Now, let's add a repeat control to our XPage and Name the repeat collection countryVar. Set the Iteration's Bind Data using: to Advanced and Use Expression Language (EL), and type in HelloWorld.countries, like this:

 

Now inside the repeat, add a line of text that Says:

When I am in [ countryVar.countryName ], I like to visit [ countryVar.capitalCity ] and have some [ countryVar.goodFood ].

Replacing the [ ] with input fields, bound to EL expression contained withing the blocks above.

Your final XPages code should look like this:




    
                    refreshMode="complete">
                            HelloWorld.AddCountry('United States', 'Washington, D.C.', 'Apple Pie');
            }]]>

        

    


    
                    refreshMode="complete">
                            HelloWorld.AddCountry('Germany', 'Berlin', 'Beer');
            }]]>

        

    

    
    
                    refreshMode="complete">
                            HelloWorld.AddCountry();
            }]]>

        

    


            var="countryVar">

        When I am in
        
        , I like to visit
        
        and have some
        
        


    


Go ahead, save it and give it a try, or you can view an online working sample.

Here's what you should see:

In my next post, we'll go even further into this example, showing you how to remove items from the detail, how to commit it to disk, and how to add some validation and conversion!

Happy Coding!

 

[For your convenince, below is the code for the two Java Classes HelloWorld and HelloCountry]

package com.ZetaOne.myFirstBeans;

import java.util.Vector;
import com.ZetaOne.myFirstBeans.HelloCountry;

public class HelloWorld {

    private Vector myCountries;
    private String SomeVariable;
    private String AnotherVariable;

    // Class Constructor...
    public HelloWorld() {
        myCountries = new Vector();
    }

    // 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;
    }

    public void AddCountry(String country, String capital, String goodFood) {
        myCountries.add(new HelloCountry(country, capital, goodFood));
    }

    public void AddCountry() {
        myCountries.add(new HelloCountry());
    }    
    
    public java.util.Vector getCountries() {
        return myCountries;
    }    
}

 

 

package com.ZetaOne.myFirstBeans;

public class HelloCountry {

    private String CountryName;
    private String CapitalCity;
    private String GoodFood;

    public HelloCountry(String country, String capital, String goodFood) {
        CountryName = country;
        CapitalCity = capital;
        GoodFood = goodFood;
    }
    
    public HelloCountry() {
        CountryName = "";
        CapitalCity = "";
        GoodFood = "";
    }
    
    public String getCountryName() {
        return CountryName;
    }
    public void setCountryName(String countryName) {
        CountryName = countryName;
    }
    public String getCapitalCity() {
        return CapitalCity;
    }
    public void setCapitalCity(String capitalCity) {
        CapitalCity = capitalCity;
    }
    public String getGoodFood() {
        return GoodFood;
    }
    public void setGoodFood(String goodFood) {
        GoodFood = goodFood;
    }
    
}



5 responses to Getting Deeper into the Managed Bean - Creating a Cached Master/Detail Recordset

fred, December 5, 2010 8:50 AM

Great Post, but what is the "save" button doing?

I'm doing something similar, but i don't know how i can process the entered values..
Can i download your example from somewhere?

thanks


Nick Wall, August 14, 2010 5:58 PM

Keep these posts coming, great stuff...much appreciated.


Jeremy Hodge, August 9, 2010 9:15 PM

Mostly out of habit, knowing it would work for the repeat control ... If i were coding / optimizing it for performance, I probably would look at a different structure, maybe an ArrayList or LinkedList ... LinkedList would be speedier removing arbitrary items, but requires more garbage collecting ... ArrayList could potentially consume less memory too ... but I haven't tried an ArrayList or LinkedList with the repeat control yet either. I assume it works though.


Stephan H. Wissel, August 9, 2010 8:48 PM

Excellent deep dive. Just wondering, other than Lotus' own fondness for vectors, what made you pick a vector over any of the other (more common) collection classes?


Matt Vargish, August 9, 2010 3:10 PM

Really excellent article, thanks!

I posted yesterday about my experiences with using the Eclipse debugger directly in DDE to remote debug Java -- mostly focused on code invoked via agents because I haven't written any backing beans yet, and stepping through the generated JSF stuff wasn't very interesting... Was just thinking this morning that I should try it, and your first post on this topic just saved me hours of figuring out the details.

FWIW you can step through the managed bean no problem, my post is here if your interested: http://getthemostfromnotes.com/tsblog.nsf/d6plinks/KFRA-886LD3

Looking forward to more in this series!