/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2003-2008, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.data.postgis;
import java.io.IOException;
import java.util.NoSuchElementException;
import java.util.logging.Logger;
import org.geotools.data.DataSourceException;
import org.geotools.data.DefaultQuery;
import org.geotools.data.FeatureLock;
import org.geotools.data.FeatureLockException;
import org.geotools.data.FeatureLocking;
import org.geotools.data.FeatureReader;
import org.geotools.data.LockingManager;
import org.geotools.data.Query;
import org.geotools.feature.FeatureIterator;
import org.geotools.feature.IllegalAttributeException;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.filter.Filter;
/**
* Extends PostgisFeatureLocking with support for Locking.
*
* <p>
* This class will be, horror, modey. While the are plenty of Object Oriented
* ways to fix this I have a deadline right now.
* </p>
*
* <p>
* When the DataStore is constructed it will create a LockingManager only if
* the Postgis implementation does not support database locking. If the
* lockingManger is present it will be used.
* </p>
*
* <p>
* If the lockingManger is not present, the this class will use Database
* locking
* </p>
*
* @author Jody Garnett, Refractions Research, Inc
* @source $URL$
* @version $Id$
*/
public class PostgisFeatureLocking extends PostgisFeatureStore
implements FeatureLocking<SimpleFeatureType, SimpleFeature> {
/** The logger for the postgis module. */
private static final Logger LOGGER = org.geotools.util.logging.Logging.getLogger(
"org.geotools.data.postgis");
FeatureLock featureLock = FeatureLock.TRANSACTION;
public PostgisFeatureLocking(PostgisDataStore postgisDataStore,
SimpleFeatureType featureType) throws IOException {
super(postgisDataStore, featureType);
}
/**
* Provide a FeatureLock for locking operations to operate against.
*
* <p>
* Initial Transactional duration locks can be restored with
* setFeatureLock( FetaureLock.TRANSACTION )
* </p>
*
* @param lock FeatureLock (or FeatureLock.TRANSACTION );
*
* @throws NullPointerException If lock was <code>null</code>
*
* @see org.geotools.data.FeatureLocking#setFeatureLock(org.geotools.data.FeatureLock)
*/
public void setFeatureLock(FeatureLock lock) {
if (lock == null) {
throw new NullPointerException(
"A FeatureLock is required - did you mean FeatureLock.TRANSACTION?");
}
featureLock = lock;
}
/**
* Lock all Features
*
* @return Number of Locked features
*
* @throws IOException
*
* @see org.geotools.data.FeatureLocking#lockFeatures()
*/
public int lockFeatures() throws IOException {
return lockFeatures(Filter.INCLUDE);
}
/**
* Lock features matching <code>filter</code>.
*
* @param filter
*
* @return Number of locked Features
*
* @throws IOException
*
* @see org.geotools.data.FeatureLocking#lockFeatures(org.geotools.filter.Filter)
*/
public int lockFeatures(Filter filter) throws IOException {
return lockFeatures(new DefaultQuery(getSchema().getTypeName(), filter));
}
public int lockFeatures( org.geotools.filter.Filter filter ) throws IOException {
return lockFeatures(new DefaultQuery(getSchema().getTypeName(), filter));
}
/**
* Lock features matching Query.
*
* <p>
* FeatureStores that have provided their own locking to will need to
* override this method.
* </p>
*
* @param query
*
* @return Number of locked Features
*
* @throws IOException If we could not determine which feature to lock
* based on Query
* @throws UnsupportedOperationException When DataStore does not provide a
* LockingManager
* @throws DataSourceException If feature to be locked does not exist
*
* @see org.geotools.data.FeatureLocking#lockFeatures(org.geotools.data.Query)
*/
public int lockFeatures(Query query) throws IOException {
LockingManager lockingManager = getDataStore().getLockingManager();
if (lockingManager == null) {
throw new UnsupportedOperationException(
"DataStore not using lockingManager, must provide alternate implementation");
}
String typeName = getSchema().getTypeName();
if ((query.getTypeName() != null)
&& !typeName.equals(query.getTypeName())) {
throw new IOException("Query typeName does not match "
+ getSchema().getTypeName() + ":" + query);
}
// Reduce the Query to only return the FetureID here?
// Good idea, but it's not working right now, so we're just using the query passed in.
Query optimizedQuery = new DefaultQuery(typeName, query.getFilter(),
query.getMaxFeatures(), Query.NO_NAMES, query.getHandle());
FeatureIterator<SimpleFeature> reader = getFeatures(query).features();
SimpleFeature feature;
int count = 0;
LOGGER.info("got reader from query " + optimizedQuery
+ ", reader has next " + reader.hasNext());
try {
while (reader.hasNext()) {
try {
feature = (SimpleFeature) reader.next();
lockingManager.lockFeatureID(typeName, feature.getID(),
transaction, featureLock);
count++;
LOGGER.info("locked feature " + feature);
} catch (FeatureLockException locked) {
LOGGER.info("feature lock exception");
// could not acquire - don't increment count
} catch (NoSuchElementException nosuch) {
throw new DataSourceException("Problem with "
+ query.getHandle() + " while locking", nosuch);
}
}
} finally {
reader.close();
}
return count;
}
/**
* HACK HACK HACK!!! Don't use unless you're working on geoserver. just
* using ints for return now, to easily swap out with what we've got going
* on right now.
*
* @param feature DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws IOException DOCUMENT ME!
* @throws UnsupportedOperationException DOCUMENT ME!
*/
public int lockFeature(SimpleFeature feature) throws IOException {
LockingManager lockingManager = getDataStore().getLockingManager();
if (lockingManager == null) {
throw new UnsupportedOperationException(
"DataStore not using lockingManager, must provide alternate implementation");
}
try {
//TODO: more checking here, check feature.typename == this.typename
//perhaps even feature.getFeatureType == this.featureType.
lockingManager.lockFeatureID(tableName, feature.getID(),
getTransaction(), featureLock);
return 1;
} catch (FeatureLockException locked) {
return 0;
}
}
/**
* Unlock all Features.
*
* @throws IOException
*
* @see org.geotools.data.FeatureLocking#unLockFeatures()
*/
public void unLockFeatures() throws IOException {
unLockFeatures(Filter.INCLUDE);
}
/**
* Unlock Features specified by <code>filter</code>.
*
* @param filter
*
* @throws IOException
*
* @see org.geotools.data.FeatureLocking#unLockFeatures(org.geotools.filter.Filter)
*/
public void unLockFeatures(Filter filter) throws IOException {
unLockFeatures(new DefaultQuery(getSchema().getTypeName(), filter));
}
/**
* Unlock features specified by the <code>query</code>.
*
* <p>
* FeatureStores that have provided their own locking to will need to
* override this method.
* </p>
*
* @param query
*
* @throws IOException
* @throws UnsupportedOperationException If lockingManager is not provided
* by DataStore subclass
* @throws DataSourceException Filter describes an unlocked Feature, or
* authorization not held
*
* @see org.geotools.data.FeatureLocking#unLockFeatures(org.geotools.data.Query)
*/
public void unLockFeatures(Query query) throws IOException {
LockingManager lockingManager = getDataStore().getLockingManager();
if (lockingManager == null) {
throw new UnsupportedOperationException(
"DataStore not using lockingManager, must provide alternate implementation");
}
// Could we reduce the Query to only return the FetureID here?
//
FeatureIterator<SimpleFeature> reader = getFeatures(query).features();
String typeName = getSchema().getTypeName();
SimpleFeature feature;
try {
while (reader.hasNext()) {
try {
feature = (SimpleFeature) reader.next();
lockingManager.unLockFeatureID(typeName, feature.getID(),
getTransaction(), featureLock);
} catch (NoSuchElementException nosuch) {
throw new DataSourceException("Problem with "
+ query.getHandle() + " while locking", nosuch);
}
}
} finally {
reader.close();
}
}
}