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]

Reply via email to