/*
* 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.xsi;
import java.net.URI;
import org.geotools.xml.XSIElementHandler;
import org.geotools.xml.handlers.XMLTypeHelper;
import org.geotools.xml.schema.Element;
import org.geotools.xml.schema.ElementGrouping;
import org.geotools.xml.schema.Type;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
/**
* ElementTypeHandler purpose.
*
* <p>
* Represtents an 'element' declaration.
* </p>
*
* @author dzwiers, Refractions Research, Inc. http://www.refractions.net
* @author $Author:$ (last modification)
* @source $URL$
* @version $Id$
*/
public class ElementTypeHandler extends ElementGroupingHandler {
/** 'element' */
public final static String LOCALNAME = "element";
/** UNBOUNDED */
private static int offset = 0;
private String id;
private String name;
private String type;
private String ref = null;
private String defaulT;
private String fixed;
private String substitutionGroup;
private int maxOccurs = 1;
private int minOccurs = 1;
private int finaL;
private int block;
private boolean form;
private boolean abstracT;
private boolean nillable;
private Object child;
// private List constraints;
private int hashCodeOffset = getOffset();
private DefaultElement cache = null;
/*
* helper for hashCode()
*/
private static int getOffset() {
return offset++;
}
/**
* @see java.lang.Object#hashCode()
*/
public int hashCode() {
return (LOCALNAME.hashCode() * ((id == null) ? 1 : id.hashCode()) * ((ref == null)
? 1 : ref.hashCode()) * ((name == null) ? 1 : name.hashCode()))
+ hashCodeOffset;
}
/**
* @see org.geotools.xml.XSIElementHandler#getHandler(java.lang.String,
* java.lang.String)
*/
public XSIElementHandler getHandler(String namespaceURI, String localName)
throws SAXException {
if (SchemaHandler.namespaceURI.equalsIgnoreCase(namespaceURI)) {
// child types
//
// simpleType
if (SimpleTypeHandler.LOCALNAME.equalsIgnoreCase(localName)) {
SimpleTypeHandler sth = new SimpleTypeHandler();
if (child == null) {
child = sth;
} else {
throw new SAXNotRecognizedException(
"Extension may only have one 'simpleType' or 'complexType' declaration.");
}
return sth;
}
// complexType
if (ComplexTypeHandler.LOCALNAME.equalsIgnoreCase(localName)) {
ComplexTypeHandler sth = new ComplexTypeHandler();
if (child == null) {
child = sth;
} else {
throw new SAXNotRecognizedException(
"Extension may only have one 'simpleType' or 'complexType' declaration.");
}
return sth;
}
// TODO add constraint checking
// // ref
// if (UniqueHandler.LOCALNAME.equalsIgnoreCase(localName)) {
// UniqueHandler sth = new UniqueHandler();
// constraints.add(sth);
//
// return sth;
// }
//
// // key
// if (KeyHandler.LOCALNAME.equalsIgnoreCase(localName)) {
// KeyHandler sth = new KeyHandler();
// constraints.add(sth);
//
// return sth;
// }
//
// // key
// if (KeyrefHandler.LOCALNAME.equalsIgnoreCase(localName)) {
// KeyrefHandler sth = new KeyrefHandler();
// constraints.add(sth);
//
// return sth;
// }
}
return null;
}
/**
* @see org.geotools.xml.XSIElementHandler#startElement(java.lang.String,
* java.lang.String, org.xml.sax.Attributes)
*/
public void startElement(String namespaceURI, String localName,
Attributes atts) throws SAXException {
// abstract
String abstracT1 = atts.getValue("", "abstracT");
if (abstracT1 == null) {
abstracT1 = atts.getValue(namespaceURI, "abstracT");
}
if ((abstracT1 == null) || "".equalsIgnoreCase(abstracT1)) {
this.abstracT = false;
} else {
this.abstracT = Boolean.getBoolean(abstracT1);
}
// block
String block1 = atts.getValue("", "block");
if (block1 == null) {
block1 = atts.getValue(namespaceURI, "block");
}
this.block = ComplexTypeHandler.findBlock(block1);
// default
defaulT = atts.getValue("", "default");
if (defaulT == null) {
defaulT = atts.getValue(namespaceURI, "default");
}
// final
String finaL1 = atts.getValue("", "final");
if (finaL1 == null) {
finaL1 = atts.getValue(namespaceURI, "final");
}
this.finaL = ComplexTypeHandler.findFinal(finaL1);
// fixed
fixed = atts.getValue("", "fixed");
if (fixed == null) {
fixed = atts.getValue(namespaceURI, "fixed");
}
// form
String form1 = atts.getValue("", "form");
if (form1 == null) {
form1 = atts.getValue(namespaceURI, "form");
}
this.form = "qualified".equalsIgnoreCase(form1);
// id
id = atts.getValue("", "id");
if (id == null) {
id = atts.getValue(namespaceURI, "id");
}
// maxOccurs
String maxOccurs1 = atts.getValue("", "maxOccurs");
if (maxOccurs1 == null) {
maxOccurs1 = atts.getValue(namespaceURI, "maxOccurs");
}
if ((maxOccurs1 != null) && !"".equalsIgnoreCase(maxOccurs1)) {
if ("unbounded".equalsIgnoreCase(maxOccurs1)) {
this.maxOccurs = ElementGrouping.UNBOUNDED;
} else {
this.maxOccurs = Integer.parseInt(maxOccurs1);
}
} else {
this.maxOccurs = 1;
}
// minOccurs
String minOccurs1 = atts.getValue("", "minOccurs");
if (minOccurs1 == null) {
minOccurs1 = atts.getValue(namespaceURI, "minOccurs");
}
if ((minOccurs1 != null) && !"".equalsIgnoreCase(minOccurs1)) {
this.minOccurs = Integer.parseInt(minOccurs1);
} else {
this.minOccurs = 1;
}
// name
name = atts.getValue("", "name");
if (name == null) {
name = atts.getValue(namespaceURI, "name");
}
// nillable
String nillable1 = atts.getValue("", "nillable");
if (nillable1 == null) {
nillable1 = atts.getValue(namespaceURI, "nillable");
}
if ((nillable1 == null) || "".equalsIgnoreCase(nillable1)) {
this.nillable = false;
} else {
this.nillable = Boolean.valueOf(nillable1).booleanValue();
}
// ref
ref = atts.getValue("", "ref");
if (ref == null) {
ref = atts.getValue(namespaceURI, "ref");
}
// substitutionGroup
substitutionGroup = atts.getValue("", "substitutionGroup");
if (substitutionGroup == null) {
substitutionGroup = atts.getValue(namespaceURI, "substitutionGroup");
}
// type
type = atts.getValue("", "type");
if (type == null) {
type = atts.getValue(namespaceURI, "type");
}
if ((ref != null) || "".equalsIgnoreCase(ref)) {
if (!(((name == null) || "".equalsIgnoreCase(name))
&& ((type == null) || "".equalsIgnoreCase(type)))) {
throw new SAXException(
"Elements cannot have both a 'ref' and a 'name' + 'type' attribute");
}
name = type = ref;
}
}
/**
* @see org.geotools.xml.XSIElementHandler#getLocalName()
*/
public String getLocalName() {
return LOCALNAME;
}
/**
* <p>
* returns the element name
* </p>
*
*/
public String getName() {
return name;
}
/**
* @see org.geotools.xml.XSIHandlers.ElementGroupingHandler#compress(org.geotools.xml.XSIHandlers.SchemaHandler)
*/
protected ElementGrouping compress(SchemaHandler parent)
throws SAXException {
synchronized(this){
if (cache != null)
return cache;
cache = new DefaultElement();
}
cache.id = id;
cache.name = name;
cache.namespace = parent.getTargetNamespace();
cache.defaulT = defaulT;
cache.fixed = fixed;
cache.block = block;
cache.finaL = finaL;
cache.abstracT = abstracT;
cache.form = form;
cache.nillable = nillable;
cache.minOccurs = minOccurs;
cache.maxOccurs = maxOccurs;
if (substitutionGroup != null) {
cache.substitutionGroup = parent.lookUpElement(substitutionGroup);
}
if (child == null) {
cache.type = parent.lookUpType(type);
} else if (child instanceof SimpleTypeHandler) {
cache.type = ((SimpleTypeHandler) child).compress(parent);
} else {
cache.type = ((ComplexTypeHandler) child).compress(parent);
}
if (ref != null) {
Element e = parent.lookUpElement(ref);
if (e == null) {
throw new SAXException("Element '" + ref
+ "' was referenced and not found");
}
cache.name = e.getName();
cache.type = e.getType();
if ((defaulT == null) || "".equalsIgnoreCase(defaulT)) {
cache.defaulT = e.getDefault();
}
if ((fixed == null) || "".equalsIgnoreCase(fixed)) {
cache.fixed = e.getFixed();
}
if (block == 0) {
cache.block = e.getBlock();
}
if (finaL == 0) {
cache.finaL = e.getFinal();
}
cache.minOccurs = (minOccurs == 1) ? e.getMinOccurs() : minOccurs;
cache.maxOccurs = (maxOccurs == 1) ? e.getMaxOccurs() : maxOccurs;
if (substitutionGroup != null) {
cache.substitutionGroup = e.getSubstitutionGroup();
}
}
// TODO add constraint checking
return cache;
}
/**
* @see org.geotools.xml.XSIElementHandler#getHandlerType()
*/
public int getHandlerType() {
return DEFAULT;
}
/**
* @see org.geotools.xml.XSIElementHandler#endElement(java.lang.String,
* java.lang.String)
*/
public void endElement(String namespaceURI, String localName){
// do nothing
}
/**
* <p>
* Default implementation of an element
* </p>
*
* @author dzwiers
*/
private static class DefaultElement implements Element {
int block;
int finaL;
boolean abstracT;
boolean form;
boolean nillable;
int maxOccurs;
int minOccurs;
String name;
String id;
String defaulT;
String fixed;
URI namespace;
Element substitutionGroup;
Type type;
/**
* @see org.geotools.xml.xsi.ElementGrouping#findChildElement(java.lang.String)
*/
public Element findChildElement(String name1) {
if (this.name != null) {
if (this.name.equalsIgnoreCase(name1)) {
return this;
}
}
return (type == null) ? null : type.findChildElement(name1);
}
/**
* @see org.geotools.xml.xsi.Element#isAbstract()
*/
public boolean isAbstract() {
return abstracT;
}
/**
* @see org.geotools.xml.xsi.Element#getBlock()
*/
public int getBlock() {
return block;
}
/**
* @see org.geotools.xml.xsi.Element#getDefault()
*/
public String getDefault() {
return defaulT;
}
/**
* @see org.geotools.xml.xsi.Element#getFinal()
*/
public int getFinal() {
return finaL;
}
/**
* @see org.geotools.xml.xsi.Element#getFixed()
*/
public String getFixed() {
return fixed;
}
/**
* @see org.geotools.xml.xsi.Element#isForm()
*/
public boolean isForm() {
return form;
}
/**
* @see org.geotools.xml.xsi.ElementGrouping#getMaxOccurs()
*/
public int getMaxOccurs() {
return maxOccurs;
}
/**
* @see org.geotools.xml.xsi.ElementGrouping#getMinOccurs()
*/
public int getMinOccurs() {
return minOccurs;
}
/**
* @see org.geotools.xml.xsi.Element#getLocalName()
*/
public String getName() {
return name;
}
/**
* @see org.geotools.xml.xsi.Element#isNillable()
*/
public boolean isNillable() {
return nillable;
}
/**
* @see org.geotools.xml.xsi.Element#getSubstitutionGroup()
*/
public Element getSubstitutionGroup() {
return substitutionGroup;
}
/**
* @see org.geotools.xml.xsi.Element#getBinding()
*/
public Type getType() {
return type;
}
public int getGrouping() {
return ELEMENT;
}
/**
* @see org.geotools.xml.xsi.Element#getId()
*/
public String getId() {
return id;
}
/**
* @see org.geotools.xml.schema.Element#getNamespace()
*/
public URI getNamespace() {
return namespace;
}
public Element findChildElement(String localName, URI namespaceURI) {
if (this.name != null) {
if (this.name.equalsIgnoreCase(localName) && getNamespace().equals(namespaceURI)) {
return this;
}
}
return (type == null) ? null : XMLTypeHelper.findChildElement(type, localName, namespaceURI);
}
}
}