How to Use MVC Beans for eBusiness to Administer eDirectory Using Your Browser
Articles and Tips: article
Senior eBusiness Architect
Financial Fusion
jhanson583@aol.com
01 Dec 2000
This AppNote discusses how Web programmers can design and implement eDirectory administration utilities from a Web browser, so that they caneasily be ported to other remote devices.
- The Need for Thin-Client eDirectory Administration
- Abstracting Design to Avoid Device Dependency
- Application Task Examples
- Summary
The Need for Thin-Client eDirectory Administration
Advances in mobile computing technologies have made the ability for network administrators to manage resources remotely very real. With the directory- services client community moving into arenas spanning devices from browsers to Web-enabled cell phones, the need to interface with many different devices is suddenly urgent. However, designing and implementing distributed applications to meet the needs of the Web-browsing community is difficult enough without worrying about compatibility with Web phones, palm devices, and so on.
This AppNote discusses how Web programmers can design and implement eDirectory administration utilities from a Web browser, so that they can easily be ported to other remote devices. We will construct a three-tier utility that mimics the functionality of common tree-browsing management applications. However, the concepts can easily be transported to list-based or table-based UI designs.
In this AppNote we use Java server-side technologies such as servlets and Java Beans to perform command dispatching and execute business logic on the middle tier. Java Beans and Enterprise Java Beans (EJB) are used to access data on the back end. To construct the user interface we will use Java Beans, HTML, Java Server Pages (JSP) and JavaScript. We will utilize the model-view-controller (MVC) design pattern to avoid inter-code dependencies, isolate bug fixing, and enable new features and enhancements to be easily implemented using "plug-in" style techniques.
Novell ships a suite of Java components called MVC Beans for eBusiness that provide access to eDirectory and are optimized for Web application develop- ment using the MVC design pattern. These components will provide most of our business logic and data access. We will construct our utility based around these components.
Abstracting Design to Avoid Device Dependency
Web applications typically consist of an HTTP request passed from a Web browser to a Web server or Web application server where some form of business logic (or data access) is performed. The response is formed in HTML and passed back to the Web browser. We can abstract this interaction between the client and server using the model-view-controller (MVC) pattern.
Controller
In the MVC pattern, the request is initially handled by a servlet residing within the Web application environment. This servlet acts as the controller of the Web application. The controller-servlet reacts to the request by retrieving data for the client and by executing business logic for the client. The controller-servlet then passes a response in the form of HTML back to the client.
Model
Using one servlet to handle data access, perform business logic, form HTML responses, and so on, leads to an implementation that is not easily customized for different domains and/or client devices. We solve this problem by letting the controller-servlet handle the incoming requests, but supplying the controller- servlet with Java Beans that perform data access and business logic. As long as we carefully craft the interfaces that the Java Beans expose, we can easily replace the beans with other beans that access different data sources or perform different business logic. This can all take place without re-installing the application or bringing down the server. The beans we use for data access and business logic will be referred to as "command beans" and will make up the model of our application.
View
We want to take our design even further towards shielding ourselves from customization problems and, at the same time, provide a clean mechanism for supporting multiple client devices. We do this by introducing Java Server Pages and "format beans" as the means to produce the user interface that is passed back to the client.
Java Server Pages (JSPs) are simply HTML pages with a few special tags introduced that allow Java code to be embedded within the HTML. On its first invocation, a JSP is compiled on the server into a Java servlet. The resulting servlet then handles the duties of forming the response that is passed back to the client. An HTML author can customize the JSP at any point after its creation and the server will then re-compile the JSP on its next invocation and the customization will be exposed to the client. This eliminates the need to recompile any other part of the application, and can be done while the server and application are running.
Format beans are Java Beans that handle complex user-interface construction such as complex tables, charts, images, and so on. Format beans are used within a JSP page to eliminate the need for advanced Java programming skills by an HTML author. The HTML author can choose which format bean to use to produce the type of user interface desired. Format beans can be written to produce user interfaces for all kinds of client devices. These devices can include Web browsers, palm devices, Web-enabled phones, XML-enabled devices and others. Java Server Pages and format beans make up the view portion of our application.
Application Task Examples
Novell's MVC Beans for eBusiness provide command and format beans as well as controller servlets to form the base framework for many types of domains. We will be using Novell's eDirectory command beans in the examples that follow to perform all kinds of directory services management duties.
Authenticating Remote Users
One of the first items of business is to make sure the client request originates from an authorized user. For our examples, we will consider any existing user in our directory services tree, at a given context, an authorized user. For our application to gather enough information to authenticate a user to our directory services tree, we need to present the user with an HTML form or similar interface that provides text input fields for a tree name, a context, the user's name (ID), and the user's password. The values from these fields will be passed to our controller servlet to be used as credentials with which we can attempt to authenticate the user.
Passing userIDs with passwords across an HTTP connection immediately raises one concern: how to transport the user's password across the wire securely. A number of mechanisms are currently used to handle this problem, such as basic base-64 encoded authentication, certificate authentication, transporting data across a secure-socket layer (SSL) connection, using a custom HTML form, and others. We will leave this discussion for a later article. For now, we will assume that all pieces of the credentials make it across the wire securely.
Once we have the tree name, context, user name, and password, we can use these as input properties to the AuthenticateEDir command bean. After setting the input properties on the AuthenticateEDir command bean, we call the perform method on the bean.
The following code examples demonstrate how a servlet can look for authentication credentials and either validate those credentials or pass back a request to the client to get the credentials.
import javax.servlet.*; import javax.servlet.http.*; public class MyEDirServlet extends HttpServlet { private AuthenticateEDir authBean = null; private String treeName = ""; private String context = ""; private String userID = ""; private String password = ""; public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { doGet(req, res); } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // if session is new, we need to respond to the client and // request the authentication credentials if ((authBean == null) && (getCredentials(request) == false)) { writeAuthenticationResponse(response); return; } if ((authBean = doAuthentication(treeName, context, userID, password))== null) { throw new ServletException("Invalid userID and/or password"); } storeSessionValues(request); callJSPPage(request, response); } } boolean getCredentials(HttpServletRequest request) { // test credentials retrieved from query parameters and return boolean // flag accordingly if ((treeName = request.getParameter("TREE_NAME")) == null) { return(false); } if ((context = request.getParameter("CONTEXT")) == null) { return(false); } if ((userID = request.getParameter("USER_ID")) == null) { return(false); } if ((password = request.getParameter("PASSWORD")) == null) { return(false); } return(true); } void writeAuthenticationResponse(HttpServletResponse response) { // This method is where the programmer can decide what kind of authentication // mechanism is required and what kind of response to pass to the client. // The different mechanisms can be basic authentication, certificate // authentication, custom HTML forms, etc. } void callJSPPage(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { getServletContext().getRequestDispatcher("/treebrowser.jsp").forward(request, response); }
When we establish the fact that we are working with a new client and that the authentication credentials have been passed to our servlet, we attempt to authenticate the client as shown in the following code sample.
public AuthenticateEDir doAuthentication(String treeName, String context, String userName, String password) { authBean = new AuthenticateEDir(); authBean.setTreeName(treeName); authBean.setUserContext(context); authBean.setUserID(userName); authBean.setUserPassword(password); try { authBean.perform(); return authBean; // user authentication succeeded } catch(com.novell.web.command.CommandException e) { } return null; // user authentication failed }
To end a session with a user, use the UnauthenticateEDir command bean to un-authenticate the user. Do this by passing the saved AuthenticateEDir bean in as the only input property of the AuthenticateEDir command bean, then call the perform method on the bean as shown in the following code sample.
public void doUnauthentication(AuthenticateEDir authBean) throws ServletException { UnauthenticateEDir cmdBean = new UnauthenticateEDir(); cmdBean.setAuthenticatedObject(authBean); try { cmdBean.perform(); } catch(com.novell.web.command.CommandException e) { throw new ServletException(e.toString()); } }
Maintaining State for Each User
Since the HTTP protocol is stateless (does not maintain state across multiple requests from the same user), we need a way to preserve the state of the user's session. We do this by exploiting the state-saving mechanism presented to us by the HttpSession object. The HttpSession object is retrieved from the request object. Once the session object is retrieved, we use it to store objects containing any arbitrary data that we need to keep track of during our session with each client.
The following example demonstrates how to retrieve the session object and then use it to store an instance of the AuthenticateEDir bean and other Objects to be used throughout the session.
void storeSessionValues(HttpServletRequest request) { HttpSession session = getSession(request); session.putValue("authBean", authBean); // The following values are stored in order to be retrieved and used by // a JSP that will create our user interface/view session.putValue("TreeName", treeName); session.putValue("edirBrowserFmt", new com.novell.web.format.beans.EDirTreeBrowserFormat()); } HttpSession getSession(HttpServletRequest request) { HttpSession session = null; if (request.isRequestedSessionIdValid()) { session = request.getSession(false); } else { session = request.getSession(true); } }
Building the Tree View
Once we have successfully authenticated the user and stored the needed objects in the session object, we can concentrate on building the tree-view explorer that will be used as the main point of interest throughout the duration of our application's interaction with the client. We will construct a user interface that is similar to many explorer-style user interfaces used to present hierarchical name-spaces such as file systems, class diagrams, and so on. To construct our tree-view explorer interface, we will use the EDirTreeBrowserFormat format bean that is shipped with Novell's MVC Beans for eBusiness.
The following example shows how to construct a tree-view explorer interface using the EDirTreeBrowserFormat bean. This example assumes an introductory level of experience with JSP 1.0 by the user. As stated before, we can build device independency into our application by utilizing format beans and JSPs. In this example we could easily replace the EDirTreeBrowser- Format bean with a format bean designed for a handheld device such as a Web-enabled phone, without affecting any other part of the application.
The first matter of business is to declare the EDirTreeBrowserFormat bean that we will use. We give it the name, "edirBrowserFmt" with a scope of "session". This means we can refer to the bean throughout the document as edirBrowserFmt and we can rely on the bean to "live" for the duration of the session with our client.
<jsp:useBean id="edirBrowserFmt" class="com.novell.web.format.beans.EDirTreeBrowserFormat" scope="session"/> <% HttpSession theSession = request.getSession(false); // the following three lines rely on the servlet to place the desired // values into the session before this page is called String treeName = (String)theSession.getValue("TreeName"); String action = request.getParameter("Action"); String nodePath = request.getParameter("NodePath"); boolean initializing = theSession.isNew(); if ((action != null) && action.equalsIgnoreCase("Reset")) { initializing = true; } %> <CENTER><H3>eDirectory Administration</H3></CENTER> <HR> <% if (treeName != null) { edirBrowserFmt.removeAllViewElements(); if (initializing) { // on our first invocation, we set up the size of the tree-view // explorer, the location of our tree-view images, the relative URI for // our Web application and other properties 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)) { // the following block demonstrates how to customize the default // view pane of a node. This is accomplished by passing in HTML // statements to be appended to each other as the view to be //displayed. 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()%> <% } %>
Customizing Entry Views
As demonstrated in our last example, we can customize the view pane that is displayed for a given node by passing in HTML statements to be appended to each other. The following example customizes the view pane for the root node by showing a link and an image.
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>"); } }
Adding New Entries
One of the primary duties of a directory services management application is to add entries to the tree as needed. The following example demonstrates how to use the CreateEDirEntry command bean to create a new entry and add it the directory services tree at a particular context. Since we are adding a new User entry and the only mandatory attribute needed for a User entry is the Surname, we only add the Surname to the mandatory attributes Hashtable before calling the perform method. However, if additional mandatory attributes were required, we would add those to the Hashtable as name/value pairs as well.
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(); } catch(com.novell.web.command.CommandException e) { throw new ServletException(e.toString()); }
Deleting Entries
Another primary duty of a directory services management application is to delete entries from the tree. The following example demonstrates how to use the DestroyEDirEntry command bean to remove a given entry from the directory services tree at a particular context. The only input properties required for this action are the AuthenticatedEDir bean, the tree name, and the full context of the entry.
DestroyEDirEntry cmdBean = new DestroyEDirEntry(); cmdBean.setAuthenticatedObject(authBean); cmdBean.setTreeName(treeName); cmdBean.setContext(context); try { cmdBean.perform(); } catch(com.novell.web.command.CommandException e) { throw new ServletException(e.toString()); }
Modifying Existing Entries
Directory services management applications also must provide the ability to modify individual values of the attributes for entries in the directory services tree. The following example demonstrates how to use the AddValuesTo- Attribute command bean to add new values to the Description attribute of an entry in the tree. Note that we can add multiple values at a time by passing in the values in an array of EDirAttrValue objects.
AddValuesToAttribute cmdBean = new AddValuesToAttribute(); cmdBean.setAuthenticatedObject(authBean); cmdBean.setTreeName(treeName); cmdBean.setContext(context); cmdBean.setAttributeName("Description"); cmdBean.setValues(new EDirAttrValue[] { new EDirAttrValueCaseIgnoreString("newvalue1"), new EDirAttrValueCaseIgnoreString("newvalue2") }); try { cmdBean.perform(); } catch(com.novell.web.command.CommandException e) { throw new ServletException(e.toString()); }
Summary
Management duties for a directory services application can prove to be complex and difficult to maintain and enhance. By utilizing the model/view/ controller pattern and the command and format beans provided by Novell's MVC Beans for eBusiness, we can greatly reduce the time required to develop the application, as well as provide a very clean mechanism for future enhancements and bug fixes.
For Further Reference
Following are suggested references for further information on the topics covered in this AppNote.
"How to Develop Web Applications for WebSphere Using MVC Beans", Novell AppNotes, August 2000
"WebSphere Components", Novell Developer Notes, December 1999
"Writing a Web Application For WebSphere Application Server", NetWare Connection, September 2000
Novell Developer Kit, IBM WebSphere Application Server for NetWare
IBM WebSphere for NetWare product home page
IBM/AlphaWorks AlphaBeans Web site
JavaSoft Java Server Pages Web site
* 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.