Java tutorial
/* Xholon Runtime Framework - executes event-driven & dynamic applications * Copyright (C) 2005, 2006, 2007, 2008 Ken Webb * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 * of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.primordion.xholon.base; import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.core.client.JsArray; import com.google.gwt.core.client.JsArrayMixed; import com.google.gwt.json.client.JSONObject; //import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.TextAreaElement; //import java.io.IOException; //import java.io.PrintWriter; import java.io.Serializable; //import java.io.Writer; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.Vector; import org.client.HtmlElementCache; import org.primordion.xholon.app.AbstractApplication; import org.primordion.xholon.app.IApplication; import org.primordion.xholon.common.mechanism.CeAction; import org.primordion.xholon.common.mechanism.CeAnnotation; import org.primordion.xholon.common.mechanism.CeControl; import org.primordion.xholon.common.mechanism.CeRole; import org.primordion.xholon.exception.XholonConfigurationException; import org.primordion.xholon.io.xml.IXholon2Xml; import org.primordion.xholon.io.xml.IXml2Xholon; import org.primordion.xholon.io.xml.IXmlWriter; import org.primordion.xholon.service.AbstractXholonService; import org.primordion.xholon.service.IXholonService; import org.primordion.xholon.service.XholonDirectoryService; import org.primordion.xholon.service.creation.ITreeNodeFactory; import org.primordion.xholon.util.ClassHelper; import org.primordion.xholon.util.IJavaTypes; import org.primordion.xholon.util.Misc; // only imports java standard classes, and Xholon // logging //import org.slf4j.Logger; // use either slf4j or apache.commons.logging //import org.slf4j.LoggerFactory; //import org.apache.commons.logging.Log; // Xholon default; use either slf4j or apache.commons.logging //import org.apache.commons.logging.LogFactory; // Xholon default //import org.primordion.xholon.gwt.Log; // old GWT // null logging import org.primordion.xholon.logging.Log; // for use with GWT 2.5.1 import org.primordion.xholon.logging.LogFactory; // for use with GWT 2.5.1 // GWT 2.5.1 logging //import java.util.logging.Level; //import java.util.logging.Logger; /** * Xholon is an abstract class that implements a lot of the functionality defined in the IXholon interface. * @see IXholon * @author <a href="mailto:ken@primordion.com">Ken Webb</a> * @see <a href="http://www.primordion.com/Xholon">Xholon Project website</a> * @since 0.1 (Created on Jun 8, 2005) */ public abstract class Xholon implements IXholon, IDecoration, Comparable, Serializable { private static final long serialVersionUID = 1271821389789389499L; /** Parent node, or null if root. */ protected transient IXholon parentNode = null; /** First (leftmost) child, or null. */ protected IXholon firstChild = null; /** Next (right) sibling, or null. */ protected IXholon nextSibling = null; /** Unique ID of this Xholon instance. */ protected transient int id = XHOLON_ID_DEFAULT; /** Xholon Class associated with this Xholon. */ protected IXholonClass xhc = null; /** IXholon logger. */ //protected static final Logger logger = LoggerFactory.getLogger("Xholon"); // slf4j protected static final Log logger = LogFactory.getLog("Xholon"); // apache.commons.logging, Xholon null log //protected static final Log logger = new Log(); // gwt //protected static final Logger logger = Logger.getLogger("Xholon"); // GWT 2.5.1 /** * print2Console() will ignore any string that starts with this character. * ASCII \cQ or \cq U+0011 DEVICE CONTROL ONE */ protected static final String PRINT2CONSOLE_IGNORE_ME = "\u0011"; /** Constructor. */ public Xholon() { } // ******************************************************************************************* // TreeNode - the following are methods that were implemented in the now deprecated TreeNode interface /* * @see org.primordion.xholon.base.IXholon#remove() */ public void remove() { if (hasChildNodes()) { firstChild.remove(); } if (hasNextSibling()) { nextSibling.remove(); } getFactory().returnTreeNode(this); } /** * Get the factory that creates IXholon instances. * @return The factory. */ public ITreeNodeFactory getFactory() { IApplication app = getApp(); return (app == null) ? null : app.getFactory(); } /** * Get the name of the Java class that implements the IQueue interface. * @return The class name. */ public String getIQueueImplName() { IApplication app = getApp(); return (app == null) ? null : app.getIQueueImplName(); } /** * Get the message Q. * @return An instance of IQueue. */ public IQueue getMsgQ() { IApplication app = getApp(); return (app == null) ? null : app.getMsgQ(); } /** * Get the system message Q. * @return An instance of IQueue. */ public IQueue getSystemMsgQ() { IApplication app = getApp(); return (app == null) ? null : app.getSystemMsgQ(); } /** * Get whether or not capture of interactions is enabled. * @return true or false */ public boolean getInteractionsEnabled() { if (getApp() == null) { return false; } else { return getApp().getUseInteractions(); } } /** * Get the object that handles the capture and subsequent display of interactions. * @return An instance of IInteraction. */ public IInteraction getInteraction() { IApplication app = getApp(); return (app == null) ? null : app.getInteraction(); } /* * @see org.primordion.xholon.base.IXholon#getApp() */ public IApplication getApp() { if (xhc != null) { // this is a shortcut to the Application return xhc.getApp(); } else if (getParentNode() != null) { return getParentNode().getApp(); } return null; } /* * @see org.primordion.xholon.base.IXholon#setApp(org.primordion.xholon.app.IApplication) */ public void setApp(IApplication app) { logger.warn("To implement Xholon setApp(), override it in a subclass."); } /** * Get the singleton instance of XPath. * @return The singleton instance of XPath. */ public final IXPath getXPath() { IXPath xp = (IXPath) getService(AbstractXholonService.XHSRV_XPATH); if (xp == null) { // use the static factory if the XPathService is not yet available String unavailStr = "XPathService is unavailable. Will try to use XPathFactory: "; xp = XPathFactory.getInstance(); if (xp == null) { logger.debug(unavailStr + "failed"); } else { logger.debug(unavailStr + "succeeded"); } } return xp; } /** * Get the singleton instance of org.slf4j.Logger. * Note: the two versions of getLogger() cannot both be active at the same time. * @return An instance of org.slf4j.Logger */ //public static final Logger getLogger() {return logger;} /** * Get the singleton instance of org.apache.commons.logging.Log. * Note: the two versions of getLogger() cannot both be active at the same time. * @return An instance of org.apache.commons.logging.Log */ public static final Log getLogger() { return logger; } /* * @see org.primordion.xholon.base.IXholon#getParentNode() */ public IXholon getParentNode() { return parentNode; } /* * @see org.primordion.xholon.base.IXholon#getFirstChild() */ public IXholon getFirstChild() { return firstChild; } /* * @see org.primordion.xholon.base.IXholon#getNextSibling() */ public IXholon getNextSibling() { return nextSibling; } /* * @see org.primordion.xholon.base.IXholon#getPreviousSibling() */ public IXholon getPreviousSibling() { if (isRootNode()) { return null; // this is the root node } IXholon node = getParentNode().getFirstChild(); if (node == this) { return null; // this node is already the first sibling } IXholon leftNode = node; while (leftNode.getNextSibling() != null) { node = leftNode.getNextSibling(); if (node == this) { return leftNode; } leftNode = node; // should never get here } return null; } /* * @see org.primordion.xholon.base.IXholon#setParentNode(org.primordion.xholon.base.TreeNode) */ public void setParentNode(IXholon treeNode) { parentNode = treeNode; } /* * @see org.primordion.xholon.base.IXholon#setFirstChild(org.primordion.xholon.base.TreeNode) */ public void setFirstChild(IXholon treeNode) { firstChild = treeNode; } /* * @see org.primordion.xholon.base.IXholon#setNextSibling(org.primordion.xholon.base.TreeNode) */ public void setNextSibling(IXholon treeNode) { nextSibling = treeNode; } /* * @see org.primordion.xholon.base.IXholon#getRootNode() */ public IXholon getRootNode() { IXholon node = this; while (!node.isRootNode()) { node = node.getParentNode(); } return node; } /* * @see org.primordion.xholon.base.IXholon#findFirstChildWithXhClass(int) * This method has been duplicated in IFindChildSibWith. */ public IXholon findFirstChildWithXhClass(int childXhClassId) { IXholon node = getFirstChild(); while (node != null) { int foundXhcId = node.getXhcId(); if (foundXhcId == childXhClassId) { return node; } node = node.getNextSibling(); } return null; } /* * @see org.primordion.xholon.base.IXholon#findFirstChildWithXhClass(java.lang.String) */ public IXholon findFirstChildWithXhClass(String childXhClassName) { if (childXhClassName == null) { return null; } IXholon node = getFirstChild(); while (node != null) { String foundXhcName = node.getXhcName(); if (childXhClassName.equals(foundXhcName)) { return node; } node = node.getNextSibling(); } return null; } /* * @see org.primordion.xholon.base.IXholon#setParentChildLinks() */ public void setParentChildLinks(IXholon parent) { setParentNode(parent); parent.setFirstChild(this); } /* * @see org.primordion.xholon.base.IXholon#setParentSiblingLinks(org.primordion.xholon.base.TreeNode) */ public void setParentSiblingLinks(IXholon previousSibling) { setParentNode(previousSibling.getParentNode()); // previousSibling already has parent previousSibling.setNextSibling(this); } /* * @see org.primordion.xholon.base.IXholon#removeChild() */ public void removeChild() { if (!isRootNode()) { IXholon lNode = getPreviousSibling(); IXholon rNode = getNextSibling(); if (lNode == null) { // this is the first (leftmost) sibling if (rNode == null) { getParentNode().setFirstChild(null); } else { getParentNode().setFirstChild(rNode); // nextSibling is new firstChild of parent } } else { if (rNode == null) { lNode.setNextSibling(null); } else { lNode.setNextSibling(rNode); } } setParentNode(null); setNextSibling(null); } } /* * @see org.primordion.xholon.base.IXholon#insertAfter(org.primordion.xholon.base.IXholon) */ public void insertAfter(IXholon newLeftSibling) { if (newLeftSibling.hasNextSibling()) { parentNode = newLeftSibling.getParentNode(); nextSibling = newLeftSibling.getNextSibling(); newLeftSibling.setNextSibling(this); } else { // last sibling setParentSiblingLinks(newLeftSibling); } } /* * @see org.primordion.xholon.base.IXholon#insertAfter(java.lang.String, java.lang.String) */ public IXholon insertAfter(String xhClassName, String roleName) { IXholon newNode = null; try { newNode = getFactory().getXholonNode(); } catch (XholonConfigurationException e) { logger.error(e.getMessage(), e.getCause()); return newNode; // TODO not sure what should be returned in this case } newNode.setId(getNextId()); newNode.setXhc(getClassNode(xhClassName)); newNode.setRoleName(roleName); newNode.insertAfter(this); return newNode; } /* * @see org.primordion.xholon.base.IXholon#insertAfter(java.lang.String, java.lang.String, java.lang.String) */ public IXholon insertAfter(String xhClassName, String roleName, String implName) { IXholon newNode = null; try { newNode = getFactory().getXholonNode(implName); } catch (XholonConfigurationException e) { logger.error(e.getMessage(), e.getCause()); return newNode; // TODO not sure what should be returned in this case } newNode.setId(getNextId()); newNode.setXhc(getClassNode(xhClassName)); newNode.setRoleName(roleName); newNode.insertAfter(this); return newNode; } /* * @see org.primordion.xholon.base.IXholon#insertBefore(org.primordion.xholon.base.IXholon) */ public void insertBefore(IXholon newNextSibling) { parentNode = newNextSibling.getParentNode(); if (parentNode.getFirstChild() == newNextSibling) { parentNode.setFirstChild(this); } else { IXholon lSibling = newNextSibling.getPreviousSibling(); lSibling.setNextSibling(this); } setNextSibling(newNextSibling); } /* * @see org.primordion.xholon.base.IXholon#insertBefore(java.lang.String, java.lang.String) */ public IXholon insertBefore(String xhClassName, String roleName) { IXholon newNode = null; try { newNode = getFactory().getXholonNode(); } catch (XholonConfigurationException e) { logger.error(e.getMessage(), e.getCause()); return newNode; // TODO not sure what should be returned in this case } newNode.setId(getNextId()); newNode.setXhc(getClassNode(xhClassName)); newNode.setRoleName(roleName); newNode.insertBefore(this); return newNode; } /* * @see org.primordion.xholon.base.IXholon#insertBefore(java.lang.String, java.lang.String, java.lang.String) */ public IXholon insertBefore(String xhClassName, String roleName, String implName) { IXholon newNode = null; try { newNode = getFactory().getXholonNode(implName); } catch (XholonConfigurationException e) { logger.error(e.getMessage(), e.getCause()); return newNode; // TODO not sure what should be returned in this case } newNode.setId(getNextId()); newNode.setXhc(getClassNode(xhClassName)); newNode.setRoleName(roleName); newNode.insertBefore(this); return newNode; } /* * @see org.primordion.xholon.base.IXholon#insertFirstChild(org.primordion.xholon.base.IXholon) */ public void insertFirstChild(IXholon newParentNode) { if (newParentNode.getFirstChild() == null) { setParentChildLinks(newParentNode); } else { IXholon newSibling = newParentNode.getFirstChild(); insertBefore(newSibling); } } /* * @see org.primordion.xholon.base.IXholon#appendChild(org.primordion.xholon.base.IXholon) */ public void appendChild(IXholon newParentNode) { if (newParentNode.getFirstChild() == null) { setParentChildLinks(newParentNode); } else { setParentSiblingLinks(newParentNode.getLastChild()); } } /* * @see org.primordion.xholon.base.IXholon#appendChild(org.primordion.xholon.base.IXholon, java.lang.String, java.lang.String) */ public IXholon appendChild(String xhClassName, String roleName) { IXholon newNode = null; IXholonClass xhcNode = getClassNode(xhClassName); // get the name of the Java implementation class, if known String implName = null; if (xhcNode != null) { implName = xhcNode.getImplName(); } try { if (implName != null) { newNode = getFactory().getXholonNode(implName); } else { newNode = getFactory().getXholonNode(); } } catch (XholonConfigurationException e) { logger.error(e.getMessage(), e.getCause()); return newNode; // TODO not sure what should be returned in this case } newNode.setId(getNextId()); newNode.setXhc(xhcNode); if (roleName != null) { newNode.setRoleName(roleName); } newNode.appendChild(this); return newNode; } /* * @see org.primordion.xholon.base.IXholon#appendChild(java.lang.String, java.lang.String, java.lang.String) */ public IXholon appendChild(String xhClassName, String roleName, String implName) { IXholon newNode = null; try { newNode = getFactory().getXholonNode(implName); } catch (XholonConfigurationException e) { logger.error(e.getMessage(), e.getCause()); return newNode; // TODO not sure what should be returned in this case } newNode.setId(getNextId()); newNode.setXhc(getClassNode(xhClassName)); if (roleName != null) { newNode.setRoleName(roleName); } newNode.appendChild(this); return newNode; } /* * @see org.primordion.xholon.base.IXholon#appendsOwnChildren() */ public boolean appendsOwnChildren() { return false; } /* * @see org.primordion.xholon.base.IXholon#replaceNode(org.primordion.xholon.base.IXholon) */ public void replaceNode(IXholon replacementNode) { if (!isRootNode()) { // insert the replacement node into the tree as a sibling of the current tree replacementNode.insertAfter(this); } // move first child of the current node, to become child of the replacement node // it will automatically bring any of its siblings along with it IXholon aChild = getFirstChild(); if (aChild != null) { aChild.appendChild(replacementNode); aChild = aChild.getNextSibling(); } // correct the parent node of each child while (aChild != null) { aChild.setParentNode(replacementNode); aChild = aChild.getNextSibling(); } // remove the current node from the tree and from the model removeChild(); remove(); } /* * @see org.primordion.xholon.base.IXholon#swapNode(org.primordion.xholon.base.IXholon) */ public void swapNode(IXholon otherNode) { IXholon thisParent = parentNode; IXholon otherParent = otherNode.getParentNode(); IXholon thisNextSibling = nextSibling; IXholon otherNextSibling = otherNode.getNextSibling(); if (thisParent != otherParent) { // no change if both have same parent removeChild(); otherNode.removeChild(); // insert this node if (otherNextSibling == null) { appendChild(otherParent); } else { insertBefore(otherNextSibling); } // insert other node if (thisNextSibling == null) { otherNode.appendChild(thisParent); } else { otherNode.insertBefore(thisNextSibling); } } } // standard tree utility functions /* * @see org.primordion.xholon.base.IXholon#depth() */ public int depth() { if (isRootNode()) { return 0; } else { return 1 + getParentNode().depth(); } } /* * @see org.primordion.xholon.base.IXholon#height() */ public int height() { int hL = 0; int hR = 0; if (isExternal()) { return 0; } else { if (hasChildNodes()) { hL = firstChild.height(); } if (hasNextSibling()) { hR = nextSibling.height(); } return hL > hR ? hL + 1 : hR + 1; } } /* * @see org.primordion.xholon.base.IXholon#getNumLevels() */ public int getNumLevels() { if (hasChildNodes()) { return ((Xholon) firstChild).getNumLevelsR() + 1; } else { return 0; } } /** * Recursively search all subtrees for the maximum number of levels. * @return The maximum number of levels. */ protected int getNumLevelsR() { int hL = 0; int hR = 0; if (isExternal()) { return 0; } else { if (hasChildNodes()) { hL = ((Xholon) firstChild).getNumLevelsR() + 1; } if (hasNextSibling()) { hR = ((Xholon) nextSibling).getNumLevelsR(); } return hL > hR ? hL : hR; } } /* * @see org.primordion.xholon.base.IXholon#treeSize() */ public int treeSize() { int lSize = 0; int rSize = 0; IXholon node = getFirstChild(); if (node != null) { lSize = node.treeSize(); } node = getNextSibling(); if (node != null) { rSize = node.treeSize(); } return (1 + lSize + rSize); } /** * This node is the root node of the tree or subtree, if either: * <p>(1) its parent is null, or</p> * <p>(2) its parent's XhcId == CeControl.ControlCE .</p> * TODO but children of View node should not be root nodes * @see org.primordion.xholon.base.IXholon#isRootNode() */ public boolean isRootNode() { if (parentNode == null) { return true; } else { return parentNode.getXhcId() == CeControl.ControlCE; } } /* * @see org.primordion.xholon.base.IXholon#isExternal() */ public boolean isExternal() { return ((firstChild == null) && (nextSibling == null)); } /* * @see org.primordion.xholon.base.IXholon#isInternal() */ public boolean isInternal() { return ((firstChild != null) || (nextSibling != null)); } /* * @see org.primordion.xholon.base.IXholon#isLeaf() */ public boolean isLeaf() { return (firstChild == null); } /* * @see org.primordion.xholon.base.IXholon#isAttributeHandler() */ public boolean isAttributeHandler() { return false; } /* * @see org.primordion.xholon.base.IXholon#getChildNodes(boolean) */ public Vector getChildNodes(boolean deep) { Vector v = new Vector(); return getChildNodes(v, deep); } /** * Helper function to recursively get all children. * @param v Vector that gets filled with children. * @param deep If true then return entire nested subtree, if false return only immediate children. * @return Vector containing children. */ protected Vector getChildNodes(Vector v, boolean deep) { IXholon nextChild = getFirstChild(); while (nextChild != null) { v.addElement(nextChild); if (deep) { ((Xholon) nextChild).getChildNodes(v, deep); } nextChild = nextChild.getNextSibling(); } return v; } @Override public String getChildrenAsCsv(String nameTemplate, String separator) { if (nameTemplate == null) { nameTemplate = GETNAME_DEFAULT; } if (separator == null) { separator = ","; } StringBuilder sb = new StringBuilder(); IXholon nextChild = getFirstChild(); while (nextChild != null) { sb.append(nextChild.getName(nameTemplate)); nextChild = nextChild.getNextSibling(); if (nextChild != null) { sb.append(separator); } } return sb.toString(); } /* * @see org.primordion.xholon.base.IXholon#getNthChild(int, boolean) */ public IXholon getNthChild(int n, boolean deep) { Vector v = getChildNodes(deep); if (v.size() > n) { return (IXholon) v.elementAt(n); } else { return null; } } /* * @see org.primordion.xholon.base.IXholon#hasParentNode() */ public boolean hasParentNode() { if (parentNode == null) { return false; } else { return true; } } /* * @see org.primordion.xholon.base.IXholon#hasChildNodes() */ public boolean hasChildNodes() { return (firstChild != null); } /* * @see org.primordion.xholon.base.IXholon#hasNextSibling() */ public boolean hasNextSibling() { return (nextSibling != null); } /* * @see org.primordion.xholon.base.IXholon#hasChildOrSiblingNodes() */ public boolean hasChildOrSiblingNodes() { if (hasChildNodes()) { return true; } else { return hasNextSibling(); } } /* * @see org.primordion.xholon.base.IXholon#hasSiblingNodes() */ public boolean hasSiblingNodes() { if (hasNextSibling()) { return true; } if (getFirstSibling() != null) { return true; } return false; } /* * @see org.primordion.xholon.base.IXholon#getNumChildren(boolean) */ public int getNumChildren(boolean doFullSubtree) { // not very efficient return getChildNodes(doFullSubtree).size(); } /* * @see org.primordion.xholon.base.IXholon#getLastChild() */ public IXholon getLastChild() { if (hasChildNodes()) { if (firstChild.hasNextSibling()) { return firstChild.getLastSibling(); } else { return firstChild; } } return null; } /* * @see org.primordion.xholon.base.IXholon#getLastSibling() */ public IXholon getLastSibling() { IXholon node = this; while (node.hasNextSibling()) { node = node.getNextSibling(); } if (node == this) { return null; } else { return node; } } /* * @see org.primordion.xholon.base.IXholon#getFirstSibling() */ public IXholon getFirstSibling() { IXholon node = null; if (!isRootNode()) { node = parentNode.getFirstChild(); if (node == this) { return null; } else { return node; } } else { return null; } } /* * @see org.primordion.xholon.base.IXholon#getSelfAndSiblings(boolean) */ public Vector getSelfAndSiblings(boolean includeSameClassOnly) { if (!isRootNode()) { Vector v = parentNode.getChildNodes(false); if (includeSameClassOnly) { Vector scV = new Vector(); for (int i = 0; i < v.size(); i++) { IXholon node = (IXholon) v.get(i); if (node.getXhcId() == this.getXhcId()) { scV.add(node); } } return scV; } else { return v; } } else { return new Vector(); } } /* * @see org.primordion.xholon.base.IXholon#getSiblings() */ public Vector getSiblings() { if (!isRootNode()) { Vector v = parentNode.getChildNodes(false); v.removeElement(this); return v; } else { return new Vector(); } } @Override public String getSiblingsAsCsv(String nameTemplate, String separator) { StringBuilder sb = new StringBuilder(); if (!isRootNode()) { if (nameTemplate == null) { nameTemplate = GETNAME_DEFAULT; } if (separator == null) { separator = ","; } IXholon nextSibling = getParentNode().getFirstChild(); //getFirstSibling(); while (nextSibling != null) { if (this == nextSibling) { // do not include this node nextSibling = nextSibling.getNextSibling(); } else { sb.append(nextSibling.getName(nameTemplate)); nextSibling = nextSibling.getNextSibling(); if (nextSibling != null) { sb.append(separator); } } } } return sb.toString(); } /* * @see org.primordion.xholon.base.IXholon#getNthSibling(int) */ public IXholon getNthSibling(int n) { Vector v = getSiblings(); if (v.size() > n) { return (IXholon) v.elementAt(n); } else { return null; } } /* * @see org.primordion.xholon.base.IXholon#getNumSiblings() */ public int getNumSiblings() { // not very efficient return getSiblings().size(); } /* * @see org.primordion.xholon.base.IXholon#getSelfAndSiblingsIndex(boolean) */ public int getSelfAndSiblingsIndex(boolean includeSameClassOnly) { return getSelfAndSiblings(includeSameClassOnly).indexOf(this); } /* * @see org.primordion.xholon.base.IXholon#isUniqueSibling() */ public boolean isUniqueSibling() { if (!hasSiblingNodes()) { return true; } List siblings = getSiblings(); for (int i = 0; i < siblings.size(); i++) { if (this.getXhcId() == ((IXholon) siblings.get(i)).getXhcId()) { return false; } } return true; } /* * @see org.primordion.xholon.base.IXholon#isUniqueSiblingRoleName() */ public boolean isUniqueSiblingRoleName() { String roleName = this.getRoleName(); if (roleName == null) { roleName = ""; } if (!hasSiblingNodes()) { return true; } List siblings = getSiblings(); for (int i = 0; i < siblings.size(); i++) { IXholon sibling = (IXholon) siblings.get(i); if (this.getXhcId() == sibling.getXhcId()) { String siblingRoleName = sibling.getRoleName(); if (siblingRoleName == null) { siblingRoleName = ""; } if (roleName.equals(siblingRoleName)) { return false; } } } return true; } @Override public native Object getNeighbors() /*-{ var links = this.links(false, true); var neighbors = []; links.forEach(function(link) { neighbors.push(link.reffedNode); }); return neighbors; }-*/; @Override public native Object getNeighbors(boolean placeGraph, boolean linkGraph) /*-{ var links = this.links(placeGraph, linkGraph); var neighbors = []; links.forEach(function(link) { neighbors.push(link.reffedNode); }); return neighbors; }-*/; /* * @see org.primordion.xholon.base.IXholon#getNeighbors(int, int, java.lang.String) */ public Vector getNeighbors(int distance, int include, String excludeBecName) { Vector v = new Vector(); return getNeighbors(v, distance, include, excludeBecName); } /** * Get neighbor nodes. These include optionally parent, siblings and children. * @param v Vector containing the returned nodes * @param distance How far within the tree to search for neighbors. * @param include whether to include (P)arent and/or (S)iblings and/or (C)hildren * @param excludeBecName name of a XholonClass, used to limit the scope of the returned Vector. * TODO this uses an IXholon method * @return Vector containing all neighbors (instances of TreeNode). */ protected Vector getNeighbors(Vector v, int distance, int include, String excludeBecName) { int i; IXholon node; // PSC Parent Sibling Children if ((include & NINCLUDE_Pxx) == NINCLUDE_Pxx) { // parent IXholon myParent = getParentNode(); if (myParent != null) { if ((excludeBecName == null) || !(myParent.getXhcName().equals(excludeBecName))) { v.addElement(myParent); if (distance > 1) { // recurse ((Xholon) myParent).getNeighbors(v, distance - 1, NINCLUDE_PSx, excludeBecName); } } } } if ((include & NINCLUDE_xSx) == NINCLUDE_xSx) { // siblings Vector mySibV = getSiblings(); for (i = 0; i < mySibV.size(); i++) { node = (Xholon) mySibV.elementAt(i); v.addElement(node); if (distance > 1) { // recurse ((Xholon) node).getNeighbors(v, distance - 1, NINCLUDE_xxC, excludeBecName); } } } if ((include & NINCLUDE_xxC) == NINCLUDE_xxC) { // children Vector myChildV = getChildNodes(false); for (i = 0; i < myChildV.size(); i++) { node = (Xholon) myChildV.elementAt(i); v.addElement(node); if (distance > 1) { // recurse ((Xholon) node).getNeighbors(v, distance - 1, NINCLUDE_xxC, excludeBecName); } } } return v; } /* * @see org.primordion.xholon.base.IXholon#initStatics() */ public void initStatics() { } /* * @see org.primordion.xholon.base.IXholon#preConfigure() */ public void preConfigure() { println("TreeNode: preConfigure()\n"); } /* * @see org.primordion.xholon.base.IXholon#configure(java.lang.String, int) */ public int configure(String instructions, int instructIx) { println("Xholon: configure(String instructions) " + instructions + " " + instructIx + "\n"); return instructIx; } /* * @see org.primordion.xholon.base.IXholon#print(java.lang.Object) */ public void print(Object obj) { if (Msg.appM) { // && obj instanceof String) { if (obj == null) { print2Console("null", false); } else { print2Console(obj.toString(), true); } } } /* * @see org.primordion.xholon.base.IXholon#println(java.lang.Object) */ public void println(Object obj) { if (Msg.appM) { // && obj instanceof String) { if (obj == null) { print2Console("null\n", true); } else { print2Console(obj.toString() + "\n", true); } } } /** * Print to a console. * This can be very slow, so limit the number of calls, * for example by consolidating text using a StringBuilder before calling. * @param str A String to append to the end of the console. * @param scroll Whether or not to scroll to the bottom of the text area. */ protected void print2Console(String str, boolean scroll) { if (str.startsWith(PRINT2CONSOLE_IGNORE_ME)) { return; } Element element = HtmlElementCache.xhout; if (element != null) { element = element.getFirstChildElement(); } if (element != null) { TextAreaElement textfield = element.cast(); textfield.setValue(textfield.getValue() + str); // optionally scroll to the bottom of the text area if (scroll) { textfield.setScrollTop(textfield.getScrollHeight()); } } } // ******************************************************************************************* // Xholon /* * @see org.primordion.xholon.base.IXholon#initialize() */ public void initialize() { // initialize all instance variables to initial safe values parentNode = null; firstChild = null; nextSibling = null; id = 0; xhc = null; } /** * Get the next available id for assignment to an instance of Xholon. * @return A unique ID. */ protected int getNextId() { return getApp().getNextId(); } /** * Set the next available id back to 0. * This should only be called when loading a new model in, to replace an existing one. */ protected void resetNextId() { getApp().resetNextId(); } /* * @see org.primordion.xholon.base.IXholon#getId() */ public int getId() { return id; } /* * @see org.primordion.xholon.base.IXholon#getIdentity() */ public IXholon getIdentity() { return this; } /* * @see org.primordion.xholon.base.IXholon#getName() */ public String getName() { String rn = getRoleName(); if (rn == null) { rn = ""; } else { rn += ":"; } if (xhc == null) { return rn + this.getClass().getName() + "_" + id; } else { String cName = xhc.getName(); if (cName == null) { return rn + "_" + id; } return rn + cName.substring(0, 1).toLowerCase() + cName.substring(1) + "_" + id; // Convention: first letter of enities are lower case, classes upper case } } /* * @see org.primordion.xholon.base.IXholon#getName(java.lang.String) */ public String getName(String template) { if (template.equals(GETNAME_DEFAULT)) { return getName(); } if (template.length() != GETNAME_SIZE_TEMPLATE) { return getName(); } String nameBuffer = ""; String rn = getRoleName(); for (int pos = 0; pos < GETNAME_SIZE_TEMPLATE; pos++) { char ch = template.charAt(pos); switch (pos) { case 0: // roleName switch (ch) { case 'r': if (rn != null) { nameBuffer += getRoleName(); } break; case 'R': // roleName or className, but not both if ((rn == null) || (rn.length() == 0)) { if (xhc == null) { nameBuffer += this.getClass().getName() + "_"; } else { nameBuffer += xhc.getName(); } } else { nameBuffer += getRoleName(); } break; case 'S': // toString() nameBuffer += toString(); break; case '^': break; default: rn = "" + ch; nameBuffer += ch; break; } break; case 1: // ":" switch (ch) { case ':': if (rn != null) { nameBuffer += ch; } break; case '^': break; default: if (rn != null) { nameBuffer += ch; } break; } break; case 2: // Xholon className switch (ch) { case 'c': // first letter of className should be lowercase if (xhc == null) { nameBuffer += this.getClass().getName() + "_"; //"unknownClassName_"; } else { String cName = xhc.getName(); nameBuffer += cName.substring(0, 1).toLowerCase() + cName.substring(1); } break; case 'C': if (xhc == null) { nameBuffer += this.getClass().getName() + "_"; //"UnknownClassName_"; } else { nameBuffer += xhc.getName(); } break; case 'l': // local part - first letter of className should be lowercase if (xhc == null) { nameBuffer += this.getClass().getName() + "_"; //"unknownClassName_"; } else { String cName = xhc.getLocalPart(); nameBuffer += cName.substring(0, 1).toLowerCase() + cName.substring(1); } break; case 'L': // local part if (xhc == null) { nameBuffer += this.getClass().getName() + "_"; //"UnknownClassName_"; } else { nameBuffer += xhc.getLocalPart(); } break; case 'D': case 'd': if (xhc == null) { nameBuffer += this.getClass().getName() + "_"; //"UnknownClassName_"; } else { nameBuffer += xhc.getName(String.valueOf(ch)); } break; case '^': break; default: nameBuffer += ch; break; } break; case 3: // "_" switch (ch) { case '_': nameBuffer += ch; break; case '^': break; default: nameBuffer += ch; break; } break; case 4: // id switch (ch) { case 'i': nameBuffer += getId(); break; case '^': break; default: nameBuffer += ch; break; } break; case 5: // optional directive switch (ch) { case 'V': // XholonJsApi val() double dval = getVal(); if (dval != 0.0) { nameBuffer += " " + dval; } break; case 'W': // XholonJsApi val() double dvalw = getVal(); if (dvalw != 0.0) { nameBuffer = "" + dvalw; // replace what's already in the nameBuffer; for example, use this in MathML so Cn will return just its value } break; case 'T': // XholonJsApi text() String sval = getVal_String(); if ((sval != null) && (sval.length() > 0)) { nameBuffer += sval; } break; case 'B': nameBuffer += " " + getVal_boolean(); break; // XholonJsApi bool() case 'O': // XholonJsApi obj() Object oval = getVal_Object(); if (oval != null) { nameBuffer += " " + oval.toString(); } break; case '^': break; default: break; } break; default: // should never happen break; } } return nameBuffer; } /* * @see org.primordion.xholon.base.IXholon#setId(int) */ public void setId(int entityId) { id = entityId; } /* * @see org.primordion.xholon.base.IXholon#setName(java.lang.String) */ public void setName(String name) { } /* * @see org.primordion.xholon.base.IXholon#getVal() */ public double getVal() { return 0.0; } /* * @see org.primordion.xholon.base.IXholon#setVal(double) */ public void setVal(double val) { } /* * @see org.primordion.xholon.base.IXholon#setVal_double(double) */ public void setVal_double(double val) { setVal(val); } /* * @see org.primordion.xholon.base.IXholon#incVal(double) */ public void incVal(double incAmount) { } /* * @see org.primordion.xholon.base.IXholon#incVal(int) * conflicts with incVal(double) in JS */ public void incVal(int incAmount) { } /* * @see org.primordion.xholon.base.IXholon#decVal(double) */ public void decVal(double decAmount) { } /* * @see org.primordion.xholon.base.IXholon#decVal(int) * conflicts with decVal(double) in JS */ public void decVal(int decAmount) { } /* * @see org.primordion.xholon.base.IXholon#getVal_boolean() */ public boolean getVal_boolean() { return false; } /* * @see org.primordion.xholon.base.IXholon#getVal_byte() */ public byte getVal_byte() { return 0; } /* * @see org.primordion.xholon.base.IXholon#getVal_char() */ public char getVal_char() { return '\u0000'; } /* * @see org.primordion.xholon.base.IXholon#getVal_double() */ public double getVal_double() { return 0.0; } /* * @see org.primordion.xholon.base.IXholon#getVal_float() */ public float getVal_float() { return 0.0f; } /* * @see org.primordion.xholon.base.IXholon#getVal_int() */ public int getVal_int() { return 0; } /* * @see org.primordion.xholon.base.IXholon#getVal_long() */ public long getVal_long() { return 0L; } /* * @see org.primordion.xholon.base.IXholon#getVal_Object() */ public Object getVal_Object() { return null; } /* * @see org.primordion.xholon.base.IXholon#getVal_short() */ public short getVal_short() { return 0; } /* * @see org.primordion.xholon.base.IXholon#getVal_String() */ public String getVal_String() { return null; } /* * @see org.primordion.xholon.base.IXholon#setVal(boolean) */ public void setVal(boolean val) { } /* * @see org.primordion.xholon.base.IXholon#setVal_boolean(boolean) */ public void setVal_boolean(boolean val) { setVal(val); } /* * @see org.primordion.xholon.base.IXholon#setVal(byte) * conflicts with incVal(double) in JS */ public void setVal(byte val) { } /* * @see org.primordion.xholon.base.IXholon#setVal_byte(byte) */ public void setVal_byte(byte val) { setVal(val); } /* * @see org.primordion.xholon.base.IXholon#setVal(char) * conflicts with setVal(double) in JS */ public void setVal(char val) { } /* * @see org.primordion.xholon.base.IXholon#setVal_char(char) */ public void setVal_char(char val) { setVal(val); } /* * @see org.primordion.xholon.base.IXholon#setVal(float) * conflicts with setVal(double) in JS */ public void setVal(float val) { } /* * @see org.primordion.xholon.base.IXholon#setVal_float(float) */ public void setVal_float(float val) { setVal(val); } /* * @see org.primordion.xholon.base.IXholon#setVal(int) * conflicts with setVal(double) in JS */ public void setVal(int val) { } /* * @see org.primordion.xholon.base.IXholon#setVal_int(int) */ public void setVal_int(int val) { setVal(val); } /* * @see org.primordion.xholon.base.IXholon#setVal(long) * conflicts with setVal(double) in JS */ public void setVal(long val) { } /* * @see org.primordion.xholon.base.IXholon#setVal_long(long) */ public void setVal_long(long val) { setVal(val); } /* * @see org.primordion.xholon.base.IXholon#setVal(java.lang.Object) */ public void setVal(Object val) { } /* * @see org.primordion.xholon.base.IXholon#setVal_Object(java.lang.Object) */ public void setVal_Object(Object val) { setVal(val); } /* * @see org.primordion.xholon.base.IXholon#setVal(short) * conflicts with setVal(double) in JS */ public void setVal(short val) { } /* * @see org.primordion.xholon.base.IXholon#setVal_short(short) */ public void setVal_short(short val) { setVal(val); } /* * @see org.primordion.xholon.base.IXholon#setVal(java.lang.String) */ public void setVal(String val) { } /* * @see org.primordion.xholon.base.IXholon#setVal_String(java.lang.String) */ public void setVal_String(String val) { setVal(val); } /* * @see org.primordion.xholon.base.Xholon#setAttributeVal(java.lang.String, java.lang.String) */ public int setAttributeVal(String attrName, String attrVal) { int classType = IJavaTypes.JAVACLASS_UNKNOWN; if (attrName.equals("val")) { classType = Misc.getJavaDataType(attrVal); switch (classType) { case IJavaTypes.JAVACLASS_boolean: setVal(Misc.atob(attrVal, 0)); break; case IJavaTypes.JAVACLASS_double: setVal(Misc.atod(attrVal, 0)); break; case IJavaTypes.JAVACLASS_float: setVal(Misc.atof(attrVal, 0)); break; case IJavaTypes.JAVACLASS_int: setVal(Misc.atoi(attrVal, 0)); break; case IJavaTypes.JAVACLASS_long: setVal(Misc.atol(attrVal, 0)); break; case IJavaTypes.JAVACLASS_String: setVal(attrVal); break; default: break; } } else if (attrName.equals("id")) { classType = Misc.getJavaDataType(attrVal); switch (classType) { case IJavaTypes.JAVACLASS_double: setVal(Misc.atod(attrVal, 0)); break; case IJavaTypes.JAVACLASS_float: setVal(Misc.atof(attrVal, 0)); break; case IJavaTypes.JAVACLASS_int: setId(Misc.atoi(attrVal, 0)); break; case IJavaTypes.JAVACLASS_long: setVal(Misc.atol(attrVal, 0)); break; case IJavaTypes.JAVACLASS_String: setVal(attrVal); break; default: break; } } else { // TODO don't handle namespaced attrName (ex: "xmlns:xi") setAttributeValNative(attrName, attrVal); } return classType; } /** * Set an attribute and it's value using JavaScript. * This is primarily intended to support the use of XML attributes in Xholon Workbooks. * Example: * <Words roleName="English" lang="en">tree, leaf, cat, car, bird (crow), sun, cloud, house</Words> * where lang="en" would cause this method to be invoked by the XML parser. */ protected native void setAttributeValNative(String attrName, String attrVal) /*-{ this[attrName] = attrVal; }-*/; /* * @see org.primordion.xholon.base.IXholon#getClassNode(java.lang.String) */ public IXholonClass getClassNode(String cName) { IApplication app = getApp(); return (app == null) ? null : app.getClassNode(cName); } /* * @see org.primordion.xholon.base.IXholon#getClassNode(int) */ public IXholonClass getClassNode(int id) { IApplication app = getApp(); return (app == null) ? null : app.getClassNode(id); } /* * @see org.primordion.xholon.base.IXholon#getXhc() */ public IXholonClass getXhc() { return xhc; } /* * @see org.primordion.xholon.base.IXholon#getXhcId() */ public int getXhcId() { if (xhc == null) { return -1; } else { return xhc.getId(); } } /* * @see org.primordion.xholon.base.IXholon#getXhcName() */ public String getXhcName() { if (xhc == null) { return "UnknownClassName"; } else { return xhc.getName(); } } /* * @see org.primordion.xholon.base.IXholon#setXhc(org.primordion.xholon.base.XholonClass) */ public void setXhc(IXholonClass xhcNode) { if (xhcNode == null) { logger.error("Xholon setXhc(IXholonClass xhcNode) input arg " + getName() + " is null"); } xhc = xhcNode; } /* * @see org.primordion.xholon.base.IXholon#getXhType() */ public int getXhType() { if (xhc == null) { return IXholonClass.XhtypeNone; } else { return xhc.getXhType(); } } /* * @see org.primordion.xholon.base.IXholon#isContainer() */ public boolean isContainer() { return true; } /* * @see org.primordion.xholon.base.IXholon#isActiveObject() */ public boolean isActiveObject() { return false; } /* * @see org.primordion.xholon.base.IXholon#isPassiveObject() */ public boolean isPassiveObject() { return false; } /* * @see org.primordion.xholon.base.IXholon#hasAncestor(java.lang.String) */ public boolean hasAncestor(String tnName) { IXholon node = this; while (node != null) { if (node.getName().equals(tnName)) { return true; } node = node.getParentNode(); } return false; } /* * @see org.primordion.xholon.base.IXholon#setPorts() */ public void setPorts() { } /** * Bind port names to referenced nodes. * This is intended for use in a GWT environment, with nodes that have ad-hoc ports * where the port name (fieldName) is not yet defined. * It calls a JavaScript native method to create new ports. * The application might be a Chameleon app (XhChameleon) or a Bestiary app, or something similar. * The app might be defined in a XholonWorkbook, with or without Chameleon/Bestiary. * The ports must be defined in the XholonClass. * The ports are not typically available by calling app.getAppSpecificObjectVals(), * which only knows about Java GWT compile-time ports. * One way to use this method is to override the configure() method, * with just the single line "bindPorts();" , for example in XhChameleon. * * TODO don't replace a port that's already bound ? */ public void bindPorts() { List<PortInformation> xhcPortList = this.getXhc().getPortInformation(); // eval the XPath expressions to determine the reffed nodes Iterator<PortInformation> portIt = xhcPortList.iterator(); while (portIt.hasNext()) { PortInformation pi = (PortInformation) portIt.next(); String xpathExpression = pi.getXpathExpression(); if (xpathExpression == null) { // this is probably an IPort with portReplication // see XholonWithPorts configurePorts(String instructions, int instructIx) int index = pi.getFieldNameIndex(); String fieldName = pi.getFieldName(); int multiplicity = pi.getIportMultiplicity(); // = 0; // default boolean isConjugated = pi.isIportIsConjugated(); // = false; // default String[] providedInterfaceNames = pi.getIportProvidedInterfaceNames().split(","); // = new String[0]; String[] requiredInterfaceNames = pi.getIportRequiredInterfaceNames().split(","); // = new String[0]; try { IPort iport = Port.createPort(this, multiplicity, null, providedInterfaceNames, null, requiredInterfaceNames, isConjugated); if ("port".equals(fieldName)) { // port IPort array setPort(index, iport); } else { // non-"port" IPort scalar bindPort(this, fieldName, iport); } } catch (RuntimeException e) { consoleLog("Unable to set up an IPort port. The port variable may be null." + e); } } else { IXholon reffedNode = null; String fieldName = pi.getFieldName(); if (xpathExpression.startsWith("RemoteNodeService")) { reffedNode = this.bindRemotePort(fieldName, xpathExpression); } else { reffedNode = this.getXPath().evaluate(xpathExpression.trim(), this); } if (reffedNode != null) { int index = pi.getFieldNameIndex(); if (fieldName != null) { if (index == PortInformation.PORTINFO_NOTANARRAY) { // -1 //if ("port".equals(fieldName)) { // TODO ? // setPort(0, reffedNode); //} if ("trop".equals(fieldName)) { setPort(0, reffedNode); } else { bindPort(this, fieldName, reffedNode); } } else { // this is an array, possibly a "port" port if ("port".equals(fieldName)) { setPort(index, reffedNode); } else if ("trop".equals(fieldName)) { setPort(index, reffedNode); } //else if ("replication".equals(fieldName)) { // consoleLog("Xholon bindPorts() fieldName == replication"); // // TODO handle this portReplication within a an IPort port // // OK the system already handles the portReplication //} else { bindPort(this, fieldName, index, reffedNode); } } } } } } } public native void consoleLog(Object obj) /*-{ if ($wnd.console && $wnd.console.log) { $wnd.console.log(obj); } }-*/; protected native void bindPort(IXholon node, String fieldName, IXholon reffedNode) /*-{ if ($wnd.console && $wnd.console.log) { $wnd.console.log("bindPort"); $wnd.console.log(node.toString()); $wnd.console.log(fieldName); $wnd.console.log(reffedNode.toString()); } node[fieldName] = reffedNode; }-*/; protected native void bindPort(IXholon node, String fieldName, int index, IXholon reffedNode) /*-{ if (!node[fieldName]) { node[fieldName] = []; } node[fieldName][index] = reffedNode; }-*/; /** * Bind to a remote port using the RemoteNodeService. * Return a new instance of PeerJS.java or other implementation of IRemoteNode.java . * Handle both port name="port" and name="trop". * <p>"RemoteNodeService-PeerJS,Alligator,OPTIONAL_KEY,OPTIONAL_DEBUG"</p> * @param remoteNodeExpr An expression that specifies the remote node (ex: ). * @return A proxy node, or null. */ protected IXholon bindRemotePort(String portName, String remoteNodeExpr) { boolean isTrop = false; if ("trop".equals(portName)) { isTrop = true; } String[] rnsParams = remoteNodeExpr.split(",", 2); //consoleLog(rnsParams); IXholon remoteNode = this.getService(rnsParams[0]); if (remoteNode != null) { //consoleLog(remoteNode.getName()); IMessage respMsg = null; if (isTrop) { // have remoteNode listen for a remote connection (where -3898 (101) = SIG_LISTEN_REQ) respMsg = remoteNode.sendSyncMessage(-3898, rnsParams[1], this); } else { // have node initiate a remote connection (where -3897 (102) = SIG_CONNECT_REQ) respMsg = remoteNode.sendSyncMessage(-3897, rnsParams[1], this); } //consoleLog(respMsg); } else { this.println("Unable to create a remoteNode instance from " + rnsParams[0]); this.println( "If you are using PeerJS, be sure you are using XholonWebRTC.html which includes peer.js, rather than Xholon.html ."); } return remoteNode; } /* * @see org.primordion.xholon.base.IXholon#configure() */ public void configure() { // execute recursively if (firstChild != null) { firstChild.configure(); } if (nextSibling != null) { nextSibling.configure(); } } /* * @see org.primordion.xholon.base.IXholon#postConfigure() */ public void postConfigure() { // execute recursively if (firstChild != null) { firstChild.postConfigure(); } if (nextSibling != null) { nextSibling.postConfigure(); } } /** * Get port reference. * This is based on the XML XPath and XPointer standards. * Examples: * <p>"#xpointer(ancestor::AnElevatorSystem/Floor[1]/CallButton[1])"</p> * <p>"nameOrIdOfOtherApplication#xpointer(/HelloWorldSystem/Hello)"</p> * <p>"ancestor::AnElevatorSystem/Floor[1]/CallButton[1]"</p> * @param instructions A string that may contain a port reference with an XPath location path. * @param instructIx Index into the string where the port reference starts. * @return The Xholon instance identified by the XPath location path, * or the current node if there was no match. */ protected IXholon getPortRef(String instructions, int instructIx) { IXholon node = this; int xpointerInc = 11; // increment past '"#xpointer(' string int endIxInc = 2; // increment past xpointer ')' end string while (instructIx < instructions.length()) { switch (instructions.charAt(instructIx)) { case '"': // opening " IXholon contextNode = this; if (instructions.charAt(instructIx + 1) != '#') { // this references an IXholon in another application or at a remote location, // or this app isn't using #xpointer(...) instructIx++; int endIndex = instructions.indexOf('#', instructIx); if (endIndex == -1) { // this app isn't using #xpointer(...), // so just return the entire contents between the opening and closing " xpointerInc = 0; //1; // increment past opening '"' endIxInc = 1; // increment past closing '"' } else { String otherAppName = instructions.substring(instructIx, endIndex); IApplication otherApp = getApp().getApplicationOther(otherAppName); if (otherApp != null) { contextNode = otherApp.getRoot(); } instructIx = endIndex - 1; // point just before the # } } // TODO do a proper parsing of the "#xpointer( instructIx += xpointerInc; // point to first char after "#xpointer( // look for final ) within this port ref; may be other ( and ) int endIx = instructions.indexOf(IInheritanceHierarchy.NAVINFO_SEPARATOR, instructIx); if (endIx == -1) { // this is the last one endIx = instructions.length() - endIxInc; } else { endIx -= endIxInc; } String nodePath = instructions.substring(instructIx, endIx).trim(); node = getXPath().evaluate(nodePath, contextNode); instructIx = endIx + endIxInc; // point beyond closing )" break; case IInheritanceHierarchy.NAVINFO_SEPARATOR: // end of a port reference return node; default: break; } } return node; } /* * @see org.primordion.xholon.base.IXholon#preReconfigure() */ public void preReconfigure() { // execute recursively if (firstChild != null) { firstChild.preReconfigure(); } if (nextSibling != null) { nextSibling.preReconfigure(); } } /* * @see org.primordion.xholon.base.IXholon#reconfigure() */ public void reconfigure() { // execute recursively if (firstChild != null) { firstChild.reconfigure(); } if (nextSibling != null) { nextSibling.reconfigure(); } } /* * @see org.primordion.xholon.base.IXholon#postReconfigure() */ public void postReconfigure() { // execute recursively if (firstChild != null) { firstChild.postReconfigure(); } if (nextSibling != null) { nextSibling.postReconfigure(); } } /* * @see org.primordion.xholon.base.IXholon#preAct() */ public void preAct() { // execute recursively if (firstChild != null) { firstChild.preAct(); } if (nextSibling != null) { nextSibling.preAct(); } } /* * @see org.primordion.xholon.base.IXholon#act() */ public void act() { // execute recursively if (firstChild != null) { firstChild.act(); } if (nextSibling != null) { nextSibling.act(); } } /* * @see org.primordion.xholon.base.IXholon#actNr() */ public void actNr() { } /* * @see org.primordion.xholon.base.IXholon#postAct() */ public void postAct() { // execute recursively if (firstChild != null) { firstChild.postAct(); } if (nextSibling != null) { nextSibling.postAct(); } } /* * @see org.primordion.xholon.base.Xholon#cleanup() */ public void cleanup() { // execute recursively if (firstChild != null) { firstChild.cleanup(); } if (nextSibling != null) { nextSibling.cleanup(); } } // tree traversal print functions that MAY be overridden in concrete subclasses /* * @see org.primordion.xholon.base.IXholon#preOrderPrint(int) */ public void preOrderPrint(int level) { printNode(level); if (firstChild != null) { firstChild.preOrderPrint(level + 1); } if (nextSibling != null) { nextSibling.preOrderPrint(level); } } /* * @see org.primordion.xholon.base.IXholon#inOrderPrint(int) */ public void inOrderPrint(int level) { if (firstChild != null) { firstChild.inOrderPrint(level + 1); } printNode(level); if (nextSibling != null) { nextSibling.inOrderPrint(level); } } /* * @see org.primordion.xholon.base.IXholon#postOrderPrint(int) */ public void postOrderPrint(int level) { if (firstChild != null) { firstChild.postOrderPrint(level); } if (nextSibling != null) { nextSibling.postOrderPrint(level + 1); } printNode(level); } /** * Called by the various xOrderPrint() routines. * @param level Level in the tree, where the root node is level 0. */ protected void printNode(int level) { // Xholon classic approach /*while (level > 0) { print( "." ); level--; } if (xhc == null) { println( "UnknownClassName" ); } else { println( getName() ); }*/ if (xhc == null) { print("UnknownClassName "); } else { print(getName() + " "); } } /** * @see org.primordion.xholon.base.IXholon#visit(org.primordion.xholon.base.IXholon) * @param visitor A visitor. */ public boolean visit(IXholon visitor) { if (!visitor.visit(this)) { // the visitor has completed its task and doesn't need to visit any more nodes return false; } // visit the children of this visitee node IXholon visitee = getFirstChild(); while (visitee != null) { // don't allow visiting the visitor if (visitee != visitor) { // TODO return false if visitee.visit(visitor); returns false //visitee.visit(visitor); // OLD if (!visitee.visit(visitor)) { return false; } ; // NEW } visitee = visitee.getNextSibling(); } return true; } /* * @see org.primordion.xholon.base.IXholon#writeXml(int, java.io.Writer) */ /*public void writeXml( int level, Writer fw ) { StringBuffer indent = new StringBuffer(level); for (int i = 0; i < level; i++) { indent.append('\t'); } try { IXholon node = getFirstChild(); if (node != null) { fw.write(indent + "<" + getXhcName() + ">\n"); node.writeXml(level+1, fw); fw.write(indent + "</" + getXhcName() + ">\n"); } else { fw.write(indent + "<" + getXhcName() + "/>\n"); } node = getNextSibling(); if (node != null) { node.writeXml(level, fw); } } catch (IOException e) { logger.error("", e); //e.printStackTrace(); } }*/ /* * @see org.primordion.xholon.base.IXholon#handleNodeSelection() */ public Object handleNodeSelection() { String parentStr = ""; if (hasParentNode()) { parentStr = (String) parentNode.handleNodeSelection(this); } return parentStr + toString(); } /* * @see org.primordion.xholon.base.IXholon#handleNodeSelection(org.primordion.xholon.base.IXholon) */ public Object handleNodeSelection(IXholon otherNode) { return ""; } // UML2 /* * @see org.primordion.xholon.base.IXholon#sendMessage(int, java.lang.Object, org.primordion.xholon.base.IXholon) * TODO This should probably be in XholonWithPorts because only a xholon with ports can send a message. * However, that would restrict its flexibility. * Possibly a xholon without ports might want to send messages to its parent, siblings, children, etc. * So leave it here for now. */ public void sendMessage(int signal, Object data, IXholon sender) { sendMessage(new Message(signal, data, sender, this)); } /* * @see org.primordion.xholon.base.IXholon#sendMessage(int, java.lang.Object, org.primordion.xholon.base.IXholon, int) */ public void sendMessage(int signal, Object data, IXholon sender, int index) { sendMessage(new Message(signal, data, sender, this, index)); } /* * @see org.primordion.xholon.base.IXholon#sendMessage(org.primordion.xholon.base.IMessage) */ public void sendMessage(IMessage msg) { if (getInteractionsEnabled()) { getInteraction().addMessage(msg); } int rc = getMsgQ().enqueue(msg); if (rc == IQueue.Q_FULL) { println("Xholon sendMessage() Q_FULL " + msg); } // TODO handle Q_FULL } /* * @see org.primordion.xholon.base.IXholon#processReceivedMessage(org.primordion.xholon.base.Message) */ public void processReceivedMessage(IMessage msg) { if ((msg.getSignal() == ISignal.SIGNAL_XHOLON_CONSOLE_REQ) && (this.getActionList() != null)) { this.doAction((String) msg.getData()); } else if (msg.getSignal() == ISignal.SIGNAL_BPLEX) { // ex (using Dev Tools): var bait = temp1; bait["FishingRodbplex"].msg(-12, ["FishingRodbplex"], bait); // ex: var bait = temp1; bait["FishingRodbplex"].msg(-12, {bplexName:"FishingRodbplex"}, bait); Object data = msg.getData(); if (data == null) { return; } String clogStr = "bplex msg sender:" + msg.getSender() + " this:" + this.getName(); String bplexName = null; if (data instanceof JavaScriptObject) { clogStr += " datatype:JavaScriptObject"; JavaScriptObject jso = (JavaScriptObject) data; bplexName = (String) getJsoPropertyValue(jso, "bplexName"); if (bplexName == null) { // this may be a JavaScript Array JsArrayMixed marr = jso.cast(); if (marr.length() == 0) { return; } bplexName = marr.getString(0); if (marr.length() > 1) { // TODO the msg might contain a second nested message, or some other IXholon(s) or Object(s) //anode = (Object)marr.getObject(1); } clogStr += " Array"; } else { clogStr += " Object"; } } else if (data instanceof Object[]) { clogStr += " datatype:Java Object[]"; Object[] oarr = (Object[]) data; if (oarr.length == 0) { return; } bplexName = (String) oarr[0]; } else { return; } consoleLog(clogStr); //this.setColor("indigo"); // this works if (msg.getSender() != this) { // send to next node in the bplex if (bplexName != null) { IXholon nextBplexNode = getPortNative(this, bplexName); if (nextBplexNode != null) { // send the same message contents to the next node in the bplex nextBplexNode.sendMessage(msg.getSignal(), data, msg.getSender()); } } } } else { forwardMessage(msg); } } /* * @see org.primordion.xholon.base.IXholon#registerMessageForwardee(org.primordion.xholon.base.IXholon, int[]) */ public void registerMessageForwardee(IXholon forwardee, int[] signal) { } /* * @see org.primordion.xholon.base.IXholon#forwardMessage(org.primordion.xholon.base.Message) */ public void forwardMessage(IMessage msg) { logger.warn("Unexpected async message received : " + msg); } /* * @see org.primordion.xholon.base.IXholon#processMessageQ() * TODO same issue as in sendMessage() re whether would be better in XholonWithPorts */ public void processMessageQ() { // println("Xholon: processMessageQ()"); // Only process the messages that are currently in the Q. // Don't process messages added to Q during this timestep. int numMsgs = getMsgQ().getSize(); for (int qq = 0; qq < numMsgs; qq++) { IMessage rxMsg = (IMessage) getMsgQ().dequeue(); if (getInteractionsEnabled()) { getInteraction().processReceivedMessage(rxMsg); } if (isSystemMessage(rxMsg)) { // this might be a system message processSystemMessage(rxMsg); } else { try { rxMsg.getReceiver().processReceivedMessage(rxMsg); } catch (RuntimeException e) { logger.error("Xholon processMessageQ()", e); } } } } /* * @see org.primordion.xholon.base.IXholon#sendSystemMessage(int, java.lang.Object, org.primordion.xholon.base.IXholon) */ public void sendSystemMessage(int signal, Object data, IXholon sender) { sendSystemMessage(new Message(signal, data, sender, this)); } /* * @see org.primordion.xholon.base.IXholon#sendSystemMessage(org.primordion.xholon.base.Message) */ public void sendSystemMessage(IMessage msg) { int rc = getSystemMsgQ().enqueue(msg); if (rc == IQueue.Q_FULL) { logger.debug("Xholon sendSystemMessage() Q_FULL " + msg); } // TODO handle Q_FULL } /* * @see org.primordion.xholon.base.IXholon#processSystemMessageQ() */ public void processSystemMessageQ() { // println("Xholon: processMessageQ()"); // Only process the messages that are currently in the Q. // Don't process messages added to Q during this timestep. int numMsgs = getSystemMsgQ().getSize(); for (int qq = 0; qq < numMsgs; qq++) { IMessage rxMsg = (IMessage) getSystemMsgQ().dequeue(); if (isSystemMessage(rxMsg)) { // this might be a system message processSystemMessage(rxMsg); } else { try { rxMsg.getReceiver().processReceivedMessage(rxMsg); } catch (RuntimeException e) { logger.error("Xholon processSystemMessageQ()", e); } } } } /** * * @param msg * @return */ protected boolean isSystemMessage(IMessage msg) { if (msg.getSignal() < ISignal.SIGNAL_SYSTEM_MESSAGE) { return true; } else { return false; } } /** * Process a system message. * @param msg A message received through the system queue. */ protected void processSystemMessage(IMessage msg) { switch (msg.getSignal()) { default: try { msg.getReceiver().processReceivedMessage(msg); } catch (RuntimeException e) { logger.error("Xholon processSystemMessage(msg)", e); } break; } } // Synchronous Messaging /* * @see org.primordion.xholon.base.IXholon#sendSyncMessage(int, java.lang.Object, org.primordion.xholon.base.IXholon) */ public IMessage sendSyncMessage(int signal, Object data, IXholon sender) { return sendSyncMessage(new Message(signal, data, sender, this)); } /* * @see org.primordion.xholon.base.IXholon#sendSyncMessage(int, java.lang.Object, org.primordion.xholon.base.IXholon, int) */ public IMessage sendSyncMessage(int signal, Object data, IXholon sender, int index) { return sendSyncMessage(new Message(signal, data, sender, this, index)); } /* * @see org.primordion.xholon.base.IXholon#sendSyncMessage(org.primordion.xholon.base.Message) */ public IMessage sendSyncMessage(IMessage msg) { if (getInteractionsEnabled()) { IInteraction interaction = getInteraction(); interaction.addSyncMessage(msg); IMessage responseMsg = (IMessage) processReceivedSyncMessage(msg); interaction.addSyncMessage(responseMsg); return responseMsg; } else { return processReceivedSyncMessage(msg); } } /* * @see org.primordion.xholon.base.IXholon#processReceivedSyncMessage(org.primordion.xholon.base.Message) */ public IMessage processReceivedSyncMessage(IMessage msg) { //logger.warn("Unexpected sync message received : " + msg); //return new Message(ISignal.SIGNAL_UNKNOWN, null, this, msg.getSender()); return forwardSyncMessage(msg); } /* * @see org.primordion.xholon.base.IXholon#forwardSyncMessage(org.primordion.xholon.base.Message) */ public IMessage forwardSyncMessage(IMessage msg) { logger.warn("Unexpected sync message received : " + msg); return new Message(ISignal.SIGNAL_UNKNOWN, null, this, msg.getSender()); } /* * The default action for any Xholon, whether or not it's a state machine, is to remove itself from the * xholon composite structure tree, and return itself and its children (recursively) to the factory for * possible recycling. * @see org.primordion.xholon.base.IXholon#terminate() */ public void terminate() { removeChild(); remove(); } @Override /** * TODO include non-port ports; see * but don't call getAllPorts() which is too slow when used in D3 Circle Pack */ public List<IXholon> searchForReferencingNodes() { List<IXholon> reffingNodes = new ArrayList<IXholon>(); IXholon myRoot = getRootNode(); if (myRoot.getClass() != Control.class) { ((Xholon) myRoot).searchForReferencingNodesRecurse(this, reffingNodes); } return reffingNodes; } /** * Search for instances of Xholon with ports that reference this instance. * See enhancements in Xholon2Etrice.java * @param reffedNode The Xholon node that we're looking for references to. * @param reffingNodes A list that is being filled with references. */ public void searchForReferencingNodesRecurse(Xholon reffedNode, List<IXholon> reffingNodes) { IXholon[] port = getPort(); if (port != null) { for (int i = 0; i < port.length; i++) { if (port[i] != null) { if (port[i] == reffedNode) { reffingNodes.add(this); } } } } if (firstChild != null) { ((Xholon) firstChild).searchForReferencingNodesRecurse(reffedNode, reffingNodes); } // don't search nextSibling if this is xhRoot and nextSibling is srvRoot if ((nextSibling != null) && (this.id != 0)) { ((Xholon) nextSibling).searchForReferencingNodesRecurse(reffedNode, reffingNodes); } } @Override public List<IXholon> searchForLinkingNodes() { List<IXholon> reffingNodes = new ArrayList<IXholon>(); IXholon myRoot = getRootNode(); if (myRoot.getClass() != Control.class) { ((Xholon) myRoot).searchForLinkingNodesRecurse(this, reffingNodes); } return reffingNodes; } /** * Search for instances of Xholon with ports that reference this instance. * @param reffingNodes A list that is being filled with references. */ public void searchForLinkingNodesRecurse(Xholon reffedNode, List<IXholon> reffingNodes) { /**IXholon[] port = getPort(); if (port != null) { for (int i = 0; i < port.length; i++) { if (port[i] != null) { if (port[i] == reffedNode) { reffingNodes.add(this); } } } }*/ JsArray<JavaScriptObject> arr = this.getLinksNative(false, true); for (int i = 0; i < arr.length(); i++) { JavaScriptObject obj = arr.get(i); if ((IXholon) getJsoPropertyValue(obj, "reffedNode") == reffedNode) { reffingNodes.add(this); } } if (firstChild != null) { ((Xholon) firstChild).searchForLinkingNodesRecurse(reffedNode, reffingNodes); } // don't search nextSibling if this is xhRoot and nextSibling is srvRoot if ((nextSibling != null) && (this.id != 0)) { ((Xholon) nextSibling).searchForLinkingNodesRecurse(reffedNode, reffingNodes); } } /* * @see org.primordion.xholon.base.IXholon#performActivity(int, org.primordion.xholon.base.Message) */ public void performActivity(int activityId, IMessage msg) { println("Xholon: performActivity(activityId) " + activityId + " " + msg); } /* * @see org.primordion.xholon.base.IXholon#performBooleanActivity(int) */ public boolean performBooleanActivity(int activityId) { println("Xholon: performBooleanActivity(activityId) " + activityId); return false; } /* * @see org.primordion.xholon.base.IXholon#performGuard(int, org.primordion.xholon.base.Message) */ public boolean performGuard(int activityId, IMessage msg) { println("Xholon: performGuard(activityId) " + activityId); return false; } // Turtle public void performActivity(int activityId) { println("Xholon: performActivity(activityId) " + activityId); } // GP, and other evolutionary computation, ECJ, Behavior encoded as an Activity subtree /* * @see org.primordion.xholon.base.IXholon#performVoidActivity(org.primordion.xholon.base.IXholon) */ public void performVoidActivity(IXholon activity) { println("Xholon: performVoidActivity(activity) " + activity.getId()); } /* * @see org.primordion.xholon.base.IXholon#performDoubleActivity(org.primordion.xholon.base.IXholon) */ public double performDoubleActivity(IXholon activity) { println("Xholon: performDoubleActivity(activity) " + activity.getId()); return 1.0; } /* * @see org.primordion.xholon.base.IXholon#performBooleanActivity(org.primordion.xholon.base.IXholon) */ public boolean performBooleanActivity(IXholon activity) { println("Xholon: performBooleanActivity(activity) " + activity.getId()); return false; } /* * @see org.primordion.xholon.base.IXholon#setPort(org.primordion.xholon.base.IXholon[]) */ public void setPort(IXholon[] port) { } /* * @see org.primordion.xholon.base.IXholon#getPort() */ public IXholon[] getPort() { return null; } /* * @see org.primordion.xholon.base.IXholon#setPort(int, org.primordion.xholon.base.IXholon) */ public void setPort(int portNum, IXholon portRef) { } /* * @see org.primordion.xholon.base.IXholon#getPort(int) * Subclasses that use ports must override this function. */ public IXholon getPort(int portNum) { return null; } /* * @see org.primordion.xholon.base.IXholon#getAllPorts(org.primordion.xholon.base.IXholon) */ public List getAllPorts() { // There are three ways to do this: // (1) specification: uses Reflection, which calls node.getXhc().getPortInformation() //return ReflectionFactory.instance().getAllPorts(this, false); // (2) actual: uses AppGenerator-generated code in Application subclasses // this works for Java GWT ports that are bound by GWT at compile-time //return node.getApp().getAppSpecificObjectVals(node, (Class<IXholon>)node.getClass()).toArray(); // (3) actual: ports that are bound by JavaScript using bindPorts() IXholon node = this; Class<IXholon> clazz = (Class<IXholon>) node.getClass(); return getApp().getAppSpecificObjectVals(this, clazz); } @Override public List getLinks(boolean placeGraph, boolean linkGraph) { List list = new ArrayList(); JsArray<JavaScriptObject> arr = this.getLinksNative(placeGraph, linkGraph); for (int i = 0; i < arr.length(); i++) { JavaScriptObject obj = arr.get(i); String fieldName = (String) getJsoPropertyValue(obj, "fieldName"); int fieldNameIndex = getJsoPropertyValueInt(obj, "fieldNameIndex"); IXholon reffedNode = (IXholon) getJsoPropertyValue(obj, "reffedNode"); String xpathExpression = (String) getJsoPropertyValue(obj, "xpathExpression"); list.add(new PortInformation(fieldName, fieldNameIndex, reffedNode, xpathExpression)); } return list; } protected native JsArray<JavaScriptObject> getLinksNative(boolean placeGraph, boolean linkGraph) /*-{ return this.links(placeGraph, linkGraph); }-*/; protected final native Object getJsoPropertyValue(JavaScriptObject obj, String jsoPropertyName) /*-{ return obj[jsoPropertyName]; }-*/; protected final native int getJsoPropertyValueInt(JavaScriptObject obj, String jsoPropertyName) /*-{ return obj[jsoPropertyName]; }-*/; protected final native IXholon getPortNative(IXholon node, String portName) /*-{ return node[portName]; }-*/; /* * @see org.primordion.xholon.base.IXholon#isBound(org.primordion.xholon.base.IXholon) */ public boolean isBound(IXholon port) { if (port == null) { return false; } else { //return port.isBound(port); return true; } } /* * @see org.primordion.xholon.base.IXholon#getService(java.lang.String) */ public IXholon getService(String serviceName) { IXholon root = getRootNode(); if (root == null) { return null; } //if (root.getXhc() == null && IApplication.class.isAssignableFrom(root.getClass())) { if (root.getXhc() == null && ClassHelper.isAssignableFrom(AbstractApplication.class, root.getClass())) { // this must be the Application node return root.getService(serviceName); } else { // this might be the model root IXholon srvRoot = root.getNextSibling(); if (srvRoot == null) { // try to locate srvRoot through root's xhclass if (root.getXhc() == null) { return null; } IApplication app = getApp(); if (app == null) { return null; } return app.getService(serviceName); } IXholon serviceLocator = srvRoot.getFirstChild(); if (serviceLocator == null) { return null; } return serviceLocator.getService(serviceName); } } /* * @see org.primordion.xholon.base.IXholon#setRoleName(java.lang.String) * Subclasses that use roles might override this method, for better performance. * TODO not all node types can use the service to find role children */ public void setRoleName(String roleName) { IXholon role = findFirstChildWithXhClass(CeRole.RoleCE); if (role == null) { // create a new Role node role = appendChild("Role", roleName, Role.getImplName()); } else { role.setRoleName(roleName); } } /* * @see org.primordion.xholon.base.IXholon#getRoleName() * Subclasses that use roles might override this method, for better performance. * TODO not all node types can use the service to find role children */ public String getRoleName() { IXholon role = findFirstChildWithXhClass(CeRole.RoleCE); if (role != null) { return role.getRoleName(); } else { return null; } } /* * @see org.primordion.xholon.base.IXholon#setUid(java.lang.String) */ public void setUid(String uid) { this.setUidNative(uid); } /* * @see org.primordion.xholon.base.IXholon#getUid() */ public String getUid() { return this.getUidNative(); } protected native void setUidNative(String uidArg) /*-{ this["uuid"] = uidArg; }-*/; protected native String getUidNative() /*-{ return this["uuid"] ? this["uuid"] : null; }-*/; /* * @see org.primordion.xholon.base.IXholon#setUri(java.lang.String) */ public void setUri(String uri) { } /* * @see org.primordion.xholon.base.IXholon#getUri() */ public String getUri() { if (xhc == null) { return null; } IMechanism mech = xhc.getMechanism(); if (mech == null) { return null; } StringBuffer uri = new StringBuffer().append(mech.getNamespaceUri()).append("/") .append(this.getName(GETNAME_LOCALPART_ID)); return uri.toString(); } /* * @see org.primordion.xholon.base.IXholon#setAnnotation(java.lang.String) */ public void setAnnotation(String annotation) { IXholon ann = findFirstChildWithXhClass(CeAnnotation.AnnotationCE); if (ann != null) { ann.setVal(annotation); } else { // create a new annotation, or update an existing one XholonDirectoryService xds = (XholonDirectoryService) getService(IXholonService.XHSRV_XHOLON_DIRECTORY); if (xds == null) { return; } ann = (IXholon) new Annotation(annotation); ann.setParentNode(this); xds.put(Annotation.makeUniqueKey(this), ann); } } public void setAnno(String annotation) { this.setAnnotation(annotation); } /* * @see org.primordion.xholon.base.IXholon#getAnnotation() */ public String getAnnotation() { XholonDirectoryService xds = (XholonDirectoryService) getService(IXholonService.XHSRV_XHOLON_DIRECTORY); if (xds == null) { return null; } IXholon ann = (IXholon) xds.get(Annotation.makeUniqueKey(this)); if (ann != null) { return ann.getVal_String(); } ann = findFirstChildWithXhClass(CeAnnotation.AnnotationCE); if (ann != null) { return ann.getVal_String(); } //return null; if ("true".equals(this.getApp().getParam("AnnoUseXholonClassValue"))) { return this.xhc.getAnnotation(); } else { return null; } } public String getAnno() { return this.getAnnotation(); } /* * @see org.primordion.xholon.base.IXholon#hasAnnotation() */ public boolean hasAnnotation() { IXholon service = getService(IXholonService.XHSRV_XHOLON_DIRECTORY); if (service == null) { return false; } if (((XholonDirectoryService) service).get(Annotation.makeUniqueKey(this)) != null) { return true; } if (findFirstChildWithXhClass(CeAnnotation.AnnotationCE) != null) { //return false; return true; } //return true; if ("true".equals(this.getApp().getParam("AnnoUseXholonClassValue"))) { return this.xhc.hasAnnotation(); } else { return false; } } public boolean hasAnno() { return this.hasAnnotation(); } /* * @see org.primordion.xholon.base.IXholon#showAnnotation() */ public void showAnnotation() { XholonDirectoryService xds = (XholonDirectoryService) getService(IXholonService.XHSRV_XHOLON_DIRECTORY); if (xds == null) { return; } IXholon ann = (IXholon) xds.get(Annotation.makeUniqueKey(this)); if (ann == null) { ann = findFirstChildWithXhClass(CeAnnotation.AnnotationCE); } if (ann != null) { ann.showAnnotation(); } else if ("true".equals(this.getApp().getParam("AnnoUseXholonClassValue"))) { this.xhc.showAnnotation(); } } public void showAnno() { this.showAnnotation(); } /* * @see java.lang.Comparable#compareTo(java.lang.Object) */ public int compareTo(Object o) { String nameTemplate = "^:c_i^"; String thisName = getName(nameTemplate); String otherName = ((IXholon) o).getName(nameTemplate); return thisName.compareTo(otherName); } /* * @see org.primordion.xholon.base.IXholon#getActionList() */ public String[] getActionList() { String[] al = getActionListNative(); if (al != null) { return al; } /* example: <ActionList> <ActionOne/> <!-- a sub-xholonclass of Action --> <ActionTwo/> <ActionThree/> </ActionList> */ IXholon actionList = findFirstChildWithXhClass(CeAction.ActionListCE); if (actionList != null) { return actionList.getActionList(); } else { return null; } } /* * */ protected native String[] getActionListNative() /*-{ var alNames = null; if (this.actionList) { alNames = []; for (var prop in this.actionList) { var pname = prop; alNames.push(pname); } } return alNames; }-*/; /* * @see org.primordion.xholon.base.IXholon#setActionList(java.lang.String[]) */ public void setActionList(String[] actionList) { IXholon aList = findFirstChildWithXhClass(CeAction.ActionListCE); if (aList == null) { // create a new ActionList node aList = appendChild("ActionList", null); } if (aList != null) { aList.setActionList(actionList); } } /* * @see org.primordion.xholon.base.IXholon#doAction(java.lang.String) */ public void doAction(String action) { if (!doActionNative(action)) { IXholon actionList = findFirstChildWithXhClass(CeAction.ActionListCE); if (actionList != null) { actionList.doAction(action); } } } /* * */ protected native boolean doActionNative(String action) /*-{ if (this.actionList) { var a = this.actionList[action]; if (a) { a(); return true; } } return false; }-*/; /** * Get a configured instance of Xml2Xholon. * @return */ public IXml2Xholon getXml2Xholon() { //String className = "org.primordion.xholon.io.xml.Xml2Xholon"; IXml2Xholon xml2Xholon = new org.primordion.xholon.io.xml.Xml2Xholon(); /* //xml2Xholon = new Xml2Xholon(); try { xml2Xholon = (IXml2Xholon)Class.forName(className).newInstance(); } catch (InstantiationException e) { logger.error("Unable to instatiate optional Xml2Xholon class {}", e); } catch (IllegalAccessException e) { logger.error("Unable to load optional Xml2Xholon class {}", e); } catch (ClassNotFoundException e) { logger.error("Unable to load optional Xml2Xholon class " + className); } catch (NoClassDefFoundError e) { logger.error("Unable to load optional Xml2Xholon class {}", e); }*/ IApplication app = getApp(); if (app == null) { return null; } if (xml2Xholon != null) { xml2Xholon.setInheritanceHierarchy(app.getInherHier()); xml2Xholon.setTreeNodeFactory(app.getFactory()); xml2Xholon.setApp(app); } return xml2Xholon; } /** * Get a new instance of Xholon2Xml. * @return */ public IXholon2Xml getXholon2Xml() { //String className = "org.primordion.xholon.io.xml.Xholon2Xml"; IXholon2Xml xholon2Xml = new org.primordion.xholon.io.xml.Xholon2Xml(); /*try { xholon2Xml = (IXholon2Xml)Class.forName(className).newInstance(); } catch (InstantiationException e) { logger.error("Unable to instatiate optional Xholon2Xml class {}", e); } catch (IllegalAccessException e) { logger.error("Unable to load optional Xholon2Xml class {}", e); } catch (ClassNotFoundException e) { logger.error("Unable to load optional Xholon2Xml class " + className); } catch (NoClassDefFoundError e) { logger.error("Unable to load optional Xholon2Xml class {}", e); }*/ return xholon2Xml; } /* * @see org.primordion.xholon.base.IXholon#toXml(org.primordion.xholon.io.xml.IXholon2Xml, org.primordion.xholon.io.xml.XmlWriter) */ public void toXml(IXholon2Xml xholon2xml, IXmlWriter xmlWriter) { String localName = getXhcName(); String prefix = null; String namespaceUri = null; String nameTemplate = xholon2xml.getNameTemplate(); boolean isPrefixed = (this.getXhc() != null) && (this.getXhc().isPrefixed()); // write start element if (isPrefixed) { prefix = xhc.getPrefix(); // remove the prefix from the name int beginIndex = localName.indexOf(':'); if (beginIndex != -1) { localName = localName.substring(beginIndex + 1); } namespaceUri = xhc.getMechanism().getNamespaceUri(); xmlWriter.writeStartElement(prefix, localName, namespaceUri); } else { if (nameTemplate == null) { xmlWriter.writeStartElement(localName); } else { xmlWriter.writeStartElement(this.getName(nameTemplate)); } } // write attributes if (xholon2xml.isWriteAttributes()) { toXmlAttributes(xholon2xml, xmlWriter); } xholon2xml.writeSpecial(this); toXmlText(xholon2xml, xmlWriter); // write annotation if (xholon2xml.isWriteAnnotations()) { String ann = xholon2xml.findAnnotation(this); if (ann != null) { xmlWriter.writeStartElement("Annotation"); xmlWriter.writeText(ann); xmlWriter.writeEndElement("Annotation"); } } // write children IXholon childNode = getFirstChild(); while (childNode != null) { childNode.toXml(xholon2xml, xmlWriter); childNode = childNode.getNextSibling(); } // write end element if (isPrefixed) { xmlWriter.writeEndElement(localName, namespaceUri); } else { if (nameTemplate == null) { xmlWriter.writeEndElement(localName); } else { xmlWriter.writeEndElement(this.getName(nameTemplate)); } } } /* * @see org.primordion.xholon.base.IXholon#toXmlAttributes(org.primordion.xholon.io.xml.IXholon2Xml, org.primordion.xholon.io.xml.XmlWriter) */ public void toXmlAttributes(IXholon2Xml xholon2xml, IXmlWriter xmlWriter) { if (getXhc() == null) { // if the xhNode is itself a XholonClass node, then the XholonClass = null return; } if (xholon2xml.isWriteStandardAttributes()) { toXmlAttributes_standard(xholon2xml, xmlWriter); } if (xholon2xml.getXhAttrStyle() == IXholon2Xml.XHATTR_TO_NULL) { return; } // application specific attributes IReflection ir = ReflectionFactory.instance(); // get attributes that belong directly to the concrete Java class, excluding statics Object attribute[][] = ir.getAppSpecificAttributes(this, xholon2xml.getXhAttrReturnAll(), false, false); for (int i = 0; i < attribute.length; i++) { Class clazz = (Class) attribute[i][2]; if (clazz.isArray()) { // for now, ignore arrays continue; } // TODO for now, should ignore collections and anything else that is not a primitive String name = (String) attribute[i][0]; if (name == null) { continue; } if ("roleName".equalsIgnoreCase(name)) { continue; } else if ("uid".equalsIgnoreCase(name)) { continue; } else if ("uri".equalsIgnoreCase(name)) { continue; } Object value = attribute[i][1]; if (value == null) { continue; } // don't write attributes of type IXholon //if (IXholon.class.isAssignableFrom(value.getClass())) { if (ClassHelper.isAssignableFrom(Xholon.class, value.getClass())) { continue; } toXmlAttribute(xholon2xml, xmlWriter, name, value.toString(), clazz); } // handle other attributes, which were probably created as JavaScript properties if (xholon2xml.isWriteJavaScriptAttributes()) { IXholon xcs = getService(IXholonService.XHSRV_XHOLON_CREATION); if (xcs != null) { // exclude JavaScript variables that contain "$" IMessage msg = xcs.sendSyncMessage( ITreeNodeFactory.SIG_REPORT_EXTRA_ATTRS_IN_XHOLON_NODE_NO_DOLLAR_REQ, this, this); JavaScriptObject obj = (JavaScriptObject) msg.getData(); JSONObject jsonObj = new JSONObject(obj); if (jsonObj.size() > 0) { Set<String> keySet = jsonObj.keySet(); Iterator<String> jsIt = keySet.iterator(); while (jsIt.hasNext()) { String propName = jsIt.next(); String propValue = jsonObj.get(propName).toString(); if (propValue.startsWith("\"")) { // remove start and end double quote propValue = propValue.substring(1, propValue.length() - 1); } toXmlAttribute(xholon2xml, xmlWriter, propName, propValue, null); } } } } } /** * <p>Write the standard Xholon attributes to XML. * The standard attributes are:</p> * <ul> * <li>id (optional)</li> * <li>roleName (if a value exists)</li> * <li>uid (if a value exists)</li> * <li>ports (optional)</li> * </ul> * @param xholon2xml * @param xmlWriter The XML writer. */ protected void toXmlAttributes_standard(IXholon2Xml xholon2xml, IXmlWriter xmlWriter) { // standard Xholon attributes if (xholon2xml.isWriteXholonId()) { xmlWriter.writeAttribute("id", Integer.toString(getId())); } if (xholon2xml.isWriteXholonRoleName()) { String rnStr = getRoleName(); if (rnStr != null) { xmlWriter.writeAttribute("roleName", rnStr); } } String uidStr = getUid(); if (uidStr != null) { xmlWriter.writeAttribute("uid", uidStr); } if (xholon2xml.isWritePorts()) { List portList = getAllPorts(); for (int i = 0; i < portList.size(); i++) { PortInformation portInfo = (PortInformation) portList.get(i); xmlWriter.writeStartElement("port"); xmlWriter.writeAttribute("name", portInfo.getFieldName()); xmlWriter.writeAttribute("index", Integer.toString(portInfo.getFieldNameIndex())); String pathExpr = ""; IApplication thisApp = getApp(); //Application.getApplication(this); IApplication reffedApp = getApp().getApplicationOther(portInfo.getReffedNode()); if (thisApp != reffedApp) { // the port references a node in another IApplication pathExpr += reffedApp.getModelName(); } pathExpr += "#xpointer(//"; pathExpr += portInfo.getReffedNode().getXhcName(); pathExpr += "[@id='"; pathExpr += portInfo.getReffedNode().getId(); pathExpr += "'])"; xmlWriter.writeAttribute("connector", pathExpr); xmlWriter.writeEndElement("port"); } } } /* * @see org.primordion.xholon.base.IXholon#toXmlAttribute(org.primordion.xholon.io.xml.IXholon2Xml, org.primordion.xholon.io.xml.XmlWriter, java.lang.String, java.lang.String, java.lang.Class) */ public void toXmlAttribute(IXholon2Xml xholon2xml, IXmlWriter xmlWriter, String name, String value, Class clazz) { switch (xholon2xml.getXhAttrStyle()) { case IXholon2Xml.XHATTR_TO_XMLATTR: xmlWriter.writeAttribute(name, value); break; case IXholon2Xml.XHATTR_TO_XMLELEMENT: String attributeTag = getAttributeTag(clazz); xmlWriter.writeStartElement(attributeTag); xmlWriter.writeAttribute("roleName", name); xmlWriter.writeText(value); xmlWriter.writeEndElement(attributeTag); break; default: break; } } /* * @see org.primordion.xholon.base.IXholon#toXmlText(org.primordion.xholon.io.xml.IXholon2Xml, org.primordion.xholon.io.xml.IXmlWriter) */ public void toXmlText(IXholon2Xml xholon2xml, IXmlWriter xmlWriter) { // do nothing by default } @Override public String makeTextXmlEmbeddable(String str) { if (str == null) { return ""; } for (int i = 0; i < str.length(); i++) { switch (str.charAt(i)) { case '<': case '&': return "<![CDATA[" + str + "]]>"; default: break; } } return str; } /** * Get the type of XML Attribute tag that corresponds to a particular Java class. * TODO This method may return an invalid Xholon class name. * @param clazz A Java class. * @return A name of a subclass of the Xholon Attribute class. */ protected String getAttributeTag(Class clazz) { String thisClassName = clazz.getName(); thisClassName = thisClassName.substring(thisClassName.lastIndexOf('.') + 1); String tag = "Attribute_" + thisClassName; return tag; } public Object getAttributeXh(String name) { return ((XholonDirectoryService) getService(IXholonService.XHSRV_XHOLON_DIRECTORY)) .get(XholonDirectoryService.makeUniqueKey(this, name)); } public void setAttributeXh(String name, Object value) { ((XholonDirectoryService) getService(IXholonService.XHSRV_XHOLON_DIRECTORY)) .put(XholonDirectoryService.makeUniqueKey(this, name), value); } public void removeAttributeXh(String name) { ((XholonDirectoryService) getService(IXholonService.XHSRV_XHOLON_DIRECTORY)) .remove(XholonDirectoryService.makeUniqueKey(this, name)); } public boolean hasAttributeXh(String name) { return ((XholonDirectoryService) getService(IXholonService.XHSRV_XHOLON_DIRECTORY)) .containsKey(XholonDirectoryService.makeUniqueKey(this, name)); } public IAttribute getAttributeNodeXh(String name) { //Object obj = getAttributeXh(name); // TODO complete this; obj may be an Object, an IXholon, or an IAttribute // if possible use getXhc().hasAncestor() return null; } public void setAttributeNodeXh(IAttribute newAttr) { } public IAttribute removeAttributeNodeXh(IAttribute oldAttr) { return null; } /** * Two xholons are equal only if they are the same object. * @see java.lang.Object#equals(java.lang.Object) */ public boolean equals(Object obj) { return (this == obj); } /* * @see java.lang.Object#hashCode() */ //public int hashCode() //{ // return super.hashCode(); //} /** * Hashify this Xholon subtree. * This is intended to be used as a hash, to differentiate two trees, typically at two points in time. * The string is unique, while being as short as possible. * Note that there are many possibilities for what a stringify/hashify method might return. * TODO possibly have one method that returns a short hash-like value (hashify), * and another that returns a more human-readable value (stringify). * TODO for more hash possibilities, see: * http://stackoverflow.com/questions/1988665/hashing-a-tree-structure * @param type "sxpres" (default) or "newick" or null (for default) * @return a simple Newick-like string. * ((Height)Block,Brick,Brick)BlocksAndBricks; NO - can't tell the difference between the 2 Brick nodes * ((Height_3)Block_2,Brick_4,Brick_5)BlocksAndBricks_1; NO - too long, but OK for stringify * ((3)2,4,5)1; * ((),,); NO - need to differentiate between trees where siblings have moved * OR S-expression * (BlocksAndBricks(Block(Height) Brick Brick)) * (1 (2 (3) 4 5)) */ public String hashify(String type) { StringBuilder sb = new StringBuilder(); switch (type) { case "newick": hashifyNewick(this, sb); sb.append(";"); break; case "sxpres": default: sb.append("("); hashifySXpres(this, sb); sb.append(")"); break; } return sb.toString(); } /** * Recursively hashify a Xholon subtree, with output in a simple Newick format. * @param node A node in the Xholon hierarchy. * @param sb A StringBuilder instance. */ protected void hashifyNewick(IXholon node, StringBuilder sb) { if (node.hasChildNodes()) { sb.append("("); IXholon childNode = node.getFirstChild(); while (childNode != null) { hashifyNewick(childNode, sb); childNode = childNode.getNextSibling(); if (childNode != null) { sb.append(","); } } sb.append(")"); } sb.append(node.getId()); } /** * Recursively hashify a Xholon subtree, with output in a Lisp S-expression format. * @param node A node in the Xholon hierarchy. * @param sb A StringBuilder instance. */ protected void hashifySXpres(IXholon node, StringBuilder sb) { sb.append(node.getId()); if (node.hasChildNodes()) { sb.append(" ("); IXholon childNode = node.getFirstChild(); while (childNode != null) { hashifySXpres(childNode, sb); childNode = childNode.getNextSibling(); if (childNode != null) { sb.append(" "); } } sb.append(")"); } } /** * Process new items from a Meteor collection. * The Meteor collection acts like a queue. * @param collName */ @Override public void processMeteorQ(String collName) { IXholon meteorService = getService(IXholonService.XHSRV_METEOR_PLATFORM); if (meteorService != null) { //consoleLog("Xholon: processMeteorQ( " + collName); meteorService.processMeteorQ(collName); } } /** * Has the Meteor platform been loaded into the DOM? */ @Override public native boolean isExistsMeteor() /*-{ if ($wnd.Meteor) { var ready = $wnd.xh.param("ReadyForMeteor"); //$wnd.console.log(ready); if (ready == null) { // param("ReadyForMeteor") is not in use //$wnd.console.log("ready is null"); return true; } else if (ready == "true") { //$wnd.console.log("ready is true"); return true; } else { //$wnd.console.log("ready is else"); return false; } } else { return false; } }-*/; @Override public native String getColor() /*-{ if (typeof this.decoration == "undefined") {return null;} return this.decoration.color; }-*/; @Override public native void setColor(String color) /*-{ if (typeof this.decoration == "undefined") { this.decoration = {}; } this.decoration.color = color; if (color == null) {return;} // handle rgba(red,green,blue,alpha) example: "rgba(255,255,255,1.0)" if ((color.substring(0,5) == "rgba(") && (color.charAt(color.length-1) == ")")) { var arr = color.substring(5,color.length-1).split(","); if (arr.length == 4) { this.decoration.opacity = arr[3]; } } // handle #rrggbbaa example: "#FFFFFFFF" else if ((color.charAt(0) == "#") && (color.length == 9)) { var opacity = Number("0x" + color.substring(7,9)) / 255; this.decoration.opacity = opacity; } }-*/; @Override public native String getOpacity() /*-{ if (typeof this.decoration == "undefined") {return null;} return this.decoration.opacity; }-*/; @Override public native void setOpacity(String opacity) /*-{ if (typeof this.decoration == "undefined") { this.decoration = {}; } this.decoration.opacity = opacity; }-*/; @Override public native String getFont() /*-{ if (typeof this.decoration == "undefined") {return null;} return this.decoration.font; }-*/; @Override public native void setFont(String font) /*-{ if (typeof this.decoration == "undefined") { this.decoration = {}; } this.decoration.font = font; }-*/; @Override public native String getIcon() /*-{ if (typeof this.decoration == "undefined") {return null;} return this.decoration.icon; }-*/; @Override public native void setIcon(String icon) /*-{ if (typeof this.decoration == "undefined") { this.decoration = {}; } this.decoration.icon = icon; }-*/; @Override public native String getToolTip() /*-{ if (typeof this.decoration == "undefined") {return null;} return this.decoration.toolTip; }-*/; @Override public native void setToolTip(String toolTip) /*-{ if (typeof this.decoration == "undefined") { this.decoration = {}; } this.decoration.toolTip = toolTip; }-*/; @Override public native String getSymbol() /*-{ if (typeof this.decoration == "undefined") {return null;} return this.decoration.symbol; }-*/; @Override public native void setSymbol(String symbol) /*-{ if (typeof this.decoration == "undefined") { this.decoration = {}; } this.decoration.symbol = symbol; }-*/; @Override public native String getFormat() /*-{ if (typeof this.decoration == "undefined") {return null;} return this.decoration.format; }-*/; @Override public native void setFormat(String format) /*-{ if (typeof this.decoration == "undefined") { this.decoration = {}; } this.decoration.format = format; }-*/; @Override public native void setGeo(String geo) /*-{ if (typeof this.decoration == "undefined") { this.decoration = {}; } this.decoration.geo = geo; }-*/; @Override public native String getGeo() /*-{ if (typeof this.decoration == "undefined") {return null;} return this.decoration.geo; }-*/; @Override public native void setSound(String geo) /*-{ if (typeof this.decoration == "undefined") { this.decoration = {}; } this.decoration.sound = sound; }-*/; @Override public native String getSound() /*-{ if (typeof this.decoration == "undefined") {return null;} return this.decoration.sound; }-*/; @Override public native Object subtrees(String stNames) /*-{ if (stNames) { if (!this["subtrees"]) { this["subtrees"] = {}; } var arr = stNames.split(","); for (var i = 0; i < arr.length; i++) { var subtreeName = arr[i]; var existingNode = this.xpath(subtreeName); if (existingNode) { this["subtrees"][subtreeName] = existingNode.remove(); } else { //var node = this.action("build " + subtreeName).parent().last().remove(); // Avatar this.append("<" + subtreeName + "/>"); if (this.last()) { var node = this.last().remove(); this["subtrees"][subtreeName] = node; } } } } return this["subtrees"]; }-*/; @Override public native IXholon subtree(String stName) /*-{ if (stName && this["subtrees"] && this["subtrees"][stName]) { return this["subtrees"][stName]; } return null; }-*/; /* * @see java.lang.Object#toString() */ public String toString() { return getName(); } }