1
2
3
4
5
6
7
8
9
10 package com.sri.emo.dbobj;
11
12 import java.util.ArrayList;
13 import java.util.Iterator;
14 import java.util.List;
15 import java.util.Vector;
16 import com.jcorporate.expresso.core.controller.Transition;
17 import com.jcorporate.expresso.core.db.DBException;
18 import com.jcorporate.expresso.core.dbobj.DBField;
19 import com.jcorporate.expresso.core.dbobj.RowSecuredDBObject;
20 import com.jcorporate.expresso.core.dbobj.ValidValue;
21 import com.jcorporate.expresso.core.misc.StringUtil;
22 import com.jcorporate.expresso.core.registry.RequestRegistry;
23 import com.jcorporate.expresso.core.security.ReadOnlyUser;
24 import com.jcorporate.expresso.core.security.SuperUser;
25 import com.sri.emo.controller.PartAction;
26
27
28 /***
29 * The types of relations between nodes in the model.
30 * <h4>Explanation of Strength of Relation</h4>
31 * Strong relation mean that a tree-based delete or tagging will FOLLOW relation down tree.
32 * A weak relation terminates any tree at the src node.
33 *
34 * @author Larry Hamel, Michael Rimov
35 */
36 public class RelationType extends RowSecuredDBObject implements IViewable {
37 /***
38 * Serial UUID.
39 */
40 private static final long serialVersionUID = 2L;
41
42 public static final String RELATION_TYPE_NAME = "RELATION_TYPE_NAME";
43 public static final String RELATION_TYPE_DISPLAY_NAME = "REL_DISPLAY_NAME";
44 public static final String RELATION_TYPE_DESCRIP = "REL_TYPE_DESCRIP";
45
46 /***
47 * marker for whether this relation has an inverse ("reflexive" relations have inverses)
48 */
49 public static final String RELATION_INVERSE = "REL_INVERSE";
50
51 public static final String RELATION_STRENGTH = "RELATION_STRENGTH";
52
53
54
55 public static final String DEST_IS_PART_OF_SRC = "DEST_IS_PART_OF_SRC";
56 public static final String DEST_CONTAINS_SRC = "DEST_CONTAINS_SRC";
57 public static final String DEST_ASSOCIATED_SRC = "DEST_ASSOCIATED_SRC";
58 public static final String DEST_IS_EXAMPLE_OF_SRC = "DEST_IS_EXAMPLE_OF_SRC";
59
60 /***
61 * Strong relations will
62 * result in a child being destroyed with the parent (Unless the child
63 * also belongs to a strong relation of another parent.
64 */
65 public static final String STRONG_RELATION = "STRONG";
66 /***
67 * Indicates that there is an association, but there is no use of it
68 * for dealing with entity traversals when selecting trees.
69 */
70 public static final String WEAK_RELATION = "WEAK";
71
72
73 /***
74 * we automatically populate this subset of relations
75 */
76 public static final String[][] ALL_RELATION_TYPES = {
77 {
78 RelationType.DEST_CONTAINS_SRC, "I am a part of",
79 "is an association to other objects that contain or subsume this one. For example, a windshield is a part of an automobile.",
80 RelationType.DEST_IS_PART_OF_SRC,
81 WEAK_RELATION
82 },
83 {
84 RelationType.DEST_IS_PART_OF_SRC, "These are parts of me",
85 "is an association to other objects that are components or steps within this one. For example, an automobile contains a windshield.",
86 RelationType.DEST_CONTAINS_SRC,
87 STRONG_RELATION
88 },
89 {
90 RelationType.DEST_ASSOCIATED_SRC, "Associated",
91 "is a simple association between objects.",
92 "",
93 WEAK_RELATION
94 },
95 };
96
97
98 /***
99 * Default constructor for <code>RelationType</code>
100 * creates a new object of this type with no connection
101 * yet allocated.
102 *
103 * @throws DBException If the new object cannot be
104 * created
105 */
106 public RelationType() throws DBException {
107 }
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("relation_type");
117 setDescription("Relation Type");
118 addField(RELATION_TYPE_NAME, DBField.VARCHAR_TYPE, 255, false,
119 "Name of relation type");
120 addField(RELATION_TYPE_DISPLAY_NAME, DBField.VARCHAR_TYPE, 255, false,
121 "Description of type");
122 addField(RELATION_TYPE_DESCRIP, DBField.LONGVARCHAR_TYPE, 0, true,
123 "Description of type");
124 addField(RELATION_INVERSE, DBField.VARCHAR_TYPE, 255, true,
125 "Name of relation which is inverse, if any");
126
127 addField(RELATION_STRENGTH, DBField.VARCHAR_TYPE, 64, true, "Strength");
128 setMultiValued(RELATION_STRENGTH);
129
130 setMultiValued(RELATION_INVERSE);
131 setLookupObject(RELATION_INVERSE, getClass().getName());
132 addKey(RELATION_TYPE_NAME);
133 }
134
135 /***
136 * Popup list for inverse relations.
137 *
138 * @param fieldName The name of the fields for which a value set is requested
139 * @return A Vector of ValidValue objects, omitting the "this" relation since a relation cannot be its own inverse
140 * @throws DBException upon error
141 */
142 public synchronized Vector getValidValues(String fieldName)
143 throws DBException {
144 Vector v = new Vector();
145 v.add(new ValidValue("", "(none)"));
146
147 if (RelationType.RELATION_INVERSE.equals(fieldName)) {
148 RelationType type = new RelationType();
149 type.setRequestingUser(getRequestingUser());
150 type.setDataContext(getDataContext());
151
152 ArrayList list = type.searchAndRetrieveList(RELATION_TYPE_DISPLAY_NAME);
153
154 for (Iterator iterator = list.iterator(); iterator.hasNext();) {
155 RelationType relationType = (RelationType) iterator.next();
156
157
158 if (relationType.getRelTypeName().equals(getRelTypeName())) {
159 continue;
160 }
161
162 v.add(new ValidValue(relationType.getRelTypeName(),
163 relationType.getRelTypeDisplayName()));
164 }
165 } else if (RELATION_STRENGTH.equals(fieldName)) {
166 v.add(new ValidValue(STRONG_RELATION, "Strong--tree continues"));
167 v.add(new ValidValue(WEAK_RELATION, "Weak--tree stopped here"));
168 }
169
170 return v;
171 }
172
173 public void setInverseRel(String inverse) throws DBException {
174 setField(RELATION_INVERSE, inverse);
175 }
176
177 public String getInverseRel() throws DBException {
178 return getField(RELATION_INVERSE);
179 }
180
181 public static String getRelTypeDisplayName(final String typename) throws
182 DBException {
183 RelationType atype = new RelationType();
184 atype.setRequestingUser(RequestRegistry.getUser());
185 atype.setRelType(typename);
186 atype.retrieve();
187
188 return atype.getRelTypeDisplayName();
189 }
190
191 public boolean hasInverseRelation(String type) throws DBException {
192 return StringUtil.notNull(getInverseRel()).length() > 0;
193 }
194
195 public String getRelTypeDescrip() throws DBException {
196 return getField(RELATION_TYPE_DESCRIP);
197 }
198
199 public String getRelTypeName() throws DBException {
200 return getField(RELATION_TYPE_NAME);
201 }
202
203 public String getRelTypeDisplayName() throws DBException {
204 return getField(RELATION_TYPE_DISPLAY_NAME);
205 }
206
207 public void setRelType(String nodeRelation) throws DBException {
208 setField(RELATION_TYPE_NAME, nodeRelation);
209 }
210
211 public boolean isReflexive() throws DBException {
212 return hasInverseRelation(getRelTypeName());
213 }
214
215 /***
216 * @return the inverse relation, or null if not found
217 * @throws DBException upon error
218 * @see #hasInverseRelation(java.lang.String)
219 */
220 public RelationType getInverseRelType() throws DBException {
221 RelationType newinv = new RelationType();
222 newinv.setRelType(getInverseRel());
223
224 if (newinv.find()) {
225 return newinv;
226 } else {
227 return null;
228 }
229 }
230
231 /***
232 * Delete a record from the target table
233 *
234 * @throws DBException if delete is not allowed for the current user
235 */
236 public void delete() throws DBException {
237 super.delete();
238
239
240 if (getInverseRel().length() > 0) {
241 RelationType newinv = getInverseRelType();
242
243 if (newinv != null) {
244 newinv.setInverseRel("");
245 newinv.update();
246 }
247 }
248 }
249
250 /***
251 * If the user is allowed to add, invoke the superclass add
252 *
253 * @throws DBException If the user is not permitted to add
254 * or if the add fails
255 */
256 public void add() throws DBException {
257 super.add();
258
259
260 if (getInverseRel().length() > 0) {
261 RelationType newinv = getInverseRelType();
262
263 if (newinv != null) {
264 newinv.setInverseRel(getRelTypeName());
265 newinv.update();
266 }
267 }
268 }
269
270 /***
271 * get all Relations of this type, across entire universe of object types
272 *
273 * @return list of all Relations of this type, across entire universe of object types
274 * @throws DBException upon error
275 */
276 public List getRelations()
277 throws DBException {
278 List parts = getParts();
279 List result = new ArrayList();
280
281 for (Iterator iterator = parts.iterator(); iterator.hasNext();) {
282 Part apart = (Part) iterator.next();
283 result.addAll(apart.getRelations());
284 }
285
286 return result;
287 }
288
289 /***
290 * Get parts of ANY object with this relation type from database, NOT from cache.
291 *
292 * @return List of parts.
293 * @throws DBException upon database query error.
294 */
295 public List getParts() throws DBException {
296 Part partsearch = new Part();
297 partsearch.setNodeRelation(getRelTypeName());
298 partsearch.isOwnedAttribute(false);
299
300
301
302 ReadOnlyUser user = partsearch.getRequestingUser();
303 partsearch.setRequestingUser(SuperUser.INSTANCE);
304 List list = partsearch.searchAndRetrieveList(Part.PARENT_TYPE);
305
306 for (Iterator iterator = list.iterator(); iterator.hasNext();) {
307 Part part = (Part) iterator.next();
308 part.setRequestingUser(user);
309 }
310
311 return list;
312 }
313
314 public void setRelDescrip(String descrip) throws DBException {
315 setField(RELATION_TYPE_DESCRIP, descrip);
316 }
317
318 public void setRelDisplayName(String displayName) throws DBException {
319 setField(RELATION_TYPE_DISPLAY_NAME, displayName);
320 }
321
322 /***
323 * provide a transition for viewing this object, suitable for creating an
324 * HTTP link
325 *
326 * @return transtion for viewing, including label for name of object; never null
327 * @throws DBException upon query parameter error.
328 */
329 public Transition getViewTrans() throws DBException {
330 String title = "RelationType: " + getRelTypeDisplayName();
331 Transition trans = new Transition(title, PartAction.class, PartAction.PROMPT_EDIT_RELATION);
332 trans.addParam(RelationType.RELATION_TYPE_NAME, getRelTypeName());
333 return trans;
334 }
335
336 public void setStrength(String newValue) throws DBException {
337 setField(RELATION_STRENGTH, newValue);
338 }
339
340 public String getStrength() throws DBException {
341 return getField(RELATION_STRENGTH);
342 }
343
344 public void setStrongRelation(boolean strongRelation) throws DBException {
345 if (strongRelation) {
346 this.setField(RELATION_STRENGTH, STRONG_RELATION);
347 } else {
348 setField(RELATION_STRENGTH, WEAK_RELATION);
349 }
350 }
351
352 public boolean isStrong() throws DBException {
353 return STRONG_RELATION.equals(getStrength());
354 }
355 }