Package org.geotools.xml.handlers

Source Code of org.geotools.xml.handlers.ComplexElementHandler$DefaultElementValue

/*
*    GeoTools - The Open Source Java GIS Toolkit
*    http://geotools.org
*
*    (C) 2004-2008, Open Source Geospatial Foundation (OSGeo)
*   
*    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;
*    version 2.1 of the License.
*
*    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.
*/
package org.geotools.xml.handlers;

import java.net.URI;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.naming.OperationNotSupportedException;

import org.geotools.xml.DocumentFactory;
import org.geotools.xml.XMLElementHandler;
import org.geotools.xml.schema.All;
import org.geotools.xml.schema.Any;
import org.geotools.xml.schema.Choice;
import org.geotools.xml.schema.ComplexType;
import org.geotools.xml.schema.Element;
import org.geotools.xml.schema.ElementGrouping;
import org.geotools.xml.schema.ElementValue;
import org.geotools.xml.schema.Group;
import org.geotools.xml.schema.Sequence;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;


/**
* <p>
* This class is intended to handle parsing an xml element from an instance
* document for elements who's type is both known and complex. This handler is
* used within the XMLSAXHandler to handle sax events generated by the  SAX
* parser.
* </p>
*
* @author dzwiers www.refractions.net
*
* @see ComplexType
*
*
* @source $URL$
*/
public class ComplexElementHandler extends XMLElementHandler {
   
    /** <code>serialVersionUID</code> field */
    private static final long serialVersionUID = ComplexElementHandler.class.hashCode();
   
    private ComplexType type; // saves casting all over
    private Element elem;
    private String text;
    private Attributes attr;
    private List elements;
    private Object value = null;
    private ElementHandlerFactory ehf;

    /**
     * Creates a new ComplexElementHandler object for Element  elem using
     * ElementHandlerFactory ehf.
     *
     * @param ehf ElementHandlerFactory
     * @param elem Element
     *
     * @throws SAXException
     */
    public ComplexElementHandler(ElementHandlerFactory ehf, Element elem)
        throws SAXException {
        this.ehf = ehf;

        if (elem == null) {
            logger.warning("ComplexType provided was null");
            throw new SAXException(new NullPointerException(
                    "ComplexType provided was null"));
        }

        this.elem = elem;

        try {
            type = (ComplexType) elem.getType();
        } catch (ClassCastException e) {
            logger.warning(e.toString());
            throw new SAXException(e);
        }
    }

    /**
     * @see org.geotools.xml.XMLElementHandler#getElement()
     */
    public Element getElement() {
        return elem;
    }

    /**
     * @see org.geotools.xml.XMLElementHandler#characters(java.lang.String)
     */
    public void characters(String text1) throws SAXException {
        if (type.isMixed()) {
            if (this.text != null) {
                this.text = this.text.concat(text1);
            } else {
                this.text = text1;
            }
        } else {
            if (!"".equals(text1.trim())) {
                if (type.getName() == null) {
                    throw new SAXException(
                        "This type may not have mixed content");
                }

                throw new SAXException("The " + type.getName()
                    + " type may not have mixed content");
            }
        }
    }

    /**
     * @param namespaceURI
     * @param localName
     * @param hints
     * @throws SAXException
     * @throws OperationNotSupportedException
     */
    public void endElement(URI namespaceURI, String localName, Map hints)
        throws OperationNotSupportedException, SAXException {
        text = (text == null) ? null : text.trim();
       
        if(hints == null){
            hints = new HashMap();
            hints.put(ElementHandlerFactory.KEY,ehf);
        }else{
            if(!hints.containsKey(ElementHandlerFactory.KEY))
                hints.put(ElementHandlerFactory.KEY,ehf);
        }

        if (elements == null) {
            if (type != null) {
                ElementValue[] vals;
        if(type.isMixed()){
          vals = new ElementValue[1];
                  vals[0] = new DefaultElementValue(null, text); // null is ok as
                      // this represents the mixed content
        }else{
          vals = new ElementValue[0];
        }
                value = type.getValue(elem, vals, attr, hints);
            } else {
                value = text;
            }

            return;
        }

        // validate the complex element ... throws an exception when it's been bad
        boolean validate = hints == null || !hints.containsKey(DocumentFactory.VALIDATION_HINT) ||
      hints.get(DocumentFactory.VALIDATION_HINT)==null || !(hints.get(DocumentFactory.VALIDATION_HINT) instanceof Boolean) ||
      ((Boolean)hints.get(DocumentFactory.VALIDATION_HINT)).booleanValue();
        if(validate)
          validateElementOrder();
       
        ElementValue[] vals = new ElementValue[elements.size()
            + (type.isMixed() ? 1 : 0)];

        for (int i = 0; i < elements.size(); i++) {
            XMLElementHandler xeh = (XMLElementHandler) elements.get(i);
            vals[i] = new DefaultElementValue(xeh.getElement(), xeh.getValue());
        }

        if (type.isMixed()) {
            vals[vals.length - 1] = new DefaultElementValue(null, text);

            // null is ok as this represents the mixed content
        }

        value = type.getValue(elem, vals, attr, hints);

        // clean memory
        attr = null;
        elements = null;
        text = null;
    }

