quarta-feira, 1 de julho de 2015

FormHandlers ATG

What is Formhandler?


In many web applications users input are taken from the forms. A form may need to handle user input in a variety of formats, check input for validity, handle errors, and pass input to a servlet for processing or to a database for storage.  ATG java classes that process these forms are none other than Formhandlers.

A Formhandler is just like any other component. They can exist out-of-the box, and can be used as-is OR they can be extended like any other component OR they can be created right from scratch.

To start with, formhandlers mostly are of "request" scope as we dont want our form-data to be manipulated multiple times. If our formhandler's scope is session or global, our submitted form data can be modified within a session or globally by any user worldwide.

A form handler class must include one or more handler methods. A handler method is typically invoked when the user clicks the submit button, and handles the processing of the form. Depending on the purpose of the form handler, it can have several different handler methods that each perform a different operation.


Following are the tasks assigned to Form Handlers by ATG :
  • Validate data before it is submitted.
  • Detect missing information and display appropriate messages to the user.
  • Direct users to different pages depending on form submission results.
  • Read and write database or repository data.


Out of The Box Formhandlers:


ATG provides hundreds of readymade form handlers for performing all sorts of tasks:

  • ProfileFormHandler - Handling login/logout/registration etc.
  • CartModifierFormHandler - For Handling add/remove/update items to/in the cart.
  • RepositoryFormHandler - For saving data to repository.
  • ExpressCheckoutFormHandler - For checkout process and placing an order. etc. etc.

Please note that for every handleXXX method in OOTB formhandlers, there is a preXXX and postXXX method called before and after the actual handler code.
You can chose to override these pre and post methods if necessary rather than overriding the actual handler method itself.

For example, in ProfileFormHandler, there is a method handleLogin. For this method there are two methods preLoginUser and postLoginUser. Therefore, you can put all your email and password validation in preLoginUser method and some of the post login actions you can override postLoginUser. In these cases you dont need to override the whole handler method itself.
Check the original API for individual formhandler to check these handler and pre/post methods.

How to create a formhandler from scratch:


A better way to create a new form handler is to subclass a Dynamo class that implements DropletFormHandler interface. Dynamo provides three form handler base classes that implement this interface:

  • atg.droplet.DropletFormHandler: Inteface.
  • atg.droplet.EmptyFormHandler: Implements DropletFormHandler
  • atg.droplet.GenericFormHandler: Extends EmptyFormHandler
  • atg.droplet.TransactionalFormHandler: Extends GenericFormHandler. 

EmptyFormHandler: atg.droplet.EmptyFormHandler implements the DropletFormHandler interface and provides empty implementations of the methods in th
is interface.

GenericFormHandler: atg.droplet.GenericFormHandler extends EmptyFormHandler. It provides simple implementations of DropletFormHandler interface methods and adds basic error handling logic. If errors occur in processing a form that uses GenericFormHandler, the errors are saved and exposed as properties of the form handler component. This form handler is included in the public API

TransactionalFormHandler: atg.droplet.TransactionalFormHandler extends atg.droplet.GenericFormHandler; it treats the form processing operation as a transaction. Although this form handler methods are processed discretely, their results are saved simultaneously. The transaction management occurs in the beforeGet and afterGet methods. This establishes the transaction before any of properties are set or handler methods are called, rather than in the handler methods themselves.

You can create a form handler by extending one of these classes or any of their subclasses. Some of the classes that extend the base class in ATG API are:
  • SimpleSQLFormHandler for working with form data that is stored in a SQL database.
  • RepositoryFormHandler for saving repository data to a database.
  • ProfileFormHandler class to connect forms with user profiles stored in a profile repository
  • SearchFormHandler for specifying properties available to a search engine.


Steps in Writing a Custom FormHandler:


1. Firstly, there should be a FORM to have fields. So, we create a JSP and create a form. Inside a form, we write the <dsp:input> tags for getting the input from user against the form fields. See below screenshot for details.


Here, we have created a form with two text fields named, fName and lName with a submit button.
We have not provided a form-action yet. We will be discussing actions in further steps.

