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
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
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
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
76
77
78
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
124
125
126
127
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
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
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
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
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
236 private void writeObject(java.io.ObjectOutputStream out)
237 throws IOException
238 {
239
240 out.writeObject(formId);
241
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
255 this.formId = (String)(in.readObject());
256
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 }