View Javadoc

1   /* ===================================================================
2    * Copyright 2002-04 SRI International.
3    * Released under the MOZILLA PUBLIC LICENSE Version 1.1
4    * which can be obtained at http://www.mozilla.org/MPL/MPL-1.1.html
5    * This software is distributed on an "AS IS"
6    * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
7    * See the License for the specific language governing rights and
8    * limitations under the License.
9    * =================================================================== */
10  package com.sri.emo.dbobj;
11  
12  import com.jcorporate.expresso.core.controller.ExpressoRequest;
13  import com.jcorporate.expresso.core.controller.Transition;
14  import com.jcorporate.expresso.core.db.DBConnection;
15  import com.jcorporate.expresso.core.db.DBException;
16  import com.jcorporate.expresso.core.dbobj.DBField;
17  import com.jcorporate.expresso.core.dbobj.RowSecuredDBObject;
18  import com.jcorporate.expresso.core.security.ReadOnlyUser;
19  import com.jcorporate.expresso.core.security.User;
20  import com.sri.emo.controller.PartAction;
21  import com.sri.emo.dbobj.model_tree.ModelVisitable;
22  import com.sri.emo.dbobj.model_tree.ModelVisitor;
23  
24  import java.text.DecimalFormat;
25  import java.util.List;
26  import java.util.Vector;
27  
28  
29  /***
30   * Encapsulate the finite list of types allowed for a node.
31   *
32   * @author larry hamel
33   */
34  public class NodeType extends RowSecuredDBObject implements Comparable, ModelVisitable, IViewable {
35      /***
36  	 * 
37  	 */
38  	private static final long serialVersionUID = 1L;
39  	public static final String NODE_TYPE_TABLE_NAME = "node_type";
40      public static final String NODE_TYPE_ID = "NODE_TYPE_ID";
41      public static final String NODE_TYPE_NAME = "NODE_TYPE_NAME";
42      public static final String DISPLAY_TITLE = "DISPLAY_TITLE";
43      public static final String NODE_TYPE_DESCRIP = "NODE_TYPE_DESCRIP";
44      public static final String NODE_TYPE_VERSION = "NODE_TYPE_VERSION";
45  
46      /***
47       * Class name for special handling if any.
48       */
49      public static final String NODE_TYPE_HANDLER = "NODE_TYPE_HANDLER";
50  
51      /***
52       * boolean for whether, when outputting xml, this node type should be
53       * 'abbreviated' as an ID rather than a full XML tree.
54       * Useful for large objects (like template, design pattern)
55       */
56      public static final String USE_ID_FOR_REFERENCE = "USE_ID_FOR_REF";
57  
58      // a type for indicating that any type
59      public static final String ANY_OBJECT = "ANY_OBJECT";
60      private String mSpecialHandlerStr;
61      private INodeHandler mSpecialHandler;
62  
63      /***
64       * Default constructor for <code>NodeType</code>
65       * creates a new object of this type with no connection
66       * yet allocated.
67       *
68       * @throws DBException If the new object cannot be
69       *                     created
70       */
71      public NodeType() throws DBException {
72      }
73  
74      /***
75       * Do not use anymore.
76       *
77       * @param request ExpressoRequest
78       * @throws DBException
79       * @deprecated Use RequestRegistry to propagate request contexts.
80       */
81      public NodeType(final ExpressoRequest request) throws DBException {
82          super(request);
83      }
84  
85      /***
86       * Constructor
87       *
88       * @param theConnection DBConnection to be used to
89       *                      communicate with the database
90       * @param theUser       User name attempting to access the
91       *                      object
92       * @throws DBException If the user cannot access this
93       *                     object or the object cannot be initialized
94       */
95      public NodeType(final DBConnection theConnection, final int theUser)
96              throws DBException {
97          super(theConnection, theUser);
98      }
99  
100     /***
101      * Constructor that takes the user security context.
102      *
103      * @param userSecurityContext ReadOnlyUser
104      * @throws DBException upon construction error
105      */
106     public NodeType(final ReadOnlyUser userSecurityContext) throws DBException {
107         super(userSecurityContext);
108     }
109 
110     /***
111      * Defines the database table name and fields for this DB object
112      *
113      * @throws DBException if the operation cannot be performed
114      */
115     protected synchronized void setupFields() throws DBException {
116         setTargetTable(NODE_TYPE_TABLE_NAME);
117         setDescription("Node Type");
118         addField(NODE_TYPE_ID, DBField.AUTOINC_TYPE, 0, false, "ID of type");
119         addField(NODE_TYPE_NAME, DBField.VARCHAR_TYPE, 255, false,
120                 "Internal name of type");
121         addField(DISPLAY_TITLE, DBField.VARCHAR_TYPE, 255, false,
122                 "Display title of type");
123         addField(NODE_TYPE_DESCRIP, DBField.LONGVARCHAR_TYPE, 0, true,
124                 "Description of type");
125         addField(NODE_TYPE_VERSION, DBField.DOUBLE_TYPE, 0, true,
126                 "version of type");
127         addField(NODE_TYPE_HANDLER, DBField.VARCHAR_TYPE, 255, true,
128                 "class name of special handler");
129         addField(USE_ID_FOR_REFERENCE, DBField.BOOLEAN_TYPE, 0, true,
130                 "boolean for whether, when outputting xml, this part should be" +
131                         " 'abbreviated' as an ID rather than a full XML tree.  " +
132                         "Useful for large objects (like template, design pattern)");
133 
134         addKey(NODE_TYPE_ID);
135 
136         // unique type names
137         addIndex("internal_type_name", NODE_TYPE_NAME, true);
138 
139         addDetail(Part.class.getName(), NODE_TYPE_NAME, Part.PARENT_TYPE);
140         addDetail(Node.class.getName(), NODE_TYPE_NAME, Node.NODE_TYPE);
141         addDetail(PickList.class.getName(), NODE_TYPE_NAME, PickList.NODE_TYPE);
142     } /* setupFields() */
143 
144     /***
145      * Convenience method.
146      *
147      * @param type the internal entity name
148      * @return String the display name.
149      * @throws DBException upon database access error.
150      */
151     public static String getDisplayName(String type)
152             throws DBException {
153         String result = "item";
154         NodeType nodeType = new NodeType();
155         nodeType.setEntityName(type);
156 
157         if (nodeType.find()) {
158             result = nodeType.getDisplayName();
159         }
160 
161         return result;
162     }
163 
164     public static boolean isValidType(String type) {
165         boolean result = false;
166 
167         if ((type != null) && (type.length() > 0)) {
168             result = PartsFactory.getEntity(type) != null;
169         }
170 
171         return result;
172     }
173 
174     public String getId() throws DBException {
175         return getField(NODE_TYPE_ID);
176     }
177 
178     public String getEntityName() throws DBException {
179         return getField(NODE_TYPE_NAME);
180     }
181 
182     public String getEntityDescription() throws DBException {
183         return getField(NODE_TYPE_DESCRIP);
184     }
185 
186     public void setId(String id) throws DBException {
187         setField(NODE_TYPE_ID, id);
188     }
189 
190     public String getDisplayName() throws DBException {
191         return getField(DISPLAY_TITLE);
192     }
193 
194     /***
195      * queries db for all parts; not efficient for repeated use.
196      *
197      * @return an array of parts
198      * @throws DBException upon database access error.
199      * @see PartsFactory#getParts for more efficient (cached) usage
200      */
201     public Part[] getParts() throws DBException {
202         Part query = new Part();
203         query.setRequestingUser(this.getRequestingUser());
204         query.setDataContext(getDataContext());
205         query.setParentType(getEntityName());
206 
207         List list = query.searchAndRetrieveList(Part.PART_NUM);
208 
209         return (Part[]) list.toArray(new Part[0]);
210     }
211 
212     /***
213      * Potentially hazardous function due to memory requirements for lots
214      * of nodes, but for small node sets, this is a valueable function
215      * for navigating the hierarchy of nodes.
216      *
217      * @return List of nodes.
218      * @throws DBException
219      */
220     public List getAllNodes() throws DBException {
221         Node n = new Node();
222         n.setNodeType(getId());
223         return n.searchAndRetrieveList();
224     }
225 
226     /***
227      * set name.  this is NOT primary key
228      *
229      * @param defaultType the type name
230      * @throws DBException upon database access error.
231      */
232     public void setEntityName(String defaultType) throws DBException {
233         if (defaultType != null) {
234             setField(NODE_TYPE_NAME, defaultType);
235         }
236     }
237 
238     public static NodeType[] getAllTypes()
239             throws DBException {
240         NodeType allTypes = new NodeType();
241         List types = allTypes.searchAndRetrieveList(NodeType.DISPLAY_TITLE);
242 
243         return (NodeType[]) types.toArray(new NodeType[types.size()]);
244     }
245 
246     public static NodeType getFromId(int id) throws DBException {
247         NodeType type = new NodeType();
248         type.setRequestingUser(User.getAdmin());
249         type.setId("" + id);
250         type.retrieve();
251 
252         return type;
253     }
254 
255     public static NodeType getFromTypeString(String s)
256             throws DBException {
257         NodeType type = new NodeType();
258         type.setRequestingUser(User.getAdmin());
259         type.setDBName(DBConnection.DEFAULT_DB_CONTEXT_NAME);
260         type.setEntityName(s);
261 
262         if (!type.find()) {
263             throw new DBException("cannot find NodeType with name: " + s);
264         }
265 
266         return type;
267     }
268 
269     public String getVersion() throws DBException {
270         return getField(NODE_TYPE_VERSION);
271     }
272 
273 
274     /***
275      * Override of getValues to provide specific name to display formatting.
276      * {@inheritDoc}
277      *
278      * @return Vector of ValidValue Value/Description pairs Node Types
279      * @throws DBException If the values cannot be retrieved
280      */
281     public Vector getValues() throws DBException {
282         return getValuesDefault(NODE_TYPE_ID, DISPLAY_TITLE);
283     } /* getValues() */
284 
285 
286     public String getSpecialHandlerName() throws DBException {
287         return getField(NODE_TYPE_HANDLER);
288     }
289 
290     /***
291      * If the user is allowed to add, invoke the superclass add
292      *
293      * @throws DBException If the user is not permitted to add
294      *                     or if the add fails
295      */
296     public synchronized void add() throws DBException {
297         setVersion("1.0");
298         super.add();
299 
300         // add empty parts array
301         PartsFactory.addType(this);
302     } /* add() */
303 
304     private void setVersion(String f) throws DBException {
305         setField(NODE_TYPE_VERSION, f);
306     }
307 
308     /***
309      * Update the database with the new info
310      * SIDE-EFFECT: increments version number each time there is an update
311      *
312      * @throws DBException if update is not allowed for the current user
313      */
314     public synchronized void update() throws DBException {
315         float incrementedVersion = getFieldFloat(NODE_TYPE_VERSION) + 0.01f;
316 
317         // make sure we don't perpetuate rounding error
318         DecimalFormat format = new DecimalFormat("0.0");
319         setVersion(format.format(incrementedVersion));
320         super.update();
321     } /*  update() */
322 
323     public void incrementVersion() throws DBException {
324         update(); // increments as a side-effect
325     }
326 
327     public boolean hasCustomHandler() throws DBException {
328         return getCustomHandler() != null;
329     }
330 
331     /***
332      * Retrieve a custom handler, null if there is none.
333      *
334      * @return the custom handler or null if this part does not have one
335      * @throws DBException upon database access error.
336      */
337     public INodeHandler getCustomHandler() throws DBException {
338         // mSpecialHandlerStr is the flag for cached value; first
339         // access will set cache value to "" or classname
340         if (mSpecialHandlerStr == null) {
341             mSpecialHandlerStr = getField(NodeType.NODE_TYPE_HANDLER);
342 
343             if ((mSpecialHandlerStr != null) &&
344                     (mSpecialHandlerStr.length() > 0)) {
345                 try {
346                     Class myclass = Class.forName(mSpecialHandlerStr);
347                     mSpecialHandler = (INodeHandler) myclass.newInstance();
348                 } catch (ClassNotFoundException e) {
349                     throw new DBException(e);
350                 } catch (InstantiationException e) {
351                     throw new DBException(e);
352                 } catch (IllegalAccessException e) {
353                     throw new DBException(e);
354                 }
355             }
356         }
357 
358         return mSpecialHandler;
359     }
360 
361     public void setCustomHandler(String customHandler)
362             throws DBException {
363         setField(NodeType.NODE_TYPE_HANDLER, customHandler);
364     }
365 
366     /***
367      * Compares this object with the specified object for order.  Returns a
368      * negative integer, zero, or a positive integer as this object is less
369      * than, equal to, or greater than the specified object.<p>
370      * <p/>
371      * In the foregoing description, the notation
372      * <tt>sgn(</tt><i>expression</i><tt>)</tt> designates the mathematical
373      * <i>signum</i> function, which is defined to return one of <tt>-1</tt>,
374      * <tt>0</tt>, or <tt>1</tt> according to whether the value of <i>expression</i>
375      * is negative, zero or positive.
376      * <p/>
377      * The implementor must ensure <tt>sgn(x.compareTo(y)) ==
378      * -sgn(y.compareTo(x))</tt> for all <tt>x</tt> and <tt>y</tt>.  (This
379      * implies that <tt>x.compareTo(y)</tt> must throw an exception iff
380      * <tt>y.compareTo(x)</tt> throws an exception.)<p>
381      * <p/>
382      * The implementor must also ensure that the relation is transitive:
383      * <tt>(x.compareTo(y)&gt;0 &amp;&amp; y.compareTo(z)&gt;0)</tt> implies
384      * <tt>x.compareTo(z)&gt;0</tt>.<p>
385      * <p/>
386      * Finally, the implementer must ensure that <tt>x.compareTo(y)==0</tt>
387      * implies that <tt>sgn(x.compareTo(z)) == sgn(y.compareTo(z))</tt>, for
388      * all <tt>z</tt>.<p>
389      * <p/>
390      * It is strongly recommended, but <i>not</i> strictly required that
391      * <tt>(x.compareTo(y)==0) == (x.equals(y))</tt>.  Generally speaking, any
392      * class that implements the <tt>Comparable</tt> interface and violates
393      * this condition should clearly indicate this fact.  The recommended
394      * language is "Note: this class has a natural ordering that is
395      * inconsistent with equals."
396      *
397      * @param o the Object to be compared.
398      * @return a negative integer, zero, or a positive integer as this object
399      *         is less than, equal to, or greater than the specified object.
400      * @throws ClassCastException if the specified object's type prevents it
401      *                            from being compared to this Object.
402      */
403     public int compareTo(Object o) {
404         int result = 0;
405 
406         try {
407             result = getDisplayName().compareTo(((NodeType) o).getDisplayName());
408         } catch (DBException e) {
409             e.printStackTrace();
410         }
411 
412         return result;
413     }
414 
415     public void setDisplayName(String name) throws DBException {
416         setField(DISPLAY_TITLE, name);
417     }
418 
419     public void setEntityDescription(String s) throws DBException {
420         setField(NODE_TYPE_DESCRIP, s);
421     }
422 
423     /***
424      * Whether or not this node type prefers to export xml as a reference or not.
425      * <p/>
426      * (large entities like template and ed. standard prefer being exported as refs)
427      * </p>
428      *
429      * @return boolean
430      * @throws DBException upon database access error.
431      */
432     public boolean isReferenceIdPreferred() throws DBException {
433         return getFieldBoolean(USE_ID_FOR_REFERENCE);
434     }
435 
436     /***
437      * Whether or not this node type prefers to export xml as a reference or not.
438      * <p>(large entities like template and ed. standard prefer being exported as refs)</p>
439      *
440      * @param is boolean
441      * @throws DBException upon database access error.
442      */
443     public void isReferenceIdPreferred(boolean is) throws DBException {
444         setField(USE_ID_FOR_REFERENCE, is);
445     }
446 
447     /***
448      * provide a transition for viewing this object, suitable for creating an
449      * HTTP link
450      *
451      * @return transtion for viewing, including label for name of object; never null
452      * @throws DBException upon self-query error.
453      */
454     public Transition getViewTrans() throws DBException {
455         Transition trans = new Transition(getDisplayName(), PartAction.class, PartAction.PROMPT_EDIT_ENTITY);
456         trans.addParam(NodeType.NODE_TYPE_ID, getId());
457         return trans;
458     }
459 
460     public void acceptVisitor(ModelVisitor visitor) {
461         visitor.visitNodeType(this);
462     }
463 
464 } // fini