2. Now that you have a form with some fields, we need to pass it to some JAVA code to process it. The "JAVA code" resides inside our formhandler. In our formhandler (or to say our component which extends GenericFormHandler and has request scope), we should have JAVA fields corresponding to the fields in out JSP form. These JAVA fields can have same name or something else it does not matter. See below screenshot.


Our class extends GenericFormHandler class, has two fields firstName and lastName which correspond to form fields fName and lName in the JSP.
Next, we have setters and getters for these two fields.

3. Now we have a form, we have a formhandler with corresponding fields. We need to map the JSP form fields to our formhandler's "corresponding" properties. We do this in our JSP. See below screenshot to see the highlighted changes in the JSP.


We import the component (configuration file) which points to the class we crated in Step#2. Next, we provide a "bean=" attribute to the <dsp:input> tags to map the text fields to formhandler fields.

4. Our form is created, we have fields mapped to formhandler. Now we need to submit the form and do some real action. For this, we follow the below steps:


4.1. Create a method named public boolean handleXXX(final DynamoHttpServletRequest pRequest, final DynamoHttpServletResponse pResponse) in your formHandler. Here, "XXX" can be replaced by your logical name. (Below screenshot)


4.2. This method can access the fields in the formhandler which are mapped to JSP Form Fields.
4.3. Write custom code in handleXXX() method to perform specific action (like storing these fields in repository or session or anywhere)
4.4. Next you call this custom method from your JSP's submit action. See below screenshot for this. 


Here, you are telling the submit button to call your handler method written in your java file (your formhandler class). HelloWorldFormHandler.myForm represents your handleMyForm method in your formhandler.Whatever you name your handler method (handleMyForm), just remove the "handle" keyword (it becomes MyForm), convert the next character into lowercase (it becomes myForm), and use it in your formhandler (marked in red box), and your are good to go.
Now that we have got our basic flow sorted, you must be wondering, "NO url has been provided in the form for "action" attribute in form tag.

How to redirect a form in case of failure or success:


The class GenericFormHandler, which you extend, has a method called checkFormRedirect() which is of type boolean. You can use this method to control redirects. The API call of this method looks somewhat like:

public boolean checkFormRedirect(pSuccessURL, pFailureURL, pRequest, pResponse);

Now, this method redirects to pSuccessURL if no form errors are found in the form. Otherwise, it redirects topFailureURL.Therefore, you can use it in the following way (see below screenshot):



Now, in the same class (HelloWorldFormHandler.java), we have added two new variables viz. helloWorldSuccessURL and helloWorldFailureURL. We have setters and getters for these methods. Also, we have called the checkFormRedirect() method in our handler method to redirect to appropriate pages.

We can set these success/failure URLs in configuration file for this component (just like we set any other component property in the configuration file), OR we could pass it form the JSP (just like we mapped fName and lName to component properties, except, fName and lName were input fields of type "text", these URLs will be of type "hidden"). See below screenshot for the JSP snippet.


We're mostly done with the basics of formhandlers but wait. what if you add "action" attribute to your <dsp:form> tag and provide an action URL? How would ATG behave?Let us say you provide "action=<some URL>" in your <dsp:form> tag. Now there could be two scenarios:

1. You have used checkFormRedirect() method in your handler method.In this case, the action attribute in the <dsp:form> tag will be ignored.
2. You have NOT used checkFormRedirect() method in your handler method.In this case, your form will redirect to URL mentioned in the action attribute of the <dsp:form> tag irrespective of failure or success.


Displaying Error Messages in FormHandlers:


Following are the form handler component properties to handle form errors/exceptions:
  • formError: Boolean that is set to true if any errors occur during form processing.
  • formExceptions: A vector of the exceptions that occur during form processing.  If your form handler is session-scoped, clear the formExceptions property after you display errors to the user.
  • propertyExceptions: A read-only property that returns a Dictionary of subproperties, one for each property set by the form. For each property that generates an exception, a corresponding subproperty in the propertyExceptions Dictionary contains that exception

And use this droplet to loop through and display the error messages that are generated by a form:
<dsp: droplet name="/atg/dynamo/droplet/ErrorMessageForEach"> 
       <dsp:oparam name="output">
                <dsp:valueof param="message"/><br>
        </dsp:oparam>
</dsp:droplet>

Nenhum comentário:

Postar um comentário