Package org.xmlBlaster.util.context

Source Code of org.xmlBlaster.util.context.ContextNode

/*------------------------------------------------------------------------------
Name:      ContextNode.java
Project:   xmlBlaster.org
Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
------------------------------------------------------------------------------*/
package org.xmlBlaster.util.context;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

import javax.management.ObjectName;

import org.xmlBlaster.util.Global;
import org.xmlBlaster.util.ReplaceVariable;
import org.xmlBlaster.util.StringPairTokenizer;
import org.xmlBlaster.util.def.Constants;

/**
* This represents one node in the administrative hierarchy, and is a linked
* list to its parent and its childs.
*
* @author xmlBlaster@marcelruff.info
* @see <a href="http://www.xmlBlaster.org/xmlBlaster/doc/requirements/admin.commands.html">The admin.commands requirement</a>
*/
public final class ContextNode
{
   private static Logger log = Logger.getLogger(ContextNode.class.getName());
   /** Name for logging output */
   public final static String SEP = "/";
   public final static String ROOT_MARKER_TAG = SEP+"xmlBlaster";
   /** Use to mark a cluster node name */
   public final static String CLUSTER_MARKER_TAG = "node";
   /** Use to mark a client */
   public final static String SUBJECT_MARKER_TAG = "client";
   /** Use to mark a contrib */
   public final static String CONTRIB_MARKER_TAG = "contrib";
   /** Use to mark a login session */
   public final static String SESSION_MARKER_TAG = "session";
   /** Use for client side XmlBlasterAccess */
   public final static String CONNECTION_MARKER_TAG = "connection";
   /** Use to mark a queue */
   public final static String QUEUE_MARKER_TAG = "queue";
   /** Use to mark a service */
   public final static String SERVICE_MARKER_TAG = "service";
   /** Use to mark a plugin inside the RunlevelManager (xmlBlasterPlugins.xml) */
   public final static String RUNLEVEL_PLUGIN_MARKER_TAG = "plugin";
   /** Use to mark a protocol plugin like XMLRPC or email */
   public final static String PROTOCOL_MARKER_TAG = "protocol";
   /** Use to mark a message store map */
   public final static String MAP_MARKER_TAG = "map";
   /** Use to mark a topic */
   public final static String TOPIC_MARKER_TAG = "topic";
   /** Use to mark a subscription */
   public final static String SUBSCRIPTION_MARKER_TAG = "subscription";
   /** Use to mark event methods */
   public final static String EVENT_MARKER_TAG = "event";
   /** Use to mark a system and configuration properties and command line arguments */
   public final static String SYSPROP_MARKER_TAG = "sysprop";
   /** Use to mark logging settings */
   public final static String LOGGING_MARKER_TAG = "logging";
   /** Use to mark a remote cluster node configuration */
   public final static String CLUSTERCONF_MARKER_TAG = "nodeconf";
   /** Use to mark a remote cluster node configuration */
   public final static String CLUSTERMASTER_MARKER_TAG = "master";

   /** For XPath conforming query */
   public final static String SCHEMA_XPATH = "xpath";
   /** For JMX conforming ObjectName string */
   public final static String SCHEMA_JMX = "jmx";
   /** For JMX conforming ObjectName string, "org.xmlBlaster:" is our JMX domain */
   public final static String SCHEMA_JMX_DOMAIN = "org.xmlBlaster";
   /** For URL conforming string */
   public final static String SCHEMA_URL = "url";

   private String className; // e.g. "node"
   private String instanceName; // e.g. "heron"
   private ContextNode parent;
   private Map childs; // key=absoluteName, value contains 'new WeakReference(ContextNode)'
  
   public static char QUOTE = '\"';

   //Placeholder for top level node
   public final static ContextNode ROOT_NODE = null; // new ContextNode(null, "/xmlBlaster", "", (ContextNode)null);

   /**
    * @deprecated Use constructor without global
    */
   public ContextNode(Global glob, String className, String instanceName, ContextNode parent) {
      this(className, instanceName, parent);
   }

   /**
    * @param className The tag name like 'node' (ContextNode.CLUSTER_MARKER_TAG) or 'client' (ContextNode.SUBJECT_MARKER_TAG)
    * @param instanceName The instance like 'heron' or 'joe', can be null
    * @param parent The parent node or null if root ContextNode ('node/heron' etc)
    */
   public ContextNode(String className, String instanceName, ContextNode parent) {
      if (className == null) {
         throw new IllegalArgumentException("ContextNode: Missing className argument");
      }
      this.className = className;
      setInstanceName(instanceName);
      this.parent = parent;
      if (this.parent != null) this.parent.addChild(this);
   }

