summaryrefslogtreecommitdiff
path: root/src/com/memberwebs/ldapxml/map/LXSAXHandler.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/memberwebs/ldapxml/map/LXSAXHandler.java')
-rw-r--r--src/com/memberwebs/ldapxml/map/LXSAXHandler.java488
1 files changed, 488 insertions, 0 deletions
diff --git a/src/com/memberwebs/ldapxml/map/LXSAXHandler.java b/src/com/memberwebs/ldapxml/map/LXSAXHandler.java
new file mode 100644
index 0000000..d81c240
--- /dev/null
+++ b/src/com/memberwebs/ldapxml/map/LXSAXHandler.java
@@ -0,0 +1,488 @@
+/*
+ * Copyright (c) 2004, Nate Nielsen
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ *
+ * CONTRIBUTORS
+ * Nate Nielsen <nielsen@memberwebs.com>
+ *
+ */
+
+package com.memberwebs.ldapxml.map;
+
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Set;
+import java.util.Stack;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+
+/**
+ * Parses an XML file into an in memory LX map representation.
+ *
+ * @author nielsen@memberwebs.com
+ * @version 0.5
+ */
+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";
+
+ // The root of the map being built
+ private LXMap m_map;
+
+ // 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;
+
+ /**
+ * 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_map = 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 LXMap)
+ {
+ 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_map = new LXMap(m_nameMap, m_nameSet);
+ m_cur = m_map;
+
+ 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 resulting LX Map.
+ *
+ * @return The map.
+ */
+ public final LXMap getMap()
+ {
+ return m_map;
+ }
+
+ /**
+ * 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);
+ }
+}