001: /*
002:
003: This software is OSI Certified Open Source Software.
004: OSI Certified is a certification mark of the Open Source Initiative.
005:
006: The license (Mozilla version 1.0) can be read at the MMBase site.
007: See http://www.MMBase.org/license
008:
009: */
010: package org.mmbase.module.corebuilders;
011:
012: import java.util.*;
013:
014: import org.mmbase.core.CoreField;
015: import org.mmbase.storage.search.*;
016: import org.mmbase.storage.search.implementation.*;
017: import org.mmbase.cache.Cache;
018: import org.mmbase.module.core.*;
019: import org.mmbase.util.logging.*;
020:
021: /**
022: *
023: * InsRel, the main relation object, holds relations, and methods to
024: * handle them. An insrel defines a relation between two objects.
025: * <p>
026: * This class can be extended to create insrels that can also hold
027: * extra values and custom methods (named relations for example).
028: * </p>
029: *
030: * @author Daniel Ockeloen
031: * @author Pierre van Rooden
032: * @version $Id: InsRel.java,v 1.54 2007/02/11 19:21:12 nklasens Exp $
033: */
034: public class InsRel extends MMObjectBuilder {
035:
036: /** Base 'insrel' builder name */
037: public static final String INSREL_BUILDER = "insrel";
038:
039: /** Name of the field containing the source object number */
040: public static final String FIELD_SNUMBER = "snumber";
041: /** Name of the field containing the source object number */
042: public static final String FIELD_SOURCE = FIELD_SNUMBER;
043: /** Name of the field containing the destination object number */
044: public static final String FIELD_DNUMBER = "dnumber";
045: /** Name of the field containing the destination object number */
046: public static final String FIELD_DESTINATION = FIELD_DNUMBER;
047: /** Name of the field containing the role (reldef) object number */
048: public static final String FIELD_RNUMBER = "rnumber";
049: /** Name of the field containing the role (reldef) object number */
050: public static final String FIELD_ROLE = FIELD_RNUMBER;
051: /** Name of the field containing the directionality */
052: public static final String FIELD_DIR = "dir";
053: /** Name of the field containing the directionality */
054: public static final String FIELD_DIRECTIONALITY = FIELD_DIR;
055:
056: private static final Logger log = Logging
057: .getLoggerInstance(InsRel.class);
058:
059: /**
060: * Indicates whether the relations use the 'dir' field (that is, whether the
061: * field has been defined in the xml file). Used for backward compatibility.
062: * The default is <code>true</code> - the value is set to <code>false</code> if any of the
063: * relation builders does not contain a <code>dir</code> field (a warning is issued).
064: */
065: public static boolean usesdir = true;
066:
067: /**
068: * Hold the relnumber to use when creating a node of this builder.
069: */
070: public int relnumber = -1;
071:
072: /**
073: * Cache system, holds the relations from the 25
074: * most used relations
075: * @todo Is this cache still used?
076: */
077:
078: private Cache<Integer, Vector<MMObjectNode>> relatedCache = new Cache<Integer, Vector<MMObjectNode>>(
079: 25) {
080: public String getName() {
081: return "RelatedCache";
082: }
083:
084: public String getDescription() {
085: return "Cache for Related Nodes";
086: }
087: };
088:
089: /* perhaps this would be nice?
090: private Cache relationsCache = new Cache(25) {
091: public String getName() { return "RelationsCache"; }
092: public String getDescription() { return "Cache for Relations"; }
093: };
094: */
095:
096: /**
097: * needed for autoload
098: */
099: public InsRel() {
100: relatedCache.putCache();
101: // relationsCache.putCache();
102: }
103:
104: /**
105: * Initializes the builder. Determines whether the <code>dir</code> field is defined (and thus whether directionality is supported).
106: * If the field cannot be found, a <em>"Warning: No dir field. Directionality support turned off."</em> warning message is issued.
107: * @return A <code>boolean</code> value, always success (<code>true</code>), as any exceptions are
108: * caught and logged.
109: * @see #usesdir
110: */
111: public boolean init() {
112: CoreField dirField = getField(FIELD_DIRECTIONALITY);
113: boolean hasDirField = dirField != null && dirField.inStorage();
114: if (!created()) {
115: // check whether directionality is in use, and whether a dir field is present.
116: // if a non-dir supporting builder is attempted to be used, a fatal error is logged.
117: // the table is not created. MMbase continues, but anny atept to use this builder will fail
118: // (one way or the other).
119: // If the builder to be created is insrel (the basic builder), the system ignores the error
120: // and continues without directionality (backward compatibility).
121: //
122: if (usesdir && !hasDirField
123: && (!getTableName().equals(INSREL_BUILDER))) {
124: log
125: .fatal("FATAL ERROR: Builder "
126: + getTableName()
127: + " has no dir field but directionality support was turned on.");
128: log.fatal("Table for " + getTableName()
129: + " was NOT created.");
130: log.fatal("MMBase continues, but use of the "
131: + getTableName() + " builder will fail.");
132: return false;
133: }
134: }
135: boolean res = super .init();
136: checkAddTmpField("_dnumber");
137: checkAddTmpField("_snumber");
138: if (res && usesdir && !hasDirField) {
139: log
140: .warn("No dir field. Directionality support turned off.");
141: usesdir = false;
142: }
143: return res;
144: }
145:
146: /**
147: * Fixes a relation node. Determines the source and destination numbers, and checks the object
148: * types against the types specified in the relation definition ( {@link TypeRel} ). If the
149: * types differ, the source and destination are likely mis-aligned, and if the relation in the
150: * other direction is indeed allowed, then they are swapped to produce a correct relation node.
151: *
152: * @param node The node to fix
153: * @return The node again
154: */
155: private MMObjectNode alignRelNode(MMObjectNode node) {
156: int source = getNodeType(node.getIntValue(FIELD_SOURCE));
157: int destination = getNodeType(node
158: .getIntValue(FIELD_DESTINATION));
159: int role = node.getIntValue(FIELD_ROLE);
160: TypeRel typeRel = mmb.getTypeRel();
161: if (!typeRel.reldefCorrect(source, destination, role)
162: && typeRel.reldefCorrect(destination, source, role)) {
163: destination = node.getIntValue(FIELD_SOURCE);
164: node.setValue(FIELD_SOURCE, node
165: .getIntValue(FIELD_DESTINATION));
166: node.setValue(FIELD_DESTINATION, destination);
167: }
168: return node;
169: }
170:
171: /**
172: * Insert a new Instance Relation.
173: * @param owner Administrator
174: * @param source Identifying number of the source object
175: * @param destination Identifying number of the destination object
176: * @param role Identifying number of the relation defintition
177: * @return A <code>integer</code> value identifying the newly inserted relation
178: * @deprecated Use insert(String, MMObjectNode) instead.
179: */
180: public int insert(String owner, int source, int destination,
181: int role) {
182: int result = -1;
183: MMObjectNode node = getNewNode(owner);
184: if (node != null) {
185: node.setValue(FIELD_SOURCE, source);
186: node.setValue(FIELD_DESTINATION, destination);
187: node.setValue(FIELD_ROLE, role);
188: result = insert(owner, node);
189: } else {
190: log.error("insert(" + owner + "," + source + ","
191: + destination + "," + role
192: + "): Cannot create new node(" + node + ")!");
193: }
194: return result;
195: }
196:
197: /**
198: * Insert a new Instance Relation.
199: * @param owner Administrator
200: * @param node Relation node to add
201: * @return A <code>integer</code> value identifying the newly inserted relation
202: */
203: public int insert(String owner, MMObjectNode node) {
204: int result = -1;
205: int source = node.getIntValue(FIELD_SOURCE);
206: if (source >= 0) {
207: int destination = node.getIntValue(FIELD_DESTINATION);
208: if (destination >= 0) {
209: int role = node.getIntValue(FIELD_ROLE);
210: if (role > 0) {
211: if (usesdir) {
212: MMObjectNode reldef = getNode(role);
213: int dir = reldef
214: .getIntValue(FIELD_DIRECTIONALITY);
215: if (dir <= 0)
216: dir = 2;
217: node.setValue(FIELD_DIRECTIONALITY, dir);
218: }
219: node = alignRelNode(node);
220: if (log.isDebugEnabled()) {
221: log.debug("insert(" + owner + "," + node + ")");
222: }
223: result = super .insert(owner, node);
224: // remove cache for these nodes (enforce update)
225: deleteRelationCache(source);
226: deleteRelationCache(destination);
227: } else {
228: log
229: .error("insert("
230: + owner
231: + ","
232: + node
233: + "): rnumber("
234: + role
235: + ") is not greater than 0! (something is seriously wrong)");
236: }
237: } else {
238: log
239: .error("insert("
240: + owner
241: + ","
242: + node
243: + "): dnumber("
244: + destination
245: + " is not greater than 0! (something is seriously wrong)");
246: }
247: } else {
248: log
249: .error("insert("
250: + owner
251: + ","
252: + node
253: + "): snumber("
254: + source
255: + ") is not greater than 0! (something is seriously wrong)");
256: }
257: return result;
258: }
259:
260: /**
261: * Remove a node from the cloud.
262: * @param node The node to remove.
263: */
264: public void removeNode(MMObjectNode node) {
265: int source = node.getIntValue(FIELD_SOURCE);
266: int destination = node.getIntValue(FIELD_DESTINATION);
267: super .removeNode(node);
268: deleteRelationCache(source);
269: deleteRelationCache(destination);
270: }
271:
272: /**
273: * Get relation(s) for a MMObjectNode
274: * @param source Identifying number of the object to find the relations of.
275: * @return If succesful, an <code>Enumeration</code> listing the relations.
276: * If no relations exist, the method returns <code>null</code>.
277: * @see #getRelationsVector(int)
278: */
279: public Enumeration<MMObjectNode> getRelations(int source) {
280: return getRelations(source, -1);
281: }
282:
283: /**
284: * Get relation(s) for a MMObjectNode, using a specified role (reldef) as a filter
285: * @param source Identifying number of the object to find the relations of.
286: * @param role The number of the relation definition (role) to filter on
287: * @return an <code>Enumeration</code> listing the relations.
288: * @see #getRelationsVector(int, int)
289: */
290: public Enumeration<MMObjectNode> getRelations(int source, int role) {
291: return getRelationsVector(source, role).elements();
292: }
293:
294: /**
295: * Get relations for a specified MMObjectNode
296: * @param source this is the number of the MMObjectNode requesting the relations
297: * @param otype the object type of the nodes you want to have. -1 means any node.
298: * @param role Identifying number of the role (reldef)
299: * @return An <code>Enumeration</code> whose enumeration consists of <code>MMObjectNode</code> object related to the source
300: * according to the specified filter(s).
301: */
302: public Enumeration<MMObjectNode> getRelations(int source,
303: int otype, int role) {
304: return getRelations(source, otype, role, true);
305: }
306:
307: /**
308: * Gets relations for a specified MMObjectNode
309: * @param source this is the number of the MMObjectNode requesting the relations
310: * @param otype the object type of the nodes you want to have. -1 means any node.
311: * @param role Identifying number of the role (reldef)
312: * @param usedirectionality if <code>true</code> teh result si filtered on unidirectional relations.
313: * specify <code>false</code> if you want to show unidoerctional relations
314: * from destination to source.
315: * @return An <code>Enumeration</code> whose enumeration consists of <code>MMObjectNode</code> object related to the source
316: * according to the specified filter(s).
317: */
318: public Enumeration<MMObjectNode> getRelations(int source,
319: int otype, int role, boolean usedirectionality) {
320: List<MMObjectNode> re;
321: if (usedirectionality) {
322: re = getRelationsVector(source, role);
323: } else {
324: re = getAllRelationsVector(source, role);
325: }
326: if (otype == -1) {
327: return Collections.enumeration(re);
328: } else {
329: TypeDef typedef = mmb.getTypeDef();
330: MMObjectBuilder wantedBuilder = mmb.getBuilder(typedef
331: .getValue(otype));
332: List<MMObjectNode> list = new ArrayList<MMObjectNode>();
333: for (MMObjectNode node : re) {
334: int nodenr = node.getIntValue(FIELD_SOURCE);
335: if (nodenr == source) {
336: nodenr = node.getIntValue(FIELD_DESTINATION);
337: }
338: String tableName = typedef
339: .getValue(getNodeType(nodenr));
340: if (tableName != null) {
341: MMObjectBuilder nodeBuilder = mmb
342: .getBuilder(tableName);
343: if (nodeBuilder != null
344: && (nodeBuilder.equals(wantedBuilder) || nodeBuilder
345: .isExtensionOf(wantedBuilder))) {
346: list.add(node);
347: }
348: }
349: }
350: return Collections.enumeration(list);
351: }
352: }
353:
354: /**
355: * Checks whether any relations exist for a MMObjectNode.
356: * This includes unidirection relations which would otherwise not be counted.
357: * If the query fails to execute, the system will assume that relations exists.
358: * @param source Identifying number of the object to find the relations of.
359: * @return <code>true</code> if any relations exist, <code>false</code> otherwise.
360: */
361: public boolean hasRelations(int source) {
362: try {
363: NodeSearchQuery query = new NodeSearchQuery(this );
364: BasicCompositeConstraint constraint = new BasicCompositeConstraint(
365: CompositeConstraint.LOGICAL_OR);
366: constraint.addChild(getNumberConstraint(query,
367: FIELD_SOURCE, source));
368: constraint.addChild(getNumberConstraint(query,
369: FIELD_DESTINATION, source));
370: query.setConstraint(constraint);
371: return count(query) != 0;
372: } catch (SearchQueryException sqe) {
373: log.error(sqe.getMessage(), sqe); // should not happen
374: return true; // perhaps yes?
375: }
376: }
377:
378: // creates a constraint for a numeric field on a query
379: private BasicFieldValueConstraint getNumberConstraint(
380: NodeSearchQuery query, String fieldName, int value) {
381: return new BasicFieldValueConstraint(query.getField(query
382: .getBuilder().getField(fieldName)), Integer
383: .valueOf(value));
384: }
385:
386: /**
387: * Get relation(s) for an MMObjectNode, using a specified role (reldef) as a filter.
388: * This function returns all relations based on this role in which the node is either a source, or where the node is
389: * the destination, but the direction is bidirectional.
390: * @param source Identifying number of the object to find the relations of.
391: * @return A <code>List</code> containing the relation nodes.
392: * @throws SearchQueryException if a storage error occurs
393: */
394: public List<MMObjectNode> getRelationNodes(int source)
395: throws SearchQueryException {
396: return getRelationNodes(source, -1, usesdir);
397: }
398:
399: /**
400: * Get relation(s) for a MMObjectNode.
401: * @deprecated use {@link #getRelationNodes(int)}
402: */
403: public Vector<MMObjectNode> getRelationsVector(int source) {
404: try {
405: return new Vector<MMObjectNode>(getRelationNodes(source,
406: -1, usesdir));
407: } catch (SearchQueryException sqe) {
408: log.error(sqe.getMessage(), sqe); // should not happen
409: return new Vector<MMObjectNode>(); //
410: }
411: }
412:
413: /**
414: * Get relation(s) for an MMObjectNode, using a specified role (reldef) as a filter.
415: * This function returns all relations based on this role in which the node is either a source, or where the node is
416: * the destination, but the direction is bidirectional.
417: * @param source Identifying number of the object to find the relations of.
418: * @param role The number of the relation definition (role) to filter on, <code>-1</code> means any role
419: * @return A <code>List</code> containing the relation nodes.
420: * @throws SearchQueryException if a storage error occurs
421: */
422: public List<MMObjectNode> getRelationNodes(int source, int role)
423: throws SearchQueryException {
424: return getRelationNodes(source, role, usesdir);
425: }
426:
427: /**
428: * Get relation(s) for a MMObjectNode, using a specified role.
429: * @deprecated use {@link #getRelationNodes(int, int, boolean)}
430: */
431: public Vector<MMObjectNode> getRelationsVector(int source, int role) {
432: try {
433: return new Vector<MMObjectNode>(getRelationNodes(source,
434: role, usesdir));
435: } catch (SearchQueryException sqe) {
436: log.error(sqe.getMessage(), sqe); // should not happen
437: return new Vector<MMObjectNode>(); //
438: }
439: }
440:
441: /**
442: * Get all relation(s) for an MMObjectNode.
443: * This function returns all relations in which the node is either a source or
444: * the destination.
445: * @param source Identifying number of the object to find the relations of.
446: * @param useDirectionality if <code>truie</code>, take directionality into account.
447: * If <code>false</code>, returns all relations, even if the direction is unidirectional.
448: * @return A <code>List</code> containing the relation nodes.
449: * @throws SearchQueryException if a storage error occurs
450: */
451: public List<MMObjectNode> getRelationNodes(int source,
452: boolean useDirectionality) throws SearchQueryException {
453: return getRelationNodes(source, -1, useDirectionality);
454: }
455:
456: /**
457: * Get all relation(s) for a MMObjectNode.
458: * @deprecated use {@link #getRelationNodes(int, boolean)}
459: */
460: public Vector<MMObjectNode> getAllRelationsVector(int source) {
461: try {
462: return new Vector<MMObjectNode>(getRelationNodes(source,
463: -1, false));
464: } catch (SearchQueryException sqe) {
465: log.error(sqe.getMessage(), sqe); // should not happen
466: return new Vector<MMObjectNode>(); //
467: }
468: }
469:
470: /**
471: * Get all relation(s) for a MMObjectNode
472: * This function returns all relations in which the node is either a source or
473: * the destination.
474: * @param source Identifying number of the object to find the relations of.
475: * @param role The number of the relation definition (role) to filter on, <code>-1</code> means any role
476: * @param useDirectionality if <code>truie</code>, take directionality into account.
477: * If <code>false</code>, returns all relations, even if the direction is unidirectional.
478: * @return A <code>List</code> containing the relation nodes.
479: * @throws SearchQueryException if a storage error occurs
480: */
481: public List<MMObjectNode> getRelationNodes(int source, int role,
482: boolean useDirectionality) throws SearchQueryException {
483: MMObjectBuilder builder = this ;
484: if (role != -1) {
485: builder = mmb.getRelDef().getBuilder(role);
486: }
487: NodeSearchQuery query = new NodeSearchQuery(builder);
488: BasicCompositeConstraint constraint = new BasicCompositeConstraint(
489: CompositeConstraint.LOGICAL_OR);
490: constraint.addChild(getNumberConstraint(query, FIELD_SOURCE,
491: source));
492: Constraint destinationConstraint = getNumberConstraint(query,
493: FIELD_DESTINATION, source);
494: if (useDirectionality) {
495: BasicFieldValueConstraint dirConstraint = getNumberConstraint(
496: query, FIELD_DIRECTIONALITY, 1);
497: dirConstraint.setOperator(FieldCompareConstraint.NOT_EQUAL);
498: BasicCompositeConstraint compositeConstraint = new BasicCompositeConstraint(
499: CompositeConstraint.LOGICAL_AND);
500: compositeConstraint.addChild(destinationConstraint);
501: compositeConstraint.addChild(dirConstraint);
502: destinationConstraint = compositeConstraint;
503: }
504: constraint.addChild(destinationConstraint);
505: if (role != -1) {
506: BasicCompositeConstraint roleConstraint = new BasicCompositeConstraint(
507: CompositeConstraint.LOGICAL_AND);
508: roleConstraint.addChild(constraint);
509: roleConstraint.addChild(getNumberConstraint(query,
510: FIELD_ROLE, role));
511: constraint = roleConstraint;
512: }
513: query.setConstraint(constraint);
514: List<MMObjectNode> nodes = builder.getNodes(query);
515: return nodes;
516: }
517:
518: /**
519: * Get all relation(s) for a MMObjectNode.
520: * @deprecated use {@link #getRelationNodes(int, int, boolean)}
521: */
522: public Vector<MMObjectNode> getAllRelationsVector(int source,
523: int role) {
524: try {
525: return new Vector<MMObjectNode>(getRelationNodes(source,
526: role, false));
527: } catch (SearchQueryException sqe) {
528: log.error(sqe.getMessage(), sqe); // should not happen
529: return new Vector<MMObjectNode>(); //
530: }
531: }
532:
533: /**
534: * Test whether a relation exists and returns the corresponding node.
535: * Note that this test is strict: it determines whether a relation exists from a source to a destination
536: * with a specific role. If only a role-relation exists where source and destination are reversed, this method
537: * assumed that this is a different relation type, and it returns <code>null</code>.
538: * @param source Identifying number of the source object
539: * @param destination Identifying number of the destination object
540: * @param role Identifying number of the role (reldef)
541: * @throws SearchQueryException if a storage error occurs
542: * @return The corresponding <code>MMObjectNode</code> if the exact relation exists,<code>null</code> otherwise
543: */
544: public MMObjectNode getRelationNode(int source, int destination,
545: int role) throws SearchQueryException {
546: MMObjectNode result = null;
547: MMObjectBuilder builder = mmb.getRelDef().getBuilder(role);
548: NodeSearchQuery query = new NodeSearchQuery(builder);
549: BasicCompositeConstraint constraint = new BasicCompositeConstraint(
550: CompositeConstraint.LOGICAL_AND);
551: constraint.addChild(getNumberConstraint(query, FIELD_SOURCE,
552: source));
553: constraint.addChild(getNumberConstraint(query,
554: FIELD_DESTINATION, destination));
555: constraint
556: .addChild(getNumberConstraint(query, FIELD_ROLE, role));
557: query.setConstraint(constraint);
558: Iterator<MMObjectNode> i = builder.getNodes(query).iterator();
559: if (i.hasNext()) {
560: result = i.next();
561: }
562: return result;
563: }
564:
565: /**
566: * Test whether a relation exists and returns the corresponding node.
567: * Note that this test is strict: it determines whether a relation exists from a source to a destination
568: * with a specific role. If only a role-relation exists where source and destination are reversed, this method
569: * assumed that this is a different relation type, and it returns <code>null</code>.
570: * @param source Identifying number of the source object
571: * @param destination Identifying number of the destination object
572: * @param role Identifying number of the role (reldef)
573: * @return The corresponding <code>MMObjectNode</code> if the exact relation exists,<code>null</code> otherwise
574: */
575: public MMObjectNode getRelation(int source, int destination,
576: int role) {
577: try {
578: return getRelationNode(source, destination, role);
579: } catch (SearchQueryException sqe) {
580: log.error(sqe.getMessage()); // should not happen
581: return null;
582: }
583: }
584:
585: /**
586: * get MMObjectNodes related to a specified MMObjectNode
587: * @param sourceNode this is the source MMObjectNode
588: * @param nodeType Specifies the type of the nodes you want to have e.g. "pools"
589: */
590: public Enumeration<MMObjectNode> getRelated(String sourceNode,
591: String nodeType) {
592: try {
593: int source = Integer.parseInt(sourceNode);
594: int otype = mmb.getTypeDef().getIntValue(nodeType);
595: return getRelated(source, otype);
596: } catch (Exception e) {
597: // why is this silentely catched ?
598: }
599: return null;
600: }
601:
602: /**
603: * get MMObjectNodes related to a specified MMObjectNode
604: * @param source this is the number of the source MMObjectNode
605: * @param nodeType Specifies the type of the nodes you want to have e.g. "pools"
606: */
607: public Enumeration<MMObjectNode> getRelated(int source,
608: String nodeType) {
609: try {
610: int otype = -1;
611: if (nodeType != null) {
612: otype = mmb.getTypeDef().getIntValue(nodeType);
613: }
614: return getRelated(source, otype);
615: } catch (Exception e) {
616: // why is this silentely catched ?
617: }
618: return null;
619: }
620:
621: /**
622: * Get MMObjectNodes of a specified type related to a specified MMObjectNode
623: * @param source this is the number of the source MMObjectNode
624: * @param otype the object type of the nodes you want to have
625: * @return An <code>Enumeration</code> of <code>MMObjectNode</code> object related to the source
626: */
627: public Enumeration<MMObjectNode> getRelated(int source, int otype) {
628: Vector<MMObjectNode> se = getRelatedVector(source, otype);
629: if (se != null)
630: return se.elements();
631: return null;
632: }
633:
634: /**
635: * get MMObjectNodes related to a specified MMObjectNode
636: * @param sourceNode this is the number of the source MMObjectNode (in string format)
637: * @param nodeType Specifies the type of the nodes you want to have e.g. "pools"
638: * @param roleName the role of teh relation (name in reldef)
639: */
640: public Enumeration<MMObjectNode> getRelated(String sourceNode,
641: String nodeType, String roleName) {
642: try {
643: int source = Integer.parseInt(sourceNode);
644: int otype = mmb.getTypeDef().getIntValue(nodeType);
645: int role = mmb.getRelDef().getNumberByName(roleName);
646: return getRelated(source, otype, role);
647: } catch (Exception e) {
648: }
649: return null;
650: }
651:
652: /**
653: * get MMObjectNodes related to a specified MMObjectNode
654: * @param source this is the number of the source MMObjectNode
655: * @param nodeType Specifies the type of the nodes you want to have e.g. "pools"
656: * @param roleName the name of the role of the relation (name in reldef)
657: */
658: public Enumeration<MMObjectNode> getRelated(int source,
659: String nodeType, String roleName) {
660: try {
661: int otype = mmb.getTypeDef().getIntValue(nodeType);
662: int role = mmb.getRelDef().getNumberByName(roleName);
663: return getRelated(source, otype, role);
664: } catch (Exception e) {
665: }
666: return null;
667: }
668:
669: /**
670: * Get MMObjectNodes of a specified type related to a specified MMObjectNode
671: * @param source this is the number of the source MMObjectNode
672: * @param otype the object type of the nodes you want to have
673: * @param role Identifying number of the role (reldef)
674: * @return An <code>Enumeration</code> of <code>MMObjectNode</code> object related to the source
675: */
676: public Enumeration<MMObjectNode> getRelated(int source, int otype,
677: int role) {
678: Vector<MMObjectNode> se = getRelatedVector(source, otype, role);
679: if (se != null)
680: return se.elements();
681: return null;
682: }
683:
684: /**
685: * Get MMObjectNodes related to a specified MMObjectNode
686: * @param source this is the number of the MMObjectNode requesting the relations
687: * @param otype the object type of the nodes you want to have. -1 means any node.
688: * @return A <code>Vector</code> whose enumeration consists of <code>MMObjectNode</code> object related to the source
689: * according to the specified filter(s).
690: * @deprecated
691: **/
692: public Vector<MMObjectNode> getRelatedVector(int source, int otype) {
693: return getRelatedVector(source, otype, -1);
694: }
695:
696: /**
697: * Get MMObjectNodes related to a specified MMObjectNode
698: * @param source this is the number of the MMObjectNode requesting the relations
699: * @param otype the object type of the nodes you want to have. -1 means any node.
700: * @param role Identifying number of the role (reldef)
701: * @return A <code>Vector</code> whose enumeration consists of <code>MMObjectNode</code> object related to the source
702: * according to the specified filter(s).
703: * @deprecated
704: */
705: public Vector<MMObjectNode> getRelatedVector(int source, int otype,
706: int role) {
707: Vector<MMObjectNode> list = null;
708: if (role == -1) {
709: list = relatedCache.get(Integer.valueOf(source));
710: }
711: if (list == null) {
712: list = new Vector<MMObjectNode>();
713: for (Enumeration<MMObjectNode> e = getRelations(source,
714: role); e.hasMoreElements();) {
715: MMObjectNode node = e.nextElement();
716: int nodenr = node.getIntValue(FIELD_SOURCE);
717: if (nodenr == source) {
718: nodenr = node.getIntValue(FIELD_DESTINATION);
719: }
720: MMObjectNode node2 = getNode(nodenr);
721: if (node2 != null) {
722: list.add(node2);
723: }
724: }
725: if (role == -1) {
726: relatedCache.put(Integer.valueOf(source), list);
727: }
728: }
729: // oke got the Vector now lets get the correct otypes
730: Vector<MMObjectNode> results = null;
731: if (otype == -1) {
732: results = new Vector<MMObjectNode>(list);
733: } else {
734: results = new Vector<MMObjectNode>();
735: for (MMObjectNode node : list) {
736: if (node.getOType() == otype) {
737: results.addElement(node);
738: }
739: }
740: }
741: return results;
742: }
743:
744: public String getGUIIndicator(MMObjectNode node) {
745: return node.getStringValue(FIELD_SOURCE) + "->"
746: + node.getStringValue(FIELD_DESTINATION);
747: }
748:
749: /**
750: * Get the display string for a given field of this node.
751: * Returns for 'snumber' the name of the source object,
752: * for 'dnumber' the name of the destination object, and
753: * for 'rnumber' the name of the relation definition.
754: * @param field name of the field to describe.
755: * @param node Node containing the field data.
756: * @return A <code>String</code> describing the requested field's content
757: **/
758: public String getGUIIndicator(String field, MMObjectNode node) {
759: try {
760: if (field.equals(FIELD_DIRECTIONALITY)) {
761: int dir = node.getIntValue(FIELD_DIRECTIONALITY);
762: if (dir == 2) {
763: return "bidirectional";
764: } else if (dir == 1) {
765: return "unidirectional";
766: } else {
767: return "unknown";
768: }
769: } else if (field.equals(FIELD_SOURCE)) {
770: MMObjectNode node2 = getNode(node
771: .getIntValue(FIELD_SOURCE));
772: String ty = "="
773: + mmb.getTypeDef().getValue(node2.getOType());
774: if (node2 != null) {
775: return "" + node.getIntValue(FIELD_SOURCE) + ty
776: + "(" + node2.getGUIIndicator() + ")";
777: }
778: } else if (field.equals(FIELD_DESTINATION)) {
779: MMObjectNode node2 = getNode(node
780: .getIntValue(FIELD_DESTINATION));
781: String ty = "="
782: + mmb.getTypeDef().getValue(node2.getOType());
783: if (node2 != null) {
784: return "" + node.getIntValue(FIELD_DESTINATION)
785: + ty + "(" + node2.getGUIIndicator() + ")";
786: }
787: } else if (field.equals(FIELD_ROLE)) {
788: MMObjectNode node2 = mmb.getRelDef().getNode(
789: node.getIntValue(FIELD_ROLE));
790: return "" + node.getIntValue(FIELD_ROLE) + "="
791: + node2.getGUIIndicator();
792: }
793: } catch (Exception e) {
794: }
795: return null;
796: }
797:
798: /**
799: * Checks whether a specific relation exists.
800: * Maintains a cache containing the last checked relations
801: *
802: * Note that this routine returns false both when a source/destination are swapped, and when a typecombo
803: * does not exist - it is not possible to derive whether one or the other has occurred.
804: *
805: * @param source Number of the source node
806: * @param destination Number of the destination node
807: * @param role Number of the relation definition
808: * @return A <code>boolean</code> indicating success when the relation exists, failure if it does not.
809: * @deprecated Use {@link TypeRel#reldefCorrect} instead
810: */
811: public boolean reldefCorrect(int source, int destination, int role) {
812: return mmb.getTypeRel()
813: .reldefCorrect(source, destination, role);
814: }
815:
816: /**
817: * Deletes the Relation cache.
818: * This is to be called if caching gives problems.
819: * Make sure that you can't use the deleteRelationCache(int source) instead.
820: **/
821: public void deleteRelationCache() {
822: relatedCache.clear();
823: }
824:
825: /**
826: * Delete a specified relation from the relationCache
827: * @param source the number of the relation to remove from the cache
828: **/
829: public void deleteRelationCache(int source) {
830: relatedCache.remove(Integer.valueOf(source));
831: }
832:
833: /**
834: * Search the relation definition table for the identifying number of
835: * a relation, by name.
836: * Success is dependent on the uniqueness of the relation's name (not enforced, so unpredictable).
837: * @param name The name on which to search for the relation
838: * @return A <code>int</code> value indicating the relation's object number, or -1 if not found.
839: **/
840: public int getGuessedNumber(String name) {
841: RelDef reldef = mmb.getRelDef();
842: if (reldef != null) {
843: return reldef.getNumberByName(name);
844: }
845: return -1;
846: }
847:
848: /**
849: * Set defaults for a node.
850: * Tries to determine a default for 'relnumber' by searching the RelDef table for an occurrence of the node's builder.
851: * Uses the table-mapping system, and should be replaced.
852: * @param node The node whose defaults to set.
853: */
854: public void setDefaults(MMObjectNode node) {
855: super .setDefaults(node);
856: if (tableName.equals(INSREL_BUILDER))
857: return;
858:
859: if (relnumber == -1) {
860: MMObjectNode n = mmb.getRelDef().getDefaultForBuilder(this );
861: if (n == null) {
862: log.warn("Can not determine default reldef for ("
863: + getTableName() + ")");
864: } else {
865: relnumber = n.getNumber();
866: }
867: }
868: node.setValue(FIELD_ROLE, relnumber);
869: }
870: }
|