1 package pl.caltha.forms.internal.model;
2
3 import org.xml.sax.Attributes;
4
5 import pl.caltha.forms.ConstructionException;
6 import pl.caltha.forms.internal.ui.Node;
7 import pl.caltha.forms.internal.ui.ReferenceNode;
8 import pl.caltha.forms.internal.util.Util;
9
10 /***
11 * Form model element & binding expression implementation.
12 * Bind expressions are calculated relatively to connected ui node's
13 * context node.
14 *
15 * @author <a href="mailto:zwierzem@ngo.pl">Damian Gajda</a>
16 * @version $Id: Bind.java,v 1.1 2005/01/19 06:55:35 pablo Exp $
17 */
18 public class Bind
19 {
20 /*** XML ID of this bind element. */
21 private String id;
22
23 /*** Compiled ref attribute of this bind element. */
24 private InstanceReference instanceReference;
25 /*** Compiled readOnly attribute of this bind element. */
26 private InstanceReference readOnlyReference;
27 /*** Compiled required attribute of this bind element. */
28 private InstanceReference requiredReference;
29 /*** Compiled relevant attribute of this bind element. */
30 private InstanceReference relevantReference;
31
32 /*** Bind object with default values. */
33 private final static Bind defaultBind = new Bind();
34 /*** Default value of read only attribute. */
35 private final static boolean DEFAULT_READ_ONLY = false;
36 /*** Default value of required attribute. */
37 private final static boolean DEFAULT_REQUIRED = false;
38 /*** Default value of relevant attribute. */
39 private final static boolean DEFAULT_RELEVANT = true;
40
41 /*** Constructor for a default bind element.
42 * Default bind element is used for controls which do refer to bind
43 * elements defined in main form definition file.
44 * It has following values:
45 * <ul>
46 * <li><code>ref (instanceReference)</code> - <code>null</code></li>
47 * <li><code>readOnly</code> - <code>false</code></li>
48 * <li><code>required</code> - <code>false</code></li>
49 * <li><code>relevant</code> - <code>true</code></li>
50 * </ul>
51 */
52 private Bind()
53 {
54 instanceReference = null;
55 readOnlyReference = null;
56 requiredReference = null;
57 relevantReference = null;
58
59
60
61
62
63
64 }
65
66 /*** Constructor used during form definition building.
67 * @param atts Attributes of this bind element.
68 * @throws ConstructionException Thrown on incorrect attribute values.
69 */
70 public Bind(Attributes atts)
71 throws ConstructionException
72 {
73 this(
74 Util.getSAXAttributeVal(atts, "id"),
75 Util.getSAXAttributeVal(atts, "ref"),
76 Util.getSAXAttributeVal(atts, "readOnly"),
77 Util.getSAXAttributeVal(atts, "required"),
78 Util.getSAXAttributeVal(atts, "relevant")
79 );
80 }
81
82 /*** Basic constructor.
83 * @param id ID attribute
84 * @param instanceRef ref attribute - this one is used as an instance
85 * reference in controls which do not have their own
86 * references and refer to this bind element.
87 * @param readOnly readOnly attribute. If it has <code>true</code> value controls referring
88 * to this bind element are displayed as read only.
89 *
90 * This is an XPath expression which should evaluate to
91 * boolean value. It is not checked if this is the case. Please remember
92 * that if this expression does not evaluate to boolean it will either
93 * cause exceptions or will be evaluated to boolean in a way Java normally does.
94 * @param required required attribute. If it has <code>true</code> value controls referring
95 * to this bind element are treated as required ones - ie. they must
96 * have non null values.
97 *
98 * This is an XPath expression which should evaluate to
99 * boolean value. It is not checked if this is the case. Please remember
100 * that if this expression does not evaluate to boolean it will either
101 * cause exceptions or will be evaluated to boolean in a way Java normally does.
102 * @param relevant relevant attribute. If it has <code>true</code> value controls referring
103 * to this bind element are treated as visible and working ones, otherwise
104 * they are not rendered.
105 *
106 * This is an XPath expression which should evaluate to
107 * boolean value. It is not checked if this is the case. Please remember
108 * that if this expression does not evaluate to boolean it will either
109 * cause exceptions or will be evaluated to boolean in a way Java normally does.
110 * @throws ConstructionException Thrown on invalid XPath expressions in attribute definitions.
111 */
112 private Bind(String id, String instanceRef, String readOnly, String required, String relevant)
113 throws ConstructionException
114 {
115 if(id != null)
116 {
117 this.id = id;
118 }
119 else
120 {
121 throw new ConstructionException("Null id for bind element.");
122 }
123
124 this.instanceReference = makeInstanceReference("ref", instanceRef);
125 this.readOnlyReference = makeInstanceReference("readOnly", readOnly);
126 this.requiredReference = makeInstanceReference("required", required);
127 this.relevantReference = makeInstanceReference("relevant", relevant);
128 }
129
130 /*** Returns id of this bind element (expression).
131 * @return XML ID of this bind element.
132 */
133 public String getId()
134 {
135 return id;
136 }
137
138 /*** Object representing this bind element's ref attribute.
139 * Bind element's ref attribute can be null.
140 * @return this bind element's instance reference or null
141 */
142 public InstanceReference getInstanceReference()
143 {
144 return instanceReference;
145 }
146
147 /*** Returns value of this bind element's read only expression for a given
148 * instance.
149 * @param instance Instance of form's user data.
150 * @return value of this bind element's read only expression.
151 */
152 public boolean getReadOnly(InstanceImpl instance, ReferenceNode uiNode)
153 {
154 return evalProperty("readOnly", readOnlyReference, instance, uiNode, DEFAULT_READ_ONLY);
155 }
156
157 /*** Returns value of this bind element's relevant expression for a given
158 * instance.
159 * @param instance Instance of form's user data.
160 * @return value of this bind element's relevant expression.
161 */
162 public boolean getRelevant(InstanceImpl instance, ReferenceNode uiNode)
163 {
164 return evalProperty("relevant", relevantReference, instance, uiNode, DEFAULT_RELEVANT);
165 }
166
167 /*** Returns value of this bind element's required expression for a given
168 * instance.
169 * @param instance Instance of form's user data.
170 * @return value of this bind element's required expression.
171 */
172 public boolean getRequired(InstanceImpl instance, ReferenceNode uiNode)
173 {
174 return evalProperty("required", requiredReference, instance, uiNode, DEFAULT_REQUIRED);
175 }
176
177 /*** Returns bind expression object with default values.
178 * @return default bind object
179 */
180 public static Bind getDefault()
181 {
182 return defaultBind;
183 }
184
185 /*** This method evaluates XPath expressions and stores their results
186 * in Instances bind property cache.
187 * If XPath expression is <code>null</code> a given default value is
188 * returned but not stored (it is not neccessary).
189 */
190 private boolean evalProperty(String refName, InstanceReference instRef, InstanceImpl instance,
191 ReferenceNode uiNode, boolean defaultValue)
192 {
193 if(instRef != null)
194 {
195 if(instRef.isAbsolute())
196 {
197 Boolean propValue = (Boolean)(instance.getBindProperty(instRef));
198 if(propValue == null)
199 {
200 propValue = new Boolean( instRef.getStringValue(instance) );
201 instance.setBindProperty(instRef, propValue);
202 }
203 return propValue.booleanValue();
204 }
205 else
206 {
207 String key = refName+((Node)uiNode).getName();
208 Boolean propValue = (Boolean)(instance.getBindProperty(key));
209 if(propValue == null)
210 {
211 Object context = uiNode.getRef().evaluate(instance);
212 propValue = new Boolean( instRef.getStringValue(context) );
213 instance.setBindProperty(key, propValue);
214 }
215 return propValue.booleanValue();
216 }
217 }
218 else
219 {
220 return defaultValue;
221 }
222 }
223
224 /*** This utility method for constructor creates {@link InstanceReference}
225 * objects from a given name and XPath expression.
226 */
227 private InstanceReference makeInstanceReference(String name, String xpath)
228 throws ConstructionException
229 {
230 InstanceReference instRef = null;
231 try
232 {
233 if(xpath != null)
234 {
235 instRef = new InstanceReference(name, xpath);
236 }
237 }
238 catch(ConstructionException ce)
239 {
240 throw new ConstructionException("Bind element cannot not be constructed, wrong '"+name+"' attribute ", ce);
241 }
242 return instRef;
243 }
244 }