    /*
     * This starts off the fun or checking element order for complex types
     * (note mixtures of All, Any, Choice, Element, Group, Sequence).
     *
     */
    private void validateElementOrder() throws SAXException {
        if ((elements == null) || (elements.size() == 0)) {
            // TODO ensure we have enough elements
            return;
        }

        int i = 0;
        int count =0;
        int[] i2 = new int[2];
        int cache = 0; // old pos.
        i2[1]=1;
        while(i<elements.size() && i2[1] == 1){
          i2[0] = i;
          i2[1] = 0;
            cache = i2[0];
            i2 = valid(type.getChild(), i);
            if( i2[1] == 0 && i == i2[0] ){
              // done running
              if (count < type.getChild().getMinOccurs()) {
                  StringBuffer buf = new StringBuffer();
                  buf.append("Too few elements for " );
                  buf.append( elem.getNamespace()+":"+elem.getName() );
                  buf.append( " (type = "+type.getName()+") " );
                  buf.append( ": " );
                  buf.append( count );
                  buf.append( " children, " );
                  buf.append( type.getChild().getMinOccurs() );
                  buf.append( " minOccurs" );               
                throw new SAXException( buf.toString() );
                }
            }else{
                if(cache == i2[0]){
                    // we have not progressed .. progress us
                    i = i2[0]+1;
                }else{
                    i = i2[0];
                }
              count++;
            }
        }
        if(count > type.getChild().getMaxOccurs()){
          StringBuffer buf = new StringBuffer();
          buf.append("Too many elements for " );
          buf.append( elem.getNamespace()+":"+elem.getName() );
          buf.append( " (type = "+type.getName()+") " );
          buf.append( ": " );
          buf.append( count );
          buf.append( " children, " );
          buf.append( type.getChild().getMaxOccurs() );
          buf.append( " maxOccurs" );                     
        throw new SAXException( buf.toString() );
        }

        if (i != elements.size()) {
          StringBuffer buf = new StringBuffer();
          buf.append("Invalid Element ordering for " );
          buf.append( elem.getNamespace()+":"+elem.getName() );
          buf.append( " (type = "+type.getName()+") " );
          buf.append( ". There were "+(elements.size()-i)+"elements which were unaccounted for" );             
        throw new SAXException( buf.toString() );
        }
    }

    /*
     * Generic validation method which simulates recursion, and avoids casting :)
     * The index is the starting index in the list of elements, for the particular
     * ElementGrouping. The last index matched is returned.
     */
    private int[] valid(ElementGrouping eg, int index) throws SAXException {
        if (eg == null) {
            return new int[]{index,1};
        }

        switch (eg.getGrouping()) {
        case ElementGrouping.SEQUENCE:
            int[] tmp = valid((Sequence) eg, index);
                        return tmp;

        case ElementGrouping.ALL:
            return valid((All) eg, index);

        case ElementGrouping.ANY:
            return valid((Any) eg, index);

        case ElementGrouping.CHOICE:
            return valid((Choice) eg, index);

        case ElementGrouping.GROUP:
            return valid((Group) eg, index);

        case ElementGrouping.ELEMENT:
            tmp = valid((Element) eg, index);
            return tmp;
        }

        return new int[]{index,1};
    }

    /*
     * Validates an All tag
     * @see valid(ElementGrouping)
     */
    private int[] valid(All all, int index) {
        Element[] elems = all.getElements();
        int[] r = new int[elems.length];

        for (int i = 0; i < r.length; i++)
            r[i] = 0;

        boolean c = true;
        int head = index;
        while (c) {
            c = false;

            for (int i = 0; i < elems.length; i++) {
                if (elems[i].getType().getName().equalsIgnoreCase(((XMLElementHandler) elements
                            .get(head)).getName())) {
                    r[i]++;
                    head++;
                    i = elems.length;
                    c = true;
                }
            }
        }

        for (int i = 0; i < r.length; i++) {
            if ((r[i] < elems[i].getMinOccurs())
                    || (r[i] > elems[i].getMaxOccurs())) {
                return new int[]{index,0};
            }
        }

        return new int[]{head,1};
    }

