001    //$Header: /deegreerepository/deegree/src/org/deegree/io/datastore/Datastore.java,v 1.28 2007/01/16 13:58:34 mschneider Exp $
002    /*----------------------------------------------------------------------------
003     This file is part of deegree, http://deegree.org/
004     Copyright (C) 2001-2009 by:
005       Department of Geography, University of Bonn
006     and
007       lat/lon GmbH
008    
009     This library is free software; you can redistribute it and/or modify it under
010     the terms of the GNU Lesser General Public License as published by the Free
011     Software Foundation; either version 2.1 of the License, or (at your option)
012     any later version.
013     This library is distributed in the hope that it will be useful, but WITHOUT
014     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
015     FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
016     details.
017     You should have received a copy of the GNU Lesser General Public License
018     along with this library; if not, write to the Free Software Foundation, Inc.,
019     59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020    
021     Contact information:
022    
023     lat/lon GmbH
024     Aennchenstr. 19, 53177 Bonn
025     Germany
026     http://lat-lon.de/
027    
028     Department of Geography, University of Bonn
029     Prof. Dr. Klaus Greve
030     Postfach 1147, 53001 Bonn
031     Germany
032     http://www.geographie.uni-bonn.de/deegree/
033    
034     e-mail: info@deegree.org
035    ----------------------------------------------------------------------------*/
036    package org.deegree.io.datastore;
037    
038    import java.util.ArrayList;
039    import java.util.Collection;
040    import java.util.List;
041    import java.util.Set;
042    
043    import org.deegree.datatypes.QualifiedName;
044    import org.deegree.framework.log.ILogger;
045    import org.deegree.framework.log.LoggerFactory;
046    import org.deegree.framework.trigger.TriggerProvider;
047    import org.deegree.i18n.Messages;
048    import org.deegree.io.datastore.schema.MappedFeatureType;
049    import org.deegree.io.datastore.schema.MappedGMLSchema;
050    import org.deegree.io.datastore.schema.content.MappingGeometryField;
051    import org.deegree.model.crs.CoordinateSystem;
052    import org.deegree.model.crs.UnknownCRSException;
053    import org.deegree.model.feature.Feature;
054    import org.deegree.model.feature.FeatureCollection;
055    import org.deegree.model.filterencoding.Filter;
056    import org.deegree.ogcwebservices.wfs.WFService;
057    import org.deegree.ogcwebservices.wfs.operation.Lock;
058    import org.deegree.ogcwebservices.wfs.operation.LockFeature;
059    import org.deegree.ogcwebservices.wfs.operation.Query;
060    
061    /**
062     * A datastore implementation must extend this class.
063     * <p>
064     * Describes the access to a datastore that encapsulates the access to a database or file. The
065     * accessible objects are {@link Feature} instances. Primarily, datastores are used as persistence
066     * layer by the {@link WFService} class.
067     *
068     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth </a>
069     * @author <a href="mailto:tfr@users.sourceforge.net">Torsten Friebe </a>
070     * @author <a href="mailto:schneider@lat-lon.de">Markus Schneider </a>
071     * @author last edited by: $Author: mschneider $
072     *
073     * @version $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
074     */
075    public abstract class Datastore {
076    
077        private static final TriggerProvider TP = TriggerProvider.create( Datastore.class );
078    
079        private static final ILogger LOG = LoggerFactory.getLogger( Datastore.class );
080    
081        private Collection<MappedGMLSchema> schemas = new ArrayList<MappedGMLSchema>( 10 );
082    
083        private DatastoreConfiguration config;
084    
085        /**
086         * Returns the datastore specific annotation parser.
087         *
088         * @return the datastore specific annotation parser
089         */
090        public abstract AnnotationDocument getAnnotationParser();
091    
092        /**
093         * Configures the datastore with the supplied configuration.
094         *
095         * @param config
096         *            configuration
097         * @throws DatastoreException
098         */
099        @SuppressWarnings("unused")
100        public void configure( DatastoreConfiguration config )
101                                throws DatastoreException {
102            this.config = config;
103        }
104    
105        /**
106         * Returns the configuration parameters of the datastore.
107         *
108         * @return the configuration parameters of the datastore
109         */
110        public DatastoreConfiguration getConfiguration() {
111            return this.config;
112        }
113    
114        /**
115         * Adds the given GML application schema to the set of schemas that are handled by this
116         * datastore instance.
117         * <p>
118         * Note that this method may be called several times for every GML schema that uses this
119         * datastore instance.
120         *
121         * @param schema
122         *            GML application schema to bind
123         * @throws DatastoreException
124         */
125        @SuppressWarnings("unused")
126        public void bindSchema( MappedGMLSchema schema )
127                                throws DatastoreException {
128            this.schemas.add( schema );
129        }
130    
131        /**
132         * Returns the GML application schemas that are handled by this datastore.
133         *
134         * @return the GML application schemas that are handled by this datastore
135         */
136        public MappedGMLSchema[] getSchemas() {
137            return this.schemas.toArray( new MappedGMLSchema[this.schemas.size()] );
138        }
139    
140        /**
141         * Returns the feature type with the given name.
142         *
143         * @param ftName
144         *            name of the feature type
145         * @return the feature type with the given name, or null if the <code>Datastore</code> does
146         *         not this feature type
147         */
148        public MappedFeatureType getFeatureType( QualifiedName ftName ) {
149            MappedFeatureType ft = null;
150            MappedGMLSchema[] schemas = getSchemas();
151            for ( int i = 0; i < schemas.length; i++ ) {
152                ft = schemas[i].getFeatureType( ftName );
153                if ( ft != null ) {
154                    break;
155                }
156            }
157            return ft;
158        }
159    
160        /**
161         * Closes the datastore so it can free dependent resources.
162         *
163         * @throws DatastoreException
164         */
165        public abstract void close()
166                                throws DatastoreException;
167    
168        /**
169         * Performs a query against the datastore.
170         *
171         * @param query
172         *            query to be performed
173         * @param rootFts
174         *            the root feature types that are queried, more than one type means that the types
175         *            are joined
176         * @return requested feature instances
177         * @throws DatastoreException
178         * @throws UnknownCRSException
179         */
180        public abstract FeatureCollection performQuery( final Query query, final MappedFeatureType[] rootFts )
181                                throws DatastoreException, UnknownCRSException;
182    
183        /**
184         * Performs a query against the datastore (in the given transaction context).
185         *
186         * @param query
187         *            query to be performed
188         * @param rootFts
189         *            the root feature types that are queried, more than one type means that the types
190         *            are joined
191         * @param context
192         *            context (used to specify the JDBCConnection, for example)
193         * @return requested feature instances
194         * @throws DatastoreException
195         * @throws UnknownCRSException
196         */
197        public abstract FeatureCollection performQuery( final Query query, final MappedFeatureType[] rootFts,
198                                                        final DatastoreTransaction context )
199                                throws DatastoreException, UnknownCRSException;
200    
201        /**
202         * Determines the ids of all features to be locked by the given parts of a {@link LockFeature}
203         * request, this includes all descendant and super features of the targeted features as well.
204         *
205         * @param requestParts
206         *            the parts of a <code>LockFeature</code> request that this <code>Datastore</code>
207         *            is responsible for
208         * @return the ids of all features that have to be locked
209         * @throws DatastoreException
210         */
211        public Set<FeatureId> determineFidsToLock( @SuppressWarnings("unused")
212        List<Lock> requestParts )
213                                throws DatastoreException {
214            throw new DatastoreException( Messages.getMessage( "DATASTORE_METHOD_UNSUPPORTED", this.getClass().getName(),
215                                                               "#determineFeaturesToLock( LockFeature )" ) );
216        }
217    
218        /**
219         * Acquires transactional access to the datastore instance. There's only one active transaction
220         * per datastore allowed.
221         *
222         * @return transaction object that allows to perform transactions operations on the datastore
223         * @throws DatastoreException
224         */
225        public DatastoreTransaction acquireTransaction()
226                                throws DatastoreException {
227            throw new DatastoreException( Messages.getMessage( "DATASTORE_METHOD_UNSUPPORTED", this.getClass().getName(),
228                                                               "#acquireTransaction()" ) );
229        }
230    
231        /**
232         * Returns the transaction to the datastore. This makes the transaction available to other
233         * clients again (via {@link #acquireTransaction()}). Underlying resources (such as
234         * JDBCConnections are freed).
235         * <p>
236         * The transaction should be terminated, i.e. {@link DatastoreTransaction#commit()} or
237         * {@link DatastoreTransaction#rollback()} must have been called before.
238         *
239         * @param ta
240         *            the DatastoreTransaction to be returned
241         * @throws DatastoreException
242         */
243        public void releaseTransaction( @SuppressWarnings("unused")
244        DatastoreTransaction ta )
245                                throws DatastoreException {
246            throw new DatastoreException( Messages.getMessage( "DATASTORE_METHOD_UNSUPPORTED", this.getClass().getName(),
247                                                               "#releaseTransaction()" ) );
248        }
249    
250        /**
251         * Transforms the incoming {@link Query} so that the {@link CoordinateSystem} of all spatial
252         * arguments (BBOX, etc.) in the {@link Filter} match the SRS of the targeted
253         * {@link MappingGeometryField}s.
254         * <p>
255         * NOTE: If this transformation can be performed by the backend (e.g. by Oracle Spatial), this
256         * method should be overwritten to return the original input {@link Query}.
257         *
258         * @param query
259         *            query to be transformed
260         * @return query with spatial arguments transformed to target SRS
261         */
262        protected Query transformQuery( Query query ) {
263            LOG.logDebug( "Transforming query." );
264            Object[] result = TP.doPreTrigger( this, query );
265            return (Query) result[0];
266        }
267    
268        /**
269         * Transforms the {@link FeatureCollection} so that the geometries of all contained geometry
270         * properties use the requested SRS.
271         *
272         * @param fc
273         *            feature collection to be transformed
274         * @param targetSRS
275         *            requested SRS
276         * @return transformed FeatureCollection
277         */
278        protected FeatureCollection transformResult( FeatureCollection fc, String targetSRS ) {
279            LOG.logDebug( "Transforming result to SRS '" + targetSRS + "'." );
280            Object[] result = TP.doPostTrigger( this, fc, targetSRS );
281            return (FeatureCollection) result[0];
282        }
283    
284        /**
285         * Returns whether the datastore is capable of performing a native coordinate transformation
286         * (using an SQL function call for example) into the given SRS.
287         * <p>
288         * <code>Datastore</code> implementations capable of performing native coordinate
289         * transformations must override this class.
290         *
291         * @param targetSRS
292         *            target spatial reference system (usually "EPSG:XYZ")
293         * @return true, if the datastore can perform the coordinate transformation, false otherwise
294         */
295        protected boolean canTransformTo( @SuppressWarnings("unused")
296        String targetSRS ) {
297            return false;
298        }
299    }