View Javadoc

1   package pl.caltha.forms.internal.model;
2   
3   import java.io.IOException;
4   import java.util.HashMap;
5   import java.util.Iterator;
6   
7   import org.dom4j.Document;
8   import org.dom4j.Node;
9   
10  import pl.caltha.forms.Instance;
11  import pl.caltha.forms.internal.FormImpl;
12  import pl.caltha.services.xml.validation.DOM4JValidationErrorCollector;
13  import pl.caltha.services.xml.validation.DOM4JValidator;
14  
15  /***
16   * Container for user form data.
17   *
18   * @author <a href="mailto:zwierzem@ngo.pl">Damian Gajda</a>
19   * @version $Id: InstanceImpl.java,v 1.4 2005/02/21 13:54:29 zwierzem Exp $
20   */
21  public class InstanceImpl extends AbstractInstance
22      implements Instance, java.io.Serializable
23  {
24      //-----------------------------------------------------------------------
25      // Parent form definition connection
26      /*** Reference to contatining Form object. */
27      protected FormImpl form;
28  
29      /*** ID of a form for which this instance was created. */
30      protected String formId;
31  
32      //------------------------------------------------------------------------
33      // Runtime instance state
34      /*** Instance Id produced from Form's name and screen name. */
35      protected String id;
36  
37      /*** Dirty flag. */
38      private boolean isDirty = false;
39  
40      /*** Submit requested flag, this one is set if a user clicked a submit button. */
41      private boolean submitRequested = false;
42  
43      /*** This map contains state values for dynamic UI elements. */
44      private HashMap uiStateMap = new HashMap();
45  
46      /*** Error collector used for validation. */
47      private DOM4JValidationErrorCollector errorCollector = new DOM4JValidationErrorCollector();
48  
49      /*** This field is <code>true</code> if this instance has all required values. */
50      private boolean hasRequired = false;
51  
52      //------------------------------------------------------------------------
53      // Runtime cache
54      /*** This map contains context nodes for UI elements - it decreases
55       * number of XPath evaluations. */
56      protected HashMap contextNodeCache = new HashMap();
57  
58      /*** This map contains results for bind expression evaluation - it decreases
59       * number of XPath evaluations. */
60      protected HashMap bindPropertyCache = new HashMap();
61  
62      /*** Value cache buffer is used for instance in Select controls. */
63      private StringBuilder valueCacheBuffer = new StringBuilder(1024);
64  
65      /*** Creates Instance from a given DOM4J Document and UI.
66       */
67      public InstanceImpl(FormImpl form, String schemaURI, Document instanceDocument)
68      {
69          super(schemaURI, instanceDocument);
70          this.form = form;
71          this.formId = form.getId();
72      }
73  
74      //------------------------------------------------------------------------
75      // Instance methods
76  
77      //-------------------------------------
78      // HTML form indentification methods
79  
80      /*** Getter for session wide instance id.
81       * @return Value of instance id. */
82      public String getId()
83      {
84          return id;
85      }
86  
87      //-------------------------------------
88  
89      /*** Returns <code>true</code> if instance has been changed by the user. */
90      public boolean isDirty()
91      {
92          return isDirty;
93      }
94  
95      /*** Sets a dirty flag on instance object - for use when changing instance's
96       * internal data - like dom4j document. */
97      public void setDirty(boolean dirtyFlag)
98      {
99          isDirty = dirtyFlag;
100     }
101 
102     /*** Returns <code>true</code> if instance is valid and the user requested
103      * a submit operation on this instance. */
104     public boolean isSubmitted()
105     {
106         return submitRequested && isValid();
107     }
108 
109     /*** Return <code>true</code> if instance has valid values and all
110      * of required values are inputed. */
111     public boolean isValid()
112     {
113         return hasRequired && (errorCollector.getErrorsByNode().size() == 0);
114     }
115 
116     /*** Return <code>true</code> if instance has all required values. */
117     public boolean hasRequired()
118     {
119         return hasRequired;
120     }
121 
122      //------------------------------------------------------------------------
123     // methods used internally by form-tool
124     //------------------------------------------------------------------------
125 
126     //------------------------------------------------------------------------
127     // Methods used during Instance processing
128     public FormImpl getForm()
129     {
130         return form;
131     }
132 
133     /*** Sets <code>submitted</code> flag. */
134     public void setSubmitted()
135     {
136         this.submitRequested = true;
137     }
138 
139     public boolean validate(DOM4JValidator validator)
140     throws Exception
141     {
142         return validator.validate(instanceDocument, schemaURI, errorCollector);
143     }
144 
145     /*** Cleans a bind property cache. It is used when setting new values in
146      * an Instance. */
147     public void preprocessInit()
148     {
149         errorCollector.init();
150         submitRequested = false;
151         bindPropertyCache.clear();
152     }
153 
154     public void setHasRequired(boolean hasRequired)
155     {
156         this.hasRequired = hasRequired;
157     }
158 
159     public boolean hasError(Node contextNode)
160     {
161         return errorCollector.getErrorsByNode().containsKey(contextNode);
162     }
163 
164     //------------------------------------------------------------------------
165     // State Values access
166     /*** Sets a UI state value for this instance. */
167     public void setStateValue(Node contextNode, Object key, Object value)
168     {
169         HashMap stateMap = (HashMap)(uiStateMap.get(contextNode));
170         if(stateMap == null)
171         {
172             stateMap = new HashMap();
173         }
174         stateMap.put(key, value);
175         uiStateMap.put(contextNode, stateMap);
176     }
177 
178     /*** Gets a UI state value for this instance. */
179     public Object getStateValue(Node contextNode, Object valueKey)
180     {
181         HashMap stateMap = (HashMap)(uiStateMap.get(contextNode));
182         if(stateMap != null)
183         {
184             return stateMap.get(valueKey);
185         }
186         return null;
187     }
188 
189     //------------------------------------------------------------------------
190     // Context Nodes cache access
191     public void setContextNode(Object key, Object contextNode)
192     {
193         contextNodeCache.put(key, contextNode);
194     }
195 
196     public void clearContextNode(Object key)
197     {
198         if(contextNodeCache.containsKey(key))
199         {
200             contextNodeCache.put(key, null);
201         }
202     }
203 
204     public Object getContextNode(Object key)
205     {
206         return contextNodeCache.get(key);
207     }
208 
209     //------------------------------------------------------------------------
210     // Bind property cache methods
211     /*** Sets a value of a Bind property. */
212     public void setBindProperty(Object key, Object propValue)
213     {
214         bindPropertyCache.put(key, propValue);
215     }
216 
217     /*** Gets a cached value of a Bind property. */
218     public Object getBindProperty(Object key)
219     {
220         return bindPropertyCache.get(key);
221     }
222 
223     //------------------------------------------------------------------------
224     // Value cache buffer access
225     /*** This method is used while setting the value for this instance, it marks
226      * the instance dirty. */
227     public StringBuilder getValueBuffer()
228     {
229         this.isDirty = true;
230 
231         return valueCacheBuffer;
232     }
233 
234     //------------------------------------------------------------------------
235     // Serialization methods
236     private void writeObject(java.io.ObjectOutputStream out)
237     throws IOException
238     {
239         // 1. serialize formId
240         out.writeObject(formId);
241         // 2. serialize UI state
242         HashMap xPathKeyedUIStateMap = new HashMap();
243         for(Iterator iter = uiStateMap.keySet().iterator(); iter.hasNext();)
244         {
245             Node contextNode = (Node)(iter.next());
246             xPathKeyedUIStateMap.put(contextNode.getUniquePath(), uiStateMap.get(contextNode));
247         }
248         out.writeObject(xPathKeyedUIStateMap);
249     }
250 
251     private void readObject(java.io.ObjectInputStream in)
252     throws IOException, ClassNotFoundException
253     {
254         // 1. deserialize formId
255         this.formId = (String)(in.readObject());
256         // 2. deserialize UI state
257         HashMap xPathKeyedUIStateMap = (HashMap)(in.readObject());
258         for(Iterator iter = xPathKeyedUIStateMap.keySet().iterator(); iter.hasNext();)
259         {
260             String uniqueXPath = (String)(iter.next());
261             Node contextNode = instanceDocument.selectSingleNode(uniqueXPath);
262             uiStateMap.put(contextNode, xPathKeyedUIStateMap.get(uniqueXPath));
263         }
264     }
265 }