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 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      // types of relations
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                      "", // null means no inverse
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     } /* setupFields() */
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                 // omit the "this" relation in list
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     } /* getValidValues(String) */
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         // handle inverse
240         if (getInverseRel().length() > 0) {
241             RelationType newinv = getInverseRelType();
242 
243             if (newinv != null) {
244                 newinv.setInverseRel("");
245                 newinv.update();
246             }
247         }
248     } /* delete() */
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         // handle inverse
260         if (getInverseRel().length() > 0) {
261             RelationType newinv = getInverseRelType();
262 
263             if (newinv != null) {
264                 newinv.setInverseRel(getRelTypeName());
265                 newinv.update();
266             }
267         }
268     } /* add() */
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         // use superuser privileges for lookup temporarily,
301         // since we always want to allow lookup of existing parts
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 } // fini