On Wed, 17 Sep 2003, Adam Hardy wrote: > Date: Wed, 17 Sep 2003 13:14:27 +0200 > From: Adam Hardy <[EMAIL PROTECTED]> > Reply-To: Struts Users Mailing List <[EMAIL PROTECTED]> > To: Struts Users Mailing List <[EMAIL PROTECTED]> > Subject: Re: struts-faces > > Hi Craig, > I remember a while ago in one of these architecture- theme emails you > discussed the OO nature of struts & it had been said that the > action-form class and the action class broke the OO encapsulation > principle, by having data in one and functionality in another. You said > if you were going to design struts again, you would probably address this. > > Does JSFaces bring these two closer together? Or is this an area where > Faces is not involved? I see you say that in a combination of struts & > Faces, you would still use actions and forms. >
JavaServer Faces is designed to give you options to organize things either way. Here's one example of a logon form (and associated back-end logic) that combines the Struts notions of ActionForm and Action into a single class (corresponds to the syntax in the EA4 release): JSP PAGE (/logon.jsp): ===================== ... <h:form> <h:output_errors/> <h:panel_grid columns="2"> <h:output_text value="Username:"/> <h:input_text id="username" valueRef="logonForm.username"/> <h:output_text value="Password:"/> <h:input_secret id="password" valueRef="logonForm.password"/> <h:command_button label="Log On" type="submit" actionRef="logonForm.logon"/> <h:command_button label="Reset" type="reset"/> </h:panel_grid> </h:form> ... FACES CONFIGURATION FILE (faces-config.xml): =========================================== ... <managed-bean> <managed-bean-name>logonForm</managed-bean-name> <managed-bean-class>mypackage.MyLogonForm</managed-bean-class> <managed-bean-scope>request</managed-bean-scope> </managed-bean> ... <navigation-rule> <from-tree-id>/logon.jsp</from-tree-id> <navigation-case> <from-outcome>success</from-outcome> <to-tree-id>/mainmenu.jsp</to-tree-id> </navigation-case> </navigation-rule> ... BACKING CLASS: ============= package mypackage; public class MyLogonForm { // No required base class or interface // Property for "username" field private String username; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } // Property for "password" field private String password; public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } // Return an Action for processing a logon public Action getLogon() { return new Action() { public String invoke() { return logon(); } } } // The actual logon processing logic private String logon() { DAO dao = ...; // Data Access Object for user database User user = dao.findUser(this.username); if ((user != null) && password.equals(user.getPassword())) { ... record successful logon ... // Return logical outcome denoting success return ("success"); } else { // Add an error message FacesContext.getCurrentInstance().addMessage(...); // Return logical outcome denoting "redisplay this page" return (null); } } } In this scenario, you can see that the form field values are stored in the same bean as the processing logic. Therefore, the processing logic can just use the field values directly (they are in the instance variables). However, it's only in the same class because the page author used "logonForm" at the beginning of the valueRef and actionRef expressions -- they could just as easily have been stored in separate files. A couple of things not real obvious from this simple example, but interesting nevertheless: * The <managed-bean> declaration causes a new instance of the specified class to be created in (in this case) request scope, if it is not there already, similar to the way that Struts creates form beans for you as needed. However, JavaServer Faces generalizes this to happen automatically whenever it evaluates a reference expression and the first element does not identify an existing attribute in some scope. This can be very handy for instantiating "service" or "processor" objects whose precise characteristics are defined in the configuration file, rather than being coded in the page. * JavaServer Faces uses logical outcomes to manage navigation, similar to the way that Struts uses the returned ActionForward for this. The returned value is matched against a set of navigation rules that choose the next page to be displayed based on three criteria: - What page am I currently displaying? (Wildcard rules are allowed) - What action was performed? (You can have more than one submit button) - What logical outcome is returned? If no rule matches, the current page is redisplayed. I've adopted the convention in my code to return null as the logical outcome if this is what I want (i.e. the logon failure case here). * Struts encourages you to use Strings for field values that might need conversion, in order to redisplay correctly in case of conversion errors. You don't need to worry about that with JavaServer Faces, because the redisplay is handled by the components themselves. You will generally use the native data types for your field properties. * Programmers used to ASP.NET are familiar with the ability to programmatically interact with the actual user interface components themselves in code-behind files. It's very likely that this approach will also be accomodated in the final version of JavaServer Faces. The above example is likely to be typical if you're writing a new applicaton from scratch based on JavaServer Faces. But what if you've got an existing application based on Struts, and you just want to use JavaServer Faces to get the fancy UI widgets? That's where you would use the struts-faces integration library, because it lets you change just the JSP pages, and keep all your back end actions and form beans from before. > The reason I ask is that I just had a hard time redesigning a page > because my initial design failed. The page allows an edit of one parent > object, while showing a list of its child objects with > move-to-new-parent / delete controls. I got in a mess initially over > whether to use the parent or child's form and action for the child > operations. > In Struts, I would tend to model this sort of thing as a single form rather than two different forms. In JavaServer Faces, there will be a nice "editable table" or "data grid" type component that supports this type of use case. > Fortunately I solved it nicely by nesting the child objects in the > parent form, and passing the whole lot to the parent's model, which then > worked out if it needed to call the child's model for any operations. > Makes sense. > > Adam > Craig --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]