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: hrubach $
072     *
073     * @version $Revision: 23693 $, $Date: 2010-04-20 14:33:55 +0200 (Di, 20 Apr 2010) $
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        public static final int SRS_UNDEFINED = -1;
086    
087        /**
088         * Returns the datastore specific annotation parser.
089         *
090         * @return the datastore specific annotation parser
091         */
092        public abstract AnnotationDocument getAnnotationParser();
093    
094        /**
095         * Configures the datastore with the supplied configuration.
096         *
097         * @param config
098         *            configuration
099         * @throws DatastoreException
100         */
101        @SuppressWarnings("unused")
102        public void configure( DatastoreConfiguration config )
103                                throws DatastoreException {
104            this.config = config;
105        }
106    
107        /**
108         * Returns the configuration parameters of the datastore.
109         *
110         * @return the configuration parameters of the datastore
111         */
112        public DatastoreConfiguration getConfiguration() {
113            return this.config;
114        }
115    
116        /**
117         * Adds the given GML application schema to the set of schemas that are handled by this
118         * datastore instance.
119         * <p>
120         * Note that this method may be called several times for every GML schema that uses this
121         * datastore instance.
122         *
123         * @param schema
124         *            GML application schema to bind
125         * @throws DatastoreException
126         */
127        @SuppressWarnings("unused")
128        public void bindSchema( MappedGMLSchema schema )
129                                throws DatastoreException {
130            this.schemas.add( schema );
131        }
132    
133        /**
134         * Returns the GML application schemas that are handled by this datastore.
135         *
136         * @return the GML application schemas that are handled by this datastore
137         */
138        public MappedGMLSchema[] getSchemas() {
139            return this.schemas.toArray( new MappedGMLSchema[this.schemas.size()] );
140        }
141    
142        /**
143         * Returns the feature type with the given name.
144         *
145         * @param ftName
146         *            name of the feature type
147         * @return the feature type with the given name, or null if the <code>Datastore</code> does
148         *         not this feature type
149         */
150        public MappedFeatureType getFeatureType( QualifiedName ftName ) {
151            MappedFeatureType ft = null;
152            MappedGMLSchema[] schemas = getSchemas();
153            for ( int i = 0; i < schemas.length; i++ ) {
154                ft = schemas[i].getFeatureType( ftName );
155                if ( ft != null ) {
156                    break;
157                }
158            }
159            return ft;
160        }
161    
162        /**
163         * Closes the datastore so it can free dependent resources.
164         *
165         * @throws DatastoreException
166         */
167        public abstract void close()
168                                throws DatastoreException;
169    
170        /**
171         * Performs a query against the datastore.
172         *
173         * @param query
174         *            query to be performed
175         * @param rootFts
176         *            the root feature types that are queried, more than one type means that the types
177         *            are joined
178         * @return requested feature instances
179         * @throws DatastoreException
180         * @throws UnknownCRSException
181         */
182        public abstract FeatureCollection performQuery( final Query query, final MappedFeatureType[] rootFts )
183                                throws DatastoreException, UnknownCRSException;
184    
185        /**
186         * Performs a query against the datastore (in the given transaction context).
187         *
188         * @param query
189         *            query to be performed
190         * @param rootFts
191         *            the root feature types that are queried, more than one type means that the types
192         *            are joined
193         * @param context
194         *            context (used to specify the JDBCConnection, for example)
195         * @return requested feature instances
196         * @throws DatastoreException
197         * @throws UnknownCRSException
198         */
199        public abstract FeatureCollection performQuery( final Query query, final MappedFeatureType[] rootFts,
200                                                        final DatastoreTransaction context )
201                                throws DatastoreException, UnknownCRSException;
202    
203        /**
204         * Determines the ids of all features to be locked by the given parts of a {@link LockFeature}
205         * request, this includes all descendant and super features of the targeted features as well.
206         *
207         * @param requestParts
208         *            the parts of a <code>LockFeature</code> request that this <code>Datastore</code>
209         *            is responsible for
210         * @return the ids of all features that have to be locked
211         * @throws DatastoreException
212         */
213        public Set<FeatureId> determineFidsToLock( @SuppressWarnings("unused")
214        List<Lock> requestParts )
215                                throws DatastoreException {
216            throw new DatastoreException( Messages.getMessage( "DATASTORE_METHOD_UNSUPPORTED", this.getClass().getName(),
217                                                               "#determineFeaturesToLock( LockFeature )" ) );
218        }
219    
220        /**
221         * Acquires transactional access to the datastore instance. There's only one active transaction
222         * per datastore allowed.
223         *
224         * @return transaction object that allows to perform transactions operations on the datastore
225         * @throws DatastoreException
226         */
227        public DatastoreTransaction acquireTransaction()
228                                throws DatastoreException {
229            throw new DatastoreException( Messages.getMessage( "DATASTORE_METHOD_UNSUPPORTED", this.getClass().getName(),
230                                                               "#acquireTransaction()" ) );
231        }
232    
233        /**
234         * Returns the transaction to the datastore. This makes the transaction available to other
235         * clients again (via {@link #acquireTransaction()}). Underlying resources (such as
236         * JDBCConnections are freed).
237         * <p>
238         * The transaction should be terminated, i.e. {@link DatastoreTransaction#commit()} or
239         * {@link DatastoreTransaction#rollback()} must have been called before.
240         *
241         * @param ta
242         *            the DatastoreTransaction to be returned
243         * @throws DatastoreException
244         */
245        public void releaseTransaction( @SuppressWarnings("unused")
246        DatastoreTransaction ta )
247                                throws DatastoreException {
248            throw new DatastoreException( Messages.getMessage( "DATASTORE_METHOD_UNSUPPORTED", this.getClass().getName(),
249                                                               "#releaseTransaction()" ) );
250        }
251    
252        /**
253         * Transforms the incoming {@link Query} so that the {@link CoordinateSystem} of all spatial
254         * arguments (BBOX, etc.) in the {@link Filter} match the SRS of the targeted
255         * {@link MappingGeometryField}s.
256         * <p>
257         * NOTE: If this transformation can be performed by the backend (e.g. by Oracle Spatial), this
258         * method should be overwritten to return the original input {@link Query}.
259         *
260         * @param query
261         *            query to be transformed
262         * @return query with spatial arguments transformed to target SRS
263         */
264        protected Query transformQuery( Query query ) {
265            LOG.logDebug( "Transforming query." );
266            Object[] result = TP.doPreTrigger( this, query );
267            return (Query) result[0];
268        }
269    
270        /**
271         * Transforms the {@link FeatureCollection} so that the geometries of all contained geometry
272         * properties use the requested SRS.
273         *
274         * @param fc
275         *            feature collection to be transformed
276         * @param targetSRS
277         *            requested SRS
278         * @return transformed FeatureCollection
279         */
280        protected FeatureCollection transformResult( FeatureCollection fc, String targetSRS ) {
281            LOG.logDebug( "Transforming result to SRS '" + targetSRS + "'." );
282            Object[] result = TP.doPostTrigger( this, fc, targetSRS );
283            return (FeatureCollection) result[0];
284        }
285    
286        /**
287         * Returns whether the datastore is capable of performing a native coordinate transformation
288         * (using an SQL function call for example) into the given SRS.
289         * <p>
290         * <code>Datastore</code> implementations capable of performing native coordinate
291         * transformations must override this class.
292         *
293         * @param targetSRS
294         *            target spatial reference system (usually "EPSG:XYZ")
295         * @return true, if the datastore can perform the coordinate transformation, false otherwise
296         */
297        protected boolean canTransformTo( @SuppressWarnings("unused")
298        String targetSRS ) {
299            return false;
300        }
301    }