View Javadoc

1   package pl.caltha.forms.internal;
2   
3   import java.util.HashMap;
4   
5   import org.objectledge.parameters.Parameters;
6   
7   import pl.caltha.forms.ConstructionException;
8   import pl.caltha.forms.Form;
9   import pl.caltha.forms.FormsService;
10  import pl.caltha.forms.internal.model.Bind;
11  import pl.caltha.forms.internal.model.DefaultInstance;
12  import pl.caltha.forms.internal.model.InstanceImpl;
13  import pl.caltha.forms.internal.model.SubmitInfo;
14  import pl.caltha.forms.internal.ui.UI;
15  import pl.caltha.forms.internal.ui.UIConstants;
16  import pl.caltha.services.xml.XMLService;
17  
18  /***
19   * Represents Form definition.
20   *
21   * @author <a href="mailto:zwierzem@ngo.pl">Damian Gajda</a>
22   * @version $Id: FormImpl.java,v 1.3 2005/02/08 20:33:27 rafal Exp $
23   */
24  public class FormImpl implements Form
25  {
26      /*** FormsService. */
27      private FormsService formToolService;
28  
29      /*** XMLService is used to get validators. */
30      private XMLService xmlService;
31  
32      /*** I18nService is used to localise strings. */
33      //private I18nService i18nService;
34  
35      /*** Keeps ID for this form definition.. */
36      private String id;
37  
38      /*** Keeps URI for form definition.. */
39      private String definitionURI;
40  
41      /*** Keeps model/bind elements. */
42      private HashMap bindElements = new HashMap();
43  
44      /*** Keeps Form's SubmitInfo. */
45      protected SubmitInfo submitInfo;
46  
47      /*** Keeps URI for UI definition.. */
48      protected String uiURI;
49      /*** Keeps UI object. */
50      private UI ui;
51  
52      /*** Keeps Instance schema URI. */
53      protected String instanceSchemaURI;
54      /*** Keeps Instance URI. */
55      protected String defaultInstanceURI;
56      /*** Keeps an object representing default Instance. */
57      private DefaultInstance defaultInstance;
58      
59      //private Parameters parameters;
60  
61      /*** Creates new Form */
62      public FormImpl(FormsService formToolService, XMLService xmlService,
63          String definitionURI, String id)
64      {
65          this.definitionURI = definitionURI;
66          this.id = id;
67          this.formToolService = formToolService;
68          this.xmlService = xmlService;
69      }
70  
71      //------------------------------------------------------------------------
72      // pl.caltha.forms.Form mehods
73  
74      /*** Processes a user request merging it's data with an Instance object.
75       * <p>Processing consists of following steps:</p>
76       * <ol>
77       *  <li><b>Value extraction (from the request) and application on an Instance.</b>
78       *      <p>This step is first because form-tool is a server-side tool.
79       *      All values must be applied before Instance is validated, or
80       *      any actions, including setting values dynamically are executed
81       *      (If for instance setValue action would be executed before
82       *       applying values, the result of this action could be lost).
83       *      </p>
84       *      <p>This action triggers bind property cache clean up
85       *         ({@link pl.caltha.forms.internal.model.InstanceImpl#preprocessInit()})
86       *      </p>
87       *      <p>This action also triggers submit requested flag clean up
88       *         ({@link pl.caltha.forms.internal.model.InstanceImpl#preprocessInit()})
89       *      </p>
90       *      <p>This action also triggers error collector clean up
91       *         ({@link pl.caltha.forms.internal.model.InstanceImpl#preprocessInit()})
92       *      </p>
93       *  </li>
94       *  <li><b>Event extraction (from request) and dispatching.</b>
95       *      <p>Event dispatching triggers actions connected to controls.
96       *      These actions may also trigger another events and so on.</p>
97       *      <p>TODO: Implement event - action loop protection.</p>
98       *
99       *      <p>Right now only two kinds of events are extracted:</p>
100      *      <ol>
101      *          <li><code>activate</code> - control activation,
102      *          in this case button control activation.</li>
103      *          <li><code>submit</code> - submit button control activation.</li>
104      *      </ol>
105      *  </li>
106      *  <li><b>Instance validation</b>
107      *      <p>In client-side XForms implementation this step should be
108      *      triggered by a changed value. In server-side processing value
109      *      comparison would have to be implemented to check if any of them
110      *      was changed. It is not very wise to do value comparison because
111      *      there will be cases in which it will be faster to do validation
112      *      than to compare all values in the Instance. That's why validation
113      *      is always executed.
114      *      </p>
115      *  </li>
116      * </ol>
117      */
118     public void process(pl.caltha.forms.Instance inst, Parameters parameters)
119     throws Exception
120     {
121         InstanceImpl instance = (InstanceImpl)inst;
122         // 1. Apply new values
123         // Apply new values dispatches:
124         //  - errorCollector init
125         //  - bind expression cache should be cleared (implemented below)
126         //  - selectValues should be cleared (implemented in NodeSelect)
127         //  - submit requested clearing
128         // 1.1.1. errorCollector
129         // 1.1.2 Clear bind property cache.
130         // 1.1.2 Clear submit requested.
131         instance.preprocessInit();
132 
133         // 1.2. Set new values only if there are values sent from user's browser
134         // 2. dispatch events & execute actions
135         //
136         // SetValues and dispatchEvents is not being called
137         // for the first time instance processing.
138         // This avoids Select fields clearing.
139         String instanceId = parameters.get(UIConstants.INSTANCE_ID_NAME,null);
140         if(instanceId != null && instanceId.equals(instance.getId()))
141         {
142             ui.setValues(instance, parameters);
143             ui.dispatchEvents(instance, parameters);
144         }
145 
146         // 3. validate
147         // 3.1. Schema validate
148         instance.validate( xmlService.getDOM4JValidator() );
149         // 3.2. Check if required values are inputed
150             // Required fields checking is only for Programmers using Instance
151             // objects!!
152             // Together with submit requested it gives information on form
153             // Instance being ready or not.
154         boolean hasRequired = ui.hasRequired(instance);
155         instance.setHasRequired(hasRequired);
156     }
157 
158     /*** Returns ID for this form's definition file. This is a form definition URI
159      * ({@link Form#getDefinitionURI}) changed to be compatible with XHTML IDs. */
160     public String getId()
161     {
162         return id;
163     }
164 
165     public String getDefinitionURI()
166     {
167         return definitionURI;
168     }
169 
170     public String getUIDefinitionURI()
171     {
172         return uiURI;
173     }
174 
175     public String getDefaultInstanceURI()
176     {
177         return defaultInstanceURI;
178     }
179 
180     public String getInstanceSchemaURI()
181     {
182         return instanceSchemaURI;
183     }
184 
185     //------------------------------------------------------------------------
186     // Methods used during processing - runtime
187 
188     /*** Returns a default instance object. */
189     public DefaultInstance getDefaultInstance()
190     {
191         return defaultInstance;
192     }
193 
194     /*** Creates a new instance object. */
195     InstanceImpl createInstance(String instanceId)
196     {
197         return defaultInstance.createInstance(instanceId);
198     }
199 
200     /*** Creates a new instance object from a saved instance data. */
201     InstanceImpl createInstance(String instanceId, byte[] savedState)
202     throws Exception
203     {
204         return defaultInstance.createInstance(instanceId, savedState);
205     }
206 
207     // methods used in UI
208     public Bind getBind(String id)
209     throws ConstructionException
210     {
211         if(bindElements.containsKey(id))
212         {
213             return (Bind)(bindElements.get(id));
214         }
215         throw new ConstructionException("Cannot find bind element with id='"+id+"'");
216     }
217 
218     public SubmitInfo getSubmitInfo()
219     {
220         return submitInfo;
221     }
222 
223     public UI getUI()
224     {
225         return ui;
226     }
227 
228     public FormsService getFormToolService()
229     {
230         return formToolService;
231     }
232 
233 /*    public I18nService getI18nService()
234     {
235         return i18nService;
236     }
237 */
238     //------------------------------------------------------------------------
239     // Form building methods
240     void setDefaultInstance(DefaultInstance defaultInstance)
241     {
242         this.defaultInstance = defaultInstance;
243     }
244 
245     void addBindElement(Bind bind)
246     throws ConstructionException
247     {
248         // guard from bind elements with no id
249         String id = bind.getId();
250         if(id == null || id.equals(""))
251         {
252             throw new ConstructionException("Cannot add Bind element with no id");
253         }
254 
255         if(!bindElements.containsKey(id))
256         {
257             bindElements.put(id, bind);
258         }
259         // duplicate ids
260         else
261         {
262             throw new ConstructionException("Duplicate bind element id='"+id+"'");
263         }
264     }
265 
266     void init(UI ui)
267     throws ConstructionException
268     {
269         this.ui = ui;
270     }
271 }
272