1
2
3
4
5
6
7
8
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
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
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 }
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 }
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
301 PartsFactory.addType(this);
302 }
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
318 DecimalFormat format = new DecimalFormat("0.0");
319 setVersion(format.format(incrementedVersion));
320 super.update();
321 }
322
323 public void incrementVersion() throws DBException {
324 update();
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
339
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)>0 && y.compareTo(z)>0)</tt> implies
384 * <tt>x.compareTo(z)>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 }