Developing Web Applications for WebSphere Using MVC Beans
Articles and Tips: article
Senior Software Engineer
Novell Web Application Servers
jhanson@novell.com
01 Aug 2000
The Web Application Servers team at Novell has developed a suite of Java Beans that expose NetWare services to the Web application environment using the Model/View/Controller (MVC) pattern. These Beans are known as MVC Beans for eBusiness. This article provides an introduction to developing Web applications using MVC Beans for eBusiness.
- Introduction
- Employing the MVC Pattern in the Web Application Environment
- JavaServer Pages (JSP)
- Command Beans
- Format Beans
- Sample Code
- Summary
Introduction
Web applications consist of requests made from Web browsers or applications running on a client workstation to Web application servers using the HTTP protocol. The interaction between a Web application server and a Web client begins with an HTML page displayed in a Web browser. A user submits a form or clicks on a link, which is sent to the Web application server. This request is processed on the Web application server and the results are returned as a new HTML page to the client. The architecture and components used to handle the interactions between a Web client and a Web application server can be employed using a model/view/controller (MVC) pattern as follows:
Model - the components that expose the business logic for a particular Web application or service.
View - the components that construct HTML pages that are returned to a user by a Web application in response to HTTP requests.
Controller - the components or services that drive the Model and View components.
Employing the MVC Pattern in the Web Application Environment
Servlets are server-side Java programs that extend a Web server to handle HTTP requests. The request-handling methods of a servlet are expected to extract information from request parameters, perform business logic, and then send back HTML responses to a client.
A typical Web application generates significant amounts of HTML content to be sent back to a client. Some of this content is dynamic and some is static. A typical servlet implements business logic and generates the HTML content that is sent to the client. This model does not readily allow separation between the user interface and the business logic, and it requires the servlet programmer to recompile the servlet to make any sort of change to the business logic or user interface. Also, the multiple print statements required to generate the HTML makes the code hard to read and maintain. These problems are solved with the introduction of JavaServer Pages or JSP.
JavaServer Pages (JSP)
The basic concept of JSP is quite simple. A set of custom HTML tags is defined that allow developers to embed Java code in HTML. The JSP is converted into a Java servlet and compiled on its first invocation. Subsequent invocations are simply routed through the cached instance. This mechanism allows content to be added to a page dynamically and sent to the client. All processing of a JSP is done on the server.
The servlet/JSP interaction closely follows the model-view-controller design for applications. This design de-couples the development process and allows different skills and tools to be used for different portions of the application. The idea of this design is to use servlets to process HTTP requests and invoke the business logic and JSP to compose the user interface. MVC Beans for eBusiness builds on this development process de-coupling, to propose that business logic can be separated into Java components called "command beans," and complex user interface can be separated into Java components called "format beans." The flow of control in the processing of an HTTP request using command and format beans is:
The HTTP request is handled by a target servlet.
The servlet instantiates and calls methods belonging to one or more command beans to perform the business logic of the request.
The command beans implementing the business logic access relational databases, connectors, directory services, file systems, and so on while performing their specific actions.
The servlet then invokes a JSP after storing some command bean instances to the execution/session context for use by the JSP.
The content on the JSP is dynamically generated from the request and execution/session context and the page is sent to the client. This process may leverage formatting beans, other JSPs, and static resources such as HTML files, and image files.
Figure 1: The interaction between the different elements involved in a Java-based Web application.
Command Beans
A command bean is a Java Bean that encapsulates a single business logic task. A command bean is used by creating the bean, initializing the state of the bean by setting specific properties of the bean, instigating the bean to execute its specific business logic task by calling its "perform" method, and then getting the values of the bean's properties. This programming model helps to isolate changes in the Web application by factoring the business logic into fine-grained components that are easily managed and less reliant on other components. This model also allows easier distribution of processing using serialization to send the bean over IIOP, HTTP, etc. to a remote server to be executed and then sent back with the results.
The Command interface provides the primary interface for the command bean. It consists of three methods: isReadyToCallPerform, perform and reset. A command bean can be in one of the following states during its lifecycle:
New: The command bean is in this state immediately after creation. In this state the isReadyToCallPerform method will return false, and the output properties should not be retrieved.
Initialized: The command bean is in this state after all required input properties have been set. In this state the isReadyToCallPerform method will return true, and the output properties should not be retrieved.
Executed: The command bean is in this state after the perform method has been called. In this state the isReadyToCallPerform method will return true, and the output properties can be retrieved.
Command beans that execute locally (in the same JVM as the Web application) simply implement the Command interface. If a command bean is to execute remotely on another server it implements the TargetableCommand interface, which is an extension of the Command interface that allows for remote execution; this is done by extending the TargetableCommandImpl class. Regardless of whether the command bean executes locally or remotely the JSP/servlet executes the command bean in the same way. The steps in a command bean's execution are as follows:
The servlet instantiates the command bean. It then sets the command bean's input properties. The servlet then calls the perform method on the command bean. If the command bean executes locally, skip to step 2 below. Otherwise, these additional steps occur:
The perform method determines the target environment for the command bean.
The perform method calls the executeCommand method on the CommandTarget object passing itself (the command bean) as an input argument. This step may entail serializing the command bean and sending it via some protocol (e.g. IIOP) to the target server for execution.
The command target, after potentially de-serializing the command bean, then calls the command bean's executePerform method, which encapsulates the business logic.
The perform method, if successful, returns with its output properties set to the results of the underlying business logic task.
Control flows to the JSP, which is now free to query the output properties of the command bean.
Format Beans
The view components of a Web application are responsible for generating the HTML page that is returned to the client. Once one or more command beans are driven to the executed state, data can be retrieved from them and formatted to view in an HTML page. Simple data formatting can be done using standard HTML tags. More complex data formatting is done using format beans that take the data set and return formatted HTML.
Format beans support JSP and help format various types of dynamic content. Complex data formatting is easily done using one or more format beans. Formatting is usually specific to the characteristics of the user, such as the locale of the user. For this reason each format bean class method comes in at least two forms, one of which takes the servlet request object as a parameter and one which does not. When the request object is provided, the method will extract information from the request object to customize the formatting operation. When the request object is not provided, the method will use default values or server-wide values such as the default locale. Most of the format beans produce locale specific results. By convention, they determine the locale from the request context value "JSPLocale" which must be a java.util.Locale value. If "JSPLocale" is not set in the request context or the request context is not available, the system's default locale will be used. Each of the format classes also allows the locale to be configured into a format bean in which case the configured locale will take precedent over the JSPLocale value, if any.
Sample Code
Novell provides a comprehensive set of command and format beans called MVC Beans for eBusiness, that allow Web application developers to easily incorporate NetWare services into the Web application. This set includes beans that expose the NetWare File System, Novell's eDirectory, and the NetWare operating system internals. The following examples demonstrate how to use the MVC Beans for eBusiness provided by Novell in servlets and JSPs:
Note: Sharing beans between servlets and JSPs is accomplished using different mechanisms depending upon the "scope" of the bean. There are four possible scopes for a bean in a JSP: page, request, session, and application. Page scope cannot be used for a bean that is to be shared. A servlet uses different objects to store a bean depending upon which one of the other three scopes is specified by the jsp:usebean tag in the JSP. Examples of the use of these different objects to sotre beans for later use by a JSP are as follows:
Request scope: Servlet code: request.setAttribute("myBean", myBean); JSP code: jsp:useBean id="myBean" scope="request" class="MyBeanClass "/
Session scope:Servlet code: request.getSession(true).putValue("myBean", myBean); JSP code: jsp:useBean id="myBean" scope="session" class="MyBeanClass " /
Application scope:Servlet code: getServletContext().setAttribute("myBean", myBean); JSP code: jsp:useBean id="myBean" scope="application" class="MyBeanClass " /
Storing beans by the servlets in the following samples for later use by JSPs will be implied as request or session scope.Command Beans Samples
eDirectory
The following code shows how to authenticate from a servlet.
authBean = new AuthenticateEDir(); authBean.setTreeName(treeName); authBean.setUserContext(context); authBean.setUserID(userName); authBean.setUserPassword(password); try { authBean.perform(); out.println("authenticated"); } catch(com.novell.web.command.CommandException e) { out.println(e); }
Use the following code to search for entries of a given class.
Servlet Code
FindEDirEntries cmdBean = new FindEDirEntries(); cmdBean.setTreeName(treeName); cmdBean.setContext(context); cmdBean.setClassName(className); try { cmdBean.perform(); } catch(com.novell.web.command.CommandException e) { System.out.println(e); }
<jsp:useBean class="com.novell.web.command.beans. edir.FindEDirEntries" id="cmdBean" /> <% out.println("<BR>Entry contexts:"); String[] contexts = cmdBean.getEntryContexts(); if (contexts != null) { for (int i = 0; i < contexts.length; i++) { out.println("<BR>" +contexts[i]); } } %>
JSP Code
To create a user from a servlet, use the following example code.
AuthenticateEDir authBean = doAuthentication(); // do authentication here if (authBean == null) { return; } CreateEDirEntry cmdBean = new CreateEDirEntry(); cmdBean.setAuthenticatedObject(authBean); cmdBean.setTreeName(treeName); cmdBean.setContext(userName +"." +context); cmdBean.setEntryClassName("User"); Hashtable attrMap = new Hashtable(); attrMap.put("Surname", new EDirAttrValueDistinguishedName(surname)); cmdBean.setMandatoryAttributes(attrMap); try { cmdBean.perform(); out.println("Entry creation was successful"); } catch(com.novell.web.command.CommandException e) { out.println(e); } doUnauthentication(authBean); // do unauthentication here
To modify attribute values from a servlet, use the code that follows.
AuthenticateEDir authBean = doAuthentication(); // do authentication here if (authBean == null) { return; } ReplaceValuesOfAttribute cmdBean = new ReplaceValuesOfAttribute(); cmdBean.setAuthenticatedObject(authBean); cmdBean.setTreeName(treeName); cmdBean.setContext(context); cmdBean.setAttributeName("Description"); cmdBean.setValues(new EDirAttrValue[] { new EDirAttrValueCaseIgnoreString("newvalue1"), new EDirAttrValueCaseIgnoreString("newvalue2") }, new EDirAttrValue[] { new EDirAttrValueCaseIgnoreString("anothervalue1"), new EDirAttrValueCaseIgnoreString("anothervalue2") }); try { cmdBean.perform(); out.println("Values replace was successful"); } catch(com.novell.web.command.CommandException e) { out.println(e); } doUnauthentication(authBean); // do unauthentication here
The following code shows how to delete a user from a servlet.
AuthenticateEDir authBean = doAuthentication(); // do authentication here if (authBean == null) { return; } DestroyEDirEntry cmdBean = new DestroyEDirEntry(); cmdBean.setAuthenticatedObject(authBean); cmdBean.setTreeName(treeName); cmdBean.setContext(context); try { cmdBean.perform(); out.println("Entry destruction was successful"); } catch(com.novell.web.command.CommandException e) { out.println(e); } doUnauthentication(authBean); // do unauthentication here
Use the following to unauthenticate from a servlet.
UnauthenticateEDir cmdBean = new UnauthenticateEDir(); cmdBean.setAuthenticatedObject(authBean); // pass in previously // created authentication bean try { cmdBean.perform(); out.println("unauthenticated"); } catch(com.novell.web.command.CommandException e) { out.println(e); }
OS Internals
The following example shows code used to clear a connection from a servlet.
ClearConnection cmdBean = new ClearConnection(); cmdBean.setConnectionName("NOT_LOGGED_IN"); try { cmdBean.perform(); } catch(com.novell.web.command.CommandException e) { out.println(e); }
To list connections, use the following.
Servlet Code
ListConnections cmdBean = new ListConnections(); try { cmdBean.perform(); } catch(com.novell.web.command.CommandException e) { System.out.println(e); }
<jsp:useBean class="com.novell.web.command.beans.edir.ListConnections" id="cmdBean" /> Connections: <% String[] names = cmdBean.getNames(); if (names != null) { for (int i = 0; i < names.length; i++) { out.println("<BR>" +names[i]); } } %>
JSP Code
To broadcast a message to all connections from a servlet, use the following code.
BroadcastMessageToAll cmdBean = new BroadcastMessageToAll(); cmdBean.setMessage("Free pizza is being served..."); try { cmdBean.perform(); } catch(com.novell.web.command.CommandException e) { out.println(e); }
The code that follows shows how to display server health from a JSP.
<jsp:useBean class="com.novell.web.command.beans.os.ListHealthStats" id="listHealthStats" /> <jsp:useBean class="com.novell.web.command.beans.os.GetHealthStatValue" id="getHealthStatValue" /> <TABLE border="1"> <% try { listHealthStats.perform(); String[] statNames = listHealthStats.getNames(); if (statNames != null) { out.println("<TR><TD>#</TD>"); out.println("<TD><B>Statistic Name</B></TD>"); out.println("<TD><B>Value</B></TD></TR>"); for (int i =0; i < statNames.length; i++) { getHealthStatValue.setHealthStatName(statNames[i]); try { getHealthStatValue.perform(); out.println("<tr><td>" + i + "</td>"); out.println("<td>" + statNames[i] + "</td>"); out.println("<td>" + getHealthStatValue.getValue() +"</td></tr>"); } catch(com.novell.web.command.CommandException e) { out.println("<tr><td colspan=3>" +e.getMessage()); } } } } catch(com.novell.web.command.CommandException e) { out.println(e.getMessage()); } %> </TABLE>
The following code is used for listing volumes.
ListVolumes cmdBean = new ListVolumes(); try { cmdBean.perform(); } catch(com.novell.web.command.CommandException e) { System.out.println(e); }
Servlet Code
<jsp:useBean class="com.novell.web.command.beans.os.ListVolumes" id="cmdBean" /> Mounted Volume Names: <% String[] names = cmdBean.getNames(); if (names != null) { for (int i = 0; i < names.length; i++) { out.println("<BR>" +names[i]); } } %>
JSP Code
The following sets of code are used for listing threads from a servlet and a JSP, respectively.
ListThreads cmdBean = new ListThreads(); try { cmdBean.perform(); } catch(com.novell.web.command.CommandException e) { System.out.println(e); }
Servlet Code
<jsp:useBean class="com.novell.web.command.beans.os.ListThreads" id="cmdBean"/> Thread Names: <% String[] names = cmdBean.getNames(); if (names != null) { for (int i = 0; i < names.length; i++) { out.println("<BR>" +names[i]); } } %>
JSP Code
NetWare File System
The following code shows how to authenticate from a servlet.
AuthenticateNWFS cmdBean = new AuthenticateNWFS(); cmdBean.setServerName(serverName); cmdBean.setUserID(userContext); cmdBean.setUserPassword(userPassword); cmdBean.setPath(authPath); try { cmdBean.perform(); out.println("Authenticated"); } catch(com.novell.web.command.CommandException e) { out.println(e); }
To unathenticate from a servlet, use the code below.
UnauthenticateNWFS cmdBean = new UnauthenticateNWFS(); cmdBean.setAuthenticatedObject(authBean); // previously authenticated bean try { cmdBean.perform(); out.println("Unauthenticated"); } catch(com.novell.web.command.CommandException e) { out.println(e); }
The following is an example of how to list file and directory entries.
AuthenticateNWFS authBean = authenticateToNWFS(); // do authentication if (authObj != null) { ListNWFSEntries cmdBean = new ListNWFSEntries(); cmdBean.setAuthenticatedObject(authBean); cmdBean.setServerName(serverName); cmdBean.setVolumeName("SYS"); cmdBean.setPath("java/beans"); try { cmdBean.perform(); } catch(com.novell.web.command.CommandException e) { System.out.println(e); } unauthenticateToNWFS(authBean); // do unauthentication }
Servlet Code
<jsp:useBean class="com.novell.web.command.beans.os.ListNWFSEntries" id="cmdBean"/> Child Entries: <% String[] names = cmdBean.getEntryNames(); if (names != null) { for (int i = 0; i < names.length; i++) { out.println("<BR>" +names[i]); } } %>
JSP code
To salvage deleted files from a servlet, use the following code.
AuthenticateNWFS authBean = authenticateToNWFS(); // do authentication if (authBean!= null) { ListDeletedFiles dfBean = new ListDeletedFiles(); dfBean.setAuthenticatedObject(authBean); dfBean.setServerName(serverName); dfBean.setVolumeName("SYS"); dfBean.setPath("java/classes"); try { dfBean.perform(); int fileCount = dfBean.getFileCount(); if (fileCount > 0) { SalvageDeletedFile cmdBean = new SalvageDeletedFile(); for (int i = 0; i < fileCount; i++) { cmdBean.reset(); cmdBean.setAuthenticatedObject(authBean); cmdBean.setServerName(serverName); cmdBean.setVolumeName("SYS"); cmdBean.setPath("java/classes/" + dfBean.getNameAt(i)); cmdBean.setAlternateName("salvaged" + i); int dt = dfBean.getDeletedDateAndTimeAsIntAt(i); cmdBean.setDeletedDateAndTime(dt); cmdBean.perform(); out.println("<BR>Salvaged: " + dfBean.getNameAt(i)); } } catch(com.novell.web.command.CommandException e) { out.println(e); } unauthenticateToNWFS(authBean); // do unauthentication }
The code below shows how to purge deleted files from a servlet.
AuthenticateNWFS authBean = authenticateToNWFS(); // do authentication if (authBean != null) { ListDeletedFiles dfBean = new ListDeletedFiles(); dfBean.setAuthenticatedObject(authBean); dfBean.setServerName(serverName); dfBean.setVolumeName("SYS"); dfBean.setPath("java/classes"); try { dfBean.perform(); int fileCount = dfBean.getFileCount(); if (fileCount > 0) { PurgeDeletedFile cmdBean = new PurgeDeletedFile(); for (int i = 0; i < fileCount; i++) { cmdBean.reset(); cmdBean.setAuthenticatedObject(authBean); cmdBean.setServerName(serverName); cmdBean.setVolumeName("SYS"); cmdBean.setPath("java/classes/" + dfBean.getNameAt(i)); int dt = dfBean.getDeletedDateAndTimeAsIntAt(i); cmdBean.setDeletedDateAndTime(dt); cmdBean.perform(); out.println("<BR>Purged: " + dfBean.getNameAt(i)); } } catch(com.novell.web.command.CommandException e) { out.println(e); } unauthenticateToNWFS(authBean); // do unauthentication }
To add trustess from a servlet, use the following.
AuthenticateNWFS authBean = authenticateToNWFS(); // do authentication if (authBean != null) { AddTrusteeToEntry cmdBean = new AddTrusteeToEntry(); cmdBean.setAuthenticatedObject(authBean); cmdBean.setServerName(serverName); cmdBean.setVolumeName("SYS"); cmdBean.setPath("java/beans"); cmdBean.setTrusteeContext("jdoe.myorg"); cmdBean.setTrusteeRights(NWTrusteeRights.READ + NWTrusteeRights.WRITE + NWTrusteeRights.CREATE + NWTrusteeRights.ACCESS + NWTrusteeRights.SCAN); try { cmdBean.perform(); out.println("Trustee addition successful:"); } catch(com.novell.web.command.CommandException e) { out.println(e); } unauthenticateToNWFS(authBean); // do unauthentication }
To remove a trustee, follow the code below.
AuthenticateNWFS authBean = authenticateToNWFS(); // do authentication if (authObj != null) { RemoveTrusteeFromEntry cmdBean = new RemoveTrusteeFromEntry(); cmdBean.setAuthenticatedObject(authObj); cmdBean.setServerName(serverName); cmdBean.setVolumeName("SYS"); cmdBean.setPath("cakes"); cmdBean.setTrusteeContext("jdoe.jeffh_org"); try { cmdBean.perform(); out.println("Remove Trustee successful:"); } catch(com.novell.web.command.CommandException e) { out.println(e); } unauthenticateToNWFS(authBean); // do unauthentication }
The two sets of code that follow show how to retrieve the total free space for a volume using both servlet code and JSP code.
AuthenticateNWFS authBean = authenticateToNWFS(); // do authentication if (authBean != null) { GetVolumeFreeSpace cmdBean = new GetVolumeFreeSpace(); cmdBean.setAuthenticatedObject(authBean); cmdBean.setServerName(serverName); cmdBean.setVolumeName("SYS"); try { cmdBean.perform(); } catch(com.novell.web.command.CommandException e) { System.out.println(e); } unauthenticateToNWFS(authBean); // do unauthentication }
JSP Code
Servlet Code
<jsp:useBean class="com.novell.web.command.beans.os.GetVolumeFreeSpace" id="cmdBean"/> Volume Free Space in bytes: <%=cmdBean.getSpace()%>
Format Beans Used Within a JSP
To view the console screen, use the following.
<jsp:useBean id="nwSrvOS" class="com.novell.beans.NWSrvOS.NWSrvOS" scope="request"/> <jsp:useBean id="screenFormat" class="com.novell.web.format.beans.NWSimpleScreenFormat" scope="request"/> <%@ page import ="com.novell.beans.NWSrvOS.Screens" %> <% Screens screens = nwSrvOS.getScreens(); %> <%=screenFormat.format(request, screens.getElement(Screens.SYSTEM_CONSOLE))%>
To create a tree browser from a JSP, use the code below.
Note: This assumes a Web application has been previously created named "MVCSamples."
<jsp:useBean id="edirBrowserFmt" class="com.novell.web.format.beans.EDirTreeBrowserFormat" scope="session"/> <% HttpSession theSession = request.getSession(false); String treeName = (String)theSession.getValue("TreeName"); String action = request.getParameter("Action"); String nodePath = request.getParameter("NodePath"); boolean resetTree = theSession.isNew(); if ((action != null) && action.equalsIgnoreCase("Reset")) { String reqTreeName = request.getParameter("TreeName"); if (reqTreeName != null) { treeName = reqTreeName; theSession.putValue("TreeName", treeName); } resetTree = true; } %> <CENTER><H3>eDirectory Administration</H3></CENTER> <HR> <% if (treeName != null) { edirBrowserFmt.removeAllViewElements();
if (resetTree) { edirBrowserFmt.setTreeName(treeName); edirBrowserFmt.setWebAppURI("/webapp/MVCSamples/edir"); edirBrowserFmt.setDocName("treebrowser.jsp"); edirBrowserFmt.setSize(900, 400); edirBrowserFmt.setCaption(treeName); edirBrowserFmt.setNavigateCaption("Navigate Pane"); edirBrowserFmt.setViewCaption("View Pane"); edirBrowserFmt.setNavigateNodeWidth(200); edirBrowserFmt.setNavigateImagesURL("/webapp/MVCSamples/edir/images"); edirBrowserFmt.setContainerImageName("closedfolder.gif"); edirBrowserFmt.setLeafImageName("leaf.gif"); edirBrowserFmt.setRootNode(null); } if (nodePath != null) { edirBrowserFmt.setNodePath(nodePath); } if (action != null) { edirBrowserFmt.setAction(action); if (action.equalsIgnoreCase( com.novell.web.format.beans.EDirTreeBrowserFormat.ACTION_VIEW)) { if ((nodePath != null) && (nodePath.equalsIgnoreCase(treeName))) { edirBrowserFmt.appendViewElement("Go to <A" +"href='http://www.novell.com'>Novell</A>"); edirBrowserFmt.appendViewElement("<BR>" +"<img src='/webapp/MVCSamples/edir/images/bigimg.gif'" +" alt='Big Image' border=noborder>"); } } } theSession.putValue("TreeName", treeName); %> <%=edirBrowserFmt.format()%> <% } %>
Summary
Novell's MVC Beans for eBusiness work together to provide a complete environment for developing Web applications that expose NetWare services. These beans simplify Web application development and deployment by factoring NetWare services into manageable components that work within a Web application server environment.
References
http://developer.novell.com/websphere/
http://www.javasoft.com/products/jsp/
http://www-4.ibm.com/software/ebusiness/buildapps/understand.html
http://www.ibm.com/developer/features/framework/framework.html
http://developer.novell.com/ndk/downloadaz.htm
http://developer.novell.com/ndk/leadedge.htm
* Originally published in Novell AppNotes
Disclaimer
The origin of this information may be internal or external to Novell. While Novell makes all reasonable efforts to verify this information, Novell does not make explicit or implied claims to its validity.