    /*
     * Validates an Any tag
     * @see valid(ElementGrouping)
     */
    private int[] valid(Any any, int index) {
        if (any.getNamespace().equals(((XMLElementHandler) elements.get(index)).getElement()
                                           .getType().getNamespace())) {
            return new int[]{index+1,1};
        }

        return new int[]{index,1};
    }

    /*
     * Validates an Choice tag
     * @see valid(ElementGrouping)
     */
    private int[] valid(Choice choice, int index) throws SAXException {
        ElementGrouping[] eg = choice.getChildren();

        if (eg == null) {
            return new int[]{index,1};
        }
       
        int i = 0; // choice child index;

        int end = index;
        int t = index;
        int count = 0;
        int t2[] = null;
        while(i<eg.length && end<elements.size()){
          t2 = valid(eg[i], t);
          if(t2[1] == 0 && t2[0] == t){// nothing, next
          // move along
          if(t2[0]>end && count>=eg[i].getMinOccurs() && count<=eg[i].getMaxOccurs())
            end = t2[0];
          count = 0;
          i++;
          t = index;
          }else{
            if(count==eg[i].getMaxOccurs()){
              // move along
              if(t2[0]>end && count>=eg[i].getMinOccurs())
                end = t2[0];
              count = 0;
              i++;
              t = index;
            }else{
              t = t2[0];
              if(t == elements.size()){
                end = t;
              }
              count++;
            }
        }
        }

        return new int[]{end,end==index?0:1};
    }

    /*
     * Validates an Group tag
     * @see valid(ElementGrouping)
     */
    private int[] valid(Group group, int index) throws SAXException {
        if (group.getChild() == null) {
            return new int[]{index,1};
        }

        return valid(group.getChild(), index);
    }

    /*
     * Validates an Element tag
     * @see valid(ElementGrouping)
     */
    private int[] valid(Element element, int index) {

      // does this element equate to the index in the doc?

        int[] r = null;
       
        XMLElementHandler indexHandler = null;
        if(index<elements.size()){
            indexHandler = ((XMLElementHandler) elements.get(index));
        }else{
            // not found :)
            return new int[]{index,0};
        }
       
        if(r ==null && (indexHandler == null || indexHandler.getElement() == null))
          return new int[]{index,0};
       
        if(r == null && indexHandler.getElement() == element)
          r =  new int[]{index+1,1};
       
        if(r == null && element.getName()==null)
          return new int[]{index,0};
       
        if(r == null && (element.getName()!=null && element.getName().equalsIgnoreCase(indexHandler.getName())))
          r =  new int[]{index+1,1};
        if(r == null && element.getName()!=null){
        Element e = indexHandler.getElement();
        while(r == null && e != null){
          if(element.getName().equalsIgnoreCase(e.getName())){
            r =  new int[]{index+1,1};
          }
          e = e.getSubstitutionGroup();
        }
        }
       
        if(r == null){
            r = new int[]{index,0};
        }
        return r;
    }

    /*
     * Validates a Sequence tag
     * @see valid(ElementGrouping)
     */
    private int[] valid(Sequence seq, int index) throws SAXException {
        ElementGrouping[] eg = seq.getChildren();

        if (eg == null) {
            return new int[]{index,1};
        }

        int tIndex = index; // top of element matching list
        int t = 0; // top of child list
       
        int count = 0; // used for n-ary at a single spot
        int i2[] = new int[2];
        while(t<eg.length && tIndex<elements.size()){
          i2 = valid(eg[t],tIndex); // new top element
          if(i2[1]==1){ // they matched
              if(tIndex==i2[0]){
                  // didn't more ahead ...
                  t++; // force next spot
                  count = 0; // reset
              }else{
                  count ++;
                  if(count<=eg[t].getMaxOccurs()){
                      tIndex = i2[0]; // store index
                  }else{
                      // error, so redo
                      if(eg[t].getMinOccurs()>count){
                          // not good
//System.out.println("Seq Failed");
                          return new int[]{index,0}; // not whole sequence
                      }
                      t++;
                      count=0; // next defined type
                  }
              }
          }else{
                // didn't match
               
          // move along and retest that spot
          if(eg[t].getMinOccurs()>count){
            // not good
//System.out.println("Seq Failed");
          return new int[]{index,0}; // not whole sequence
          }
          t++;
          count=0; // next defined type
          }
        }
//System.out.println("Seq index = "+tIndex+" Matched");
        return new int[]{tIndex,1};
    }

