001: //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/trunk/src/org/deegree/io/datastore/schema/MappedGMLSchema.java $
002: /*---------------- FILE HEADER ------------------------------------------
003:
004: This file is part of deegree.
005: Copyright (C) 2001-2008 by:
006: EXSE, Department of Geography, University of Bonn
007: http://www.giub.uni-bonn.de/deegree/
008: lat/lon GmbH
009: http://www.lat-lon.de
010:
011: This library is free software; you can redistribute it and/or
012: modify it under the terms of the GNU Lesser General Public
013: License as published by the Free Software Foundation; either
014: version 2.1 of the License, or (at your option) any later version.
015:
016: This library is distributed in the hope that it will be useful,
017: but WITHOUT ANY WARRANTY; without even the implied warranty of
018: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
019: Lesser General Public License for more details.
020:
021: You should have received a copy of the GNU Lesser General Public
022: License along with this library; if not, write to the Free Software
023: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
024:
025: Contact:
026:
027: Andreas Poth
028: lat/lon GmbH
029: Aennchenstraße 19
030: 53177 Bonn
031: Germany
032: E-Mail: poth@lat-lon.de
033:
034: Prof. Dr. Klaus Greve
035: Department of Geography
036: University of Bonn
037: Meckenheimer Allee 166
038: 53115 Bonn
039: Germany
040: E-Mail: greve@giub.uni-bonn.de
041:
042: ---------------------------------------------------------------------------*/
043: package org.deegree.io.datastore.schema;
044:
045: import java.net.URI;
046: import java.util.Iterator;
047: import java.util.List;
048: import java.util.Properties;
049:
050: import org.deegree.datatypes.QualifiedName;
051: import org.deegree.datatypes.Types;
052: import org.deegree.framework.log.ILogger;
053: import org.deegree.framework.log.LoggerFactory;
054: import org.deegree.framework.xml.XMLParsingException;
055: import org.deegree.framework.xml.schema.ComplexTypeDeclaration;
056: import org.deegree.framework.xml.schema.ElementDeclaration;
057: import org.deegree.framework.xml.schema.SimpleTypeDeclaration;
058: import org.deegree.framework.xml.schema.XMLSchemaException;
059: import org.deegree.io.datastore.Datastore;
060: import org.deegree.io.datastore.DatastoreConfiguration;
061: import org.deegree.io.datastore.DatastoreException;
062: import org.deegree.io.datastore.DatastoreRegistry;
063: import org.deegree.io.datastore.idgenerator.IdGenerator;
064: import org.deegree.io.datastore.schema.MappedGMLId.IDPART_INFO;
065: import org.deegree.io.datastore.schema.content.MappingField;
066: import org.deegree.io.datastore.schema.content.MappingGeometryField;
067: import org.deegree.model.crs.CRSFactory;
068: import org.deegree.model.crs.CoordinateSystem;
069: import org.deegree.model.crs.UnknownCRSException;
070: import org.deegree.model.feature.schema.AbstractPropertyType;
071: import org.deegree.model.feature.schema.FeatureType;
072: import org.deegree.model.feature.schema.GMLSchema;
073: import org.deegree.model.feature.schema.PropertyType;
074: import org.deegree.model.feature.schema.UndefinedFeatureTypeException;
075: import org.deegree.ogcbase.CommonNamespaces;
076: import org.w3c.dom.Element;
077:
078: /**
079: * Represents a GML application schema document which is annotated with mapping (persistence)
080: * information.
081: *
082: * @author <a href="mailto:schneider@lat-lon.de">Markus Schneider </a>
083: * @author last edited by: $Author: apoth $
084: *
085: * @version $Revision: 9342 $, $Date: 2007-12-27 04:32:57 -0800 (Thu, 27 Dec 2007) $
086: */
087: public class MappedGMLSchema extends GMLSchema {
088:
089: private final static ILogger LOG = LoggerFactory
090: .getLogger(MappedGMLSchema.class);
091:
092: private static URI XSDNS = CommonNamespaces.XSNS;
093:
094: private MappedGMLSchemaDocument doc;
095:
096: private Datastore datastore;
097:
098: private boolean suppressXLinkOutput;
099:
100: private String namespacePrefix;
101:
102: private URI defaultSRS;
103:
104: private CoordinateSystem defaultCS;
105:
106: // TODO remove this hack (which is used to mark the first feature type as visible by default)
107: private boolean firstFeatureType = true;
108:
109: /**
110: * Creates a new <code>MappedGMLSchema</code> instance from the given parameters.
111: *
112: * @param targetNamespace
113: * @param simpleTypes
114: * @param complexTypes
115: * @param elementDeclarations
116: * @param namespacePrefix
117: * @param defaultSRS
118: * @param backendConfiguration
119: * @param suppressXLinkOutput
120: * @param doc
121: * @throws XMLParsingException
122: * @throws UnknownCRSException
123: * @throws XMLSchemaException
124: */
125: MappedGMLSchema(URI targetNamespace,
126: SimpleTypeDeclaration[] simpleTypes,
127: ComplexTypeDeclaration[] complexTypes,
128: ElementDeclaration[] elementDeclarations,
129: String namespacePrefix, URI defaultSRS,
130: DatastoreConfiguration backendConfiguration,
131: boolean suppressXLinkOutput, MappedGMLSchemaDocument doc)
132: throws XMLParsingException, UnknownCRSException {
133:
134: super (elementDeclarations, targetNamespace, simpleTypes,
135: complexTypes);
136:
137: this .doc = doc;
138: this .namespacePrefix = namespacePrefix;
139: this .defaultSRS = defaultSRS;
140: this .defaultCS = CRSFactory.create(defaultSRS.toString());
141: this .datastore = registerDatastore(backendConfiguration);
142: this .suppressXLinkOutput = suppressXLinkOutput;
143:
144: buildFeatureTypeMap(elementDeclarations);
145: buildSubstitutionMap(elementDeclarations);
146: resolveFeatureTypeReferences();
147: resolveTargetTables();
148: checkIdentityPartConsistency();
149:
150: try {
151: this .datastore.bindSchema(this );
152: } catch (DatastoreException e) {
153: LOG.logError(e.getMessage(), e);
154: throw new XMLParsingException(e.getMessage());
155: }
156: }
157:
158: /**
159: * Checks for all feature type definitions if it's featureIds 'identityPart' setting is valid:
160: * <ul>
161: * <li>if there is a direct fk from the feature's table to another feature table,
162: * 'identityPart' must be true</li>
163: * <li>if there is no explicit setting for the feature type, the implied setting is used,
164: * otherwise it is checked for validity</li>
165: * </ul>
166: *
167: * @throws XMLSchemaException
168: */
169: private void checkIdentityPartConsistency()
170: throws XMLSchemaException {
171: for (FeatureType ft : this .featureTypeMap.values()) {
172: MappedFeatureType mft = (MappedFeatureType) ft;
173: PropertyType[] properties = mft.getProperties();
174: for (int i = 0; i < properties.length; i++) {
175: MappedPropertyType property = (MappedPropertyType) properties[i];
176: if (property instanceof MappedFeaturePropertyType) {
177: MappedFeaturePropertyType featurePT = (MappedFeaturePropertyType) property;
178: TableRelation[] relations = featurePT
179: .getTableRelations();
180: if (relations.length == 1) {
181: if (relations[0].getFKInfo() == TableRelation.FK_INFO.fkIsToField) {
182: MappedFeatureType targetFT = featurePT
183: .getFeatureTypeReference()
184: .getFeatureType();
185: MappedGMLId id = targetFT.getGMLId();
186: if (id.getIdPartInfo() == IDPART_INFO.noIDInfo) {
187: String msg = "FeatureId for feature type '"
188: + targetFT.getName()
189: + "' has to be part of the feature's identity - feature table "
190: + "is a property of feature type '"
191: + mft.getName()
192: + "' and stores a fk.";
193: LOG.logInfo(msg);
194: } else if (id.getIdPartInfo() == IDPART_INFO.notIDPart) {
195: String msg = "Invalid schema annotation: "
196: + "FeatureId for feature type '"
197: + targetFT.getName()
198: + "' has to be part of the feature's identity - feature table "
199: + "is a property of feature type '"
200: + mft.getName()
201: + "' and stores a fk. Set 'identityPart' to true for "
202: + "feature type '"
203: + targetFT.getName() + "'.";
204: throw new XMLSchemaException(msg);
205: }
206: id.setIdentityPart(true);
207: }
208: }
209: }
210: }
211: }
212: }
213:
214: /**
215: * Retrieves a <code>Datastore</code> instance for the given configuration.
216: * <p>
217: * If a datastore with exactly the same configuration exists, the existing instance is returned.
218: *
219: * @param backendConfiguration
220: * @throws XMLSchemaException
221: */
222: private Datastore registerDatastore(
223: DatastoreConfiguration backendConfiguration)
224: throws XMLSchemaException {
225: Datastore datastore = DatastoreRegistry
226: .getDatastore(backendConfiguration);
227: if (datastore == null) {
228: try {
229: datastore = (Datastore) backendConfiguration
230: .getDatastoreClass().newInstance();
231: datastore.configure(backendConfiguration);
232: } catch (DatastoreException e) {
233: String msg = "Error configuring datastore with configuration '"
234: + backendConfiguration + "'.";
235: LOG.logError(msg, e);
236: throw new XMLSchemaException(msg, e);
237: } catch (Exception e) {
238: String msg = "Error instantiating datastore for class '"
239: + backendConfiguration.getDatastoreClass()
240: + "'.";
241: LOG.logError(msg, e);
242: throw new XMLSchemaException(msg, e);
243: }
244: try {
245: DatastoreRegistry.registerDatastore(datastore);
246: } catch (DatastoreException e) {
247: String msg = "Error registering datastore with configuration '"
248: + backendConfiguration + "'.";
249: LOG.logError(msg, e);
250: throw new XMLSchemaException(msg, e);
251: }
252: }
253: return datastore;
254: }
255:
256: /**
257: * Returns the underlying GML Application Schema document.
258: *
259: * @return the underlying GML Application Schema document
260: */
261: public MappedGMLSchemaDocument getDocument() {
262: return this .doc;
263: }
264:
265: /**
266: * Returns the {@link Datastore} instance that handles this schema.
267: *
268: * @return the Datastore instance that handles this schema
269: */
270: public Datastore getDatastore() {
271: return this .datastore;
272: }
273:
274: /**
275: * Returns whether GML output (of the associated datastore) will not use any XLinks.
276: *
277: * @return true, if the GML output will not use XLinks, false otherwise
278: */
279: public boolean suppressXLinkOutput() {
280: return this .suppressXLinkOutput;
281: }
282:
283: /**
284: * Returns the default SRS for all geometry properties in the schema.
285: *
286: * @return the default SRS for all geometry properties in the schema
287: */
288: public URI getDefaultSRS() {
289: return this .defaultSRS;
290: }
291:
292: /**
293: * Returns the default {@link CoordinateSystem} for all geometry properties in the schema.
294: *
295: * @return the default CoordinateSystem for all geometry properties in the schema
296: */
297: public CoordinateSystem getDefaultCS() {
298: return this .defaultCS;
299: }
300:
301: /**
302: * Looks up the <code>FeatureType</code> with the given <code>QualifiedName</code>.
303: *
304: * @param qName
305: * the QualifiedName to look up
306: * @return the FeatureType, if it is defined in the document, null otherwise
307: */
308: @Override
309: public MappedFeatureType getFeatureType(QualifiedName qName) {
310: return (MappedFeatureType) this .featureTypeMap.get(qName);
311: }
312:
313: /**
314: * Looks up the <code>FeatureType</code> with the given name.
315: *
316: * @param localName
317: * the name to look up
318: * @return the FeatureType, if it is defined in the document, null otherwise
319: */
320: @Override
321: public MappedFeatureType getFeatureType(String localName) {
322: return getFeatureType(new QualifiedName(localName,
323: getTargetNamespace()));
324: }
325:
326: /**
327: * Builds a {@link MappedFeatureType} from the given element declaration.
328: *
329: * @param element
330: * @return feature type with persistence information
331: * @throws XMLParsingException
332: * @throws UnknownCRSException
333: */
334: @Override
335: protected MappedFeatureType buildFeatureType(
336: ElementDeclaration element) throws XMLParsingException,
337: UnknownCRSException {
338:
339: LOG
340: .logDebug("Building (mapped) feature type from element declaration '"
341: + element.getName() + "'...");
342:
343: int visibleCode = -1;
344: boolean isVisible = false;
345: boolean isUpdatable = false;
346: boolean isDeletable = false;
347: boolean isInsertable = false;
348: QualifiedName name = new QualifiedName(this .namespacePrefix,
349: element.getName().getLocalName(), getTargetNamespace());
350: MappedComplexTypeDeclaration complexType = (MappedComplexTypeDeclaration) element
351: .getType().getTypeDeclaration();
352:
353: // extract mapping information from element annotation
354: Element annotationElement = ((MappedElementDeclaration) element)
355: .getAnnotation();
356: MappedGMLId gmlId = null;
357: String table = name.getLocalName().toLowerCase();
358: // use complexType annotation, if no element annotation present
359: if (annotationElement == null) {
360: annotationElement = complexType.getAnnotation();
361: }
362: // neither element nor complexType annotation, then use default mapping
363: if (annotationElement == null) {
364: LOG
365: .logInfo("Declaration of feature type '"
366: + name
367: + "' has no mapping information (annotation element). Defaulting to "
368: + "table name '"
369: + table
370: + "' and gmlId field 'fid' (not identity part).");
371: MappingField[] idFields = new MappingField[] { new MappingField(
372: table, "fid", Types.VARCHAR) };
373: IdGenerator idGenerator = IdGenerator.getInstance(
374: IdGenerator.TYPE_UUID, new Properties());
375: gmlId = new MappedGMLId(name.getLocalName().toUpperCase(),
376: "_", idFields, idGenerator, IDPART_INFO.noIDInfo);
377: } else {
378: gmlId = doc.extractGMLId(annotationElement, table);
379: table = gmlId.getIdFields()[0].getTable();
380: try {
381: visibleCode = doc.parseVisible(annotationElement);
382: isUpdatable = doc.parseIsUpdatable(annotationElement);
383: isDeletable = doc.parseIsDeletable(annotationElement);
384: isInsertable = doc.parseIsInsertable(annotationElement);
385: } catch (XMLParsingException e) {
386: throw new XMLSchemaException(e);
387: }
388: }
389:
390: ElementDeclaration[] subElements = complexType.getElements();
391: PropertyType[] properties = new PropertyType[subElements.length];
392: for (int i = 0; i < subElements.length; i++) {
393: MappedElementDeclaration subElement = (MappedElementDeclaration) subElements[i];
394: properties[i] = buildPropertyType(subElement, table);
395: }
396:
397: // default visibility for first feature type is true, for all others it's false
398: if (this .firstFeatureType) {
399: isVisible = true;
400: if (visibleCode == 0) {
401: isVisible = false;
402: }
403: this .firstFeatureType = false;
404: } else {
405: if (visibleCode == 1) {
406: isVisible = true;
407: }
408: }
409:
410: return new MappedFeatureType(name, element.isAbstract(),
411: properties, table, gmlId, this , isVisible, isUpdatable,
412: isDeletable, isInsertable);
413: }
414:
415: protected PropertyType buildPropertyType(
416: MappedElementDeclaration element, String table)
417: throws XMLParsingException, UnknownCRSException {
418:
419: AbstractPropertyType propertyType;
420: QualifiedName propertyName = new QualifiedName(
421: this .namespacePrefix, element.getName().getLocalName(),
422: getTargetNamespace());
423:
424: int minOccurs = element.getMinOccurs();
425: int maxOccurs = element.getMaxOccurs();
426:
427: QualifiedName typeName = element.getType().getName();
428: LOG
429: .logDebug("Building (mapped) property type from element declaration '"
430: + propertyName
431: + "', type='"
432: + typeName
433: + "'...");
434: int type = determinePropertyType(element);
435:
436: // extract mapping annotation
437: Element annotationElement = element.getAnnotation();
438:
439: // get identityPart information from annotation
440: int identityCode = -1;
441: if (annotationElement != null) {
442: identityCode = doc.parseIdentityPart(annotationElement);
443: }
444:
445: if (typeName.isInNamespace(XSDNS)) {
446: // simple property (basic xsd type)
447: if (annotationElement == null) {
448: LOG
449: .logDebug("Using default mapping for property type '"
450: + propertyName + "'.");
451: String field = propertyName.getLocalName()
452: .toLowerCase();
453: int typeCode = getDefaultSQLTypeForXSDType(typeName);
454: MappingField mappingField = new MappingField(table,
455: field, typeCode);
456: propertyType = new MappedSimplePropertyType(
457: propertyName, type, minOccurs, maxOccurs, true,
458: new TableRelation[0], mappingField);
459: } else {
460: LOG
461: .logDebug("Parsing mapping information for simple property type.");
462: boolean isIdentityPart = identityCode == 0 ? false
463: : true;
464: propertyType = doc.parseMappedSimplePropertyType(
465: annotationElement, propertyName, type,
466: minOccurs, maxOccurs, isIdentityPart, table);
467: }
468: } else {
469: switch (type) {
470: case Types.GEOMETRY: {
471: // geometry property
472: if (annotationElement == null) {
473: LOG
474: .logDebug("Using default mapping for property type '"
475: + propertyName + "'.");
476: String field = propertyName.getLocalName()
477: .toLowerCase();
478: MappingGeometryField mappingField = new MappingGeometryField(
479: table, field, Types.OTHER, -1);
480: propertyType = new MappedGeometryPropertyType(
481: propertyName, typeName, type, minOccurs,
482: maxOccurs, false, this .defaultSRS,
483: new TableRelation[0], mappingField);
484: } else {
485: LOG
486: .logDebug("Parsing mapping information for geometry property type.");
487: boolean isIdentityPart = identityCode == 1 ? true
488: : false;
489: propertyType = doc.parseMappedGeometryPropertyType(
490: annotationElement, propertyName, typeName,
491: type, minOccurs, maxOccurs, isIdentityPart,
492: table);
493: }
494: break;
495: }
496: case Types.FEATURE: {
497: // feature property
498: if (annotationElement == null) {
499: String msg = "Declaration of property type '"
500: + propertyName
501: + "' has no mapping information (annotation element missing).";
502: throw new XMLSchemaException(msg);
503: }
504: LOG
505: .logDebug("Parsing mapping information for feature property type.");
506: boolean isIdentityPart = identityCode == 0 ? false
507: : true;
508: boolean isReferenceType = "ReferenceType"
509: .equals(typeName.getLocalName());
510: propertyType = doc.parseMappedFeaturePropertyType(
511: annotationElement, propertyName, minOccurs,
512: maxOccurs, isIdentityPart, table,
513: isReferenceType);
514: break;
515: }
516: default: {
517: // no known namespace -> assume simple property with user defined simple type
518: // TODO check for inherited types
519:
520: if (annotationElement == null) {
521: LOG
522: .logDebug("Using default mapping for property type '"
523: + propertyName + "'.");
524: String field = propertyName.getLocalName()
525: .toLowerCase();
526: int typeCode = getDefaultSQLTypeForXSDType(typeName);
527: MappingField mappingField = new MappingField(table,
528: field, typeCode);
529: propertyType = new MappedSimplePropertyType(
530: propertyName, type, minOccurs, maxOccurs,
531: true, new TableRelation[0], mappingField);
532: } else {
533: LOG
534: .logDebug("Parsing mapping information for simple property type.");
535: boolean isIdentityPart = identityCode == 0 ? false
536: : true;
537: propertyType = doc
538: .parseMappedSimplePropertyType(
539: annotationElement, propertyName,
540: type, minOccurs, maxOccurs,
541: isIdentityPart, table);
542: }
543: }
544: }
545: }
546: return propertyType;
547: }
548:
549: /**
550: * @throws XMLSchemaException
551: */
552: private void resolveTargetTables() throws XMLSchemaException {
553: LOG
554: .logDebug("Resolving unspecified (null) table references for all FeaturePropertyTypes.");
555: Iterator iter = featureTypeMap.values().iterator();
556: while (iter.hasNext()) {
557: resolveTargetTables((MappedFeatureType) iter.next());
558: }
559: }
560:
561: private void resolveTargetTables(MappedFeatureType type)
562: throws XMLSchemaException {
563: PropertyType[] properties = type.getProperties();
564: for (int i = 0; i < properties.length; i++) {
565: MappedPropertyType property = (MappedPropertyType) properties[i];
566: if (property instanceof MappedFeaturePropertyType) {
567: resolveTargetTables((MappedFeaturePropertyType) property);
568: }
569: }
570: }
571:
572: private void resolveTargetTables(MappedFeaturePropertyType featurePT)
573: throws XMLSchemaException {
574: MappedFeatureType targetFeatureType = featurePT
575: .getFeatureTypeReference().getFeatureType();
576: if (!targetFeatureType.isAbstract()) {
577: TableRelation[] tableRelations = featurePT
578: .getTableRelations();
579: if (tableRelations.length == 0) {
580: String msg = "Invalid feature property mapping '"
581: + featurePT.getName()
582: + ": no relation elements - feature properties cannot be embedded in "
583: + "feature tables directly, but must use key relations to reference "
584: + "subfeatures.";
585: LOG.logError(msg);
586: throw new XMLSchemaException(msg);
587: }
588: TableRelation lastRelation = tableRelations[tableRelations.length - 1];
589: MappingField[] targetFields = lastRelation.getToFields();
590: for (int i = 0; i < targetFields.length; i++) {
591: String table = targetFields[i].getTable();
592: if (table != null) {
593: if (!targetFeatureType.getTable().equals(table)) {
594: String msg = "Invalid feature property mapping: type '"
595: + targetFeatureType.getName()
596: + "' is bound to table '"
597: + targetFeatureType.getTable()
598: + "', but last table relation specifies table '"
599: + table + "'.";
600: LOG.logError(msg);
601: throw new XMLSchemaException(msg);
602: }
603: }
604: targetFields[i].setTable(targetFeatureType.getTable());
605: }
606: }
607: }
608:
609: private void resolveFeatureTypeReferences()
610: throws UndefinedFeatureTypeException {
611: LOG
612: .logDebug("Resolving (mapped) FeatureType references for namespace '"
613: + getTargetNamespace() + "'.");
614: Iterator iter = featureTypeMap.values().iterator();
615: while (iter.hasNext()) {
616: resolveFeatureTypeReferences((MappedFeatureType) iter
617: .next());
618: }
619: }
620:
621: private void resolveFeatureTypeReferences(
622: MappedFeatureType featureType)
623: throws UndefinedFeatureTypeException {
624: LOG
625: .logDebug("Resolving (mapped) FeatureType references in definition of FeatureType '"
626: + featureType.getName() + "'.");
627: PropertyType[] properties = featureType.getProperties();
628: for (int i = 0; i < properties.length; i++) {
629: if (properties[i] instanceof MappedFeaturePropertyType) {
630: MappedFeaturePropertyType featurePT = (MappedFeaturePropertyType) properties[i];
631: resolveFeatureTypeReferences(featurePT
632: .getFeatureTypeReference());
633: }
634: }
635: }
636:
637: private void resolveFeatureTypeReferences(
638: MappedFeatureTypeReference reference)
639: throws UndefinedFeatureTypeException {
640: LOG
641: .logDebug("Resolving (mapped) FeatureType references to FeatureType '"
642: + reference.getName() + "'.");
643: if (reference.isResolved()) {
644: LOG.logDebug("Already resolved.");
645: } else {
646: MappedFeatureType featureType = getFeatureType(reference
647: .getName());
648: if (featureType == null) {
649: String msg = "Reference to feature type '"
650: + reference.getName()
651: + "' in mapping annotation can not be resolved.";
652: LOG.logDebug(msg);
653: throw new UndefinedFeatureTypeException(msg);
654: }
655: reference.resolve(featureType);
656: resolveFeatureTypeReferences(featureType);
657: }
658: }
659:
660: /**
661: * Returns all non-abstract implementations of a given feature type that are defined in this
662: * schema.
663: *
664: * @param ft
665: * must be a <code>MappedFeatureType</code>
666: * @return all non-abstract implementations of the feature type
667: */
668: @Override
669: public MappedFeatureType[] getSubstitutions(FeatureType ft) {
670: MappedFeatureType[] substitutions = new MappedFeatureType[0];
671: List<FeatureType> featureTypeList = this .substitutionMap
672: .get(ft);
673: if (featureTypeList != null) {
674: substitutions = featureTypeList
675: .toArray(new MappedFeatureType[featureTypeList
676: .size()]);
677: }
678: return substitutions;
679: }
680:
681: // TODO: implement this
682: private int getDefaultSQLTypeForXSDType(@SuppressWarnings("unused")
683: QualifiedName xsdTypeName) {
684: return -1;
685: }
686:
687: @Override
688: public String toString() {
689: StringBuffer sb = new StringBuffer(
690: "GML schema targetNamespace='");
691: sb.append(getTargetNamespace());
692: sb.append("'\n");
693: sb.append("\n*** ");
694: sb.append(featureTypeMap.size());
695: sb.append(" feature type declarations ***\n");
696: Iterator featureTypeIter = featureTypeMap.values().iterator();
697: while (featureTypeIter.hasNext()) {
698: MappedFeatureType featureType = (MappedFeatureType) featureTypeIter
699: .next();
700: sb.append(featureTypeToString(featureType));
701: if (featureTypeIter.hasNext()) {
702: sb.append("\n\n");
703: }
704: }
705: return sb.toString();
706: }
707:
708: private String featureTypeToString(MappedFeatureType ft) {
709: StringBuffer sb = new StringBuffer("- ");
710: if (ft.isAbstract()) {
711: sb.append("(abstract) ");
712: }
713: sb.append("Feature type '");
714: sb.append(ft.getName());
715: sb.append("' -> TABLE: '");
716: sb.append(ft.getTable() + "'");
717: if (ft.isUpdatable()) {
718: sb.append(" updatable");
719: }
720: if (ft.isDeletable()) {
721: sb.append(" deletable");
722: }
723: if (ft.isInsertable()) {
724: sb.append(" insertable");
725: }
726: sb.append('\n');
727: PropertyType[] properties = ft.getProperties();
728: for (int i = 0; i < properties.length; i++) {
729: sb.append(" + '");
730: sb.append(properties[i].getName());
731: sb.append("', type: ");
732: sb.append(properties[i].getType());
733: sb.append(", minOccurs: ");
734: sb.append(properties[i].getMinOccurs());
735: sb.append(", maxOccurs: ");
736: sb.append(properties[i].getMaxOccurs());
737: sb.append(" -> ");
738: // sb.append( ( (MappedPropertyType) properties[i] ).getContents()[0] );
739: if (i != properties.length - 1) {
740: sb.append("\n");
741: }
742: }
743: return sb.toString();
744: }
745: }
|