Skip to content

Commit

Permalink
[GEOS-8458] WFS 2.0 GetFeatureWithLock with lock action "some" is not…
Browse files Browse the repository at this point in the history
… supported
  • Loading branch information
aaime committed Dec 4, 2017
1 parent d92d1de commit a7bddc3
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 34 deletions.
90 changes: 60 additions & 30 deletions src/wfs/src/main/java/org/geoserver/wfs/GetFeature.java
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import org.geoserver.catalog.AttributeTypeInfo; import org.geoserver.catalog.AttributeTypeInfo;
import org.geoserver.catalog.Catalog; import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.FeatureTypeInfo; import org.geoserver.catalog.FeatureTypeInfo;
import org.geoserver.catalog.Predicates;
import org.geoserver.catalog.ResourcePool; import org.geoserver.catalog.ResourcePool;
import org.geoserver.feature.TypeNameExtractingVisitor; import org.geoserver.feature.TypeNameExtractingVisitor;
import org.geoserver.ows.Dispatcher; import org.geoserver.ows.Dispatcher;
Expand Down Expand Up @@ -75,6 +76,7 @@
import org.opengis.filter.expression.ExpressionVisitor; import org.opengis.filter.expression.ExpressionVisitor;
import org.opengis.filter.expression.Function; import org.opengis.filter.expression.Function;
import org.opengis.filter.expression.PropertyName; import org.opengis.filter.expression.PropertyName;
import org.opengis.filter.identity.FeatureId;
import org.opengis.filter.sort.SortBy; import org.opengis.filter.sort.SortBy;
import org.opengis.filter.spatial.BBOX; import org.opengis.filter.spatial.BBOX;
import org.opengis.filter.spatial.Beyond; import org.opengis.filter.spatial.Beyond;
Expand Down Expand Up @@ -110,8 +112,10 @@
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.stream.Collectors;


