Introduction
The application model encompasses both the IDE design-time environment and the application runtime environment. It is important to keep this full scope of the application model in mind as you read this article. You may be familiar with the application model from the earlier version of the IDE. However, the application model for Java Studio Creator 2 has gone through significant improvements from the earlier Java Studio Creator 2004Q2 (version 1). The article describes the current application model rather than the changes to the model.
All levels of software developers, from those getting started with the Java Studio Creator 2 IDE through advanced developers, should benefit from understanding the concepts of the application model. Developers who know the application model have a better understanding of the structure of web applications produced by the IDE. To get the most from this article, developers should have a general knowledge of the Java
[tm] Platform and JavaServer[tm] Pages. Since the application model is based on the JavaServer Faces[tm] technology application model, it is also helpful to be familiar with the JavaServer Faces technology. However, the article does introduce the JavaServer Faces concepts necessary to understand the application model. This article:
What is an Application Model?
Let's begin with the definition of the term model, since it can have many different meanings and applications. In this article, the phrase "to model" means to simulate or abstractly represent a system. Many different disciplines use models to depict the various parts of a system. For example, in weather forecasting, weather models represent known weather systems. In the mechanical realm, you have models of different types of engines, such as combustion and jet engines.
An application model gives the developer an abstract or high-level view of the system or application under development. Knowing the application model helps the developer to create the web application, particularly in terms of the application design, problem determination, and performance tuning. As you make the necessary design decisions, you can maximize the usage of the application model. Even if things do not work as expected, knowing the application model helps you determine what went wrong. The JavaServer Faces Technology Application Model
Since the Java Studio Creator 2 application model is built on the JavaServer Faces technology application model, let's start with an overview of key JavaServer Faces technology application model concepts. (See the JavaServer Faces Technology chapter in the J2EE 1.4 Tutorial, for more information on JavaServer Faces technology.)
The article first examines these models and then explains the JavaServer Faces page life cycle. The JavaServer Faces User Interface Model
The JavaServer Faces user interface model contains component Java classes, a rendering model, an event and listener model, a validation model, and a conversion model.
The JavaServer Faces application model provides two ways to specify an event handler:
The JavaServer Faces Navigation Model
The JavaServer Faces navigation model defines how a web application moves from one page to another. The navigation model consists of a handler that uses a navigation configuration file containing navigation rules. The handler responds to action events executed by action sources, such as buttons or hyperlinks.
<?xml version="1.0" encoding="UTF-8"?>
<faces-config>
<navigation-rule>
<from-view-id>/Page1.jsp</from-view-id>
<navigation-case>
<from-outcome>case1</from-outcome>
<to-view-id>/Page2.jsp</to-view-id>
</navigation-case>
</navigation-rule>
<navigation-rule>
<from-view-id>/Page2.jsp</from-view-id>
<navigation-case>
<from-outcome>back</from-outcome>
<to-view-id>/Page1.jsp</to-view-id>
</navigation-case>
</navigation-rule>
</faces-config>
Figure 2: Navigation Configuration File With Static Navigation Rules The navigation configuration determines static configuration by mapping a JavaServer Pages action method return value to a<to-view-id> tag identifying the page to navigate to. Figure 3 shows an action method that causes the web application to navigate to Page2.jsp, according to the rules in the navigation configuration file shown in Figure 2.
public String button1_action() {
return "case1";
}
Figure 3: Action Method Return Value Dynamic navigation allows the developer to change the navigation based on runtime conditions. The navigation model allows the developer to define a set of navigation rules that point from one page to many pages. The return value of an action method determines the navigation route, and program logic deduces the next page. Figure 4 shows a navigation configuration file with multiple navigation cases for Page1.jsp. These multiple navigation cases for the same page allow the navigation to be determined logically in the action method. Figure 5 shows a method triggered by a drop-down list value change. The action method dynamically determines which page to navigate to.
<?xml version="1.0" encoding="UTF-8"?>
<faces-config>
<navigation-rule>
<from-view-id>/Page1.jsp</from-view-id>
<navigation-case>
<from-outcome>case1</from-outcome>
<to-view-id>/Page2.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>case2</from-outcome>
<to-view-id>/Page3.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>case3</from-outcome>
<to-view-id>/Page4.jsp</to-view-id>
</navigation-case>
</navigation-rule>
<navigation-rule>
<from-view-id>/Page2.jsp</from-view-id>
<navigation-case>
<from-outcome>back</from-outcome>
<to-view-id>/Page1.jsp</to-view-id>
</navigation-case>
</navigation-rule>
</faces-config>
Figure 4: Navigation Configuration File With Dynamic Navigation Rules
public void dropDown1_processValueChange(ValueChangeEvent vce) {
if(dropDown1.getSelected().equals("one")) {
return case1;
} else if(dropDown1.getSelected().equals("two")) {
return case2;
} else if(dropDown1.getSelected().equals("three")) {
return case3;
} else return null;
}
Figure 5: Value Change Action Method for Dynamic Navigation The JavaServer Faces Backing Bean Model
The JavaServer Faces application model separates the user interface from the back-end objects that represent the data model. The server-side, or back-end objects that represent data and state, are called backing beans. Usually a JavaServer Faces application has at least one backing bean.
#{} syntax. Value Binding If a component's value is bound to a backing bean property, the value of the component is wired to the getter and setter methods of the associated backing bean property. Figure 6 shows the Java code in the backing bean to bind a property calledfirstName to a user interface component.
String firstName = null;
String getFirstName(){
return firstName;
}
void setFirstName(String inFirstName){
firstname = inFirstName;
}
Figure 6: Backing Bean Code to Bind a Property Figure 7 shows the JavaServer Faces EL necessary to bind the user interface component to the backing bean.
<h:outputText value="#{MyBean.firstName}" />
Figure 7: JavaServer Faces EL to Bind a Component to a Backing Bean Component Instance Binding Binding a component instance to a backing bean is useful if an event handler in the backing bean dynamically needs to change anything about the component. When a component's instance is bound to a backing bean, the
<h:outputText binding="#{MyBean.outputText1}" id="outputText1"
value="Hello World" />
Figure 8: Binding a Component to a Backing Bean After the binding, the backing bean has getter and setter methods for the component instance
HtmlOutputText outputText1 = new HtmlOutputText();
HtmlOutputText getOutputText1(){
if(showLabel) {
outputText1.setRendered(true);
} else {
outputText1.setRendered(false);
}
return outputText1;
}
void setOutputText1(HtmlOutputText inOutputText){
outputText1 = inOutputText;
}
Figure 9: Backing Bean Code With Instance Binding Notice that the backing bean includes logic to dynamically set the component rendering to true or false. Instance binding makes it much easier to effect dynamic changes to UI components in the backing beans. If you did not use instance binding, you would have to write code to get the UI component every time you needed to make a change. Figure 10 illustrates what that code might look like.
HTMLOutputText outputText1 = getFacesContext().getViewRoot()
.findComponent(":form:outputText1");
if(null != outputText1) {
//dynamically change UI component
} else {
//deal with UI component not found condition
}
Figure 10: Hypothetical Backing Bean Code Without Instance Binding Managed Backing Beans JavaServer Faces technology provides a managed bean facility to manage backing beans. The managed bean facility manages the creation and persistence of the backing beans. To have JavaServer Faces bind user interface component data to backing beans, the backing beans must be managed and declared in the managed bean facility configuration file. You also must provide an XML configuration file with the starting tag <managed-bean> <managed-bean-name>UserNumberBean</managed-bean-name> <managed-bean-class>guessNumber.UserNumberBean </managed-bean-class> <managed-bean-scope>session</managed-bean-scope> <managed-property> <property-name>minimum</property-name> <property-class>long</property-class> <value>0</value> </managed-property> <managed-property> <property-name>maximum</property-name> <property-class>long</property-class><value>10</value> </managed-property> </managed-bean> Figure 11: Managed Bean Facility Configuration File The JavaServer Faces Page Life Cycle
A JavaServer Faces page follows a defined life cycle. A browser displays a JavaServer Faces page and an end user action, such as pressing a button or clicking a hyperlink, generates a servlet request. The request follows a set logic path and eventually a response is generated and returned. The process of handling the request and generating the response is referred to in the JavaServer Faces documentation as the life cycle.
The JavaStudio Creator 2 Application Model The Java Studio Creator 2 application model is based on the JavaServer Faces application model. The Java Studio Creator development team has significantly enhanced the application model to make it both easier for developers to understand and usable within the IDE. User Interface Backing Beans Let's first look at the backing beans. The application model has a category of backing beans for handling user interface details. This backing bean category, called user interface backing beans, handles user interface properties and events. There are two backing beans in this category: page bean and page fragment bean. Page Beans A page bean represents one JavaServer Pages page. The page bean contains all implementation logic to manage the server-side aspect of a web page. It does not contain validation and conversion logic.
The application model also supports backing beans that do not have a JSP page associated with them. The section Data Backing Beans discusses these types of backing beans. Let's first look at the backing beans. The application model has a category of backing beans for handling user interface details. This backing bean category, called user interface backing beans, handles user interface properties and events. There are two backing beans in this category: page bean and page fragment bean. Since there is a one-to-one relationship between a JSP page and a page bean, each time a UI component is added to the IDE Visual Designer, a property is added to the associated page bean for the UI component. Because the application model uses both value binding and component instance binding, the IDE implements the application model by creating getters and setters for the component instance binding and assigning a default value binding. Figure 14 shows the JavaServer Page script created by the IDE when a basic Static Text component is dropped on the Visual Designer view of Page1. Notice the bindings created on the
<?xml version="1.0" encoding="UTF-8"?>
<jsp:root version="1.2" xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:ui="http://www.sun.com/web/ui">
<jsp:directive.page contentType="text/html;charset=UTF-8"
pageEncoding="UTF-8"/>
<f:view>
<ui:page binding="#{Page1.page1}" id="page1">
<ui:html binding="#{Page1.html1}" id="html1">
<ui:head binding="#{Page1.head1}" id="head1">
<ui:link binding="#{Page1.link1}" id="link1"
url="/resources/stylesheet.css"/>
</ui:head>
<ui:body binding="#{Page1.body1}" id="body1""
style="-rave-layout: grid">
<ui:form binding="#{Page1.form1}" id="form1">
<ui:staticText binding="#{Page1.staticText1}"
id="staticText1" style="position:
absolute; left: 96px; top: 24px"/>
</ui:form>
</ui:body>
</ui:html>
</ui:page>
</f:view>
</jsp:root>
Figure 14: Page1 Bindings Figure 15 shows the setters and getters created for the
private StaticText staticText1 = new StaticText();
public StaticText getStaticText1() {
return staticText1;
}
public void setStaticText1(StaticText st) {
this.staticText1 = st;
}
Figure 15: Getters and Setters in a Page Bean Events The Java Studio Creator 2 application model supports the JavaServer Faces action and value-change events. Java Studio Creator 2 components that allow values to be changed, such as drop down list or text box, support the value-change event. Components that cause an action, such as hyperlink or button, support the action event. Figure 16 shows the JSP page code created for a button.
<ui:button action="#{Page1.button1_action}" binding="#{Page1.button1}"
id="button1" style="position: absolute; left: 120px; top: 360px"
text="go"/>
Figure 16: JSP code for a Button Figure 17 shows the page bean method created to support an action event.
public String button1_action() {
// TODO: Process the button click action. Return value is a navigation
// case name where null will return to the same page.
return null;
}
Figure 17: Page Bean Method for Action Event Notice that the method name in Figure 17 matches the method binding expression method name in Figure 16.
<ui:textField binding="#{Page1.textField1}" id="textField1"
style="position: absolute; left: 120px; top:
144px" valueChangeListener="#{Page1.textField1_processValueChange}"/>
Figure 18: Value-Change Event Attribute Figure 19 shows the corresponding value-change event method in the page bean. These event methods are called on the page bean during the invoke application phase of the JavaServer Faces life cycle. The next section discusses the page bean life cycle.
public void textField1_processValueChange(ValueChangeEvent event) {
// TODO: Replace with your code
}
Figure 19: Value-Change Event Page Bean Method Page Bean Life CycleThe application model uses the JavaServer Faces standard request processing life cycle for the page bean life cycle. The Java Studio Creator 2 application model, however, simplifies the life cycle by leveraging part of the JavaServer Faces architecture known as phase listeners. Phase listeners allow applications to inject logic into the JavaServer Faces standard request processing life cycle shown in figure 12.
Figure 21 shows the Java Studio Creator 2 application model life cycle overlaid on the standard request processing life cycle when a JavaServer Faces request generates a JavaServer Faces response. In both figures 20 and 21, the yellow boxes represent the application model injected life cycle methods.
The
public void preprocess() {
FacesContext context = FacesContext.getCurrentInstance();
Map map = context.getExternalContext().getRequestParameterMap();
// see if the "next" button was sent in the request which would tell us the
// "next" button was pressed.
if (map.containsKey(nextButton.getClientId(context))) {
shippingMethodDropDown.setRequired(true);
} else {
shippingMethodDropDown.setRequired(false);
}
}
Figure 22: The preprocess Method The To take advantage of the Java Studio Creator 2 application model life cycle, you should understand what each phase does in the JavaServer Faces standard request processing life cycle. This section provides a brief description of each phase in the standard life cycle. For a more detailed explanation, please refer to the JavaServer Faces specification.
Page Fragment Bean The page fragment bean is identical to the page bean except for the injected methods. The page fragment bean has only In the Java Studio Creator 2 application model, a portlet page is the same as a web application page except for differences in the page life cycle. To best understand these life cycle differences, you should first understand how a portal interacts with a portlet. The JSR-168 Portlet specification defines the interaction between portals and portlets.
This interaction means that the portlet page being rendered cannot make assumptions about the state of the values to be shown. Unlike a web application page, a portlet page cannot assume that the page to be rendered in the render response phase is the same page built in the restore view phase. A portlet that wants to maintain state across repeated render requests must use the session bean to store stateful information. Figure 23 shows the life cycle of a portlet page when an action (postback) is invoked and the same portlet page is to be rendered. Notice that two separate instances of Page1 are created. Also notice that instance 1 of Page1 never goes through the render response phase, which means the component values are never saved for the UIViewRoot. Thus, when instance 2 of Page1 is created and goes through the restore view phase, the component tree pointed to by UIViewRoot does NOT have the values entered in instance 1 of Page1. It is important to remember that a portlet page must always be prepared to render it's values from scratch or session data. This implies you should never bind portlet page UI components to page bean properties or request bean properties. Also, you should never rely on page bean instance variables that might be set during an action event.
Let's look at an illustration of the portlet life cycle to see how it affects page rendering. Suppose you have a page bean that includes a static text field and a button as shown in Figure 24.
Let's say you also define a property called myString on the page bean and bind the static text field to this property. If the button action method contains the code shown in Figure 25, when you run the portlet application and press the button, the static text field is blank.
public String button1_action() {
this.myString = "Hello World";
return null;
}
Figure 25: Value-Change Event Page Bean Method Normally, you expect the static text field to contain the phrase Hello World. But here's what happens. When you press the button, the button action method sets the Data backing beans are different from user interface backing beans. Data backing beans are used to manage data and are not associated with any JSP pages. Request beans, session beans, and application beans are data backing beans. Data Backing Bean Scope and Life Cycle Because a data backing bean is not associated to a JSP page, a data backing bean has a different life cycle from a page bean. You need to understand the scope of these backing beans since they are used to manage data. The Java Studio Creator 2 application model defines three scopes for data backing beans: application, session, and request scope.
All data backing beans are managed by the JavaServer Faces managed bean facility. The facility creates the data backing bean only when it needs to, an approach called lazy instantiation. Here's how this lazy instantiation works. The JavaServer Faces managed bean facility creates a data backing bean, if it doesn't already exist, during the restore view life cycle phase when the method With lazy instantiation such as this, a developer using the application model should not rely on the instantiation of a data backing bean. Even though a particular scope is created, it does not mean that the backing beans associated with that scope are also created. As a result, you should avoid placing any necessary initialization code in data backing bean constructors. Instead, you should place all initialization code in a backing bean's Application Bean The application bean, created in the application scope, is used for managing data at the application level. The application bean has two life cycle methods: The The
Session Bean The session bean is created in the session scope and is used for managing data at the session level. The session bean has four life cycle methods: The The The The
Request Bean The request bean is created in the request scope and it has two life cycle methods The The User Interface Components The Java Studio Creator 2 application model includes four groups of user interface components: basic components, JavaServer Faces standard components, custom components, and non-visual components.
Applying the Application Model to a Web Application The best way to understand the Java Studio Creator 2 application model is to look at a working example. The sample application, Corporate Travel Center, can help you understand the application model. Download the sample. Unzip the file in a CorporateTravelCenter directory and open this project from within the Java Studio Creator 2 IDE. Once the project is open in the IDE, look at the Projects window. See Figure 26.
Notice the files with the .jsp file extension that appear beneath the Web Pages node. These files are the JSP pages for the user interface. Double click Page1.jsp to open Page1 in the Visual Designer. When it opens, you should see three buttons (Design, JSP, and Java) on the Visual Designer editing toolbar. See Figure 27. Click the Java button and the Java Editor opens and displays the source code for the Page1 page bean. Remember, in a Java Studio Creator 2 web application, there is one page bean for every JavaServer Pages page.
The init method contains the code shown in Figure 28.
/**
* <p>Callback method that is called whenever a page is navigated to,
* either directly via a URL, or indirectly via page navigation.
* Customize this method to acquire resources that will be needed
* for event handlers and life cycle methods, whether or not this
* page is performing post back processing.</p>
*
* <p>Note that, if the current request is a postback, the property
* values of the components do not represent any
* values submitted with this request. Instead, they represent the
* property values that were saved for this view when it was rendered.</p>
*/
public void init() {
// Perform initializations inherited from our superclass
super.init();
// Perform application initialization that must complete
// *before* managed components are initialized
// TODO - add your own initialization code here
// <editor-fold defaultstate="collapsed" desc="Creator-managed
Component Initialization">
// Initialize automatically managed components
// *Note* - this logic should NOT be modified
try {
_init();
} catch (Exception e) {
log("Page1 Initialization Failure", e);
throw e instanceof FacesException ? (FacesException) e: new
FacesException(e);
}
//
// Perform application initialization that must complete
// *after* managed components are initialized
// TODO - add your own initialization code here
}
Figure 28: Page1 init Method Code Notice that there are two comments (shown here in bold) that instruct the developer to put code before or after the managed components section. The code in the The The
/**
*<p>Callback method that is called just before rendering takes place.
* This method will <strong>only</strong> be called for the page that
* will actually be rendered (and not, for example, on a page that
* handled a postback and then navigated to a different page). Customize
* this method to allocate resources that will be required for rendering
* this page.</p>
*/
public void prerender() {
if (getSessionBean1().getPersonId() == null ) {
try {
personDataProvider.cursorFirst();
getSessionBean1().getTripRowSet().setObject(1,
personDataProvider.getValue("PERSON.PERSONID"));
getSessionBean1().setPersonId((Integer)personDataProvider.getValue
("PERSON.PERSONID"));
tripDataProvider.refresh();
} catch (Exception e) {
error("Cannot switch to person " +
personDataProvider.getValue("PERSON.PERSONID"));
log("Cannot switch to person " +
personDataProvider.getValue("PERSON.PERSONID"), e);
}
}else {
dropDown1.setSelected(getSessionBean1().getPersonId());
}
}
Figure 29: Page1 prerender Method The code in the The
/**
* <p>Callback method that is called after rendering is completed for
* this request, if <code>init()</code> was called (regardless of whether
* or not this was the page that was actually rendered). Customize this
* method to release resources acquired in the <code>init()</code>,
* <code>preprocess()</code>, or <code>prerender()</code> methods (or
* acquired during execution of an event handler).</p>
*/
public void destroy() {
tripDataProvider.close();
personDataProvider.close();
}
Figure 30: Page1 destroy Method Notice that the Finally, let's examine the value binding in this example. Click the JSP button in the Visual Designer editing toolbar, as shown in Figure 27 to open the JavaServer Pages script for Page1.jsp. In particular, notice the binding definition for the drop down list
<ui:dropDown binding="#{Page1.dropDown1}"
converter="#{Page1.dropDown1Converter}" id="dropDown1"
items="#{Page1.personDataProvider.options['PERSON.PERSONID,PERSON.NAME']}"
onChange="common_timeoutSubmitForm(this.form, 'dropDown1');"
style="left: 144px; top: 216px; position: absolute; width: 144px"
valueChangeListener="#{Page1.dropDown1_processValueChange}"/>
Figure 31: Page1 JavaServer Pages Script The definition supports instance binding because of the clause
private IntegerConverter dropDown1Converter = new IntegerConverter();
public IntegerConverter getDropDown1Converter() {
return dropDown1Converter;
}
public void setDropDown1Converter(IntegerConverter ic) {
this.dropDown1Converter = ic;
}
Figure 32: Page1 Converter Methods Summary You should now have a good understanding of the Java Studio Creator 2 application model and how it was derived from the JavaServer Faces application model. You should understand the application model event life cycle and its methods, along with the event life cycle differences between web application pages and portlet application pages.
More Developer Resources For more tech tips, articles, and expert advice for developers, visit the Java Studio Creator developer resources on the Sun Developer Network (SDN). |
| |||||||||||||||||||||||||||||||||||||||||||||
|
| ||||||||||||