    /**
     *
     * TODO summary sentence for startElement ...
     *
     * @see org.geotools.xml.XMLElementHandler#startElement(java.net.URI, java.lang.String, org.xml.sax.Attributes)
     * @param namespaceURI
     * @param localName
     * @param attr1
     */
    public void startElement(URI namespaceURI, String localName, Attributes attr1) {
        this.attr = new AttributesImpl(attr1);
    }

    /**
     *
     * TODO summary sentence for getHandler ...
     *
     * @see org.geotools.xml.XMLElementHandler#getHandler(java.net.URI, java.lang.String, java.util.Map)
     * @param namespaceURI
     * @param localName
     * @param hints
     * @return XMLElementHandler
     * @throws SAXException
     */
    public XMLElementHandler getHandler(URI namespaceURI, String localName,
        Map hints) throws SAXException {
        if (elements == null) {
            elements = new LinkedList();
        }

        logger.finest("Starting search for element handler " + localName
            + " :: " + namespaceURI);

        Element e = XMLTypeHelper.findChildElement(type, localName, namespaceURI);
        if (e != null && namespaceURI.equals(e.getNamespace())){
            XMLElementHandler r = ehf.createElementHandler(e);

            if (type.cache(r.getElement(), hints)) {
                elements.add(r);
            }

            return r;
        }

        logger.finest("Checking the document schemas");

        XMLElementHandler r = ehf.createElementHandler(namespaceURI, localName);

        if (r != null) {
            if (type.cache(r.getElement(), hints)) {
                elements.add(r);
            }

            return r;
        }

        // validation?
        if(hints != null && hints.containsKey(DocumentFactory.VALIDATION_HINT)){
            Boolean valid = (Boolean)hints.get(DocumentFactory.VALIDATION_HINT);
            if(valid != null && !valid.booleanValue()){
                return new IgnoreHandler();
            }
        }
       
        throw new SAXException("Could not find element handler for "
            + namespaceURI + " : " + localName + " as a child of "
            + type.getName() + ".");
    }

    /**
     *
     * TODO summary sentence for getValue ...
     *
     * @see org.geotools.xml.XMLElementHandler#getValue()
     * @return Object
     */
    public Object getValue() {
        // endElement sets the value
        return value;
    }

    /**
     * @see org.geotools.xml.XMLElementHandler#getName()
     */
    public String getName() {
        return elem.getName();
    }
   
    /**
     * Remove the given XMLElementHandler from the Child-List
     * @param handler
     */
    public void removeElement(XMLElementHandler handler){
    if (elements != null){
      elements.remove(handler);
    }
  }
   
    /**
     * returns the Type of the Elementhandler
   * @return type
   */
  public ComplexType getType() {
    return type;
  }

    /**
     * <p>
     * Default Implementation used to pass values to type instances
     * </p>
     *
     * @author dzwiers
     *
     * @see ElementValue
     */
    private static class DefaultElementValue implements ElementValue {
        Element t;
        Object value;

        /**
         * Stores the two values for use within the specified type
         *
         * @param t Element
         * @param o String
         */
        public DefaultElementValue(Element t, Object o) {
            this.t = t;
            value = o;
        }

        /**
         *
         * TODO summary sentence for getElement ...
         *
         * @see org.geotools.xml.schema.ElementValue#getElement()
         * @return Element
         */
        public Element getElement() {
            return t;
        }

        /**
         *
         * TODO summary sentence for getValue ...
         *
         * @see org.geotools.xml.schema.ElementValue#getValue()
         * @return Object
         */
        public Object getValue() {
            return value;
        }
        /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    public String toString() {
      StringBuffer buf = new StringBuffer();
      if( t != null && t.toString() != null ){
        buf.append( t.toString() );       
      }
      else {
        buf.append( getClass().getName() );
      }
      buf.append("[");
      buf.append( value );
      buf.append("]");
      return buf.toString();
    }
    }
}
TOP

Related Classes of org.geotools.xml.handlers.ComplexElementHandler$DefaultElementValue

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.