import static org.geoserver.ows.util.ResponseUtils.buildURL; import static org.geoserver.ows.util.ResponseUtils.buildURL;
/** /**
Expand Down Expand Up @@ -262,6 +266,54 @@ public FeatureCollectionResponse run(GetFeatureRequest request)
expandTypeNames(request, queries, getFeatureById, getCatalog()); expandTypeNames(request, queries, getFeatureById, getCatalog());
} }


// locking, since WFS 2.0 there is a "some" mode that influences how the features should
// be returned: "A value of SOME indicates that the WFS shall lock as many feature in the result set as possible.
// The response document shall only contain those features that were successfully locked ..."
String lockId = null;
if (request.isLockRequest()) {
LockFeatureRequest lockRequest = request.createLockRequest();
lockRequest.setExpiry(request.getExpiry());
lockRequest.setHandle(request.getHandle());
if (request.isLockActionSome()) {
lockRequest.setLockActionSome();
} else {
lockRequest.setLockActionAll();
}

for (int i = 0; i < queries.size(); i++) {
Query query = queries.get(i);

Lock lock = lockRequest.createLock();
lock.setFilter(query.getFilter());
lock.setHandle(query.getHandle());

//TODO: joins?
List<QName> typeNames = query.getTypeNames();
lock.setTypeName(typeNames.get(0));
lockRequest.addLock(lock);
}

LockFeature lockFeature = new LockFeature(wfs, catalog);
lockFeature.setFilterFactory(filterFactory);

LockFeatureResponse response = lockFeature.lockFeature(lockRequest);
lockId = response.getLockId();

// in this case we'll modify all queries to only return the locked features
if (request.isLockActionSome()) {
Filter lockedFeatureFilter = toFeatureIdFilter(response.getLockedFeatures());
for (Query query : queries) {
Filter filter = query.getFilter();
if (filter == null || filter == Filter.INCLUDE) {
query.setFilter(lockedFeatureFilter);
} else {
Filter joined = Predicates.and(filter, lockedFeatureFilter);
query.setFilter(joined);
}
}
}
}

// Optimization Idea // Optimization Idea
// //
// We should be able to reduce this to a two pass opperations. // We should be able to reduce this to a two pass opperations.
Expand Down Expand Up @@ -675,38 +727,16 @@ public Object loadObject() throws Exception {
throw new WFSException(request, "Error occurred getting features", e, request.getHandle()); throw new WFSException(request, "Error occurred getting features", e, request.getHandle());
} }



return buildResults(request, totalOffset, maxFeatures, count, totalCount, results, lockId, getFeatureById);

}

//locking
String lockId = null;
if (request.isLockRequest()) {
LockFeatureRequest lockRequest = request.createLockRequest();
lockRequest.setExpiry(request.getExpiry());
lockRequest.setHandle(request.getHandle());
lockRequest.setLockActionAll();

for (int i = 0; i < queries.size(); i++) {
Query query = queries.get(i);

Lock lock = lockRequest.createLock();
lock.setFilter(query.getFilter());
lock.setHandle(query.getHandle());

//TODO: joins?
List<QName> typeNames = query.getTypeNames();
lock.setTypeName(typeNames.get(0));
lockRequest.addLock(lock);
}

LockFeature lockFeature = new LockFeature(wfs, catalog);
lockFeature.setFilterFactory(filterFactory);


LockFeatureResponse response = lockFeature.lockFeature(lockRequest); private Filter toFeatureIdFilter(List<FeatureId> lockedFeatures) {
lockId = response.getLockId(); if (lockedFeatures == null || lockedFeatures.isEmpty()) {
return Filter.EXCLUDE;
} }

Set<FeatureId> ids = lockedFeatures.stream().map(fid -> filterFactory.featureId(fid.getID())).collect
return buildResults(request, totalOffset, maxFeatures, count, totalCount, results, lockId, getFeatureById); (Collectors.toSet());
return filterFactory.id(ids);
} }


static void expandTypeNames(RequestObject request, List<Query> queries, boolean getFeatureById, Catalog catalog) { static void expandTypeNames(RequestObject request, List<Query> queries, boolean getFeatureById, Catalog catalog) {
Expand Down
2 changes: 1 addition & 1 deletion src/wfs/src/main/java/org/geoserver/wfs/LockFeature.java
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ public LockFeatureResponse lockFeature(LockFeatureRequest request)
} }
} }


// should we releas all? if not set default to true // should we release all? if not set default to true


boolean lockAll = !request.isLockActionSome(); boolean lockAll = !request.isLockActionSome();


Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ public void setViewParams(List<Map<String,String>> viewParams) {
public abstract boolean isResultTypeHits(); public abstract boolean isResultTypeHits();


public abstract boolean isLockRequest(); public abstract boolean isLockRequest();

public abstract boolean isLockActionSome();


public abstract Query createQuery(); public abstract Query createQuery();


Expand Down Expand Up @@ -153,7 +155,13 @@ public boolean isResultTypeHits() {
public boolean isLockRequest() { public boolean isLockRequest() {
return adaptee instanceof GetFeatureWithLockType; return adaptee instanceof GetFeatureWithLockType;
} }


@Override
public boolean isLockActionSome() {
// no concept of "some" in WFS 1.1 GetFeatureWithLock
return false;
}

@Override @Override
public Query createQuery() { public Query createQuery() {
return new Query.WFS11(((WfsFactory)getFactory()).createQueryType()); return new Query.WFS11(((WfsFactory)getFactory()).createQueryType());
Expand Down Expand Up @@ -245,7 +253,13 @@ public boolean isResultTypeHits() {
public boolean isLockRequest() { public boolean isLockRequest() {
return adaptee instanceof net.opengis.wfs20.GetFeatureWithLockType; return adaptee instanceof net.opengis.wfs20.GetFeatureWithLockType;
} }


@Override
public boolean isLockActionSome() {
return ((net.opengis.wfs20.GetFeatureWithLockType)adaptee).getLockAction()
== net.opengis.wfs20.AllSomeType.SOME;
}

@Override @Override
public Query createQuery() { public Query createQuery() {
return new Query.WFS20(((Wfs20Factory)getFactory()).createQueryType()); return new Query.WFS20(((Wfs20Factory)getFactory()).createQueryType());
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ public void setLockId(String lockId) {


public abstract List<FeatureId> getNotLockedFeatures(); public abstract List<FeatureId> getNotLockedFeatures();


public abstract List<FeatureId> getLockedFeatures();

public static class WFS11 extends LockFeatureResponse { public static class WFS11 extends LockFeatureResponse {
public WFS11(EObject adaptee) { public WFS11(EObject adaptee) {
super(adaptee); super(adaptee);
Expand Down Expand Up @@ -67,6 +69,11 @@ public void addNotLockedFeature(FeatureId fid) {
public List<FeatureId> getNotLockedFeatures() { public List<FeatureId> getNotLockedFeatures() {
return eGet(adaptee, "featuresNotLocked.featureId", List.class); return eGet(adaptee, "featuresNotLocked.featureId", List.class);
} }

@Override
public List<FeatureId> getLockedFeatures() {
return eGet(adaptee, "featuresLocked.featureId", List.class);
}
} }


public static class WFS20 extends LockFeatureResponse { public static class WFS20 extends LockFeatureResponse {
Expand Down Expand Up @@ -99,5 +106,10 @@ public List<FeatureId> getNotLockedFeatures() {
return eGet(adaptee, "featuresNotLocked.resourceId", List.class); return eGet(adaptee, "featuresNotLocked.resourceId", List.class);
} }


@Override
public List<FeatureId> getLockedFeatures() {
return eGet(adaptee, "featuresLocked.resourceId", List.class);
}

} }
} }
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ public void testUpdateLockedFeatureWithoutLockId() throws Exception {




@Test @Test
public void testGetFeatureWithLockReleaseActionSome() throws Exception { public void testGetFeatureWithLockReleaseActionSomeOnTransaction() throws Exception {
String xml = "<wfs:GetFeature" + " service=\"WFS\"" String xml = "<wfs:GetFeature" + " service=\"WFS\""
+ " version=\"2.0.0\"" + " expiry=\"100\"" + " version=\"2.0.0\"" + " expiry=\"100\""
+ " xmlns:cdf=\"http://www.opengis.net/cite/data\"" + " xmlns:cdf=\"http://www.opengis.net/cite/data\""
Expand Down Expand Up @@ -243,6 +243,70 @@ public void testGetFeatureWithLockReleaseActionSome() throws Exception {
XMLAssert.assertXpathEvaluatesTo("1", "//wfs:totalUpdated/text()", dom); XMLAssert.assertXpathEvaluatesTo("1", "//wfs:totalUpdated/text()", dom);
XMLAssert.assertXpathExists("//wfs:UpdateResults//fes:ResourceId[@rid = '" + fid2 + "']", dom); XMLAssert.assertXpathExists("//wfs:UpdateResults//fes:ResourceId[@rid = '" + fid2 + "']", dom);
} }

@Test
public void testGetFeatureWithLockActionSome() throws Exception {
// get all features
String xml = "<wfs:GetFeature" + " service=\"WFS\""
+ " version=\"2.0.0\"" + " expiry=\"100\""
+ " xmlns:cdf=\"http://www.opengis.net/cite/data\""
+ " xmlns:fes='" + FES.NAMESPACE + "' "
+ " xmlns:wfs='" + WFS.NAMESPACE + "'>"
+ " <wfs:Query typeNames=\"cdf:Locks\"/>" + "</wfs:GetFeature>";
Document dom = postAsDOM("wfs", xml);

// get two fids
NodeList locks = dom.getElementsByTagName("cdf:Locks");
int featureCount = locks.getLength();
String fid1 = ((Element) locks.item(0)).getAttribute("gml:id");
String fid2 = ((Element) locks.item(1)).getAttribute("gml:id");

// lock the two fids
xml = "<wfs:GetFeatureWithLock" + " service=\"WFS\""
+ " version=\"2.0.0\"" + " expiry=\"100\""
+ " xmlns:cdf=\"http://www.opengis.net/cite/data\""
+ " xmlns:fes='" + FES.NAMESPACE + "' "
+ " xmlns:wfs='" + WFS.NAMESPACE + "'>"
+ " <wfs:Query typeNames=\"cdf:Locks\">" + " <fes:Filter>"
+ " <fes:ResourceId rid=\"" + fid1 + "\"/>"
+ " <fes:ResourceId rid=\"" + fid2 + "\"/>"
+ " </fes:Filter>" + " </wfs:Query>"
+ "</wfs:GetFeatureWithLock>";

dom = postAsDOM("wfs", xml);
assertEquals("wfs:FeatureCollection", dom.getDocumentElement()
.getNodeName());
XMLAssert.assertXpathExists("//cdf:Locks[@gml:id='" + fid1 + "']", dom);
XMLAssert.assertXpathExists("//cdf:Locks[@gml:id='" + fid2 + "']", dom);
XMLAssert.assertXpathEvaluatesTo("2", "count(//cdf:Locks)", dom);

String lockId = dom.getDocumentElement().getAttribute("lockId");

// now try to lock everything with "some", only the ones that can be locked should be returned
xml = "<wfs:GetFeatureWithLock" + " service=\"WFS\""
+ " version=\"2.0.0\"" + " expiry=\"100\""
+ " lockAction=\"SOME\""
+ " xmlns:cdf=\"http://www.opengis.net/cite/data\""
+ " xmlns:fes='" + FES.NAMESPACE + "' "
+ " xmlns:wfs='" + WFS.NAMESPACE + "'>"
+ " <wfs:Query typeNames=\"cdf:Locks\"/>"
+ "</wfs:GetFeatureWithLock>";

dom = postAsDOM("wfs", xml);
// print(dom);
assertEquals("wfs:FeatureCollection", dom.getDocumentElement()
.getNodeName());
XMLAssert.assertXpathNotExists("//cdf:Locks[@gml:id='" + fid1 + "']", dom);
XMLAssert.assertXpathNotExists("//cdf:Locks[@gml:id='" + fid2 + "']", dom);
XMLAssert.assertXpathEvaluatesTo(String.valueOf(featureCount - 2), "count(//cdf:Locks)", dom);

String secondLockId = dom.getDocumentElement().getAttribute("lockId");

// release locks
get("wfs?request=ReleaseLock&version=2.0&lockId=" + lockId);
get("wfs?request=ReleaseLock&version=2.0&lockId=" + secondLockId);

}


@Test @Test
public void testWorkspaceQualified() throws Exception { public void testWorkspaceQualified() throws Exception {
Expand Down

0 comments on commit a7bddc3

Please sign in to comment.