All Downloads are FREE. Search and download functionalities are using the official Maven repository.

es.rickyepoderi.wbxml.definition.WbXmlDefinition Maven / Gradle / Ivy

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *    
 * Linking this library statically or dynamically with other modules 
 * is making a combined work based on this library. Thus, the terms and
 * conditions of the GNU General Public License cover the whole
 * combination.
 *    
 * As a special exception, the copyright holders of this library give 
 * you permission to link this library with independent modules to 
 * produce an executable, regardless of the license terms of these 
 * independent modules, and to copy and distribute the resulting 
 * executable under terms of your choice, provided that you also meet, 
 * for each linked independent module, the terms and conditions of the 
 * license of that module.  An independent module is a module which 
 * is not derived from or based on this library.  If you modify this 
 * library, you may extend this exception to your version of the 
 * library, but you are not obligated to do so.  If you do not wish 
 * to do so, delete this exception statement from your version.
 *
 * Project: github.com/rickyepoderi/wbxml-stream
 * 
 */
package es.rickyepoderi.wbxml.definition;

import es.rickyepoderi.wbxml.document.OpaqueAttributePlugin;
import es.rickyepoderi.wbxml.document.OpaqueContentPlugin;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

/**
 *
 * 

WBXML is a format that assigns several identifiers to different * elements of an XML (tags, attributes, values,...). This way when you try * to parse/encode any WBXML document you need to know the language you * are using. That language specification gives you those identifiers. * It is impossible to parse/encode a unknown language specification. This * class represents a Java representation of any WBXML language definition. * This definition is based on a properties file which needs to be * provided

* *

Basically a language definition is the following list of information * (some are optional fields):

* *
    *
  • name: A simple name to classify the language (for example SyncML 1.1).
  • *
  • publicId: WBXML format defines that each language should have a identifier * (numeric). 0x01 represents the unknown language (it does not have a standard * id).
  • *
  • Formal public Id: The formal name of the XML identifier, any XML definition * has a FPI (for example SyncML version 1.1 is -//SYNCML//DTD SyncML 1.1//EN). * This FPI is used in any DOCTYPE.
  • *
  • XML URI definition: The URL where the XMl definition for the language * can be obtained (again it appears in any DOCTYPE).
  • *
  • Root element: The root element for the language (in SyncML "SyncML" tag).
  • *
  • JAXB class: This optional field should be passed if the definition * has JAXB classes created for the language (using xjc for example).
  • *
  • Namespaces: The list of namespaces the language manages (a namespace * is the uri and the prefix).
  • *
  • Tags: List of tags definition for the language (with the respective token * identifiers).
  • *
  • Attributes: List of attribute definition tokens.
  • *
  • Attribute values: List os attribute values definition tokens.
  • *
  • Extensions: List of extensions defined for this language.
  • *
  • Opaque plugins: List of opaque plugins used in opaque data representations.
  • *
  • Linked definitions: This is a non standard feature. Some definitions mix * some languages using opaques. This way definitions can have another linked * ones. The parsing/encoding methods use all of them.
  • *
* *

The properties file is parsed and an object of this kind is created * in order to parse or encode a WBXML document of this language. If the * language is not specified no WBXML document can be parsed or encoded.

* * @author ricky * @see WbXmlTagDef * @see WbXmlAttributeDef * @see WbXmlAttributeValueDef * @see WbXmlExtensionDef * @see OpaqueContentPlugin */ public class WbXmlDefinition { /** * The public ID for unknown type */ static public final long PUBLIC_ID_UNKNOWN = 0x01; /** * The public ID is defined in the STR_T table */ static public final long PUBLIC_ID_STR_T = 0x00; /** * The representative name of the definition language. */ private String name = null; /** * WBXML public identifier assigned to this language. */ private long publicId = 0L; /** * XML Formal Public ID. */ private String xmlPublicId = null; /** * URI used to download the DTD of the document. */ private String xmlUriRef = null; /** * Class used for JAXB if exists. */ private String clazz = null; /** * The tag used for root components. */ private WbXmlTagDef root = null; /** * Namespaces keyed by namespace uri. */ Map nsByNamespace = null; /** * Namespaces keyed by prefix. */ Map nsByPrefix = null; /** * Tags keyed by the token (token byte and page code). */ private Map tagsByToken = null; /** * Tags keyed by the prefixed name. */ private Map tagsByName = null; /** * Attributes keyed by the token. */ private Map attrsByToken = null; /** * Attributes keyed by the prefixed name. Cos an attribute can be * represented by several tokens (it depends on the value) a set is * used. */ private Map> attrsByName = null; private Map attrValuesByToken = null; private TreeSet attrValuesByValue = null; /** * Attribute values keyed by the token. */ private Map extsByToken = null; /** * Attributes keyed by the value. */ private TreeSet extsByValue = null; /** * Opaque plugins for attributes keyed by the token. */ private Map opaqueAttrByToken = null; /** * Opaque plugins for attributes keyed by the prefixed name. */ private Map opaqueAttrByName = null; /** * Opaque plugins for tags keyed by the token. */ private Map opaqueTagByToken = null; /** * Opaque plugins for tags keyed by the prefixed name. */ private Map opaqueTagByName = null; /** * Linked definitions for this one. */ private Map linkedDefinitions = null; /** * Constructor via name. * @param name The name of the specification */ protected WbXmlDefinition(String name) { this.name = name; nsByNamespace = new HashMap(); nsByPrefix = new HashMap(); tagsByToken = new HashMap(); tagsByName = new HashMap(); attrsByToken = new HashMap(); attrsByName = new HashMap>(); attrValuesByToken = new HashMap(); attrValuesByValue = new TreeSet(); extsByToken = new HashMap(); extsByValue = new TreeSet(); opaqueAttrByName = new HashMap(); opaqueAttrByToken = new HashMap(); opaqueTagByName = new HashMap(); opaqueTagByToken = new HashMap(); linkedDefinitions = new HashMap(); } /** * Constructor via name and public WBXML id. * @param name The name of the language * @param publicId The WBXML standard identifier for the language */ protected WbXmlDefinition(String name, long publicId) { this(name); this.publicId = publicId; } /** * Constructor via name, public WBXML id and XML Formal public id. * @param name The language name * @param publicId The WBXML identifier * @param xmlPublicId The XML formal identifier */ protected WbXmlDefinition(String name, long publicId, String xmlPublicId) { this(name, publicId); this.xmlPublicId = xmlPublicId; } /** * Constructor via name, public WBXML id, XML fornal id, teh DTD uri and root JAXB class. * @param name The name of the language. * @param publicId The WBXML identifier * @param xmlPublicId The XML formal identifier * @param xmlUriRef DTD uri for the xml * @param clazz The JAXB class that encapsulates the root element */ protected WbXmlDefinition(String name, long publicId, String xmlPublicId, String xmlUriRef, String clazz) { this(name, publicId, xmlPublicId); this.xmlUriRef = xmlUriRef; this.clazz = clazz; } /** * Getter for the name * @return The name of the language */ public String getName() { return name; } /** * Setter for the name * @param name The new name */ protected void setName(String name) { this.name = name; } /** * Getter for the WBXML public identifier * @return The identifier */ public long getPublicId() { return publicId; } /** * Setter for the WBXML public identifier * @param publicId The new identifier */ protected void setPublicId(long publicId) { this.publicId = publicId; } /** * Getter for the XML formal public identifier * @return The XML identifier */ public String getXmlPublicId() { return xmlPublicId; } /** * Setter for the XML formal public identifier * @param xmlPublicId Thw new identifier */ protected void setXmlPublicId(String xmlPublicId) { this.xmlPublicId = xmlPublicId; } /** * Getter for the DTD uri * @return The DTD uri */ public String getXmlUriRef() { return xmlUriRef; } /** * Setter for the DTD uri * @param xmlUriRef The new uri */ protected void setXmlUriRef(String xmlUriRef) { this.xmlUriRef = xmlUriRef; } /** * Setter for the root Tag, tag that represents the root element for the language. * @param root The root tag */ protected void setRoot(WbXmlTagDef root) { this.root = root; } /** * Setter using string instead of the complete tag definition. * @param root The new root */ protected void setRoot(String root) { this.root = this.tagsByName.get(root); } /** * getter for the root element of the language * @return The root tag */ public WbXmlTagDef getRoot() { return root; } /** * Getter of the root element but returning the name. * @return The root name */ public String getRootName() { return (root == null)? null : root.getNameWithPrefix(); } /** * Gettter for the class of the root element. * @return The JAXB class */ public String getClazz() { return clazz; } /** * Setter for the class. * @param clazz The new class */ protected void setClazz(String clazz) { this.clazz = clazz; } /** * Get the linked definitions for this definition. * @return The linked map of definitions (indexed by the name) */ protected Map getLinkedDefinitions() { return this.linkedDefinitions; } /** * Return the list of linked definitions of this one. * @return The list of linked definitions */ public Collection getLinkedDefs() { return this.linkedDefinitions.values(); } /** * It returns a linked definition for this one. * @param name The name of the linked def to get * @return the definition or null */ public WbXmlDefinition getLinkedDef(String name) { return this.linkedDefinitions.get(name); } /** * Add a new namespace to the list of namespaces managed by this * language definition. The methos adds it to both maps. * @param ns The new namespace to add */ protected void addNamespace(WbXmlNamespaceDef ns) { nsByNamespace.put(ns.getNamespace(), ns); nsByPrefix.put(ns.getPrefix(), ns); } /** * Add a new extension to the language definition. The method adds it * to both maps. * @param ext The new extension. */ protected void addExtension(WbXmlExtensionDef ext) { this.extsByValue.add(ext); this.extsByToken.put(ext.getToken(), ext); } /** * Add a new opaque plugin for attributes for this language definition. * The method adds it to both maps. * @param attr The attribute with a plugin associated * @param plugin The plugin */ protected void addOpaqueAttr(WbXmlAttributeDef attr, OpaqueAttributePlugin plugin) { this.opaqueAttrByName.put(attr.getNameWithPrefix(), plugin); this.opaqueAttrByToken.put(attr.getToken(), plugin); } /** * Add a new opaque plugin for tag. The methos adds it to both maps. * @param tag The tag with a plugin associated * @param plugin The plugin */ protected void addOpaqueTag(WbXmlTagDef tag, OpaqueContentPlugin plugin) { this.opaqueTagByName.put(tag.getNameWithPrefix(), plugin); this.opaqueTagByToken.put(tag.getToken(), plugin); } /** * Add a nerw Attribute definition to this language definition. The method * adds it to both maps. * @param attr The attribute to add */ protected void addAttr(WbXmlAttributeDef attr) { TreeSet set = this.attrsByName.get(attr.getNameWithPrefix()); if (set == null) { set = new TreeSet(); this.attrsByName.put(attr.getNameWithPrefix(), set); } set.add(attr); this.attrsByToken.put(attr.getToken(), attr); } /** * Add a new attribute value for this language definition. The method * adds it to both maps. * @param attrVal The attribute value to add */ protected void addAttrValue(WbXmlAttributeValueDef attrVal) { this.attrValuesByValue.add(attrVal); this.attrValuesByToken.put(attrVal.getToken(), attrVal); } /** * Add a new tag for this language definition. The method adds it to both maps. * @param tag The new tag to add */ protected void addTag(WbXmlTagDef tag) { this.tagsByName.put(tag.getNameWithPrefix(), tag); this.tagsByToken.put(tag.getToken(), tag); } /** * Method that compacts a attribute value using extensions and attribute * values. In WBXML the normal string attribute value can be compacted * using extensions or attribute values, this method search over the * definition to compact a normal string value into a list of them * that matches with a attribute value or a extension. * @param value The value to compact * @return The list of string resulted after compactation */ public List compactAttributeValue(String value) { return compactAttributeValue(value, 0); } /** * Private method that check if a extension or attribute value is found * in the value passed. If it is contained the string is splitted in three * possible parts (the part before the match, the matched string, and the * rest). Obviously the returned list is from one to three sized list. * If there is no match a null is returned. * @param value The value to search the string in * @param valueToFound The value (correspond from an extension or attribute value) to look for * @param start The start point to search (attribute values can start after 0). * @param attr true if attr, false if extension * @return The list of splitted strings or null */ private List matches(String value, String valueToFound, int start, boolean attr) { int pos = value.indexOf(valueToFound, start); if (pos >= 0) { List result = new ArrayList(); if (valueToFound.length() < 3 && (value.length() != valueToFound.length() - start)) { // if the extension is very short and it does not // substitite the whole string it is descarted result.add(value); return result; } // split the string into parts the value => three posible parts String firstPart = null; if (pos > 0) { firstPart = value.substring(0, pos); } String secondPart = value.substring(pos, pos + valueToFound.length()); String thirdPart = null; //System.err.println(pos + attrVal.getValue().length() + " > " + value.length()); if (pos + valueToFound.length() < value.length()) { thirdPart = value.substring(pos + valueToFound.length()); } if (firstPart != null && !firstPart.isEmpty()) { if (attr) { result.addAll(compactAttributeValue(firstPart, start)); } else { result.addAll(compactExtension(firstPart, start)); } } result.add(secondPart); if (thirdPart != null && !thirdPart.isEmpty()) { if (attr) { result.addAll(compactAttributeValue(thirdPart, 0)); } else { result.addAll(compactExtension(thirdPart, 0)); } } return result; } else { return null; } } /** * Recursive methodthe that searches for possible compaction matches of an * attribute value against the definition (attribute values or extensions * can be used to compact it). This method searches in a specified order, * first attribute values and then extension. In both larger definitions * are taken into account first. * @param value The attribute value to compact * @param start The start (cos an attribute can define a part of a value) * @return The list of string the value is compacted */ public List compactAttributeValue(String value, int start) { //System.err.println("compactAttributeValue: " + value + " " + start); List result = new ArrayList(); if (start > value.length()) { result.add(value); return result; } // search over all the values that are less than the specified value WbXmlAttributeValueDef valueDef = new WbXmlAttributeValueDef(value.substring(start), (byte) 0x0, (byte) 0x0); for (WbXmlAttributeValueDef attrVal : attrValuesByValue.tailSet(valueDef)) { //System.err.println("testing... " + attrVal.getValue()); List found = matches(value, attrVal.getValue(), start, true); if (found != null) { return found; } } // no matches => return same value result.add(value); return result; } /** * Similar method of compactAttributeValue but only uses extensions * (PCDATA inside a tag). * @param value The value to be compacted * @return The list of strings after compactation */ public List compactExtension(String value) { return compactExtension(value, 0); } /** * Similar method of the recursive version of compactAttributeValue. This * method searches over the extensions in order to compact the value * in a list of defined extensions. * @param value The value to be compacted * @param start The index of start * @return The string values compacted in several strings */ public List compactExtension(String value, int start) { //System.err.println("compactExtension: " + value + " " + start); List result = new ArrayList(); if (start > value.length()) { result.add(value); return result; } // search over all the values that are less than the specified value WbXmlExtensionDef extDef = new WbXmlExtensionDef(value.substring(start), (byte) 0x0); for (WbXmlExtensionDef ext : extsByValue.tailSet(extDef)) { //System.err.println("testing... " + ext.getValue()); List found = matches(value, ext.getValue(), start, false); if (found != null) { return found; } } // no matches => return same value result.add(value); return result; } /** * Method that locates an attribute in the language definition. WBXML * let define several tokens for the same attribute (different values), * so a set is returned. * @param name The prefixed attribute name * @return The set of attributes definied for the specified name or null */ public Set locateAttribute(String name) { return this.attrsByName.get(name); } /** * Locate the attribute using the attribute name and the value. Cos the * set is a TreeSet the better match is assured (the longer value, the * better). * @param name The prefixed attribute name * @param value The value of the attribute * @return The attribute definition for this name and value */ public WbXmlAttributeDef locateAttribute(String name, String value) { TreeSet attrs = this.attrsByName.get(name); if (attrs != null) { for (WbXmlAttributeDef attr : attrs) { if (name.equals(attr.getNameWithPrefix()) && (attr.getValue() == null || value.startsWith(attr.getValue()))) { return attr; } } } return null; } /** * Method that locates an attribute using the token (page code and token byte). * @param pageCode The page code * @param token The byte token * @return The attribute definition or null */ public WbXmlAttributeDef locateAttribute(byte pageCode, byte token) { return attrsByToken.get(new WbXmlToken(pageCode, token)); } /** * Method that locates an attribute value using the value. * @param value The value of the attribute value * @return The attribute value definition or null */ public WbXmlAttributeValueDef locateAttributeValue(String value) { WbXmlAttributeValueDef attrVal = new WbXmlAttributeValueDef(value, (byte) 0x0, (byte) 0x0); WbXmlAttributeValueDef res = this.attrValuesByValue.ceiling(attrVal); if (res != null && res.getValue().equals(value)) { return res; } else { return null; } } /** * Method that locates an attribute value using the token. * @param pageCode The page code * @param token The attribute value token byte * @return The attribute value definition or null */ public WbXmlAttributeValueDef locateAttributeValue(byte pageCode, byte token) { return attrValuesByToken.get(new WbXmlToken(pageCode, token)); } /** * Method that locates an extension using the extension code. * TODO: The WBXML format defined a mb_u_int32 the extension but libwbxml * uses a single byte, maybe any language uses more than 255 extensions. * @param ext The extension code * @return The extension definition or null */ public WbXmlExtensionDef locateExtension(long ext) { // TODO: extensions are a long => why a byte in the definition => CHANGE!!! return extsByToken.get((byte) ext); } /** * Method that locates an extension in the language definition using its * value. * @param value The extension value. * @return The extension definition or null */ public WbXmlExtensionDef locateExtension(String value) { WbXmlExtensionDef ext = new WbXmlExtensionDef(value, (byte) 0x0); WbXmlExtensionDef res = this.extsByValue.ceiling(ext); if (res != null && res.getValue().equals(value)) { return res; } else { return null; } } /** * Method that locates a tag using the name. * @param name The prefixed name of the tag * @return The tag definition or null */ public WbXmlTagDef locateTag(String name) { return this.tagsByName.get(name); } /** * Method that searches over the linked definitions in order the * definition that handles a specified tag. It does not return current * definition. * @param name The prefixed name of the tag * @return The linked definition or null */ public WbXmlDefinition locateLinkedDefinitionForTag(String name) { for (WbXmlDefinition def: linkedDefinitions.values()) { if (def.locateTag(name) != null) { return def; } } return null; } /** * Method that locates a tag using the token (page code and tag token). * @param pageCode The page code * @param tag The tag token * @return The tag definiotn or null */ public WbXmlTagDef locateTag(byte pageCode, byte tag) { return this.tagsByToken.get(new WbXmlToken(pageCode, tag)); } /** * Method that locates a opaque plugin for an attribute. * @param name The prefixed name of the attribute * @return the plugin or null */ public OpaqueAttributePlugin locateAttrPlugin(String name) { return this.opaqueAttrByName.get(name); } /** * Method that locates an opaque tag plugin using the tag name. * @param tag The prefixed tag name. * @return The plugin or null if not defined */ public OpaqueContentPlugin locateTagPlugin(String tag) { return this.opaqueTagByName.get(tag); } /** * return the list of namespaces defined in the definition. * @return The list of namespaces defined in the language definition. */ public Collection getNamespaces() { return this.nsByNamespace.values(); } /** * Method that obtains the prefix of a namespace uri. Take in mind that * the definition needs prefixed names if the language uses namespaces. * @param namespaceURI The namespace uri * @return The prefix for this namespace uri or null if not exists */ public String getPrefix(String namespaceURI) { WbXmlNamespaceDef ns = this.nsByNamespace.get(namespaceURI); if (ns != null) { return ns.getPrefix(); } else { return null; } } /** * Utility method to obtain a prefix from all the possible definitions * in this definition. The method used all the definitions (the main one * and the linked). * @param namespaceURI The namespaceURI to locate a prefix from * @return The prefix or null */ public String getPrefixWithLinked(String namespaceURI) { String prefix = getPrefix(namespaceURI); if (prefix != null) { return prefix; } for (WbXmlDefinition def : linkedDefinitions.values()) { prefix = def.getPrefix(namespaceURI); if (prefix != null) { return prefix; } } return null; } /** * method that obtains the namespace uri of a prefix. * @param prefix The prefix * @return The namespace uri or null */ public String getNamespaceURI(String prefix) { WbXmlNamespaceDef ns = this.nsByPrefix.get(prefix); if (ns != null) { return ns.getNamespace(); } else { return null; } } /** * Utility method to obtain a namespaceURI from all the possible definitions * used in this definition. The method uses all the language definitions * includying the linked ones. * @param prefix The prefix of the namespaceURI to search * @return The namespaceURI or null */ public String getNamespaceURIWithLinked(String prefix) { String namespaceURI = getNamespaceURI(prefix); if (namespaceURI != null) { return namespaceURI; } for (WbXmlDefinition def : linkedDefinitions.values()) { namespaceURI = def.getNamespaceURI(prefix); if (namespaceURI != null) { return namespaceURI; } } return null; } /** * Method that return the namespace definition for a specified prefix. * @param prefix The prefix * @return The namespace definition object */ public WbXmlNamespaceDef getNamespace(String prefix) { return this.nsByPrefix.get(prefix); } /** * String representation of a language definition. * @return The string representation */ @Override public String toString() { StringBuilder sb = new StringBuilder(this.getClass().getName()); sb.append(System.getProperty("line.separator")); sb.append("name: "); sb.append(name); sb.append(System.getProperty("line.separator")); sb.append("publicId: "); sb.append(publicId); sb.append(System.getProperty("line.separator")); sb.append("xmlPublicId: "); sb.append(xmlPublicId); sb.append(System.getProperty("line.separator")); sb.append("xmlUriRef: "); sb.append(xmlUriRef); sb.append(System.getProperty("line.separator")); sb.append("clazz: "); sb.append(clazz); sb.append(System.getProperty("line.separator")); sb.append("root: "); sb.append(root); sb.append("namespaces: "); sb.append(System.getProperty("line.separator")); for (WbXmlNamespaceDef ns: nsByPrefix.values()) { sb.append(ns.getPrefix()); sb.append(" -> "); sb.append(ns); } sb.append("tags:"); sb.append(System.getProperty("line.separator")); for (WbXmlTagDef tag: tagsByName.values()) { sb.append(tag); } sb.append("attributes: "); sb.append(System.getProperty("line.separator")); for (TreeSet attrs: attrsByName.values()) { for (WbXmlAttributeDef attr: attrs) { sb.append(attr); } } sb.append("values:"); sb.append(System.getProperty("line.separator")); for (WbXmlAttributeValueDef attrVal: attrValuesByValue) { sb.append(attrVal); } sb.append("extensions: "); sb.append(System.getProperty("line.separator")); for (WbXmlExtensionDef ext: extsByValue) { sb.append(ext); } sb.append("opaque attr plugins: "); sb.append(System.getProperty("line.separator")); for (WbXmlToken token: opaqueAttrByToken.keySet()) { sb.append(token); sb.append("->"); sb.append(opaqueAttrByToken.get(token).getClass().getName()); sb.append(System.getProperty("line.separator")); } sb.append("opaque tag plugins: "); sb.append(System.getProperty("line.separator")); for (WbXmlToken token: opaqueTagByToken.keySet()) { sb.append(token); sb.append("->"); sb.append(opaqueTagByToken.get(token).getClass().getName()); sb.append(System.getProperty("line.separator")); } sb.append("Linked definitions: "); sb.append(System.getProperty("line.separator")); for (WbXmlDefinition def: linkedDefinitions.values()) { sb.append(def.getName()); sb.append(System.getProperty("line.separator")); } return sb.toString(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy