📄 xmlkey.java
字号:
/*------------------------------------------------------------------------------Name: XmlKey.javaProject: xmlBlaster.orgCopyright: xmlBlaster.org, see xmlBlaster-LICENSE file------------------------------------------------------------------------------*/package org.xmlBlaster.engine.xml2java;import org.xmlBlaster.util.ReplaceVariable;import java.util.logging.Logger;import java.util.logging.Level;import org.xmlBlaster.util.XmlToDom;import org.xmlBlaster.util.XmlBlasterException;import org.xmlBlaster.util.def.ErrorCode;import org.xmlBlaster.util.I_MergeDomNode;import org.xmlBlaster.util.key.KeyData;import org.xmlBlaster.util.key.QueryKeyData;import org.xmlBlaster.util.key.MsgKeyData;import org.xmlBlaster.util.XmlNotPortable;import org.xmlBlaster.engine.ServerScope;import org.w3c.dom.NamedNodeMap;import org.w3c.dom.Attr;import java.util.Enumeration;/** * This class encapsulates the Message meta data and unique identifier. * <p /> * All XmlKey's have the same XML minimal structure:<p> * <pre> * <key oid="12345"/> * </pre> * or * <pre> * <key oid="12345"> * <!-- application specific tags --> * </key> * </pre> * * where oid is a unique key. * <p /> * A typical <b>publish</b> key could look like this:<br /> * <pre> * <key oid='4711' contentMime='text/xml'> * <AGENT id='192.168.124.20' subId='1' type='generic'> * <DRIVER id='FileProof' pollingFreq='10'> * </DRIVER> * </AGENT> * </key> * </pre> * <br /> * Note that the AGENT and DRIVER tags are application know how, which you have to supply.<br /> * A well designed xml hierarchy of your problem domain is essential for a proper working xmlBlaster * <p /> * A typical <b>subscribe</b> key could look like this:<br /> * <pre> * <key oid='4711' queryType='EXACT'/> * </pre> * <br /> * In this example you would subscribe on message 4711. * <p /> * A typical <b>subscribe</b> using XPath query syntax could look like this:<br /> * <pre> * <key oid='' queryType='XPATH'> * //DRIVER[@id='FileProof'] * </key> * </pre> * <br /> * In this example you would subscribe on all DRIVERs which have the attribute 'FileProof' * <p /> * A cluster query checking the <b>domain</b> attribute could look like this:<br /> * <pre> * <key oid='' queryType='DOMAIN' domain='RUGBY'/> * </pre> * <p /> * NOTE: The 'XPATH' query covers the 'DOMAIN' and 'EXACT' query, but is far slower. * Therefore you should try to use EXACT or in a cluster environment DOMAIN queries * first. * <br /> * More examples you find in xmlBlaster/src/dtd/XmlKey.xml * <p /> * * @see <a href="http://www.w3.org/TR/xpath" target="others">The W3C XPath specification</a> * @author xmlBlaster@marcelruff.info */public final class XmlKey{ private String ME = "XmlKey"; private ServerScope glob; private static Logger log = Logger.getLogger(XmlKey.class.getName()); private XmlToDom xmlToDom = null; public final int XML_TYPE = 0; // xml syntax public final int ASCII_TYPE = 1; // for trivial keys you can use a ASCII String (no XML) private int keyType = XML_TYPE; // XmlKey uses XML syntax (default) protected KeyData keyData; /** * A DOM tree containing exactly one (this) message to allow XPath subscriptions to check if this message matches * <pre> * <xmlBlaster> * <key oid='xx'> * ... * </key> * </xmlBlaster> * </pre> */ private org.w3c.dom.Document xmlKeyDoc = null;// Document with the root node /** * We need this query manager to allow checking if an existing XPath subscription matches this new message type. */ //private com.fujitsu.xml.omquery.DomQueryMgr queryMgr = null; /** * Parses given xml string * * @param The original key in XML syntax, for example:<br> * <pre><key oid="This is the unique attribute"></key></pre> */ public XmlKey(ServerScope glob, KeyData keyData) { this.glob = glob; this.keyData = keyData; } /** * Parses given xml string * * @param The original key in XML syntax, for example:<br> * <pre><key oid="This is the unique attribute"></key></pre> */ public XmlKey(ServerScope glob, String xmlKey_literal) throws XmlBlasterException { this.glob = glob; xmlKey_literal = xmlKey_literal.trim(); if (!xmlKey_literal.startsWith("<")) { keyType = ASCII_TYPE; // eg "Airport/Runway1/WindVeloc3" this.keyData = new MsgKeyData(glob); this.keyData.setOid(xmlKey_literal); // Works well with ASCII, but is switched off for the moment // perhaps we should make it configurable through a property file !!! // Example: xmlKey_literal="Airport.*" as a regular expression log.warning("Invalid XmlKey syntax, only XML syntax beginning with \"<\" is supported: '" + xmlKey_literal + "'"); Thread.dumpStack(); throw new XmlBlasterException(this.glob, ErrorCode.USER_ILLEGALARGUMENT, ME + " Invalid XmlKey syntax, only XML syntax beginning with \"<\" is supported"); } this.keyData = glob.getMsgKeyFactory().readObject(xmlKey_literal); } public KeyData getKeyData() { return this.keyData; } /** * @see KeyData#isDeadMessage() */ public final boolean isDeadMessage() throws XmlBlasterException { return this.keyData.isDeadMessage(); } /** * Access the literal ASCII xmlKey. * @return the literal ASCII xmlKey * @see #literal() */ public final String toString() { return toXml(); } /** * Access the literal ASCII xmlKey. * @return the literal ASCII xmlKey * @see #literal() */ public String toXml() { log.warning("Accessing raw xml key string"); Thread.dumpStack(); return this.keyData.toXml(); } /** * Access the literal XML-ASCII xmlKey. * <p /> * Note that this may vary from the original ASCII string:<br /> * When the key oid was generated locally, the literal string contains * this new generated oid as well. * @return the literal ASCII xmlKey */ public final String literal() { return this.keyData.toXml(); } /** * @deprecated use getOid() */ public final String getUniqueKey() { return this.keyData.getOid(); } /** * @deprecated use getOid() */ public final String getKeyOid() { return this.keyData.getOid(); } /** * Accessing the unique oid of <key oid="...">. * @return oid */ public final String getOid() { return this.keyData.getOid(); } public final String getContentMime() { return this.keyData.getContentMime(); } public final String getContentMimeExtended() { return this.keyData.getContentMimeExtended(); } public final String getDomain() { return this.keyData.getDomain(); } public final boolean isDefaultDomain() { return this.keyData.isDefaultDomain(); } /** * Messages starting with "_" are reserved for usage in plugins */ public final boolean isPluginInternal() { return this.keyData.isPluginInternal(); } /** * Messages starting with "__" are reserved for internal usage */ public final boolean isInternal() { return this.keyData.isInternal(); } public final boolean isAdministrative() { return this.keyData.isAdministrative(); } /** * Fills the DOM tree, and assures that a valid <key oid=""> is used. */ public org.w3c.dom.Node getRootNode() throws XmlBlasterException { loadDomTree(); return this.xmlToDom.getRootNode(); } /** * Fills the DOM tree, and assures that a valid <pre><key oid=""></pre> is used. */ private synchronized void loadDomTree() throws XmlBlasterException { if (this.xmlToDom != null) return; // DOM tree is already loaded if (keyType == ASCII_TYPE) return; // no XML -> no DOM this.xmlToDom = new XmlToDom(glob, this.keyData.toXml()); org.w3c.dom.Node node = this.xmlToDom.getRootNode(); // Finds the <key oid="..." queryType="..."> attributes, or inserts a unique oid if empty if (node == null) { log.severe("root node = null"); throw new XmlBlasterException(this.glob, ErrorCode.INTERNAL_ILLEGALARGUMENT, ME + " Internal", "root node = null"); } String nodeName = node.getNodeName(); if (!nodeName.equalsIgnoreCase("key")) { log.severe("The root node must be named \"key\"\n" + this.keyData.toXml()); throw new XmlBlasterException(this.glob, ErrorCode.USER_ILLEGALARGUMENT, ME+".WrongRootNode", "The root node must be named \"key\"\n" + this.keyData.toXml()); } NamedNodeMap attributes = node.getAttributes(); if (attributes != null && attributes.getLength() > 0) { int attributeCount = attributes.getLength(); for (int i = 0; i < attributeCount; i++) { Attr attribute = (Attr)attributes.item(i); if (attribute.getNodeName().equalsIgnoreCase("oid")) { //String val = attribute.getNodeValue(); attribute.setNodeValue(getOid()); } else if (attribute.getNodeName().equalsIgnoreCase("contentMime")) { //String contentMime = attribute.getNodeValue(); attribute.setNodeValue(getContentMime()); } else if (attribute.getNodeName().equalsIgnoreCase("contentMimeExtended")) { // String contentMimeExtended = attribute.getNodeValue(); attribute.setNodeValue(getContentMimeExtended()); } else if (attribute.getNodeName().equalsIgnoreCase("domain")) { // String domain = attribute.getNodeValue(); attribute.setNodeValue(getDomain()); } } } log.info("DOM parsed the XmlKey " + getOid()); } /** * Should be called by publish() to merge the local XmlKey DOM into the big xmlBlaster DOM tree */ public final void mergeRootNode(I_MergeDomNode merger) throws XmlBlasterException { loadDomTree(); // This domToXml() fixes JDK 1.5 adoptNode() bug with missing attribute value //log.error(ME, "DEBUG ONLY before merge: " + this.xmlToDom.domToXml("")); this.xmlToDom.mergeRootNode(merger); } /** * Allows to check if this xmlKey matches the given query. * @param queryKey An XmlKey object containing a query (XPATH, EXACT or DOMAIN) * @return true if this message key matches the query */ public final boolean match(QueryKeyData queryKey) throws XmlBlasterException { if (log.isLoggable(Level.FINE)) log.fine("Trying query=" + queryKey.toXml() + "\non key=" + literal()); if (queryKey.isDomain()) { if (queryKey.getDomain() == null) { log.warning("Your query is of type DOMAIN but you have not specified a domain: " + queryKey.toXml()); throw new XmlBlasterException(glob, ErrorCode.USER_QUERY_INVALID, ME, "Your query is of type DOMAIN but you have not specified a domain: " + queryKey.toXml()); } if (queryKey.getDomain().equals("*") || queryKey.getDomain().equals(getDomain())) { if (log.isLoggable(Level.FINE)) log.fine("Message oid='" + getOid() + "' matched for domain='" + getDomain() + "'."); return true; } } else if (queryKey.isExact()) { if (queryKey.getOid().equals(getOid())) { if (log.isLoggable(Level.FINE)) log.fine("Message oid='" + getOid() + "' matched."); return true; } } else if (queryKey.isXPath()) { if (match(queryKey.getQueryString())) { if (log.isLoggable(Level.FINE)) log.fine("Message oid='" + getOid() + "' matched with XPath query '" + queryKey.getQueryString() + "'"); return true; } } else { log.severe("Don't know queryType '" + queryKey.getQueryType() + "' for message oid='" + getOid() + "'. I'll return false for match."); return false; } if (log.isLoggable(Level.FINE)) log.fine("Message oid='" + getOid() + "' does not match with query"); return false; } /** * We need this to allow checking if an existing XPath subscription matches this new message type. * <p/> * Note that we manipulate the XML key and add a surrounding root node <xmlBlaster> * @param xpath The XPath query, check if it matches to this xmlKey * @return true if this message meta data matches the XPath query */ public final boolean match(String xpath) throws XmlBlasterException { String xmlKey_literal = this.keyData.toXml(); if (this.xmlKeyDoc == null) { try { if (log.isLoggable(Level.FINE)) log.fine("Creating tiny DOM tree and a query manager ..."); // Add the <xmlBlaster> root element ... String tmp = ReplaceVariable.replaceFirst(xmlKey_literal, "<key", "<xmlBlaster><key") + "</xmlBlaster>"; this.xmlKeyDoc = XmlToDom.parseToDomTree(glob, tmp); } catch (Exception e) { String text = "Problems building tiny key DOM tree\n" + xmlKey_literal + "\n for XPath subscriptions check: " + e.getMessage(); log.warning(text); throw new XmlBlasterException(glob, ErrorCode.USER_QUERY_INVALID, ME, text, e); } } try { Enumeration nodeIter = XmlNotPortable.getNodeSetFromXPath(xpath, this.xmlKeyDoc); if (nodeIter != null && nodeIter.hasMoreElements()) { log.info("XPath subscription '" + xpath + "' matches message '" + getKeyOid() + "'"); return true; } } catch (Exception e) { log.warning("XPath query '" + xpath + "' on tiny key DOM tree" + xmlKey_literal + "failed: " + e.getMessage()); throw new XmlBlasterException(glob, ErrorCode.USER_QUERY_INVALID, ME, "XPath query '" + xpath + "' on tiny key DOM tree" + xmlKey_literal + "failed", e); } if (log.isLoggable(Level.FINE)) log.fine("XPath subscription '" + xpath + "' does NOT match message '" + getKeyOid() + "'"); return false; } /** * After the existing XPath subscriptions have queried this message * we should release the DOM tree. */ public void cleanupMatch() { if (log.isLoggable(Level.FINE)) log.fine("Releasing tiny DOM tree"); this.xmlKeyDoc = null; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -