001: /*
002: * Geotools2 - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2002-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: */
017: package org.geotools.arcsde.data;
018:
019: import java.io.IOException;
020: import java.net.URI;
021: import java.net.URISyntaxException;
022: import java.util.ArrayList;
023: import java.util.Date;
024: import java.util.HashMap;
025: import java.util.Iterator;
026: import java.util.List;
027: import java.util.Map;
028: import java.util.NoSuchElementException;
029: import java.util.Set;
030: import java.util.logging.Level;
031: import java.util.logging.Logger;
032:
033: import org.geotools.arcsde.pool.ArcSDEConnectionPool;
034: import org.geotools.arcsde.pool.ArcSDEPooledConnection;
035: import org.geotools.data.DataSourceException;
036: import org.geotools.feature.AttributeType;
037: import org.geotools.feature.AttributeTypeFactory;
038: import org.geotools.feature.DefaultFeatureTypeFactory;
039: import org.geotools.feature.FeatureType;
040: import org.geotools.feature.FeatureTypeBuilder;
041: import org.geotools.feature.GeometryAttributeType;
042: import org.geotools.feature.SchemaException;
043:
044: import org.geotools.referencing.ReferencingFactoryFinder;
045: import org.opengis.filter.identity.FeatureId;
046: import org.opengis.filter.identity.Identifier;
047: import org.opengis.referencing.FactoryException;
048: import org.opengis.referencing.crs.CRSFactory;
049: import org.opengis.referencing.crs.CoordinateReferenceSystem;
050:
051: import com.esri.sde.sdk.client.SeColumnDefinition;
052: import com.esri.sde.sdk.client.SeCoordinateReference;
053: import com.esri.sde.sdk.client.SeException;
054: import com.esri.sde.sdk.client.SeLayer;
055: import com.esri.sde.sdk.client.SeQuery;
056: import com.esri.sde.sdk.client.SeQueryInfo;
057: import com.esri.sde.sdk.client.SeRow;
058: import com.esri.sde.sdk.client.SeShape;
059: import com.esri.sde.sdk.client.SeTable;
060: import com.vividsolutions.jts.geom.Geometry;
061: import com.vividsolutions.jts.geom.GeometryCollection;
062: import com.vividsolutions.jts.geom.LineString;
063: import com.vividsolutions.jts.geom.MultiLineString;
064: import com.vividsolutions.jts.geom.MultiPoint;
065: import com.vividsolutions.jts.geom.MultiPolygon;
066: import com.vividsolutions.jts.geom.Point;
067: import com.vividsolutions.jts.geom.Polygon;
068:
069: /**
070: * Utility class to deal with SDE specifics such as creating SeQuery objects
071: * from geotool's Query's, mapping SDE types to Java ones and JTS Geometries,
072: * etc.
073: *
074: * @author Gabriel Roldan
075: * @source $URL:
076: * http://svn.geotools.org/geotools/trunk/gt/modules/unsupported/arcsde/datastore/src/main/java/org/geotools/arcsde/data/ArcSDEAdapter.java $
077: * @version $Id: ArcSDEAdapter.java 28902 2008-01-23 13:50:41Z groldan $
078: */
079: public class ArcSDEAdapter {
080: /** Logger for ths class' package */
081: private static final Logger LOGGER = org.geotools.util.logging.Logging
082: .getLogger(ArcSDEAdapter.class.getPackage().getName());
083:
084: /** mappings of SDE attribute's types to Java ones */
085: private static final Map sde2JavaTypes = new HashMap();
086:
087: /** inverse of sdeTypes, maps Java types to SDE ones */
088: private static final Map java2SDETypes = new HashMap();
089:
090: static {
091: sde2JavaTypes.put(new Integer(SeColumnDefinition.TYPE_NSTRING),
092: String.class);
093: sde2JavaTypes.put(new Integer(SeColumnDefinition.TYPE_STRING),
094: String.class);
095: sde2JavaTypes.put(new Integer(SeColumnDefinition.TYPE_INT16),
096: Short.class);
097: sde2JavaTypes.put(new Integer(SeColumnDefinition.TYPE_INT32),
098: Integer.class);
099: sde2JavaTypes.put(new Integer(SeColumnDefinition.TYPE_INT64),
100: Long.class);
101: sde2JavaTypes.put(new Integer(SeColumnDefinition.TYPE_FLOAT32),
102: Float.class);
103: sde2JavaTypes.put(new Integer(SeColumnDefinition.TYPE_FLOAT64),
104: Double.class);
105: sde2JavaTypes.put(new Integer(SeColumnDefinition.TYPE_DATE),
106: Date.class);
107: // @TODO: not at all, only for capable open table with GeoServer
108: // sde2JavaTypes.put(new
109: // Integer(SeColumnDefinition.TYPE_BLOB),byte[].class);
110: // @TODO sde2JavaTypes.put(new Integer(SeColumnDefinition.TYPE_CLOB),
111: // String.class);
112: // @Tested for view
113: sde2JavaTypes.put(new Integer(SeColumnDefinition.TYPE_UUID),
114: String.class);
115: // @TODO sde2JavaTypes.put(new Integer(SeColumnDefinition.TYPE_XML),
116: // org.w3c.dom.Document.class);
117:
118: // deprecated codes as for ArcSDE 9.0+. Adding them to maintain < 9.0
119: // compatibility
120: // though the assigned int codes matched their new counterparts, I let
121: // them here as a reminder
122: sde2JavaTypes.put(
123: new Integer(SeColumnDefinition.TYPE_SMALLINT),
124: Short.class);
125: sde2JavaTypes.put(new Integer(SeColumnDefinition.TYPE_INTEGER),
126: Integer.class);
127: sde2JavaTypes.put(new Integer(SeColumnDefinition.TYPE_FLOAT),
128: Float.class);
129: sde2JavaTypes.put(new Integer(SeColumnDefinition.TYPE_DOUBLE),
130: Double.class);
131:
132: /**
133: * By now keep using the deprecated constants (TYPE_INTEGER, etc.),
134: * switching directly to the new ones gives problems with ArcSDE
135: * instances prior to version 9.0.
136: */
137: // SeColumnDefinition.TYPE_RASTER is not supported...
138: java2SDETypes.put(String.class, new SdeTypeDef(
139: SeColumnDefinition.TYPE_STRING, 255, 0));
140: java2SDETypes.put(Short.class, new SdeTypeDef(
141: SeColumnDefinition.TYPE_SMALLINT, 4, 0));
142: java2SDETypes.put(Integer.class, new SdeTypeDef(
143: SeColumnDefinition.TYPE_INTEGER, 10, 0));
144: java2SDETypes.put(Float.class, new SdeTypeDef(
145: SeColumnDefinition.TYPE_FLOAT, 5, 2));
146: java2SDETypes.put(Double.class, new SdeTypeDef(
147: SeColumnDefinition.TYPE_DOUBLE, 15, 4));
148: java2SDETypes.put(Date.class, new SdeTypeDef(
149: SeColumnDefinition.TYPE_DATE, 1, 0));
150: java2SDETypes.put(Long.class, new SdeTypeDef(
151: SeColumnDefinition.TYPE_INTEGER, 10, 0));
152: // java2SDETypes.put(byte[].class, new
153: // SdeTypeDef(SeColumnDefinition.TYPE_BLOB, 1, 0));
154: java2SDETypes.put(Number.class, new SdeTypeDef(
155: SeColumnDefinition.TYPE_DOUBLE, 15, 4));
156: }
157:
158: /**
159: * DOCUMENT ME!
160: *
161: * @param attribute
162: * DOCUMENT ME!
163: *
164: * @return DOCUMENT ME!
165: *
166: * @throws NullPointerException
167: * DOCUMENT ME!
168: * @throws IllegalArgumentException
169: * DOCUMENT ME!
170: */
171: public static int guessShapeTypes(GeometryAttributeType attribute) {
172: if (attribute == null) {
173: throw new NullPointerException(
174: "a GeometryAttributeType must be provided, got null");
175: }
176:
177: Class geometryClass = attribute.getType();
178:
179: int shapeTypes = 0;
180:
181: if (attribute.isNillable()) {
182: shapeTypes |= SeLayer.SE_NIL_TYPE_MASK;
183: }
184:
185: if (GeometryCollection.class.isAssignableFrom(geometryClass)) {
186: shapeTypes |= SeLayer.SE_MULTIPART_TYPE_MASK;
187:
188: if (geometryClass == MultiPoint.class) {
189: shapeTypes |= SeLayer.SE_POINT_TYPE_MASK;
190: } else if (geometryClass == MultiLineString.class) {
191: shapeTypes |= SeLayer.SE_LINE_TYPE_MASK;
192: } else if (geometryClass == MultiPolygon.class) {
193: shapeTypes |= SeLayer.SE_AREA_TYPE_MASK;
194: } else {
195: throw new IllegalArgumentException(
196: "no SDE geometry mapping for " + geometryClass);
197: }
198: } else {
199: if (geometryClass == Point.class) {
200: shapeTypes |= SeLayer.SE_POINT_TYPE_MASK;
201: } else if (geometryClass == LineString.class) {
202: shapeTypes |= SeLayer.SE_LINE_TYPE_MASK;
203: } else if (geometryClass == Polygon.class) {
204: shapeTypes |= SeLayer.SE_AREA_TYPE_MASK;
205: } else if (geometryClass == Geometry.class) {
206: LOGGER
207: .fine("Creating SeShape types for all types of geometries.");
208: shapeTypes |= (SeLayer.SE_MULTIPART_TYPE_MASK
209: | SeLayer.SE_POINT_TYPE_MASK
210: | SeLayer.SE_LINE_TYPE_MASK | SeLayer.SE_AREA_TYPE_MASK);
211: } else {
212: throw new IllegalArgumentException(
213: "no SDE geometry mapping for " + geometryClass);
214: }
215: }
216:
217: return shapeTypes;
218: }
219:
220: /**
221: * Creates the column definition as used by the ArcSDE Java API, for the
222: * given AttributeType.
223: *
224: * @param type
225: * the source attribute definition.
226: *
227: * @return an <code>SeColumnDefinition</code> object matching the
228: * properties of the source AttributeType.
229: *
230: * @throws SeException
231: * if the SeColumnDefinition constructor throws it due to some
232: * invalid parameter
233: */
234: public static SeColumnDefinition createSeColumnDefinition(
235: AttributeType type) throws SeException {
236: SeColumnDefinition colDef = null;
237: String colName = type.getName();
238: boolean nillable = type.isNillable();
239:
240: SdeTypeDef def = getSdeType(type.getType());
241:
242: int sdeColType = def.colDefType;
243: int fieldLength = def.size;
244: int fieldScale = def.scale;
245:
246: colDef = new SeColumnDefinition(colName, sdeColType,
247: fieldLength, fieldScale, nillable);
248:
249: return colDef;
250: }
251:
252: /**
253: * DOCUMENT ME!
254: *
255: * @param attClass
256: *
257: * @return an SdeTypeDef instance with default values for the given class
258: *
259: * @throws IllegalArgumentException
260: * DOCUMENT ME!
261: */
262: private static SdeTypeDef getSdeType(Class attClass)
263: throws IllegalArgumentException {
264: SdeTypeDef sdeType = (SdeTypeDef) java2SDETypes.get(attClass);
265:
266: if (sdeType == null) {
267: throw new IllegalArgumentException(
268: "No SDE type mapping for " + attClass.getName());
269: }
270:
271: return sdeType;
272: }
273:
274: /**
275: * Fetches the schema of a given ArcSDE featureclass and creates its
276: * corresponding Geotools FeatureType
277: *
278: * @param connPool
279: * DOCUMENT ME!
280: * @param typeName
281: * DOCUMENT ME!
282: *
283: * @return DOCUMENT ME!
284: *
285: * @throws IOException
286: * DOCUMENT ME!
287: * @throws DataSourceException
288: * DOCUMENT ME!
289: */
290: public static FeatureType fetchSchema(
291: ArcSDEConnectionPool connPool, String typeName,
292: String namespace) throws IOException {
293: SeLayer sdeLayer = connPool.getSdeLayer(typeName);
294: SeTable sdeTable = connPool.getSdeTable(typeName);
295: // List/*<AttributeDescriptor>*/properties =
296: // createAttributeDescriptors(connPool, sdeLayer, sdeTable, namespace);
297: List/* <AttributeType> */properties = createAttributeDescriptors(
298: connPool, sdeLayer, sdeTable, namespace);
299: FeatureType type = createSchema(typeName, namespace, properties);
300: return type;
301: }
302:
303: /**
304: * Fetchs the schema for the "SQL SELECT" like view definition
305: *
306: * @param connPool
307: * @param typeName
308: * @param viewDef
309: * @return
310: * @throws IOException
311: */
312: public static FeatureType fetchSchema(
313: ArcSDEConnectionPool connPool, String typeName,
314: String namespace, SeQueryInfo queryInfo) throws IOException {
315:
316: List attributeDescriptors;
317:
318: ArcSDEPooledConnection conn = connPool.getConnection();
319:
320: SeQuery testQuery = null;
321: try {
322: // is the first table is a layer, we'll get it to obtain CRS info
323: // from
324: String mainTable = queryInfo.getConstruct().getTables()[0];
325: SeLayer layer = null;
326: try {
327: layer = connPool.getSdeLayer(conn, mainTable);
328: } catch (NoSuchElementException e) {
329: LOGGER
330: .info(mainTable
331: + " is not an SeLayer, so no CRS info will be parsed");
332: }
333: LOGGER.fine("testing query");
334: testQuery = new SeQuery(conn);
335: testQuery.prepareQueryInfo(queryInfo);
336: testQuery.execute();
337: LOGGER.fine("definition query executed successfully");
338:
339: LOGGER.fine("fetching row to obtain view's types");
340:
341: SeRow testRow = testQuery.fetch();
342: SeColumnDefinition[] colDefs = testRow.getColumns();
343:
344: attributeDescriptors = createAttributeDescriptors(layer,
345: namespace, colDefs);
346:
347: } catch (SeException e) {
348: throw new DataSourceException(e.getSeError().getErrDesc(),
349: e);
350: } finally {
351: if (testQuery != null) {
352: try {
353: testQuery.close();
354: } catch (SeException e) {
355: }
356: }
357: conn.close();
358: }
359: FeatureType type = createSchema(typeName, namespace,
360: attributeDescriptors);
361: return type;
362: }
363:
364: /**
365: * Creates the FeatureType content for a given ArcSDE layer in the form of a
366: * list of AttributeDescriptors
367: *
368: * @param sdeLayer
369: * sde layer
370: * @param table
371: * sde business table associated to <code>layer</code>
372: *
373: * @return List<AttributeDescriptor>
374: *
375: * @throws DataSourceException
376: * if any problem is found wroking with arcsde to fetch layer
377: * metadata
378: *
379: */
380: private static List createAttributeDescriptors(
381: ArcSDEConnectionPool connPool, SeLayer sdeLayer,
382: SeTable table, String namespace) throws DataSourceException {
383: SeColumnDefinition[] seColumns = null;
384: try {
385: seColumns = table.describe();
386: } catch (SeException e) {
387: throw new DataSourceException(e);
388: }
389:
390: return createAttributeDescriptors(sdeLayer, namespace,
391: seColumns);
392: }
393:
394: private static List createAttributeDescriptors(SeLayer sdeLayer,
395: String namespace, SeColumnDefinition[] seColumns)
396: throws DataSourceException {
397: String attName;
398: boolean isNilable;
399: int fieldLen;
400: Object defValue;
401: Object metadata = null;
402:
403: final int nCols = seColumns.length;
404: List attDescriptors = new ArrayList(nCols);
405:
406: AttributeType attributeType = null;
407: Class typeClass = null;
408:
409: for (int i = 0; i < nCols; i++) {
410: SeColumnDefinition colDef = seColumns[i];
411:
412: attName = colDef.getName();
413: // didn't found in the ArcSDE Java API the way of knowing
414: // if an SeColumnDefinition is nillable. SeColumnDefinition has
415: // a nullable argument on its constructor, but no getter method
416: isNilable = true;
417: defValue = null;
418: fieldLen = colDef.getSize();
419:
420: final Integer sdeType = new Integer(colDef.getType());
421:
422: if (sdeType.intValue() == SeColumnDefinition.TYPE_SHAPE) {
423: CoordinateReferenceSystem crs = null;
424:
425: crs = parseCRS(sdeLayer);
426: metadata = crs;
427:
428: int seShapeType = sdeLayer.getShapeTypes();
429: typeClass = getGeometryTypeFromLayerMask(seShapeType);
430: isNilable = (seShapeType & SeLayer.SE_NIL_TYPE_MASK) == SeLayer.SE_NIL_TYPE_MASK;
431: defValue = ArcSDEGeometryBuilder
432: .defaultValueFor(typeClass);
433:
434: } else {
435: typeClass = (Class) sde2JavaTypes.get(sdeType);
436: if (typeClass == null) {
437: // interesting question: Do we throw an exception here, or
438: // do we allow un-handle-able columns
439: // to just 'disappear' when serving those tables?
440: // GR: just ignore them by now...
441: LOGGER.info("Unsupported column type ("
442: + sdeType.intValue() + ") for " + attName
443: + ". Ignoring the column.");
444: //do not create the attribute type and add it to the list of descriptors
445: continue;
446: }
447: // @TODO: add restrictions once the Restrictions utility methods
448: // are implemented
449: // Set restrictions = Restrictions.createLength(name, typeClass,
450: // fieldLen);
451: }
452: attributeType = AttributeTypeFactory.newAttributeType(
453: attName, typeClass, isNilable, fieldLen, defValue,
454: metadata);
455: attDescriptors.add(attributeType);
456: }
457:
458: return attDescriptors;
459: }
460:
461: private static FeatureType createSchema(String typeName,
462: String namespace, List properties) {
463: // TODO: use factory lookup mechanism once its in place
464: FeatureTypeBuilder builder = new DefaultFeatureTypeFactory();
465:
466: builder.setName(typeName);
467: try {
468: builder.setNamespace(new URI(namespace));
469: } catch (URISyntaxException e) {
470: LOGGER.warning("Illegal namespace uri: " + namespace);
471: }
472:
473: for (Iterator it = properties.iterator(); it.hasNext();) {
474: AttributeType attType = (AttributeType) it.next();
475: builder.addType(attType);
476: }
477:
478: FeatureType type;
479: try {
480: type = builder.getFeatureType();
481: } catch (SchemaException e) {
482: throw new RuntimeException(e);
483: }
484:
485: return type;
486: }
487:
488: /**
489: * Obtains the <code>SeCoordinateReference</code> of the given
490: * <code>SeLayer</code> and tries to create a
491: * <code>org.opengis.referencing.crs.CoordinateReferenceSystem</code> from
492: * its WKT.
493: *
494: * @param sdeLayer
495: * the SeLayer from which to query the CRS in ArcSDE form.
496: *
497: * @return the actual CRS or null if <code>sdeLayer</code> does not
498: * defines its coordinate system.
499: *
500: * @throws DataSourceException
501: * if the WKT can't be parsed to an opengis CRS using the
502: * CRSFactory
503: */
504: private static CoordinateReferenceSystem parseCRS(SeLayer sdeLayer)
505: throws DataSourceException {
506: CoordinateReferenceSystem crs = null;
507: SeCoordinateReference seCRS = sdeLayer.getCoordRef();
508: String WKT = seCRS.getProjectionDescription();
509: LOGGER.finer("About to parse CRS for layer "
510: + sdeLayer.getName() + ": " + WKT);
511:
512: try {
513: LOGGER.fine(sdeLayer.getName() + " has CRS envelope: "
514: + seCRS.getXYEnvelope());
515: } catch (SeException e1) {
516: // intentionally blank
517: }
518:
519: if ("UNKNOWN".equalsIgnoreCase(WKT)) {
520: LOGGER
521: .fine("ArcSDE layer "
522: + sdeLayer.getName()
523: + " does not provides a Coordinate Reference System");
524: } else {
525: try {
526: CRSFactory crsFactory = ReferencingFactoryFinder
527: .getCRSFactory(null);
528: crs = crsFactory.createFromWKT(WKT);
529: LOGGER.fine("ArcSDE CRS correctly parsed from layer "
530: + sdeLayer.getName());
531: } catch (FactoryException e) {
532: String msg = "CRS factory does not knows how to parse the "
533: + "CRS for layer "
534: + sdeLayer.getName()
535: + ": "
536: + WKT;
537: LOGGER.log(Level.CONFIG, msg, e);
538: // throw new DataSourceException(msg, e);
539: }
540:
541: }
542:
543: return crs;
544: }
545:
546: /**
547: * Returns the mapping JTS geometry type for the ArcSDE Shape type given by
548: * the bitmask <code>seShapeType</code>
549: *
550: * <p>
551: * This bitmask is composed of a combination of the following shape types,
552: * as defined in the ArcSDE Java API:
553: *
554: * <pre>
555: * SE_NIL_TYPE_MASK = 1;
556: * SE_POINT_TYPE_MASK = 2;
557: * SE_LINE_TYPE_MASK = 4;
558: * SE_AREA_TYPE_MASK = 16;
559: * SE_MULTIPART_TYPE_MASK = 262144;
560: * </pre>
561: *
562: * (Note that the type SE_SIMPLE_LINE_TYPE_MASK is not used)
563: * </p>
564: *
565: * @param seShapeType
566: * DOCUMENT ME!
567: *
568: * @return DOCUMENT ME!
569: *
570: * @throws IllegalArgumentException
571: * DOCUMENT ME!
572: */
573: public static Class getGeometryTypeFromLayerMask(int seShapeType) {
574: Class clazz = com.vividsolutions.jts.geom.Geometry.class;
575: final int MULTIPART_MASK = SeLayer.SE_MULTIPART_TYPE_MASK;
576: final int POINT_MASK = SeLayer.SE_POINT_TYPE_MASK;
577: final int SIMPLE_LINE_MASK = SeLayer.SE_SIMPLE_LINE_TYPE_MASK;
578: final int LINESTRING_MASK = SeLayer.SE_LINE_TYPE_MASK;
579: final int AREA_MASK = SeLayer.SE_AREA_TYPE_MASK;
580:
581: // if (seShapeType == SeLayer.TYPE_NIL) {
582: // // do nothing
583: // } else if (seShapeType == SeLayer.TYPE_MULTI_MASK) {
584: // clazz = GeometryCollection.class;
585: // } else if (seShapeType == SeLayer.TYPE_LINE || seShapeType ==
586: // SeLayer.TYPE_SIMPLE_LINE) {
587: // clazz = LineString.class;
588: // } else if (seShapeType == SeLayer.TYPE_MULTI_LINE
589: // || seShapeType == SeLayer.TYPE_MULTI_SIMPLE_LINE) {
590: // clazz = MultiLineString.class;
591: // } else if (seShapeType == SeLayer.TYPE_MULTI_POINT) {
592: // clazz = MultiPoint.class;
593: // } else if (seShapeType == SeLayer.TYPE_MULTI_POLYGON) {
594: // clazz = MultiPolygon.class;
595: // } else if (seShapeType == SeLayer.TYPE_POINT) {
596: // clazz = Point.class;
597: // } else if (seShapeType == SeLayer.TYPE_POLYGON) {
598: // clazz = Polygon.class;
599: // } else {
600: // in all this assignments, 1 means true and 0 false
601: final int isCollection = ((seShapeType & MULTIPART_MASK) == MULTIPART_MASK) ? 1
602: : 0;
603:
604: final int isPoint = ((seShapeType & POINT_MASK) == POINT_MASK) ? 1
605: : 0;
606:
607: final int isLineString = (((seShapeType & SIMPLE_LINE_MASK) == SIMPLE_LINE_MASK) || ((seShapeType & LINESTRING_MASK) == LINESTRING_MASK)) ? 1
608: : 0;
609:
610: final int isPolygon = ((seShapeType & AREA_MASK) == AREA_MASK) ? 1
611: : 0;
612:
613: boolean isError = false;
614:
615: // first check if the shape type supports more than one geometry
616: // type.
617: // In that case, it is *highly* recomended that it support all the
618: // geometry types, so we can safely return Geometry.class. If this
619: // is
620: // not
621: // the case and the shape type supports just a few geometry types,
622: // then
623: // we give it a chance and return Geometry.class anyway, but be
624: // aware
625: // that transactions over that layer could fail if a Geometry that
626: // is
627: // not supported is tried for insertion.
628: if ((isPoint + isLineString + isPolygon) > 1) {
629: clazz = Geometry.class;
630:
631: if (4 < (isCollection + isPoint + isLineString + isPolygon)) {
632: LOGGER
633: .warning("Be careful!! we're mapping an ArcSDE Shape type "
634: + "to the generic Geometry class, but the shape type "
635: + "does not really allows all geometry types!: "
636: + "isCollection="
637: + isCollection
638: + ", isPoint="
639: + isPoint
640: + ", isLineString="
641: + isLineString
642: + ", isPolygon=" + isPolygon);
643: } else {
644: LOGGER
645: .fine("safely mapping SeShapeType to abstract Geometry");
646: }
647: } else if (isCollection == 1) {
648: if (isPoint == 1) {
649: clazz = MultiPoint.class;
650: } else if (isLineString == 1) {
651: clazz = MultiLineString.class;
652: } else if (isPolygon == 1) {
653: clazz = MultiPolygon.class;
654: } else {
655: isError = true;
656: }
657: } else {
658: if (isPoint == 1) {
659: clazz = Point.class;
660: } else if (isLineString == 1) {
661: clazz = LineString.class;
662: } else if (isPolygon == 1) {
663: clazz = Polygon.class;
664: } else {
665: isError = true;
666: }
667: }
668:
669: // }
670: return clazz;
671: }
672:
673: /**
674: * Returns the most appropriate {@link Geometry} class that matches the
675: * shape's type.
676: *
677: * @param shape
678: * non <code>null</code> SeShape instance for which to infer
679: * the matching geometry class
680: * @return the Geometry subclass corresponding to the shape type
681: * @throws SeException
682: * propagated if thrown by {@link SeShape#getType()}
683: * @throws IllegalArgumentException
684: * if none of the JTS geometry classes can be matched to the
685: * shape type (shouldnt happen as for the
686: * {@link SeShape#getType() types} defined in the esri arcsde
687: * java api 9.0)
688: */
689: public static Class getGeometryTypeFromSeShape(SeShape shape)
690: throws SeException {
691: Class clazz = com.vividsolutions.jts.geom.Geometry.class;
692:
693: int seShapeType = shape.getType();
694:
695: if (seShapeType == SeShape.TYPE_NIL) {
696: // do nothing
697: } else if (seShapeType == SeShape.TYPE_LINE
698: || seShapeType == SeShape.TYPE_SIMPLE_LINE) {
699: clazz = LineString.class;
700: } else if (seShapeType == SeShape.TYPE_MULTI_LINE
701: || seShapeType == SeShape.TYPE_MULTI_SIMPLE_LINE) {
702: clazz = MultiLineString.class;
703: } else if (seShapeType == SeShape.TYPE_MULTI_POINT) {
704: clazz = MultiPoint.class;
705: } else if (seShapeType == SeShape.TYPE_MULTI_POLYGON) {
706: clazz = MultiPolygon.class;
707: } else if (seShapeType == SeShape.TYPE_POINT) {
708: clazz = Point.class;
709: } else if (seShapeType == SeShape.TYPE_POLYGON) {
710: clazz = Polygon.class;
711: } else {
712: throw new IllegalArgumentException(
713: "Cannot map the shape type '" + seShapeType
714: + "' to any known SeShape.TYPE_*");
715: }
716: return clazz;
717: }
718:
719: /**
720: * Returns the numeric identifier of a FeatureId, given by the full
721: * qualified name of the featureclass prepended to the ArcSDE feature id.
722: * ej: SDE.SDE.SOME_LAYER.1
723: *
724: * @param fid
725: * a geotools FeatureID
726: *
727: * @return an ArcSDE feature ID
728: *
729: * @throws IllegalArgumentException
730: * If the given string is not properly formatted
731: * [anystring].[long value]
732: */
733: public static long getNumericFid(Identifier id)
734: throws IllegalArgumentException {
735: if (!(id instanceof FeatureId))
736: throw new IllegalArgumentException(
737: "Only FeatureIds are supported when encoding id filters to SDE. Not "
738: + id.getClass());
739:
740: String fid = ((FeatureId) id).getID();
741: int dotIndex = fid.lastIndexOf('.');
742: try {
743: return Long.decode(fid.substring(++dotIndex)).longValue();
744: } catch (Exception ex) {
745: throw new IllegalArgumentException("FeatureID " + fid
746: + " does not seems as a valid ArcSDE FID");
747: }
748: }
749:
750: /**
751: * DOCUMENT ME!
752: *
753: * @param stringFids
754: * DOCUMENT ME!
755: *
756: * @return DOCUMENT ME!
757: *
758: * @throws IllegalArgumentException
759: * DOCUMENT ME!
760: */
761: public static long[] getNumericFids(Set identifiers)
762: throws IllegalArgumentException {
763: int nfids = identifiers.size();
764: long[] fids = new long[nfids];
765:
766: Iterator ids = identifiers.iterator();
767: for (int i = 0; i < nfids; i++) {
768: fids[i] = ArcSDEAdapter.getNumericFid((Identifier) ids
769: .next());
770: }
771:
772: return fids;
773: }
774:
775: /**
776: * Holds default values for the properties (size and scale) of a
777: * SeColumnDefinition, given by its column type
778: * (SeColumnDefinition.SE_STRING, etc).
779: *
780: * <p>
781: * </p>
782: *
783: * @author Gabriel Roldan, Axios Engineering
784: * @version $Revision: 1.4 $
785: */
786: private static class SdeTypeDef {
787: /** DOCUMENT ME! */
788: final int colDefType;
789:
790: /** DOCUMENT ME! */
791: final int size;
792:
793: /** DOCUMENT ME! */
794: final int scale;
795:
796: /**
797: * Creates a new SdeTypeDef object.
798: *
799: * @param colDefType
800: * DOCUMENT ME!
801: * @param size
802: * DOCUMENT ME!
803: * @param scale
804: * DOCUMENT ME!
805: */
806: public SdeTypeDef(int colDefType, int size, int scale) {
807: this .colDefType = colDefType;
808: this .size = size;
809: this .scale = scale;
810: }
811:
812: /**
813: * DOCUMENT ME!
814: *
815: * @return DOCUMENT ME!
816: */
817: public String toString() {
818: return "SdeTypeDef[colDefType=" + this .colDefType
819: + ", size=" + this .size + ", scale=" + this .scale
820: + "]";
821: }
822: }
823: }
|