/** * Insert a new object (content provided) in the cloud, including an entry for the object alias * (if provided). This method indirectly calls {@link #preCommit}. If the typerel node specified * already exists (i.e. same snumber, dnumber,a nd rnumber fielfds), the typerel creation fails * and returns -1. * * @param owner The administrator creating the node * @param node The object to insert. The object need be of the same type as the current builder. * @return An <code>int</code> value which is the new object's unique number, -1 if the insert * failed. */ @Override public int insert(String owner, MMObjectNode node) { int snumber = node.getIntValue("snumber"); int dnumber = node.getIntValue("dnumber"); int rnumber = node.getIntValue("rnumber"); if (contains(snumber, dnumber, rnumber, STRICT)) { log.error( "The typerel with snumber=" + snumber + ", dnumber=" + dnumber + ", rnumber=" + rnumber + " already exists"); throw new RuntimeException( "The typerel with snumber=" + snumber + ", dnumber=" + dnumber + ", rnumber=" + rnumber + " already exists"); } int res = super.insert(owner, node); return res; }
@Override public String toString(MMObjectNode n) { try { int snumber = n.getIntValue("snumber"); int dnumber = n.getIntValue("dnumber"); int rnumber = n.getIntValue("rnumber"); String sourceName = mmb.getTypeDef().getValue(snumber); String destName = mmb.getTypeDef().getValue(dnumber); if (sourceName == null) { sourceName = "unknown builder '" + snumber + "'"; } if (destName == null) { destName = "unknown builder '" + dnumber + "'"; } // unfilled should only happen during creation of the node. String source = snumber > -1 ? (sourceName + "(" + snumber + ")") : "[unfilled]"; String destination = dnumber > -1 ? (destName + "(" + dnumber + ")") : "[unfilled]"; MMObjectNode role = rnumber > -1 ? mmb.getRelDef().getNode(rnumber) : null; return source + "->" + destination + " (" + (role != null ? role.getStringValue("sname") : "???") + ") " + (isVirtual() ? "(virtual)" : ""); } catch (Exception e) { log.warn(e); } return "typerel-node"; }
/** * Implements for MMObjectNode * * @since MMBase-1.6.2 */ @Override public int hashCode(MMObjectNode o) { int result = 0; result = HashCodeUtil.hashCode(result, o.getIntValue("snumber")); result = HashCodeUtil.hashCode(result, o.getIntValue("dnumber")); result = HashCodeUtil.hashCode(result, o.getIntValue("rnumber")); return result; }
/** * Implements equals for a typerel node. Two nodes are equal if the snumber and dnumber fields are * the same, and the rnumber fields are the same, or one of these is '-1' (don't care). * * @since MMBase-1.6.2 */ @Override public boolean equals(MMObjectNode o1, MMObjectNode o2) { if (o2.getBuilder() instanceof TypeRel) { int r1 = o1.getIntValue("rnumber"); int r2 = o2.getIntValue("rnumber"); return o1.getIntValue("snumber") == o2.getIntValue("snumber") && o1.getIntValue("dnumber") == o2.getIntValue("dnumber") && (r1 == -1 || r2 == -1 || r1 == r2); } return false; }
/** * Returns the display string for a specified field. Returns, for snumber and dnumber, the name of * the objecttype they represent, and for rnumber the display (GUI) string for the indicated * relation definition. * * @param field The name of the field to retrieve * @param node Node from which to retrieve the data * @return A <code>String</code> describing the content of the field */ @Override public String getGUIIndicator(String field, MMObjectNode node) { try { if (field.equals("snumber")) { return mmb.getTypeDef().getValue(node.getIntValue("snumber")); } else if (field.equals("dnumber")) { return mmb.getTypeDef().getValue(node.getIntValue("dnumber")); } else if (field.equals("rnumber")) { MMObjectNode reldef = mmb.getRelDef().getNode(node.getIntValue("rnumber")); return (reldef != null ? reldef.getGUIIndicator() : "???"); } } catch (Exception e) { } return null; }
/** * Returns the display string for this node It returns a commbination of objecttypes and rolename * : "source->destination (role)". * * @param node Node from which to retrieve the data * @return A <code>String</code> describing the content of the node */ @Override public String getGUIIndicator(MMObjectNode node) { try { String source = mmb.getTypeDef().getValue(node.getIntValue("snumber")); String destination = mmb.getTypeDef().getValue(node.getIntValue("dnumber")); MMObjectNode role = mmb.getRelDef().getNode(node.getIntValue("rnumber")); return source + "->" + destination + " (" + (role != null ? role.getGUIIndicator() : "???") + ")"; } catch (Exception e) { log.warn(e); } return null; }
/** * Retrieves all relations which are 'allowed' between two specified nodes. * * @param snum The first objectnode type (the source) * @param dnum The second objectnode type (the destination) * @return An <code>Enumeration</code> of nodes containing the reldef (not typerel!) sname field */ protected Vector<String> getAllowedRelationsNames(int snum, int dnum) { Vector<String> results = new Vector<String>(); for (Enumeration<MMObjectNode> e = getAllowedRelations(snum, dnum); e.hasMoreElements(); ) { MMObjectNode node = e.nextElement(); int rnumber = node.getIntValue("rnumber"); MMObjectNode snode = mmb.getRelDef().getNode(rnumber); results.addElement(snode.getStringValue("sname")); } return results; }
/** * Retrieves the identifying number of the relation definition that is 'allowed' between two * specified node types. The results are dependent on there being only one type of relation * between two node types (not enforced, thus unpredictable). Makes use of a typeRelNodes. * * @param snum The first objectnode type (the source) * @param dnum The second objectnode type (the destination) * @return the number of the found relation, or -1 if either no relation was found, or more than * one was found. */ public int getAllowedRelationType(int snum, int dnum) { Set<MMObjectNode> set = new HashSet<MMObjectNode>(typeRelNodes.getBySourceDestination(snum, dnum)); set.addAll(inverseTypeRelNodes.getByDestinationSource(dnum, snum)); if (set.size() != 1) { return -1; } else { MMObjectNode n = set.iterator().next(); return n.getIntValue("rnumber"); } }
/** * Addes one typerel cache entries, plus inherited relations (if builder are initialized) * * @return A Set with the added entries, which can be used for logging or so, or can be * disregarded * @since MMBase-1.6.2 */ protected TypeRelSet addCacheEntry( final MMObjectNode typeRel, final boolean buildersInitialized) { if (typeRel == null) { throw new IllegalArgumentException("typeRel cannot be null"); } final TypeRelSet added = new TypeRelSet(); // store temporary, which will enable nice logging of what happened // Start to add the actual definition, this is then afterwards again, // except if one of the builders could not be found added.add(typeRel); if (mmb == null) { throw new IllegalStateException("mmb is null"); } final RelDef reldef = mmb.getRelDef(); if (reldef == null) { throw new IllegalStateException("No reldef found"); } final MMObjectNode reldefNode = reldef.getNode(typeRel.getIntValue("rnumber")); if (reldefNode == null) { throw new RuntimeException( "Could not find reldef-node for rnumber= " + typeRel.getIntValue("rnumber")); } final boolean bidirectional = (!InsRel.usesdir) || (reldefNode.getIntValue("dir") > 1); INHERITANCE: if (buildersInitialized) { // handle inheritance, which is // not possible during // initialization of MMBase. final TypeDef typeDef = mmb.getTypeDef(); final String sourceBuilderName = typeDef.getValue(typeRel.getIntValue("snumber")); final MMObjectBuilder sourceBuilder = sourceBuilderName != null ? mmb.getBuilder(sourceBuilderName) : null; final String destinationBuilderName = typeDef.getValue(typeRel.getIntValue("dnumber")); final MMObjectBuilder destinationBuilder = destinationBuilderName != null ? mmb.getBuilder(destinationBuilderName) : null; if (sourceBuilder == null) { if (destinationBuilder == null) { log.info( "Both source and destination of " + typeRel + " are not active builders. Cannot follow descendants."); } else { log.info( "The source of relation type " + typeRel + " is not an active builder. Cannot follow descendants."); } break INHERITANCE; } if (destinationBuilder == null) { log.warn( "The destination of relation type " + typeRel + " is not an active builder. Cannot follow descendants."); break INHERITANCE; } final int rnumber = typeRel.getIntValue("rnumber"); final List<MMObjectBuilder> sources = new ArrayList<MMObjectBuilder>(sourceBuilder.getDescendants()); sources.add(sourceBuilder); final List<MMObjectBuilder> destinations = new ArrayList<MMObjectBuilder>(destinationBuilder.getDescendants()); destinations.add(destinationBuilder); for (MMObjectBuilder s : sources) { for (MMObjectBuilder d : destinations) { MMObjectNode vnode = new VirtualTypeRelNode(s.getNumber(), d.getNumber(), rnumber); added.add(vnode); } } // seek all parents and store typerels for them // this cache is used by contains(INCLUDE_PARENTS / // INCLUDE_PARENTS_AND_DESCENDANTS)); MMObjectBuilder sourceParent = sourceBuilder; while (sourceParent != null) { MMObjectBuilder destinationParent = destinationBuilder; while (destinationParent != null) { MMObjectNode vnode = new VirtualTypeRelNode( sourceParent.getNumber(), destinationParent.getNumber(), rnumber); parentTypeRelNodes.add(vnode); destinationParent = destinationParent.getParentBuilder(); } sourceParent = sourceParent.getParentBuilder(); } added.add(typeRel); // replaces the ones added in the 'inheritance' // loop (so now not any more Virtual) } for (MMObjectNode node : added) { if (!node.isVirtual()) { // make sure 'real' nodes replace virtual nodes. (real and virtual nodes are equal, so will // not be added to set otherwise) // This is especially essential whey you use STRICT in contains typeRelNodes.remove(node); if (bidirectional) inverseTypeRelNodes.remove(node); } typeRelNodes.add(node); if (bidirectional) inverseTypeRelNodes.add(node); } if (log.isDebugEnabled()) { log.debug("Added to typerelcache: " + added); } return added; }