View Javadoc

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         /*this("",
59          "",     // ?? empty "" or Root "/" ??
60          "",     // or "0=1" WARNING: "false" in XPath evaluates to "true"
61          "",     // or "0=1" WARNING: "false" in XPath evaluates to "true"
62          ""      // or "1=1");
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 }