   /*
   public Global getGlobal() {
      return this.glob;
   }
   */

   /**
    * @return The tag name like 'node' (ContextNode.CLUSTER_MARKER_TAG) or 'client' (ContextNode.SUBJECT_MARKER_TAG)
    */
   public String getClassName() {
      return this.className;
   }
  
   /**
    * @param className The tag name like 'node' (ContextNode.CLUSTER_MARKER_TAG) or 'client' (ContextNode.SUBJECT_MARKER_TAG)
    */
   public boolean isOfClass(String className) {
      if (this.className == null) return false;
      return this.className.equals(className);
   }

   public void setInstanceName(String instanceName) {
      /** TODO: Needs some testing
      //Escape offending '/' in the name with quotes "joe/the/great"
      if (instanceName != null
            && instanceName.indexOf("/") != -1
            && instanceName.charAt(0) != QUOTE) {
         instanceName = QUOTE + instanceName + QUOTE;
      }
     
      //For the time being we suppress '/' in JmxWrapper.validateJmxValue()
      */
      this.instanceName = instanceName;
   }

   /**
    * @return Can be null
    */
   public String getInstanceName() {
      return this.instanceName;
   }

   /**
    * @return Is never null
    */
   public String getInstanceNameNotNull() {
      return (this.instanceName==null) ? "" : this.instanceName;
   }

   /**
    * @return The parent node or null
    */
   public ContextNode getParent() {
      return this.parent;
   }

   /**
    * Walk up the hierarchy and return the matching ContextNode.
    * @param className The context node to retrieve
    * @return The parent node or null
    */
   public ContextNode getParent(String className) {
      if (className == null) {
         return null;
      }
      if (className.equals(this.getClassName())) {
         return this;
      }
      if (this.parent != null ) {
         return this.parent.getParent(className);
      }
      return null;
   }

   /**
    * Walk up the hierarchy until we find the given className and rename the instance name.
    *
    * For example rename
    *  "org.xmlBlaster:nodeClass=node,node=clientSUB1,clientClass=connection,connection=jack"
    * to
    *  "org.xmlBlaster:nodeClass=node,node=heron,clientClass=connection,connection=jack"
    *
    * Checks the current node as well.
    *
    * @param className The class to change, e.g. "node"
    * @param instanceName The new name to use, e.g. "heron"
    */
   public void changeParentName(String className, String instanceName) {
      if (className == null) {
         return;
      }
      ContextNode found = getParent(className);
      if (found != null) {
         found.setInstanceName(instanceName);
      }
   }

   /**
    * Walk up the hierarchy until we find the given className and rename the instance name.
    *
    * For example rename
    *  "org.xmlBlaster:nodeClass=node,node=clientSUB1,clientClass=connection,connection=jack"
    * to
    *  "org.xmlBlaster:nodeClass=node,node=heron,clientClass=connection,connection=jack"
    *
    * Checks the current node as well.
    *
    * @param newParentNode The new parent name to use, e.g. "heron"
    */
   public void changeParentName(final ContextNode newParentNode) {
      if (newParentNode == null) {
         return;
      }
      ContextNode found = getParent(newParentNode.getClassName());
      if (found != null) {
         found.setInstanceName(newParentNode.getInstanceName());
      }
   }

   /**
    * Add the given child, it exists already nothing happens.
    * The child is hold as a weak reference, so you don't need to cleanup.
    * @param child The child to add
    * @return true if the child was added, the parent of your child is modified!
    *          false if it existed already or if you given child is null
    */
   public boolean addChild(ContextNode child) {
      return addChild(child, false);
   }
  
   /**
    * Add the given child, it exists already nothing happens.
    * The child is hold as a weak reference, so you don't need to cleanup.
    * @param child The child to add
    * @param doClone If true the given child is not modified
    *                 if false the given child is changed to have us as a new parent
    * @return true if the child was added,
    *          false if it existed already or if you given child is null
    */
   public boolean addChild(ContextNode child, boolean doClone) {
      if (child == null) return false;
      if (this.childs != null && this.childs.get(child.getAbsoluteName()) != null) {
            return false; // Child is already here
      }
      synchronized (this) {
         if (this.childs == null) {
            this.childs = new HashMap();
         }
         if (doClone) {
            ContextNode clone = child.getClone();
            clone.parent = this;
            this.childs.put(clone.getAbsoluteName(), new WeakReference(clone));
         }
         else {
            if (child.parent != null && this != child.parent) {
               // If child had another parent already remove it
               child.parent.removeChild(child);
            }
            child.parent = this;
            this.childs.put(child.getAbsoluteName(), new WeakReference(child));
         }
      }
      return true;
   }
  
