@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"; }
/** * 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; }
/** * 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"); } }
/** * Performs general periodic maintenance. This routine handles alle open pages/main and * pages/mirror file service requests. These requests are obtained from the netfiles builder. For * each file that should be serviced, the filechange method is called. This routine handles a * maximum of 10 page/main, and 50 page/mirror service calls each time it is called. The first * time this method is call, nothing happens (?) * * @return <code>true</code> if maintenance was performed, <code>false</code> otherwise */ public boolean probeCall() { if (first) { // skip first time this method is called first = false; } else { // handle up to 10 pages/main fileservice requests try { Netfiles bul = (Netfiles) Vwms.getMMBase().getMMObject("netfiles"); // Enumeration e=bul.search("WHERE service='pages' AND subservice='main' AND // status="+Netfiles.STATUS_REQUEST+" ORDER BY number DESC"); Enumeration e = bul.search("service=='pages'+subservice=='main'+status=" + Netfiles.STATUS_REQUEST); int i = 0; while (e.hasMoreElements() && i < 10) { MMObjectNode node = (MMObjectNode) e.nextElement(); fileChange("" + node.getIntValue("number"), "c"); i++; } } catch (Exception e) { log.error(Logging.stackTrace(e)); } // handle up to 50 pages/mirror fileservice requests try { Netfiles bul = (Netfiles) Vwms.getMMBase().getMMObject("netfiles"); Enumeration e = bul.search("service=='pages'+subservice=='mirror'+status=" + Netfiles.STATUS_REQUEST); // Enumeration e=bul.search("WHERE service='pages' AND subservice='mirror' AND // status="+Netfiles.STATUS_REQUEST+" ORDER BY number DESC"); int i = 0; while (e.hasMoreElements() && i < 50) { MMObjectNode node = (MMObjectNode) e.nextElement(); fileChange("" + node.getIntValue("number"), "c"); i++; } } catch (Exception e) { log.error(Logging.stackTrace(e)); } } return true; }
/** @javadoc */ public void handleChanged(String buildername, int number) { // method checks if this really something valid // and we should signal a new version boolean dirty = false; for (VersionCacheWhenNode whennode : whens) { List<String> types = whennode.getTypes(); // check if im known in the types part if (types.contains(buildername)) { // is there only 1 builder type ? if (log.isDebugEnabled()) log.debug("types=" + types.toString()); if (types.size() == 1) { dirty = true; } else { // so multiple prepare a multilevel ! List<String> nodes = whennode.getNodes(); List<String> fields = new Vector<String>(); fields.add(buildername + ".number"); List<String> ordervec = new Vector<String>(); List<String> dirvec = new Vector<String>(); List<MMObjectNode> vec = mmb.getClusterBuilder() .searchMultiLevelVector( nodes, fields, "YES", types, buildername + ".number==" + number, ordervec, dirvec); if (log.isDebugEnabled()) log.debug("VEC=" + vec); if (vec != null && vec.size() > 0) { dirty = true; } } } } if (dirty) { // add one to the version of this counter int version = versionnode.getIntValue("version"); versionnode.setValue("version", version + 1); versionnode.commit(); if (log.isDebugEnabled()) log.debug("Changed = " + (version + 1)); } }
/** * Handles a service-request on a file, registered in the netfiles builder. Depending on the * subservice requested, this routine calls {@link #handleMirror} or {@link #handleMain}. * * @param number Number of the node in the netfiles buidler than contain service request * information. * @param ctype the type of change on that node ("c" : node was changed) * @return <code>true</code> */ public boolean fileChange(String number, String ctype) { // log.debug("fileChange="+number+" "+ctype); // first get the change node so we can see what is the matter with it. Netfiles bul = (Netfiles) Vwms.getMMBase().getMMObject("netfiles"); MMObjectNode filenode = bul.getNode(number); if (filenode != null) { // obtain all the basic info on the file. String service = filenode.getStringValue("service"); String subservice = filenode.getStringValue("subservice"); int status = filenode.getIntValue("status"); // jump to correct subhandles based on the subservice if (subservice.equals("main")) { return handleMain(filenode, status, ctype); } else if (subservice.equals("mirror")) { return handleMirror(filenode, status, ctype); } } return true; }
/** * 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; }