PageRenderTime 61ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/projects/geotools-9.2/modules/library/data/src/main/java/org/geotools/data/store/ContentDataStore.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 691 lines | 232 code | 83 blank | 376 comment | 11 complexity | 6c156718c2c870fcf7b694c51f6a6852 MD5 | raw file
  1. /*
  2. * GeoTools - The Open Source Java GIS Toolkit
  3. * http://geotools.org
  4. *
  5. * (C) 2006-2008, Open Source Geospatial Foundation (OSGeo)
  6. *
  7. * This library is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation;
  10. * version 2.1 of the License.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. */
  17. package org.geotools.data.store;
  18. import java.io.IOException;
  19. import java.util.ArrayList;
  20. import java.util.HashMap;
  21. import java.util.List;
  22. import java.util.Map;
  23. import java.util.concurrent.ConcurrentHashMap;
  24. import java.util.logging.Logger;
  25. import org.geotools.data.DataAccess;
  26. import org.geotools.data.DataStore;
  27. import org.geotools.data.DataStoreFactorySpi;
  28. import org.geotools.data.DefaultServiceInfo;
  29. import org.geotools.data.FeatureReader;
  30. import org.geotools.data.FeatureSource;
  31. import org.geotools.data.FeatureWriter;
  32. import org.geotools.data.InProcessLockingManager;
  33. import org.geotools.data.LockingManager;
  34. import org.geotools.data.Query;
  35. import org.geotools.data.ServiceInfo;
  36. import org.geotools.data.Transaction;
  37. import org.geotools.data.simple.SimpleFeatureSource;
  38. import org.geotools.feature.FeatureCollection;
  39. import org.geotools.feature.FeatureTypes;
  40. import org.geotools.feature.NameImpl;
  41. import org.geotools.feature.SchemaException;
  42. import org.opengis.feature.FeatureFactory;
  43. import org.opengis.feature.simple.SimpleFeature;
  44. import org.opengis.feature.simple.SimpleFeatureType;
  45. import org.opengis.feature.type.FeatureType;
  46. import org.opengis.feature.type.FeatureTypeFactory;
  47. import org.opengis.feature.type.Name;
  48. import org.opengis.filter.Filter;
  49. import org.opengis.filter.FilterFactory;
  50. import org.opengis.util.TypeName;
  51. import com.vividsolutions.jts.geom.GeometryFactory;
  52. /**
  53. * Abstract base class for data stores.
  54. * <p>
  55. * A datastore contains a set of entries ({@link ContentEntry}). Each entry
  56. * corresponds to a "real world dataset". For instance, a shapefile datastore
  57. * would contain a single entry which would represent the shapefile on disk. A
  58. * postgis datastore could contain many entries, one for each table in the database.
  59. * </p>
  60. * <p>
  61. * Each entry is identified by a name ({@link Name}). The name can be qualified
  62. * with a namespace uri, or unqualified (in which the namespace uri is null). An
  63. * example of a datastore that might use qualified names is WFS, where in each
  64. * entry corresponds to a WFS "Feature Type", which have namespace qualified name.
  65. * Other datastores (such as databases) use unqualified names.
  66. * </p>
  67. * <p>
  68. * When entry names of a datastore are unqualified, a default namespace uri can
  69. * be set "globally" on the datastore itself, see {@link #setNamespaceURI(String)}.
  70. * When this value is set, unqualified entry names are implicitly qualified with
  71. * the global namespace uri.
  72. * </p>
  73. * <h3>Subclasses</h3>
  74. * <p>
  75. * At a minimum subclasses must implement the following methods:
  76. * <ul>
  77. * <li>{@link #createTypeNames()}
  78. * <li>{@link #createFeatureSource(ContentEntry)}
  79. * </ul>
  80. * The following methods may also be overriden:
  81. * <ul>
  82. * <li>{@link #createContentState(ContentEntry)}
  83. * </ul>
  84. * The following methods may be overriden but <b>only</b> to narrow the return
  85. * type to a specific subclass of {@link ContentFeatureSource}.
  86. * <ul>
  87. * <li>{@link #getFeatureSource(String)}
  88. * <li>{@link #getFeatureSource(String, Transaction)}
  89. * <li>{@link #getFeatureSource(Name, Transaction)}
  90. * </ul>
  91. * </p>
  92. * @author Jody Garnett, Refractions Research Inc.
  93. * @author Justin Deoliveira, The Open Planning Project
  94. *
  95. *
  96. *
  97. * @source $URL$
  98. */
  99. public abstract class ContentDataStore implements DataStore {
  100. /**
  101. * writer flags
  102. */
  103. protected final static int WRITER_ADD = 0x01<<0;
  104. protected final static int WRITER_UPDATE = 0x01<<1;
  105. /**
  106. * name, entry map
  107. */
  108. final protected Map<Name,ContentEntry> entries;
  109. /**
  110. * logger
  111. */
  112. final protected Logger LOGGER;
  113. /**
  114. * Factory used to create feature types
  115. */
  116. protected FeatureTypeFactory typeFactory;
  117. /**
  118. * Factory used to create features
  119. */
  120. protected FeatureFactory featureFactory;
  121. /**
  122. * Factory used to create filters
  123. */
  124. protected FilterFactory filterFactory;
  125. /**
  126. * Factory used to create geometries
  127. */
  128. protected GeometryFactory geometryFactory;
  129. /**
  130. * namespace uri of the datastore itself, or default namespace
  131. */
  132. protected String namespaceURI;
  133. /**
  134. * locking manager
  135. */
  136. protected LockingManager lockingManager = new InProcessLockingManager();
  137. /**
  138. * factory used to create the datastore
  139. */
  140. protected DataStoreFactorySpi dataStoreFactory;
  141. public ContentDataStore() {
  142. // get a concurrent map so that we can do reads in parallel with writes (writes vs writes
  143. // are actually synchronized to prevent double work, see getEntry()).
  144. this.entries = new ConcurrentHashMap<Name,ContentEntry>();
  145. // grabbing the logger here makes the logger name polymorphic (the name of the actual
  146. // subclass will be used
  147. this.LOGGER = org.geotools.util.logging.Logging.getLogger(
  148. getClass().getPackage().getName()
  149. );
  150. }
  151. //
  152. // Property accessors
  153. //
  154. /**
  155. * The factory used to create feature types.
  156. */
  157. public FeatureTypeFactory getFeatureTypeFactory() {
  158. return typeFactory;
  159. }
  160. /**
  161. * Sets the factory used to create feature types.
  162. */
  163. public void setFeatureTypeFactory(FeatureTypeFactory typeFactory) {
  164. this.typeFactory = typeFactory;
  165. }
  166. /**
  167. * Sets the factory used to create features.
  168. */
  169. public void setFeatureFactory(FeatureFactory featureFactory) {
  170. this.featureFactory = featureFactory;
  171. }
  172. /**
  173. * The factory used to create filters.
  174. */
  175. public FilterFactory getFilterFactory() {
  176. return filterFactory;
  177. }
  178. /**
  179. * The factory used to create features.
  180. */
  181. public FeatureFactory getFeatureFactory() {
  182. return featureFactory;
  183. }
  184. /**
  185. * Sets the factory used to create filters.
  186. */
  187. public void setFilterFactory(FilterFactory filterFactory) {
  188. this.filterFactory = filterFactory;
  189. }
  190. /**
  191. * The factory used to create geometries.
  192. */
  193. public GeometryFactory getGeometryFactory() {
  194. return geometryFactory;
  195. }
  196. /**
  197. * Sets the factory used to create geometries.
  198. *
  199. */
  200. public void setGeometryFactory(GeometryFactory geometryFactory) {
  201. this.geometryFactory = geometryFactory;
  202. }
  203. /**
  204. * Returns the factory used to create the data store.
  205. *
  206. * @return The data store factory, possibly <code>null</code>.
  207. */
  208. public DataStoreFactorySpi getDataStoreFactory() {
  209. return dataStoreFactory;
  210. }
  211. /**
  212. * Sets the data store factory used to create the datastore.
  213. * <p>
  214. * WARNING: This property should only be set in cases where the datastore factory is
  215. * stateless and does not maintain any references to created datastores. Setting this
  216. * property in such a case will result in a memory leak.
  217. * </p>
  218. */
  219. public void setDataStoreFactory(DataStoreFactorySpi dataStoreFactory) {
  220. this.dataStoreFactory = dataStoreFactory;
  221. }
  222. /**
  223. * The namespace uri of the datastore.
  224. *
  225. * @return The namespace uri, may be <code>null</code>.
  226. */
  227. public String getNamespaceURI() {
  228. return namespaceURI;
  229. }
  230. /**
  231. * Sets the namespace uri of the datastore.
  232. * <p>
  233. * This will be used to qualify the entries or types of the datastore.
  234. * </p>
  235. * @param namespaceURI The namespace uri, may be <code>null</code>.
  236. */
  237. public void setNamespaceURI(String namespaceURI) {
  238. this.namespaceURI = namespaceURI;
  239. }
  240. /**
  241. * The logger for the datastore.
  242. */
  243. public Logger getLogger() {
  244. return LOGGER;
  245. }
  246. //
  247. // DataStore API
  248. //
  249. public ServiceInfo getInfo() {
  250. DefaultServiceInfo info = new DefaultServiceInfo();
  251. info.setDescription("Features from "+getClass().getSimpleName() );
  252. info.setSchema( FeatureTypes.DEFAULT_NAMESPACE );
  253. return info;
  254. }
  255. /**
  256. * Returns the names of all entries or types provided by the datastore.
  257. * <p>
  258. * This method is marked final and delegates to {@link #createTypeNames()},
  259. * which subclasses are intended to implement.
  260. * </p>
  261. *
  262. * @see DataStore#getTypeNames()
  263. */
  264. public final String[] getTypeNames() throws IOException {
  265. List<Name> typeNames = createTypeNames();
  266. String[] names = new String[typeNames.size()];
  267. for (int i = 0; i < typeNames.size(); i++) {
  268. Name typeName = typeNames.get(i);
  269. names[i] = typeName.getLocalPart();
  270. }
  271. return names;
  272. }
  273. /**
  274. * Creates a new schema in the datastore.
  275. * <p>
  276. * This implementation throws a{@link UnsupportedOperationException}. Subclasses
  277. * should override to support schema creation.
  278. * </p>
  279. *
  280. *
  281. * @see DataStore#createSchema(FeatureType)
  282. */
  283. public void createSchema(SimpleFeatureType featureType)
  284. throws IOException {
  285. throw new UnsupportedOperationException();
  286. }
  287. /**
  288. * Returns the feature type or schema matching the specified name.
  289. * <p>
  290. * This method calls through to <code>getFeatureSource(typeName).getSchema()</code>
  291. * </p>
  292. *
  293. * @see DataStore#getSchema(String)
  294. */
  295. public final SimpleFeatureType getSchema(String typeName)
  296. throws IOException {
  297. ContentFeatureSource featureSource = getFeatureSource(typeName);
  298. return featureSource.getSchema();
  299. }
  300. /**
  301. * Returns the feature source matching the specified name.
  302. * <p>
  303. * Subclasses should not implement this method. However overriding in order
  304. * to perform a type narrowing to a subclasses of {@link ContentFeatureSource}
  305. * is acceptable.
  306. * </p>
  307. *
  308. * @see DataStore#getFeatureSource(String)
  309. */
  310. public ContentFeatureSource getFeatureSource(String typeName)
  311. throws IOException {
  312. return getFeatureSource(new NameImpl(namespaceURI,typeName), Transaction.AUTO_COMMIT);
  313. }
  314. /**
  315. * Returns the feature source matching the specified name and explicitly
  316. * specifies a transaction.
  317. * <p>
  318. * Subclasses should not implement this method. However overriding in order
  319. * to perform a type narrowing to a subclasses of {@link ContentFeatureSource}
  320. * is acceptable.
  321. * </p>
  322. *
  323. * @see DataStore#getFeatureSource(String)
  324. */
  325. public ContentFeatureSource getFeatureSource(String typeName, Transaction tx)
  326. throws IOException {
  327. return getFeatureSource( name(typeName), tx );
  328. }
  329. /**
  330. * Returns the feature source matching the specified name and explicitly
  331. * specifies a transaction.
  332. * <p>
  333. * Subclasses should not implement this method. However overriding in order
  334. * to perform a type narrowing to a subclasses of {@link ContentFeatureSource}
  335. * is acceptable.
  336. * </p>
  337. *
  338. * @see DataStore#getFeatureSource(String)
  339. */
  340. public ContentFeatureSource getFeatureSource(Name typeName, Transaction tx)
  341. throws IOException {
  342. ContentEntry entry = ensureEntry(typeName);
  343. ContentFeatureSource featureSource = createFeatureSource(entry);
  344. featureSource.setTransaction(tx);
  345. // if ( tx != Transaction.AUTO_COMMIT ) {
  346. // //setup the transaction state
  347. // synchronized (tx) {
  348. // if ( tx.getState( typeName ) == null ) {
  349. // tx.putState( typeName, createTransactionState(featureSource) );
  350. // }
  351. // }
  352. // }
  353. return featureSource;
  354. }
  355. /**
  356. * Returns a feature reader for the specified query and transaction.
  357. * <p>
  358. * This method is not intended to be overridden and is marked final. This
  359. * implementation delegates to {@link FeatureCollection} and wraps an iterator
  360. * in a {@link FeatureReader}.
  361. * </p>
  362. */
  363. public FeatureReader<SimpleFeatureType, SimpleFeature> getFeatureReader(Query query, Transaction tx)
  364. throws IOException {
  365. if ( query.getTypeName() == null ) {
  366. throw new IllegalArgumentException( "Query does not specify type.");
  367. }
  368. return getFeatureSource(query.getTypeName(),tx).getReader( query );
  369. }
  370. /**
  371. * Returns a feature writer for the specified query and transaction.
  372. * <p>
  373. * This method is not intended to be overridden and is marked final. This
  374. * implementation delegates to {@link FeatureCollection} and wraps an iterator
  375. * in a {@link FeatureWriter}.
  376. * </p>
  377. */
  378. public FeatureWriter<SimpleFeatureType, SimpleFeature> getFeatureWriter(String typeName, Filter filter,
  379. Transaction tx) throws IOException {
  380. ContentFeatureStore featureStore = ensureFeatureStore(typeName,tx);
  381. return featureStore.getWriter( filter , WRITER_UPDATE | WRITER_ADD );
  382. }
  383. /**
  384. * Helper method which gets a feature source ensuring that it is a feature
  385. * store as well. If not it throws an IOException.
  386. *
  387. * @param typeName The name of the feature source.
  388. * @param tx A transaction handle.
  389. *
  390. * @throws IOException If the feature source is not a store.
  391. *
  392. */
  393. protected final ContentFeatureStore ensureFeatureStore(String typeName, Transaction tx)
  394. throws IOException {
  395. ContentFeatureSource featureSource = getFeatureSource(typeName,tx);
  396. if ( !( featureSource instanceof ContentFeatureStore)) {
  397. throw new IOException(typeName + " is read only" );
  398. }
  399. return (ContentFeatureStore) featureSource;
  400. }
  401. /**
  402. * Returns a feature writer for the specified type name and transaction.
  403. * <p>
  404. * This method is convenience for <code>getFeatureWriter(typeName,Filter.INCLUDE,tx)</code>.
  405. * </p>
  406. */
  407. public final FeatureWriter<SimpleFeatureType, SimpleFeature> getFeatureWriter(String typeName, Transaction tx)
  408. throws IOException {
  409. return getFeatureWriter( typeName, Filter.INCLUDE, tx );
  410. }
  411. /**
  412. * Returns an appending feature writer for the specified type name and
  413. * transaction.
  414. * <p>
  415. * This method is not intended to be overridden and is marked final. This
  416. * implementation delegates to {@link FeatureCollection} and wraps an iterator
  417. * in a {@link FeatureWriter}.
  418. * </p>
  419. */
  420. public final FeatureWriter<SimpleFeatureType, SimpleFeature> getFeatureWriterAppend(String typeName, Transaction tx)
  421. throws IOException {
  422. ContentFeatureStore featureStore = ensureFeatureStore(typeName,tx);
  423. FeatureWriter<SimpleFeatureType, SimpleFeature> writer = featureStore.getWriter( Filter.INCLUDE , WRITER_ADD );
  424. // ensure we are at the "end" as we are being asked to return this in "append" mode
  425. while( writer.hasNext() ){
  426. writer.next();
  427. }
  428. return writer;
  429. }
  430. public final LockingManager getLockingManager() {
  431. return lockingManager;
  432. }
  433. public final void updateSchema(String typeName, SimpleFeatureType featureType)
  434. throws IOException {
  435. throw new UnsupportedOperationException();
  436. }
  437. public void dispose() {
  438. for ( ContentEntry entry : entries.values() ) {
  439. entry.dispose();
  440. }
  441. }
  442. /**
  443. * Returns the entry for a specified name, or <code>null</code> if no such
  444. * entry exists.
  445. */
  446. public ContentEntry getEntry( Name name ) {
  447. return (ContentEntry) entries.get(name);
  448. }
  449. //
  450. // Internal API
  451. //
  452. /**
  453. * Instantiates a new content state for the entry.
  454. * <p>
  455. * Subclasses may override this method to return a specific subclass of
  456. * {@link ContentState}.
  457. * </p>
  458. * @param entry The entry.
  459. *
  460. * @return A new instance of {@link ContentState} for the entry.
  461. *
  462. */
  463. protected ContentState createContentState(ContentEntry entry) {
  464. return new ContentState( entry );
  465. }
  466. /**
  467. * Helper method to wrap a non-qualified name.
  468. */
  469. final protected Name name(String typeName) {
  470. return new NameImpl(namespaceURI,typeName);
  471. }
  472. /**
  473. * Helper method to look up an entry in the datastore.
  474. * <p>
  475. * This method will create a new instance of {@link ContentEntry} if one
  476. * does not exist.
  477. * </p>
  478. * <p>
  479. * In the event that the name does not map to an entry
  480. * and one cannot be created <code>null</code> will be returned. Note that
  481. * {@link #ensureEntry(TypeName)} will throw an exception in this case.
  482. * </p>
  483. *
  484. * @param The name of the entry.
  485. *
  486. * @return The entry, or <code>null</code> if it does not exist.
  487. */
  488. final protected ContentEntry entry(Name name) throws IOException {
  489. ContentEntry entry = null;
  490. //do we already know about the entry
  491. if (!entries.containsKey(name)) {
  492. //is this type available?
  493. List<Name> typeNames = createTypeNames();
  494. if (typeNames.contains(name)) {
  495. //yes, create an entry for it
  496. synchronized (this) {
  497. if (!entries.containsKey(name)) {
  498. entry = new ContentEntry(this, name);
  499. entries.put(name, entry);
  500. }
  501. }
  502. entry = (ContentEntry) entries.get(name);
  503. }
  504. }
  505. return (ContentEntry) entries.get(name);
  506. }
  507. /**
  508. * Helper method to look up an entry in the datastore which throws an
  509. * {@link IOException} in the event that the entry does not exist.
  510. *
  511. * @param name The name of the entry.
  512. *
  513. * @return The entry.
  514. *
  515. * @throws IOException If the entry does not exist, or if there was an error
  516. * looking it up.
  517. */
  518. final protected ContentEntry ensureEntry(Name name)
  519. throws IOException {
  520. ContentEntry entry = entry(name);
  521. if (entry == null) {
  522. throw new IOException("Schema '" + name + "' does not exist.");
  523. }
  524. return entry;
  525. }
  526. /**
  527. * Creates a set of qualified names corresponding to the types that the
  528. * datastore provides.
  529. * <p>
  530. * Namespaces may be left <code>null</code> for data stores which do not
  531. * support namespace qualified type names.
  532. * </p>
  533. *
  534. * @return A list of {@link Name}.
  535. *
  536. * @throws IOException Any errors occuring connecting to data.
  537. */
  538. protected abstract List<Name> createTypeNames()
  539. throws IOException;
  540. /**
  541. * Instantiates new feature source for the entry.
  542. * <p>
  543. * Subclasses should override this method to return a specific subclass of
  544. * {@link ContentFeatureSource}.
  545. * </p>
  546. * @param entry The entry.
  547. *
  548. * @return An new instance of {@link ContentFeatureSource} for the entry.
  549. */
  550. protected abstract ContentFeatureSource createFeatureSource(ContentEntry entry)
  551. throws IOException;
  552. /**
  553. * Instantiates a new transaction state object.
  554. * <p>
  555. * Subclasses should override method to return a specific instance of
  556. * {@link Transaction.State}.
  557. * </p>
  558. * @param SimpleFeatureSource The feature source / store for the new transaction
  559. * state.
  560. */
  561. // protected abstract Transaction.State createTransactionState(ContentSimpleFeatureSource featureSource)
  562. // throws IOException;
  563. /**
  564. * Delegates to {@link #getFeatureSource(String)} with
  565. * {@code name.getLocalPart()}
  566. *
  567. * @since 2.5
  568. * @see DataAccess#getFeatureSource(Name)
  569. */
  570. public SimpleFeatureSource getFeatureSource(Name typeName)
  571. throws IOException {
  572. return getFeatureSource(typeName.getLocalPart());
  573. }
  574. /**
  575. * Returns the same list of names than {@link #getTypeNames()} meaning the
  576. * returned Names have no namespace set.
  577. *
  578. * @since 2.5
  579. * @see DataAccess#getNames()
  580. */
  581. public List<Name> getNames() throws IOException {
  582. String[] typeNames = getTypeNames();
  583. List<Name> names = new ArrayList<Name>(typeNames.length);
  584. for (String typeName : typeNames) {
  585. names.add(new NameImpl(typeName));
  586. }
  587. return names;
  588. }
  589. /**
  590. * Delegates to {@link #getSchema(String)} with {@code name.getLocalPart()}
  591. *
  592. * @since 2.5
  593. * @see DataAccess#getSchema(Name)
  594. */
  595. public SimpleFeatureType getSchema(Name name) throws IOException {
  596. return getSchema(name.getLocalPart());
  597. }
  598. /**
  599. * Delegates to {@link #updateSchema(String, SimpleFeatureType)} with
  600. * {@code name.getLocalPart()}
  601. *
  602. * @since 2.5
  603. * @see DataAccess#getFeatureSource(Name)
  604. */
  605. public void updateSchema(Name typeName, SimpleFeatureType featureType) throws IOException {
  606. updateSchema(typeName.getLocalPart(), featureType);
  607. }
  608. }