   public ContextNode getClone() {
      return ContextNode.valueOf(getAbsoluteName());
   }

   /**
    * Merges the given child, it exists already nothing happens.
    * <p />
    * <pre>
    * this = "/node/heron/client/joe"
    * child = "/node/xyz/client/joe/session/1"
    * results to "/node/heron/client/joe/session/1"
    * </pre>
    * <pre>
    * this = "/node/heron/client/joe/session/1"
    * child = "/node/xyz/service/Pop3Driver"
    * results to "/xmlBlaster/node/heron/client/joe/session/1/service/Pop3Driver"
    * </pre>
    * @param child The child to add, it is not touched as we take a clone
    * @return The new leave or null if failed
    */
   public ContextNode mergeChildTree(final ContextNode child) {
      if (child == null) return null;
      ContextNode childClone = child.getClone();
      ContextNode childParent = childClone;
      while (true) {
         ContextNode thisParent = this.getParent(childParent.getClassName());
         if (thisParent != null) {
            //System.out.println("thisParent=" + thisParent.getAbsoluteName() + " - childParent=" + childParent.getAbsoluteName());
            if (thisParent.getInstanceNameNotNull().equals(childParent.getInstanceNameNotNull())) {
               ContextNode childs[] = childParent.getChildren();
               for (int i=0; i<childs.length; i++) {
                  thisParent.addChild(childs[i]); // suppresses duplicates
               }
               return thisParent.getChild(child.getClassName(), child.getInstanceName());
            }
            ContextNode pp = thisParent.getParent();
            if (pp != null) {
               // Found a node to merge, attach it here
               pp.addChild(childParent);
               return thisParent.getChild(child.getClassName(), child.getInstanceName());
            }
            break; // nothing found to merge with
         }
         childParent = childParent.getParent();
         if (childParent==null) break;
      }
      // Append if not merged:
      this.addChild(childClone);
      return getChild(child.getClassName(), child.getInstanceName());
   }

   /**
    * @return All children, never null (but empty array)
    */
   public synchronized ContextNode[] getChildren() {
      if (this.childs == null || this.childs.size() == 0) {
         return new ContextNode[0];
      }
      WeakReference[] refs = (WeakReference[])this.childs.values().toArray(new WeakReference[this.childs.size()]);
      ArrayList list = new ArrayList(refs.length);
      for (int i=0; i<refs.length; i++) {
         Object referent = refs[i].get();
         if (referent != null) {
            list.add(referent);
         }
         else {
            this.childs.remove(refs[i]); // Cleanup the obsolete WeakReference
            // TODO: ReferenceQueue
         }
      }
      return (ContextNode[])list.toArray(new ContextNode[list.size()]);
   }
  
   /**
    * Remove a child.
    * @param child
    * @return true if the child was removed
    */
   public synchronized boolean removeChild(ContextNode child) {
      if (this.childs == null || this.childs.size() == 0 || child == null) {
         return false;
      }
      Object removed = this.childs.remove(child.getAbsoluteName());
      return (removed != null);
   }

   /**
    * Search down the children tree for the given className and instanceName.
    * Only the first match is returned
    * @param className If null only a given instanceName is searched
    * @param instanceName If null only the given className is searched
    * @return The child, is null if not found
    */
   public ContextNode getChild(String className, String instanceName) {
      return getChild(this, className, instanceName);
   }

   /**
    * Search down the children tree for the given className.
    * Only the first match is returned
    * @param className If null only a given instanceName is searched
    * @return The child, is null if not found
    */
   public ContextNode getChild(String className) {
      return getChild(this, className, null);
   }

   /**
    * Recursive search
    */
   protected ContextNode getChild(ContextNode node, String className, String instanceName) {
      if (className == null && instanceName == null) return null;
      if (className == null && node.getInstanceNameNotNull().equals(instanceName))
         return node;
      if (instanceName == null && node.getClassName().equals(className))
         return node;
      if (node.getClassName().equals(className) && node.getInstanceNameNotNull().equals(instanceName))
         return node;
      ContextNode[] childsArr = node.getChildren();
      for (int i=0; i<childsArr.length; i++) {
         return getChild(childsArr[i], className, instanceName);
      }
      return null;
   }

