001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2004-2006, GeoTools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: */
016: package org.geotools.xml.handlers.xsi;
017:
018: import java.net.URI;
019:
020: import org.geotools.xml.XSIElementHandler;
021: import org.geotools.xml.handlers.XMLTypeHelper;
022: import org.geotools.xml.schema.Element;
023: import org.geotools.xml.schema.ElementGrouping;
024: import org.geotools.xml.schema.Type;
025: import org.xml.sax.Attributes;
026: import org.xml.sax.SAXException;
027: import org.xml.sax.SAXNotRecognizedException;
028:
029: /**
030: * ElementTypeHandler purpose.
031: *
032: * <p>
033: * Represtents an 'element' declaration.
034: * </p>
035: *
036: * @author dzwiers, Refractions Research, Inc. http://www.refractions.net
037: * @author $Author:$ (last modification)
038: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/xml/src/main/java/org/geotools/xml/handlers/xsi/ElementTypeHandler.java $
039: * @version $Id: ElementTypeHandler.java 22266 2006-10-19 11:30:55Z acuster $
040: */
041: public class ElementTypeHandler extends ElementGroupingHandler {
042: /** 'element' */
043: public final static String LOCALNAME = "element";
044:
045: /** UNBOUNDED */
046: private static int offset = 0;
047: private String id;
048: private String name;
049: private String type;
050: private String ref = null;
051: private String defaulT;
052: private String fixed;
053: private String substitutionGroup;
054: private int maxOccurs = 1;
055: private int minOccurs = 1;
056: private int finaL;
057: private int block;
058: private boolean form;
059: private boolean abstracT;
060: private boolean nillable;
061: private Object child;
062:
063: // private List constraints;
064: private int hashCodeOffset = getOffset();
065: private DefaultElement cache = null;
066:
067: /*
068: * helper for hashCode()
069: */
070: private static int getOffset() {
071: return offset++;
072: }
073:
074: /**
075: * @see java.lang.Object#hashCode()
076: */
077: public int hashCode() {
078: return (LOCALNAME.hashCode()
079: * ((id == null) ? 1 : id.hashCode())
080: * ((ref == null) ? 1 : ref.hashCode()) * ((name == null) ? 1
081: : name.hashCode()))
082: + hashCodeOffset;
083: }
084:
085: /**
086: * @see org.geotools.xml.XSIElementHandler#getHandler(java.lang.String,
087: * java.lang.String)
088: */
089: public XSIElementHandler getHandler(String namespaceURI,
090: String localName) throws SAXException {
091: if (SchemaHandler.namespaceURI.equalsIgnoreCase(namespaceURI)) {
092: // child types
093: //
094: // simpleType
095: if (SimpleTypeHandler.LOCALNAME.equalsIgnoreCase(localName)) {
096: SimpleTypeHandler sth = new SimpleTypeHandler();
097:
098: if (child == null) {
099: child = sth;
100: } else {
101: throw new SAXNotRecognizedException(
102: "Extension may only have one 'simpleType' or 'complexType' declaration.");
103: }
104:
105: return sth;
106: }
107:
108: // complexType
109: if (ComplexTypeHandler.LOCALNAME
110: .equalsIgnoreCase(localName)) {
111: ComplexTypeHandler sth = new ComplexTypeHandler();
112:
113: if (child == null) {
114: child = sth;
115: } else {
116: throw new SAXNotRecognizedException(
117: "Extension may only have one 'simpleType' or 'complexType' declaration.");
118: }
119:
120: return sth;
121: }
122:
123: // TODO add constraint checking
124: // // ref
125: // if (UniqueHandler.LOCALNAME.equalsIgnoreCase(localName)) {
126: // UniqueHandler sth = new UniqueHandler();
127: // constraints.add(sth);
128: //
129: // return sth;
130: // }
131: //
132: // // key
133: // if (KeyHandler.LOCALNAME.equalsIgnoreCase(localName)) {
134: // KeyHandler sth = new KeyHandler();
135: // constraints.add(sth);
136: //
137: // return sth;
138: // }
139: //
140: // // key
141: // if (KeyrefHandler.LOCALNAME.equalsIgnoreCase(localName)) {
142: // KeyrefHandler sth = new KeyrefHandler();
143: // constraints.add(sth);
144: //
145: // return sth;
146: // }
147: }
148:
149: return null;
150: }
151:
152: /**
153: * @see org.geotools.xml.XSIElementHandler#startElement(java.lang.String,
154: * java.lang.String, org.xml.sax.Attributes)
155: */
156: public void startElement(String namespaceURI, String localName,
157: Attributes atts) throws SAXException {
158: // abstract
159: String abstracT1 = atts.getValue("", "abstracT");
160:
161: if (abstracT1 == null) {
162: abstracT1 = atts.getValue(namespaceURI, "abstracT");
163: }
164:
165: if ((abstracT1 == null) || "".equalsIgnoreCase(abstracT1)) {
166: this .abstracT = false;
167: } else {
168: this .abstracT = Boolean.getBoolean(abstracT1);
169: }
170:
171: // block
172: String block1 = atts.getValue("", "block");
173:
174: if (block1 == null) {
175: block1 = atts.getValue(namespaceURI, "block");
176: }
177:
178: this .block = ComplexTypeHandler.findBlock(block1);
179:
180: // default
181: defaulT = atts.getValue("", "default");
182:
183: if (defaulT == null) {
184: defaulT = atts.getValue(namespaceURI, "default");
185: }
186:
187: // final
188: String finaL1 = atts.getValue("", "final");
189:
190: if (finaL1 == null) {
191: finaL1 = atts.getValue(namespaceURI, "final");
192: }
193:
194: this .finaL = ComplexTypeHandler.findFinal(finaL1);
195:
196: // fixed
197: fixed = atts.getValue("", "fixed");
198:
199: if (fixed == null) {
200: fixed = atts.getValue(namespaceURI, "fixed");
201: }
202:
203: // form
204: String form1 = atts.getValue("", "form");
205:
206: if (form1 == null) {
207: form1 = atts.getValue(namespaceURI, "form");
208: }
209:
210: this .form = "qualified".equalsIgnoreCase(form1);
211:
212: // id
213: id = atts.getValue("", "id");
214:
215: if (id == null) {
216: id = atts.getValue(namespaceURI, "id");
217: }
218:
219: // maxOccurs
220: String maxOccurs1 = atts.getValue("", "maxOccurs");
221:
222: if (maxOccurs1 == null) {
223: maxOccurs1 = atts.getValue(namespaceURI, "maxOccurs");
224: }
225:
226: if ((maxOccurs1 != null) && !"".equalsIgnoreCase(maxOccurs1)) {
227: if ("unbounded".equalsIgnoreCase(maxOccurs1)) {
228: this .maxOccurs = ElementGrouping.UNBOUNDED;
229: } else {
230: this .maxOccurs = Integer.parseInt(maxOccurs1);
231: }
232: } else {
233: this .maxOccurs = 1;
234: }
235:
236: // minOccurs
237: String minOccurs1 = atts.getValue("", "minOccurs");
238:
239: if (minOccurs1 == null) {
240: minOccurs1 = atts.getValue(namespaceURI, "minOccurs");
241: }
242:
243: if ((minOccurs1 != null) && !"".equalsIgnoreCase(minOccurs1)) {
244: this .minOccurs = Integer.parseInt(minOccurs1);
245: } else {
246: this .minOccurs = 1;
247: }
248:
249: // name
250: name = atts.getValue("", "name");
251:
252: if (name == null) {
253: name = atts.getValue(namespaceURI, "name");
254: }
255:
256: // nillable
257: String nillable1 = atts.getValue("", "nillable");
258:
259: if (nillable1 == null) {
260: nillable1 = atts.getValue(namespaceURI, "nillable");
261: }
262:
263: if ((nillable1 == null) || "".equalsIgnoreCase(nillable1)) {
264: this .nillable = false;
265: } else {
266: this .nillable = Boolean.valueOf(nillable1).booleanValue();
267:
268: }
269:
270: // ref
271: ref = atts.getValue("", "ref");
272:
273: if (ref == null) {
274: ref = atts.getValue(namespaceURI, "ref");
275: }
276:
277: // substitutionGroup
278: substitutionGroup = atts.getValue("", "substitutionGroup");
279:
280: if (substitutionGroup == null) {
281: substitutionGroup = atts.getValue(namespaceURI,
282: "substitutionGroup");
283: }
284:
285: // type
286: type = atts.getValue("", "type");
287:
288: if (type == null) {
289: type = atts.getValue(namespaceURI, "type");
290: }
291:
292: if ((ref != null) || "".equalsIgnoreCase(ref)) {
293: if (!(((name == null) || "".equalsIgnoreCase(name)) && ((type == null) || ""
294: .equalsIgnoreCase(type)))) {
295: throw new SAXException(
296: "Elements cannot have both a 'ref' and a 'name' + 'type' attribute");
297: }
298:
299: name = type = ref;
300: }
301: }
302:
303: /**
304: * @see org.geotools.xml.XSIElementHandler#getLocalName()
305: */
306: public String getLocalName() {
307: return LOCALNAME;
308: }
309:
310: /**
311: * <p>
312: * returns the element name
313: * </p>
314: *
315: */
316: public String getName() {
317: return name;
318: }
319:
320: /**
321: * @see org.geotools.xml.XSIHandlers.ElementGroupingHandler#compress(org.geotools.xml.XSIHandlers.SchemaHandler)
322: */
323: protected ElementGrouping compress(SchemaHandler parent)
324: throws SAXException {
325:
326: synchronized (this ) {
327: if (cache != null)
328: return cache;
329: cache = new DefaultElement();
330: }
331:
332: cache.id = id;
333: cache.name = name;
334: cache.namespace = parent.getTargetNamespace();
335: cache.defaulT = defaulT;
336: cache.fixed = fixed;
337: cache.block = block;
338: cache.finaL = finaL;
339: cache.abstracT = abstracT;
340: cache.form = form;
341: cache.nillable = nillable;
342: cache.minOccurs = minOccurs;
343: cache.maxOccurs = maxOccurs;
344:
345: if (substitutionGroup != null) {
346: cache.substitutionGroup = parent
347: .lookUpElement(substitutionGroup);
348: }
349:
350: if (child == null) {
351: cache.type = parent.lookUpType(type);
352: } else if (child instanceof SimpleTypeHandler) {
353: cache.type = ((SimpleTypeHandler) child).compress(parent);
354: } else {
355: cache.type = ((ComplexTypeHandler) child).compress(parent);
356: }
357:
358: if (ref != null) {
359: Element e = parent.lookUpElement(ref);
360:
361: if (e == null) {
362: throw new SAXException("Element '" + ref
363: + "' was referenced and not found");
364: }
365:
366: cache.name = e.getName();
367: cache.type = e.getType();
368:
369: if ((defaulT == null) || "".equalsIgnoreCase(defaulT)) {
370: cache.defaulT = e.getDefault();
371: }
372:
373: if ((fixed == null) || "".equalsIgnoreCase(fixed)) {
374: cache.fixed = e.getFixed();
375: }
376:
377: if (block == 0) {
378: cache.block = e.getBlock();
379: }
380:
381: if (finaL == 0) {
382: cache.finaL = e.getFinal();
383: }
384:
385: cache.minOccurs = (minOccurs == 1) ? e.getMinOccurs()
386: : minOccurs;
387: cache.maxOccurs = (maxOccurs == 1) ? e.getMaxOccurs()
388: : maxOccurs;
389:
390: if (substitutionGroup != null) {
391: cache.substitutionGroup = e.getSubstitutionGroup();
392: }
393: }
394:
395: // TODO add constraint checking
396:
397: return cache;
398: }
399:
400: /**
401: * @see org.geotools.xml.XSIElementHandler#getHandlerType()
402: */
403: public int getHandlerType() {
404: return DEFAULT;
405: }
406:
407: /**
408: * @see org.geotools.xml.XSIElementHandler#endElement(java.lang.String,
409: * java.lang.String)
410: */
411: public void endElement(String namespaceURI, String localName) {
412: // do nothing
413: }
414:
415: /**
416: * <p>
417: * Default implementation of an element
418: * </p>
419: *
420: * @author dzwiers
421: */
422: private static class DefaultElement implements Element {
423: int block;
424: int finaL;
425: boolean abstracT;
426: boolean form;
427: boolean nillable;
428: int maxOccurs;
429: int minOccurs;
430: String name;
431: String id;
432: String defaulT;
433: String fixed;
434: URI namespace;
435: Element substitutionGroup;
436: Type type;
437:
438: /**
439: * @see org.geotools.xml.xsi.ElementGrouping#findChildElement(java.lang.String)
440: */
441: public Element findChildElement(String name1) {
442: if (this .name != null) {
443: if (this .name.equalsIgnoreCase(name1)) {
444: return this ;
445: }
446: }
447:
448: return (type == null) ? null : type.findChildElement(name1);
449: }
450:
451: /**
452: * @see org.geotools.xml.xsi.Element#isAbstract()
453: */
454: public boolean isAbstract() {
455: return abstracT;
456: }
457:
458: /**
459: * @see org.geotools.xml.xsi.Element#getBlock()
460: */
461: public int getBlock() {
462: return block;
463: }
464:
465: /**
466: * @see org.geotools.xml.xsi.Element#getDefault()
467: */
468: public String getDefault() {
469: return defaulT;
470: }
471:
472: /**
473: * @see org.geotools.xml.xsi.Element#getFinal()
474: */
475: public int getFinal() {
476: return finaL;
477: }
478:
479: /**
480: * @see org.geotools.xml.xsi.Element#getFixed()
481: */
482: public String getFixed() {
483: return fixed;
484: }
485:
486: /**
487: * @see org.geotools.xml.xsi.Element#isForm()
488: */
489: public boolean isForm() {
490: return form;
491: }
492:
493: /**
494: * @see org.geotools.xml.xsi.ElementGrouping#getMaxOccurs()
495: */
496: public int getMaxOccurs() {
497: return maxOccurs;
498: }
499:
500: /**
501: * @see org.geotools.xml.xsi.ElementGrouping#getMinOccurs()
502: */
503: public int getMinOccurs() {
504: return minOccurs;
505: }
506:
507: /**
508: * @see org.geotools.xml.xsi.Element#getName()
509: */
510: public String getName() {
511: return name;
512: }
513:
514: /**
515: * @see org.geotools.xml.xsi.Element#isNillable()
516: */
517: public boolean isNillable() {
518: return nillable;
519: }
520:
521: /**
522: * @see org.geotools.xml.xsi.Element#getSubstitutionGroup()
523: */
524: public Element getSubstitutionGroup() {
525: return substitutionGroup;
526: }
527:
528: /**
529: * @see org.geotools.xml.xsi.Element#getType()
530: */
531: public Type getType() {
532: return type;
533: }
534:
535: public int getGrouping() {
536: return ELEMENT;
537: }
538:
539: /**
540: * @see org.geotools.xml.xsi.Element#getId()
541: */
542: public String getId() {
543: return id;
544: }
545:
546: /**
547: * @see org.geotools.xml.schema.Element#getNamespace()
548: */
549: public URI getNamespace() {
550: return namespace;
551: }
552:
553: public Element findChildElement(String localName,
554: URI namespaceURI) {
555: if (this.name != null) {
556: if (this.name.equalsIgnoreCase(localName)
557: && getNamespace().equals(namespaceURI)) {
558: return this;
559: }
560: }
561:
562: return (type == null) ? null : XMLTypeHelper
563: .findChildElement(type, localName, namespaceURI);
564: }
565: }
566: }
|