001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/ogcwebservices/wfs/LockFeatureHandler.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree.
005     Copyright (C) 2001-2006 by:
006     EXSE, Department of Geography, University of Bonn
007     http://www.giub.uni-bonn.de/deegree/
008     lat/lon GmbH
009     http://www.lat-lon.de
010    
011     This library is free software; you can redistribute it and/or
012     modify it under the terms of the GNU Lesser General Public
013     License as published by the Free Software Foundation; either
014     version 2.1 of the License, or (at your option) any later version.
015    
016     This library is distributed in the hope that it will be useful,
017     but WITHOUT ANY WARRANTY; without even the implied warranty of
018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
019     Lesser General Public License for more details.
020    
021     You should have received a copy of the GNU Lesser General Public
022     License along with this library; if not, write to the Free Software
023     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
024    
025     Contact:
026    
027     Andreas Poth
028     lat/lon GmbH
029     Aennchenstr. 19
030     53177 Bonn
031     Germany
032     E-Mail: poth@lat-lon.de
033    
034     Prof. Dr. Klaus Greve
035     Department of Geography
036     University of Bonn
037     Meckenheimer Allee 166
038     53115 Bonn
039     Germany
040     E-Mail: greve@giub.uni-bonn.de
041    
042     ---------------------------------------------------------------------------*/
043    package org.deegree.ogcwebservices.wfs;
044    
045    import java.util.ArrayList;
046    import java.util.HashMap;
047    import java.util.List;
048    import java.util.Map;
049    import java.util.Set;
050    
051    import org.deegree.datatypes.QualifiedName;
052    import org.deegree.framework.log.ILogger;
053    import org.deegree.framework.log.LoggerFactory;
054    import org.deegree.i18n.Messages;
055    import org.deegree.io.datastore.Datastore;
056    import org.deegree.io.datastore.DatastoreException;
057    import org.deegree.io.datastore.FeatureId;
058    import org.deegree.io.datastore.LockManager;
059    import org.deegree.io.datastore.schema.MappedFeatureType;
060    import org.deegree.model.feature.Feature;
061    import org.deegree.model.feature.FeatureCollection;
062    import org.deegree.model.feature.schema.FeatureType;
063    import org.deegree.ogcwebservices.OGCWebServiceException;
064    import org.deegree.ogcwebservices.wfs.operation.FeatureResult;
065    import org.deegree.ogcwebservices.wfs.operation.GetFeature;
066    import org.deegree.ogcwebservices.wfs.operation.GetFeatureWithLock;
067    import org.deegree.ogcwebservices.wfs.operation.Lock;
068    import org.deegree.ogcwebservices.wfs.operation.LockFeature;
069    import org.deegree.ogcwebservices.wfs.operation.LockFeatureResponse;
070    import org.deegree.ogcwebservices.wfs.operation.Query;
071    
072    /**
073     * Handles {@link LockFeature} requests to the {@link WFService}.
074     * 
075     * @author <a href="mailto:schneider@lat-lon.de">Markus Schneider</a>
076     * @author last edited by: $Author: mschneider $
077     * 
078     * @version $Revision: 6535 $, $Date: 2007-04-03 18:49:53 +0200 (Di, 03 Apr 2007) $
079     */
080    class LockFeatureHandler {
081    
082        private static final ILogger LOG = LoggerFactory.getLogger( LockFeatureHandler.class );
083    
084        // shared instance to handle GetFeature requests (for GetFeatureWithLock)
085        private GetFeatureHandler getFeatureHandler;
086    
087        private WFService wfs;
088    
089        /**
090         * Creates a new instance of <code>LockFeatureHandler</code>. Only called by the associated
091         * {@link WFService} (once).
092         * 
093         * @param wfs
094         *            associated WFService
095         */
096        LockFeatureHandler( WFService wfs ) {
097            this.wfs = wfs;
098            this.getFeatureHandler = new GetFeatureHandler( wfs );
099        }
100    
101        /**
102         * Handles a {@link LockFeature} request.
103         * 
104         * @param request
105         *            <code>LockFeature</code> request to perform
106         * @return response to the request
107         * @throws OGCWebServiceException
108         */
109        LockFeatureResponse handleRequest( LockFeature request )
110                                throws OGCWebServiceException {
111    
112            LockFeatureResponse response = null;
113    
114            try {
115                List<FeatureId> fidsToLock = new ArrayList<FeatureId>();
116                Map<Datastore, List<Lock>> dsToLocksMap = buildDsToLocksMap( request );
117                for ( Datastore ds : dsToLocksMap.keySet() ) {
118                    fidsToLock.addAll( ds.determineFidsToLock( dsToLocksMap.get( ds ) ) );
119                }
120                org.deegree.io.datastore.Lock lock = LockManager.getInstance().acquireLock( request,
121                                                                                            fidsToLock );
122                Set<String> lockedFeatures = lock.getLockedFids();
123                String[] lockedFids = new String[lockedFeatures.size()];
124                String[] notLockedFids = new String[fidsToLock.size() - lockedFeatures.size()];
125                int lockedIdx = 0, notLockedIdx = 0;
126                for ( FeatureId fid : fidsToLock ) {
127                    String fidAsString = fid.getAsString();
128                    if ( lockedFeatures.contains( fidAsString ) ) {
129                        lockedFids[lockedIdx++] = fidAsString;
130                    } else {
131                        notLockedFids[notLockedIdx++] = fidAsString;
132                    }
133                }
134                response = new LockFeatureResponse( request, lock.getId(), lockedFids, notLockedFids );
135            } catch ( DatastoreException e ) {
136                LOG.logDebug( e.getMessage(), e );
137                throw new OGCWebServiceException( this.getClass().getName(), e.getMessage() );
138            }
139    
140            return response;
141        }
142    
143        /**
144         * Handles a {@link GetFeatureWithLock} request.
145         * <p>
146         * This is performed using the following strategy:
147         * <ul>
148         * <li>Perform the request as a standard {@link GetFeature} request.</li>
149         * <li>Create a corresponding {@link LockFeature} request from the {@link GetFeatureWithLock}
150         * request.</li>
151         * <li>Set the "lockId" attribute in the result feature collection.</li>
152         * <li>Remove all features from the feature collection that could not be locked.</li>
153         * </ul>
154         * 
155         * @param request
156         *            <code>GetFeatureWithLock</code> request to perform
157         * @return response to the request
158         * @throws OGCWebServiceException
159         */
160        FeatureResult handleRequest( GetFeatureWithLock request )
161                                throws OGCWebServiceException {
162    
163            FeatureResult response = this.getFeatureHandler.handleRequest( request );
164    
165            List<Lock> locks = new ArrayList<Lock>( request.getQuery().length );
166            for ( Query query : request.getQuery() ) {
167                Lock lock = new Lock( null, query.getTypeNames()[0], query.getFilter() );
168                locks.add( lock );
169            }
170            LockFeature lockRequest = LockFeature.create( WFService.VERSION, null, null,
171                                                          request.getExpiry(), request.getLockAction(),
172                                                          locks );
173            LockFeatureResponse lockResponse = handleRequest( lockRequest );
174    
175            // set "lockId" parameter in result feature collection
176            FeatureCollection fc = (FeatureCollection) response.getResponse();
177            fc.setAttribute( "lockId", lockResponse.getLockId() );
178    
179            // remove all features from the result feature collection that could not be locked (and
180            // count removed features)
181            int removed = 0;
182            for ( String notLockedFid : lockResponse.getFeaturesNotLocked() ) {
183                Feature feature = fc.getFeature( notLockedFid );
184                if ( feature != null ) {
185                    fc.remove( feature );
186                    removed ++;
187                }
188            }
189    
190            // correct "numberOfFeatures" attribute (and make it work even for resultType=HITS)
191            int before = Integer.parseInt( fc.getAttribute( "numberOfFeatures" ) );
192            fc.setAttribute( "numberOfFeatures", "" + (before - removed) );
193    
194            return response;
195        }
196    
197        /**
198         * Groups all {@link Lock}s contained in the given {@link LockFeature} request by the
199         * responsible {@link Datastore}, i.e. that serves the {@link FeatureType} to be locked.
200         * 
201         * @param request
202         * @return keys: responsible <code>Datastore</code>, values: List of <code>Lock</code>s
203         * @throws OGCWebServiceException
204         */
205        private Map<Datastore, List<Lock>> buildDsToLocksMap( LockFeature request )
206                                throws OGCWebServiceException {
207    
208            Map<Datastore, List<Lock>> dsToLocksMap = new HashMap<Datastore, List<Lock>>();
209            List<Lock> locks = request.getLocks();
210    
211            for ( Lock lock : locks ) {
212                QualifiedName ftName = lock.getTypeName();
213                MappedFeatureType ft = this.wfs.getMappedFeatureType( ftName );
214    
215                if ( ft == null ) {
216                    String msg = Messages.getMessage( "WFS_FEATURE_TYPE_UNKNOWN", ftName );
217                    throw new OGCWebServiceException( this.getClass().getName(), msg );
218                }
219                if ( ft.isAbstract() ) {
220                    String msg = Messages.getMessage( "WFS_FEATURE_TYPE_ABSTRACT", ftName );
221                    throw new OGCWebServiceException( this.getClass().getName(), msg );
222                }
223                if ( !ft.isVisible() ) {
224                    String msg = Messages.getMessage( "WFS_FEATURE_TYPE_INVISIBLE", ftName );
225                    throw new OGCWebServiceException( this.getClass().getName(), msg );
226                }
227    
228                Datastore ds = ft.getGMLSchema().getDatastore();
229                List<Lock> dsLocks = dsToLocksMap.get( ds );
230                if ( dsLocks == null ) {
231                    dsLocks = new ArrayList<Lock>();
232                    dsToLocksMap.put( ds, dsLocks );
233                }
234                dsLocks.add( lock );
235            }
236            return dsToLocksMap;
237        }
238    }