diff options
Diffstat (limited to 'src/com/memberwebs/ldapxml/helpers/LXSAXHandler.java')
-rw-r--r-- | src/com/memberwebs/ldapxml/helpers/LXSAXHandler.java | 447 |
1 files changed, 447 insertions, 0 deletions
diff --git a/src/com/memberwebs/ldapxml/helpers/LXSAXHandler.java b/src/com/memberwebs/ldapxml/helpers/LXSAXHandler.java new file mode 100644 index 0000000..fc3adab --- /dev/null +++ b/src/com/memberwebs/ldapxml/helpers/LXSAXHandler.java @@ -0,0 +1,447 @@ +package com.memberwebs.ldapxml.helpers; + +import java.util.*; + +import org.xml.sax.*; +import org.xml.sax.helpers.*; + +import com.memberwebs.ldapxml.*; + +/** + * Parses an XML file into an in memory LX map representation. + * + * @author nielsen@memberwebs.com + * @version 0.5 + */ +public class LXSAXHandler + extends DefaultHandler +{ + private static final String EL_ROOT = "lxmap"; + private static final String EL_ENTRY = "entry"; + private static final String EL_CLASS = "class"; + private static final String EL_ELEMENT = "element"; + private static final String EL_ATTRIBUTE = "attribute"; + private static final String EL_RENAME = "rename"; + private static final String EL_IGNORE = "ignore"; + private static final String AT_NAME = "name"; + private static final String AT_CLASS = "class"; + private static final String AT_MODE = "mode"; + private static final String AT_NAMESPACE = "namespace"; + private static final String AT_NS = "ns"; + private static final String AT_PLACE = "place"; + private static final String AT_HOOK = "hook"; + private static final String AT_ROOT = "root"; + private static final String VAL_INCLUSIVE = "inclusive"; + private static final String VAL_EXCLUSIVE = "exclusive"; + private static final String VAL_INLINE = "inline"; + private static final String VAL_BLOCK = "block"; + private static final String AT_VERSION = "version"; + private static final String VAL_VERSION = "1.0"; + + private static final String INTERNAL_ERROR = "LX Map parser invalid internal state"; + + + /** + * Constructs a new LXSAXHandler object. + */ + public LXSAXHandler() + { + m_elStack = new Stack(); + m_nameMap = new Hashtable(); + m_nameSet = null; + } + + /** + * Called at the start of the XML document. + */ + public void startDocument() + throws SAXException + { + m_cur = null; + m_root = null; + m_nameMap.clear(); + m_nameSet = new HashSet(); + } + + /** + * Called at the end of the XML document. + */ + public void endDocument() + throws SAXException + { + // The current LX object should be null as we're back + // to the root. If not then something went wrong. + if(m_cur != null) + throw new SAXException(new LXMapException(INTERNAL_ERROR)); + } + + + /** + * Called when a new element is encountered in the XML file. + * + * @param uri The element namespace + * @param localname The plain element name. + * @param qName The fully quallified element name. + * @param attributes The element's attributes. + */ + public void startElement(String uri, String localName, String qName, + Attributes attributes) + throws SAXException + { + try + { + // Push the current LX object on a stack so it can + // be popped as we encounter the end of elements. + + // Since null doesn't work with the collection classes + // we use 'this' to represent it. (See endElement) + if(m_cur == null) + m_elStack.push(this); + else + m_elStack.push(m_cur); + + // Now depending on what kind of LX Object we have around + // we hand of parsing to different functions. + if(m_cur == null) + { + rootHandler(uri, localName, qName, attributes); + } + else if(m_cur instanceof LXRoot) + { + entryHandler(uri, localName, qName, attributes); + } + else if(m_cur instanceof LXEntry) + { + if(!classHandler(uri, localName, qName, attributes)) + actionHandler(uri, localName, qName, attributes); + } + else if(m_cur instanceof LXClass) + { + if(!attributeHandler(uri, localName, qName, attributes)) + actionHandler(uri, localName, qName, attributes); + } + else if(m_cur instanceof LXAttribute) + { + actionHandler(uri, localName, qName, attributes); + } + else + throw new LXMapException(INTERNAL_ERROR); + + } + catch(LXMapException e) + { + throw new SAXException(e); + } + } + + /** + * Called when the end of an element is encountered. + * + * @param uri The namespace of this element. + * @param localName The plain name of this element. + * @param qName The fully qualified name of this element. + */ + public void endElement(String uri, String localName, String qName) + throws SAXException + { + // Add the current element to the naming stack + if(m_cur instanceof LXAttribute) + addName(m_cur); + + // Pop the current LX object off the stack + Object obj = m_elStack.pop(); + if(obj == null) + throw new SAXException(new LXMapException(INTERNAL_ERROR)); + + // If it's set to 'this' then it's actually + // 'null' (See startElement) + if(obj == this) + m_cur = null; + else + m_cur = (LXBase)obj; + } + + /** + * Handles elements at the root document level. + * + * @param uri The element namespace + * @param localname The plain element name. + * @param qName The fully quallified element name. + * @param attributes The element's attributes. + * @return Returns true if element was processed. + */ + private boolean rootHandler(String uri, String localName, String qName, + Attributes attributes) + throws LXMapException + { + if(qName.equals(EL_ROOT)) + { + if(!attributes.getValue(AT_VERSION).equals(VAL_VERSION)) + throw new LXMapException("Invalid LX Map version"); + + m_root = new LXRoot(); + m_cur = m_root; + + nameAttrHandler(attributes, AT_ROOT); + commonAttrHandler(attributes); + + + // Put some exceptions into the name map + m_nameMap.put("class", "objectClass"); + + String prefix = m_cur.getPrefix(); + if(prefix != null) + m_nameMap.put(prefix + ":class", "objectClass"); + + + return true; + } + + return false; + } + + /** + * Handles entry elements at the map root level. + * + * @param uri The element namespace + * @param localname The plain element name. + * @param qName The fully quallified element name. + * @param attributes The element's attributes. + * @return Returns true if element was processed. + */ + private boolean entryHandler(String uri, String localName, String qName, + Attributes attributes) + throws LXMapException + { + if(qName.equals(EL_ENTRY)) + { + LXEntry entry = new LXEntry(m_cur); + m_cur = entry; + nameAttrHandler(attributes, AT_CLASS); + commonAttrHandler(attributes); + return true; + } + + return false; + } + + /** + * Handles class elements at the map entry level. + * + * @param uri The element namespace + * @param localname The plain element name. + * @param qName The fully quallified element name. + * @param attributes The element's attributes. + * @return Returns true if element was processed. + */ + private boolean classHandler(String uri, String localName, String qName, + Attributes attributes) + throws LXMapException + { + if(qName.equals(EL_CLASS)) + { + LXClass cls = new LXClass(m_cur); + m_cur = cls; + nameAttrHandler(attributes, null); + commonAttrHandler(attributes); + classAttrHandler(attributes); + return true; + } + + return false; + } + + /** + * Handles attribute elements at the map class level. + * + * @param uri The element namespace + * @param localname The plain element name. + * @param qName The fully quallified element name. + * @param attributes The element's attributes. + * @return Returns true if element was processed. + */ + private boolean attributeHandler(String uri, String localName, String qName, + Attributes attributes) + throws LXMapException + { + if(qName.equals(EL_ATTRIBUTE)) + { + LXAttribute attr = new LXAttribute(m_cur, false); + m_cur = attr; + nameAttrHandler(attributes, null); + return true; + } + else if(qName.equals(EL_ELEMENT)) + { + LXAttribute attr = new LXAttribute(m_cur, true); + m_cur = attr; + nameAttrHandler(attributes, null); + return true; + } + + return false; + } + + /** + * Handles action elements at various levels. + * + * @param uri The element namespace + * @param localname The plain element name. + * @param qName The fully quallified element name. + * @param attributes The element's attributes. + * @return Returns true if element was processed. + */ + private boolean actionHandler(String uri, String localName, String qName, + Attributes attributes) + throws LXMapException + { + if(qName.equals(EL_IGNORE)) + { + m_cur.m_isUseable = false; + return true; + } + else if(qName.equals(EL_RENAME)) + { + m_cur.m_xmlName = attributes.getValue(AT_NAME); + + if(m_cur.m_xmlName == null) + throw new LXMapException("LX map element requires a '" + AT_NAME + "' attribute"); + } + + return false; + } + + /** + * Handles an element's name. + * + * @param attributes The element's attributes. + */ + private void nameAttrHandler(Attributes attributes, String attr) + throws LXMapException + { + if(attr == null) + attr = AT_NAME; + + m_cur.setName(attributes.getValue(attr)); + + if(m_cur.getName() == null) + throw new LXMapException("LX map element requires a '" + attr + "' attribute"); + } + + /** + * Handles an element's namespace and other basic info. + * + * @param attributes The element's attributes. + */ + private void commonAttrHandler(Attributes attributes) + throws LXMapException + { + m_cur.m_nameSpace = attributes.getValue(AT_NAMESPACE); + m_cur.m_ns = attributes.getValue(AT_NS); + m_cur.m_hook = attributes.getValue(AT_HOOK); + } + + /** + * Handles various attributes for class elements. + * + * @param attributes The element's attributes. + */ + private void classAttrHandler(Attributes attributes) + throws LXMapException + { + if(!(m_cur instanceof LXClass)) + throw new LXMapException(INTERNAL_ERROR); + + LXClass cls = (LXClass)m_cur; + + String inc = attributes.getValue(AT_MODE); + if(inc == null || inc.equals(VAL_EXCLUSIVE)) + { + cls.m_isInclusive = false; + } + else if(inc.equals(VAL_INCLUSIVE)) + { + // We don't know the list of names + m_nameSet = null; + cls.m_isInclusive = true; + } + else + throw new LXMapException("LX map invalid value for '" + AT_MODE + "' attribute"); + + String place = attributes.getValue(AT_PLACE); + if(place != null) + { + if(place.equals(VAL_INLINE)) + cls.m_isInline = true; + else if(place.equals(VAL_BLOCK)) + cls.m_isInline = false; + else + throw new LXMapException("LX map invalid value for '" + AT_PLACE + "' attribute"); + } + } + + /** + * Get the root of the resulting LX map. + * + * @return The root of the map. + */ + public final LXRoot getRoot() + { + return m_root; + } + + /** + * Get public (XML) to private (LDAP) name mappings + * for the first entry. + * + * @return The name map. + */ + public final Map getNameMap() + { + return m_nameMap; + } + + /** + * Gets a listing of the minimum set of attributes required + * to satisfy this map, or null when not known + */ + public final Set getNameSet() + { + return m_nameSet; + } + + /** + * Add an LX object to the name map. This adds both + * the prefixed name as well as the local name. + * + * @param base The LX object whose name to add. + */ + private void addName(LXBase base) + { + String name = base.getName(); + if(base.m_xmlName != null && !m_nameMap.contains(base.m_xmlName)) + m_nameMap.put(base.m_xmlName, name); + + String xmlName = base.getXmlName(); + if(xmlName != null && !m_nameMap.contains(xmlName)) + m_nameMap.put(xmlName, name); + + if(m_nameSet != null) + m_nameSet.add(name); + } + + // The root of the map being built + private LXRoot m_root; + + // The current LX map object being acted on. + private LXBase m_cur; + + // Stack of LX objects + private Stack m_elStack; + + // public (XML) to private (LDAP) name mappings + private Hashtable m_nameMap; + + // All the LDAP attributes required for this map + private HashSet m_nameSet; +}
\ No newline at end of file |