   /**
    * Access the absolute name in standard notation
    * @return e.g. "/xmlBlaster/node/heron/client/joe/session/2", never null
    */
   public String getAbsoluteName() {
      StringBuffer sb = new StringBuffer(256);
      if (this.parent == ROOT_NODE) {
         sb.append(ROOT_MARKER_TAG).append(SEP).append(this.className);
         if (this.instanceName != null) {
            sb.append(SEP).append(this.instanceName);
         }
         return sb.toString();
      }
      sb.append(this.parent.getAbsoluteName()).append(SEP).append(this.className);
      if (this.instanceName != null) {
         sb.append(SEP).append(this.instanceName);
      }
      return sb.toString();
   }

   /**
    * Access the absolute name but without root tag /xmlBlaster. <br>
    * Can be parsed by SessionName
    *
    * @return e.g. "/node/heron/client/joe/session/2", never null
    */
   public String getSessionNameCompatible() {
      String abs = getAbsoluteName();
      if (abs == null)
         return "";
      abs = ReplaceVariable.replaceFirst(abs, "/connection/", "/client/");
      int index = abs.indexOf("/xmlBlaster");
      if (index == 0)
         return abs.substring(11);
      return abs;
   }
  
   /**
    * Access the absolute name in standard notation
    * @param schema Currently only "xpath"
    * @return e.g. "xpath:/xmlBlaster/node[@id='heron']/client[@id='joe']/session[@id='2']", never null
    */
   public String getAbsoluteName(String schema) {
      StringBuffer sb = new StringBuffer(256);
      if (SCHEMA_JMX.equalsIgnoreCase(schema)) {
         // "org.xmlBlaster:nodeClass=node,node=heron,clientClass=client,client=joe,queueClass=queue,queue=subject665,entryClass=entry,entry=1002"
         // like this jconsole creates a nice tree (see JmxWrapper.java for a discussion)
         if (this.parent == ROOT_NODE) {
            sb.append(SCHEMA_JMX_DOMAIN).append(":").append("nodeClass=node,node=");
            sb.append((this.instanceName==null)?"null":ObjectName.quote(this.instanceName));
            return sb.toString();
         }
         sb.append(this.parent.getAbsoluteName(schema));
         sb.append(",").append(this.className).append("Class=").append(this.className);
         // JMX ',' make problems with or without quotes
         //     ':' is only OK if quoted
         if (this.instanceName != null) {
            sb.append(",").append(this.className).append("=").append(ObjectName.quote(this.instanceName));
         }
         return sb.toString();
      }
      else if (SCHEMA_XPATH.equalsIgnoreCase(schema)) {
         if (this.parent == ROOT_NODE) {
            sb.append(schema).append(":").append(ROOT_MARKER_TAG).append(SEP).append(this.className);
            if (this.instanceName != null) {
               sb.append("[@id='").append(this.instanceName).append("']");
            }
            return sb.toString();
         }
         sb.append(this.parent.getAbsoluteName(schema)).append(SEP).append(this.className);
         if (this.instanceName != null) {
            sb.append("[@id='").append(this.instanceName).append("']");
         }
         return sb.toString();
      }
      else /* if (SCHEMA_URL.equalsIgnoreCase(schema)) */ {
         return getAbsoluteName();
      }
   }

   /**
    * @return #getAbsoluteName()
    */
   public String toString() {
      return getAbsoluteName();
   }

   /**
    * @return e.g. "client/joe", never null
    */
   public String getRelativeName() {
      StringBuffer sb = new StringBuffer(256);
      sb.append(this.className);
      if (this.instanceName != null) {
         sb.append(SEP).append(this.instanceName);
      }
      return sb.toString();
   }

   /**
    * @param schema Currently only "xpath"
    * @return e.g. "xpath:client[@id='joe']", never null
    */
   public String getRelativeName(String schema) {
      StringBuffer sb = new StringBuffer(256);
      if (SCHEMA_JMX.equalsIgnoreCase(schema)) {
         // "org.xmlBlaster:clientClass=client,client=joe"
         sb.append(SCHEMA_JMX_DOMAIN).append(":");
         sb.append(this.className).append("Class=").append(this.className);
         if (this.instanceName != null) {
            sb.append(",").append(this.className).append("=").append(ObjectName.quote(this.instanceName));
         }
         return sb.toString();
      }
      else if (SCHEMA_XPATH.equalsIgnoreCase(schema)) {
         sb.append(schema).append(":").append(this.className);
         if (this.instanceName != null) {
            sb.append("[@id='").append(this.instanceName).append("']");
         }
         return sb.toString();
      }
      else /* if (SCHEMA_URL.equalsIgnoreCase(schema)) */ {
         return getRelativeName();
      }
   }

   /**
    * @return true if relative name equals
    */
   public boolean equalsRelative(ContextNode contextNode) {
      return getRelativeName().equals(contextNode.getRelativeName());
   }

   /**
    * Compare the absolute name.
    * @param contextNode Returns false if null
    * @return
    */
   public boolean equalsAbsolute(ContextNode contextNode) {
      if (contextNode == null) return false;
      return getAbsoluteName().equals(contextNode.getAbsoluteName());
   }

   /**
    * Parse the given string.
    * NOTE: The returned ContextNode is a new instance and NOT the instance from inside a given Global
    * @param url For example
    *             "/xmlBlaster/node/heron/client/joe/session/2"
    * @return The lowest ContextNode instance, you can navigate upwards with getParent()
    *         or ContextNode.ROOT_NODE==null.
    */
   public static ContextNode valueOf(String url) {
      if (url == null || url.length() == 0)
         return ROOT_NODE;
      String lower = url.toLowerCase();
      if (lower.startsWith("xpath")) {
         throw new IllegalArgumentException("ContextNode.valueOf(): Unkown schema in '" + url + "'");
      }
      if (url.startsWith(SCHEMA_JMX_DOMAIN+":")) { // SCHEMA_JMX
         // org.xmlBlaster:nodeClass=node,node="heron",clientClass=connection,connection="jack",queueClass=queue,queue="connection-99"
         int index = url.indexOf(":");
         String tmp = url.substring(index+1);
         String[] toks = StringPairTokenizer.parseLine(tmp, ',', QUOTE, true);
         ContextNode node = ROOT_NODE;
         for (int i=0; i<toks.length; i++) {
            index = toks[i].indexOf("=");
            String className = (index > 0) ? toks[i].substring(index+1) : null;
            if (className.startsWith("\""))
                className = className.substring(1,className.length()-1);
            String instanceName = null;
                if (i < toks.length-1) {
               index = toks[i+1].indexOf("=");
               instanceName = (index > 0) ? toks[i+1].substring(index+1) : null;
               if (instanceName.startsWith("\""))
                instanceName = instanceName.substring(1,instanceName.length()-1);
               i++;
                }
            node = new ContextNode(className, instanceName, node);
         }
         return node;
      }
      else if (url.startsWith("/xmlBlaster/node/") || url.startsWith("/node/") || !url.startsWith("/")/*relative name*/) {
         String[] toks = StringPairTokenizer.parseLine(url, '/', QUOTE, true);
         ContextNode node = ROOT_NODE;
         for (int i=0; i<toks.length; i++) {
            String className = toks[i];
            String instanceValue = null;
            if (i == 0 && "xmlBlaster".equals(className)) {
               node = ROOT_NODE;
               continue;
            }
            if (i == toks.length-1) {
               if (node != null && ContextNode.SUBJECT_MARKER_TAG.equals(node.getClassName())) {
                   className = ContextNode.SESSION_MARKER_TAG;
                   i--; // Hack: We add "session" for "client/joe/1" -> "client/joe/session/1" for backward compatibility
                   instanceValue = toks[i+1];
               }
               else {
                  // For example "/xmlBlaster/node/heron/logging"
                  instanceValue = null;
                  log.fine("Unexpected syntax in '" + url + "', missing value for class, we assume a 'null' value.");
               }
            }
            else {
               instanceValue = toks[i+1];
            }
            node = new ContextNode(className, instanceValue, node);
            i++;
         }
         return node;
      }
     
      throw new IllegalArgumentException("ContextNode.valueOf(): unknown formatting schema is not implemented: '" + url + "'");
   }

   /**
    * Dump state of this object into XML.
    * <br>
    * @return XML dump of ContextNode
    */
   public final String toXml() {
      return toXml((String)null);
   }

   /**
    * Dump state of this object into XML.
    * <br>
    * @param extraOffset indenting of tags
    * @return XML dump of ContextNode
    */
   public final String toXml(String extraOffset) {
      StringBuffer sb = new StringBuffer(256);
      if (extraOffset == null) extraOffset = "";
      String offset = Constants.OFFSET + extraOffset;

      sb.append(offset).append("<ContextNode class='").append(this.className).append("' instance='").append(this.instanceName).append("'/>");
      return sb.toString();
   }

   /**
    * Method for testing only.<p />
    *
    * Invoke: java -Djava.compiler= org.xmlBlaster.util.context.ContextNode
    */
   public static void main(String args[]) {
      try {
         ContextNode heron = new ContextNode(ContextNode.CLUSTER_MARKER_TAG, "heron", null);
         System.out.println("AbsoluteName=" + heron.getAbsoluteName() + " RelativeName=" + heron.getRelativeName());
         ContextNode jack = new ContextNode(ContextNode.SUBJECT_MARKER_TAG, "jack", heron);
         System.out.println("AbsoluteName=" + jack.getAbsoluteName() + " RelativeName=" + jack.getRelativeName());
        
         ContextNode ses2 = new ContextNode(ContextNode.SESSION_MARKER_TAG, "2", jack);
         System.out.println("AbsoluteName=" + ses2.getAbsoluteName() + " RelativeName=" + ses2.getRelativeName());
         System.out.println("AbsoluteName=" + ses2.getAbsoluteName("xpath") + " RelativeName=" + ses2.getRelativeName("xpath"));
         System.out.println("AbsoluteName=" + ses2.getAbsoluteName("jmx") + " RelativeName=" + ses2.getRelativeName("jmx"));

         {
            System.out.println("\nTopic:");
            ContextNode hello = new ContextNode(ContextNode.TOPIC_MARKER_TAG, "hello", heron);
            System.out.println("AbsoluteName=" + hello.getAbsoluteName() + " RelativeName=" + hello.getRelativeName());
            System.out.println("AbsoluteName=" + hello.getAbsoluteName("xpath") + " RelativeName=" + hello.getRelativeName("xpath"));
            System.out.println("AbsoluteName=" + hello.getAbsoluteName("jmx") + " RelativeName=" + hello.getRelativeName("jmx"));
         }
         {
            System.out.println("\nWith NULL:");
            ContextNode hello = new ContextNode(ContextNode.TOPIC_MARKER_TAG, null, heron);
            System.out.println("AbsoluteName=" + hello.getAbsoluteName() + " RelativeName=" + hello.getRelativeName());
            System.out.println("AbsoluteName=" + hello.getAbsoluteName("xpath") + " RelativeName=" + hello.getRelativeName("xpath"));
            System.out.println("AbsoluteName=" + hello.getAbsoluteName("jmx") + " RelativeName=" + hello.getRelativeName("jmx"));
         }
         {
            System.out.println("\nMERGE:");
            ContextNode root = ContextNode.valueOf("/node/heron/client/joe");
            ContextNode other = ContextNode.valueOf("/node/xyz/client/joe/session/1");
            ContextNode leaf = root.mergeChildTree(other);
            // -> /xmlBlaster/node/heron/client/joe/session/1
            System.out.println("Orig=" + root.getAbsoluteName() + " merge=" + other.getAbsoluteName() + " result=" + leaf.getAbsoluteName());
         }
         {
            System.out.println("\nMERGE:");
            ContextNode root = ContextNode.valueOf("/node/heron/client/joe/session/1");
            ContextNode other = ContextNode.valueOf("/node/xyz/service/Pop3Driver");
            ContextNode leaf = root.mergeChildTree(other);
            // -> /xmlBlaster/node/heron/client/joe/session/1/service/Pop3Driver
            System.out.println("Orig=" + root.getAbsoluteName() + " merge=" + other.getAbsoluteName() + " result=" + ((leaf==null)?"null":leaf.getAbsoluteName()) );
         }
         {
            System.out.println("\nMERGE:");
            ContextNode root = ContextNode.valueOf("/node/heron/client/joe/session/1");
            ContextNode other = ContextNode.valueOf("/node/clientjoe1/\"connection:client/joe/1\"");
            ContextNode leaf = root.mergeChildTree(other);
            // -> /xmlBlaster/node/heron/client/joe/session/1/service/Pop3Driver
            System.out.println("Orig=" + root.getAbsoluteName() + " merge=" + other.getAbsoluteName() + " result=" + ((leaf==null)?"null":leaf.getAbsoluteName()) );
         }
      }
      catch (IllegalArgumentException e) {
         System.out.println("ERROR: " + e.toString());
      }
   }
}
TOP

Related Classes of org.xmlBlaster.util.context.ContextNode

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.