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;
018:
019: import java.util.Collections;
020: import java.util.Map;
021: import java.util.logging.Level;
022: import java.util.logging.Logger;
023:
024: import org.geotools.arcsde.data.ArcSDEDataStore;
025: import org.geotools.arcsde.data.ViewRegisteringFactoryHelper;
026: import org.geotools.arcsde.pool.ArcSDEConnectionConfig;
027: import org.geotools.arcsde.pool.ArcSDEConnectionPool;
028: import org.geotools.arcsde.pool.ArcSDEConnectionPoolFactory;
029: import org.geotools.arcsde.pool.ArcSDEPooledConnection;
030: import org.geotools.data.DataSourceException;
031: import org.geotools.data.DataStore;
032: import org.geotools.data.DataStoreFactorySpi;
033:
034: import com.esri.sde.sdk.client.SeConnection;
035: import com.esri.sde.sdk.client.SeException;
036: import com.esri.sde.sdk.client.SeRelease;
037: import com.esri.sde.sdk.pe.PeCoordinateSystem;
038: import com.esri.sde.sdk.pe.PeFactory;
039:
040: /**
041: * Factory to create DataStores over a live ArcSDE instance.
042: *
043: * @author Gabriel Roldan, Axios Engineering
044: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/unsupported/arcsde/datastore/src/main/java/org/geotools/arcsde/ArcSDEDataStoreFactory.java $
045: * @version $Id: ArcSDEDataStoreFactory.java 28901 2008-01-23 13:50:05Z groldan $
046: */
047: public class ArcSDEDataStoreFactory implements DataStoreFactorySpi {
048: /** package's logger */
049: protected static final Logger LOGGER = org.geotools.util.logging.Logging
050: .getLogger(ArcSDEDataStoreFactory.class.getPackage()
051: .getName());
052:
053: /** friendly factory description */
054: private static final String FACTORY_DESCRIPTION = "ESRI(tm) ArcSDE 8.x and 9.x";
055:
056: /** DOCUMENT ME! */
057: private static Param[] paramMetadata = new Param[10];
058:
059: public static final int JSDE_VERSION_DUMMY = -1;
060: public static final int JSDE_VERSION_90 = 0;
061: public static final int JSDE_VERSION_91 = 1;
062: public static final int JSDE_VERSION_92 = 2;
063:
064: public static int JSDE_CLIENT_VERSION;
065:
066: static {
067: paramMetadata[0] = new Param("namespace", String.class,
068: "namespace associated to this data store", false);
069: paramMetadata[1] = new Param("dbtype", String.class,
070: "fixed value. Must be \"arcsde\"", true, "arcsde");
071: paramMetadata[2] = new Param("server", String.class,
072: "sever name where the ArcSDE gateway is running", true);
073: paramMetadata[3] = new Param(
074: "port",
075: Integer.class,
076: "port number in wich the ArcSDE server is listening for connections.Generally it's 5151",
077: true, new Integer(5151));
078: paramMetadata[4] = new Param(
079: "instance",
080: String.class,
081: "the specific database to connect to. Only applicable to certain databases. Value ignored if not applicable.",
082: false);
083: paramMetadata[5] = new Param("user", String.class,
084: "name of a valid database user account.", true);
085: paramMetadata[6] = new Param("password", String.class,
086: "the database user's password.", true);
087:
088: // optional parameters:
089: paramMetadata[7] = new Param("pool.minConnections",
090: Integer.class, "Minimun number of open connections",
091: false, new Integer(
092: ArcSDEConnectionPool.DEFAULT_CONNECTIONS));
093: paramMetadata[8] = new Param(
094: "pool.maxConnections",
095: Integer.class,
096: "Maximun number of open connections (will not work if < 2)",
097: false, new Integer(
098: ArcSDEConnectionPool.DEFAULT_MAX_CONNECTIONS));
099: paramMetadata[9] = new Param(
100: "pool.timeOut",
101: Integer.class,
102: "Milliseconds to wait for an available connection before failing to connect",
103: false, new Integer(
104: ArcSDEConnectionPool.DEFAULT_MAX_WAIT_TIME));
105:
106: //determine which JSDE api we're running against
107: determineJsdeVersion();
108:
109: }
110:
111: private static void determineJsdeVersion() {
112: try {
113: //you need to uncomment line 2 and comment line 1 to make the
114: //tests run in Eclipse with the ArcSDE jarfiles on the classpath.
115: //1)
116: int i = com.esri.sde.sdk.GeoToolsDummyAPI.DUMMY_API_VERSION;
117:
118: //2)
119: //if (1==1) throw new Exception();
120: JSDE_CLIENT_VERSION = JSDE_VERSION_DUMMY;
121: } catch (Throwable t) {
122: //good, we're not using the Dummy API placeholder.
123: try {
124: //SeDBTune only exists in 9.2
125: Class.forName("com.esri.sde.sdk.client.SeDBTune");
126: JSDE_CLIENT_VERSION = JSDE_VERSION_92;
127: LOGGER.info("Using ArcSDE API version 9.2 (or higher)");
128: } catch (Throwable t2) {
129: //we're using 9.1 or 9.0.
130: try {
131: int[] projcss = PeFactory.projcsCodelist();
132: if (projcss.length == 16380) {
133: //perhaps I am the hack-master.
134: JSDE_CLIENT_VERSION = JSDE_VERSION_91;
135: LOGGER.info("Using ArcSDE API version 9.1");
136: } else {
137: JSDE_CLIENT_VERSION = JSDE_VERSION_90;
138: LOGGER
139: .info("Using ArcSDE API version 9.0 (or an earlier 8.x version)");
140: }
141: } catch (Throwable crap) {
142: //not sure what happened here... This next line is
143: //un-intelligent.
144: JSDE_CLIENT_VERSION = JSDE_VERSION_90;
145: }
146: }
147: }
148: }
149:
150: /** factory of connection pools to different SDE databases */
151: private static final ArcSDEConnectionPoolFactory poolFactory = ArcSDEConnectionPoolFactory
152: .getInstance();
153:
154: /**
155: * empty constructor
156: */
157: public ArcSDEDataStoreFactory() {
158: // does nothing
159: }
160:
161: /**
162: * DOCUMENT ME!
163: *
164: * @param map
165: * DOCUMENT ME!
166: *
167: * @return DOCUMENT ME!
168: *
169: * @throws UnsupportedOperationException
170: * DOCUMENT ME!
171: */
172: public DataStore createNewDataStore(java.util.Map map) {
173: throw new UnsupportedOperationException(
174: "ArcSDE DataStore does not supports the creation of new databases. This should be done through database's specific tools");
175: }
176:
177: /**
178: * crates an SdeDataSource based on connection parameters holded in
179: * <code>params</code>.
180: *
181: * <p>
182: * Expected parameters are:
183: *
184: * <ul>
185: * <li><b>dbtype </b>: MUST be <code>"arcsde"</code></li>
186: * <li><b>server </b>: machine name where ArcSDE is running</li>
187: * <li><b>port </b>: por number where ArcSDE listens for connections on
188: * server</li>
189: * <li><b>instance </b>: database instance name to connect to</li>
190: * <li><b>user </b>: database user name with at least reading privileges
191: * over SDE instance</li>
192: * <li><b>password </b>: database user password</li>
193: * </ul>
194: * </p>
195: *
196: * @param params
197: * connection parameters
198: *
199: * @return a new <code>SdeDataStore</code> pointing to the database
200: * defined by <code>params</code>
201: *
202: * @throws java.io.IOException
203: * if somthing goes wrong creating the datastore.
204: */
205: public DataStore createDataStore(Map params)
206: throws java.io.IOException {
207: if (JSDE_CLIENT_VERSION == JSDE_VERSION_DUMMY) {
208: throw new DataSourceException(
209: "Can't connect to ArcSDE with the dummy jar.");
210: }
211:
212: ArcSDEDataStore sdeDStore = null;
213: ArcSDEConnectionConfig config = new ArcSDEConnectionConfig(
214: params);
215:
216: ArcSDEConnectionPool connPool = poolFactory.createPool(config);
217:
218: //check to see if our sdk is compatible with this arcsde instance
219: ArcSDEPooledConnection conn = null;
220: try {
221: conn = connPool.getConnection();
222: SeRelease releaseInfo = conn.getRelease();
223: int majVer = releaseInfo.getMajor();
224: int minVer = releaseInfo.getMinor();
225:
226: if (majVer == 9 && minVer > 1
227: && JSDE_CLIENT_VERSION < JSDE_VERSION_91) {
228: //we can't connect to ArcSDE 9.2 with the arcsde 9.0 jars. It just won't
229: //work when trying to draw maps. Oh well, at least we'll warn people.
230: LOGGER
231: .severe("\n\n**************************\n"
232: + "DANGER DANGER DANGER!!! You're using the ArcSDE 9.0 (or earlier) jars with "
233: + "ArcSDE "
234: + majVer
235: + "."
236: + minVer
237: + " on host '"
238: + config.getServerName()
239: + "' . "
240: + "This PROBABLY WON'T WORK. If you have issues "
241: + "or unexplained exceptions when rendering maps, upgrade your ArcSDE jars to version "
242: + "9.2 or higher. See http://docs.codehaus.org/display/GEOTOOLS/ArcSDE+Plugin\n"
243: + "**************************\n\n");
244: }
245: } finally {
246: if (conn != null)
247: conn.close();
248: }
249:
250: String namespaceUri = config.getNamespaceUri();
251: if (namespaceUri == null) {
252: sdeDStore = new ArcSDEDataStore(connPool);
253: } else {
254: sdeDStore = new ArcSDEDataStore(connPool, namespaceUri);
255: }
256:
257: ViewRegisteringFactoryHelper
258: .registerSqlViews(sdeDStore, params);
259:
260: return sdeDStore;
261: }
262:
263: /**
264: * Display name for this DataStore Factory
265: *
266: * @return DOCUMENT ME!
267: */
268: public String getDisplayName() {
269: return "ArcSDE";
270: }
271:
272: // /** Interpret connection params as a metadata entity */
273: // public DataSourceMetadataEnity createMetadata( Map params )
274: // throws IOException {
275: //
276: // ArcSDEConnectionConfig config;
277: // try {
278: // config = new ArcSDEConnectionConfig(params);
279: // } catch (NullPointerException ex) {
280: // throw new IOException( "Cannot use provided params to connect" );
281: // } catch (IllegalArgumentException ex) {
282: // throw new DataSourceException( "Cannot use provided params to
283: // connect:"+ex.getMessage(), ex );
284: // }
285: // String description =
286: // "Connection to "+config.getDatabaseName()+ " at
287: // "+config.getServerName()+":"+config.getPortNumber()+ " as "+
288: // config.getUserName();
289: // return new DataSourceMetadataEnity( config.getServerName(),
290: // config.getDatabaseName(), description );
291: // }
292:
293: /**
294: * A human friendly name for this data source factory
295: *
296: * @return this factory's description
297: */
298: public String getDescription() {
299: return FACTORY_DESCRIPTION;
300: }
301:
302: /**
303: * DOCUMENT ME!
304: *
305: * @param params
306: *
307: */
308: public boolean canProcess(Map params) {
309: if (JSDE_CLIENT_VERSION == JSDE_VERSION_DUMMY) {
310: return false;
311: }
312: boolean canProcess = true;
313:
314: try {
315: new ArcSDEConnectionConfig(params);
316: } catch (NullPointerException ex) {
317: canProcess = false;
318: } catch (IllegalArgumentException ex) {
319: canProcess = false;
320: }
321:
322: return canProcess;
323: }
324:
325: /**
326: * Test to see if this datastore is available, if it has all the appropriate
327: * libraries to construct a datastore.
328: *
329: * @return <tt>true</tt> if and only if this factory is available to
330: * create DataStores.
331: */
332: public boolean isAvailable() {
333: if (JSDE_CLIENT_VERSION == JSDE_VERSION_DUMMY) {
334: LOGGER
335: .warning("You must download and install the *real* ArcSDE JSDE jar files. "
336: + "Currently the GeoTools ArcSDE 'dummy jar' is on your classpath. "
337: + "ArcSDE connectivity is DISABLED. "
338: + "See http://docs.codehaus.org/display/GEOTOOLS/ArcSDE+Plugin");
339: return false;
340: }
341: try {
342: LOGGER
343: .finer(SeConnection.class.getName()
344: + " is in place.");
345: LOGGER.finer(PeCoordinateSystem.class.getName()
346: + " is in place.");
347: } catch (Throwable t) {
348: LOGGER
349: .log(
350: Level.WARNING,
351: "ArcSDE Java API seems to not be on your classpath. Please"
352: + " verify that all needed jars are. ArcSDE data stores"
353: + " will not be available.", t);
354: return false;
355: }
356:
357: return true;
358: }
359:
360: /**
361: * DOCUMENT ME!
362: *
363: * @return DOCUMENT ME!
364: */
365: public DataStoreFactorySpi.Param[] getParametersInfo() {
366: return paramMetadata;
367: }
368:
369: /**
370: * Returns the implementation hints. The default implementation returns en empty map.
371: */
372: public Map getImplementationHints() {
373: return Collections.EMPTY_MAP;
374: }
375: }
|