Skip to content

Commit

Permalink
Merge pull request #10 from Chicago/iss003
Browse files Browse the repository at this point in the history
Geo-spatial filtering on service, closes #3
  • Loading branch information
tomschenkjr committed May 23, 2016
2 parents 6c7bfeb + 07ebb59 commit a4ecc54
Show file tree
Hide file tree
Showing 14 changed files with 9,063 additions and 8,906 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@


public interface GenericRetrievable {
String getData(String dataSetId, String metaCollectionName, String filter, int max, String sort) throws ServiceException;
String getData(String dataSetId, String metaCollectionName, String filter, int max, String sort, String options) throws ServiceException;
OpenGridDataset getDescriptor(String metaCollectionName, String dataSetId) throws ServiceException, JsonParseException, JsonMappingException, IOException;
OpenGridDataset getDescriptorInternal(String metaCollectionName, String dataSetId, boolean removePrivates) throws ServiceException, JsonParseException, JsonMappingException, IOException;
List<String> getAllDatasetIds(String metaCollectionName) throws ServiceException, JsonParseException, JsonMappingException, IOException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
import java.util.ArrayList;
import java.util.List;

import javax.xml.crypto.dsig.keyinfo.KeyValue;

import org.bson.Document;
import org.opengrid.constants.DB;
import org.opengrid.constants.Exceptions;
Expand Down Expand Up @@ -35,7 +33,8 @@ public List<KeyValuePair> getList(String listId) {
FindIterable<Document> cur = c.find(q).limit(1);
if (cur.iterator().hasNext()) {
Document d = cur.first();
List<Document> a = (List<Document>) d.get("keyValues");
@SuppressWarnings("unchecked")
List<Document> a = (List<Document>) d.get("keyValues");
return getKeyValuePairs(a);
} else {
throw new ServiceException("Cannot find list of values with List Id '" + listId + "'.");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
package org.opengrid.data;

import java.net.UnknownHostException;
import java.util.Arrays;

import org.opengrid.util.PropertiesManager;
import org.opengrid.util.ServiceProperties;

import com.mongodb.DB;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientURI;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import com.mongodb.client.MongoDatabase;

Expand Down
18 changes: 18 additions & 0 deletions opengridservice/src/main/java/org/opengrid/data/QueryOptions.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.opengrid.data;

import com.fasterxml.jackson.annotation.JsonRawValue;

public class QueryOptions {
@JsonRawValue
private String geoFilter;

public String getGeoFilter() {
return geoFilter;
}

public void setGeoFilter( String geoFilter) {
this.geoFilter = geoFilter;
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.opengrid.data;

public class ServiceCapabilities {
//only one attribute supported right now
private boolean geoSpatialFiltering;

public boolean isGeoSpatialFiltering() {
return geoSpatialFiltering;
}

public void setGeoSpatialFiltering(boolean geoSpatialFiltering) {
this.geoSpatialFiltering = geoSpatialFiltering;
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,15 @@
import java.util.Date;
import java.util.List;

import org.bson.BsonArray;
import org.bson.BsonDocument;
import org.bson.BsonValue;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.opengrid.constants.Exceptions;
import org.opengrid.data.GenericRetrievable;
import org.opengrid.data.MongoDBHelper;
import org.opengrid.data.QueryOptions;
import org.opengrid.data.meta.OpenGridColumn;
import org.opengrid.data.meta.OpenGridDataset;
import org.opengrid.data.meta.OpenGridMeta;
Expand All @@ -19,7 +24,9 @@
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.MongoClient;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
Expand All @@ -29,7 +36,7 @@
public class OmniMongoDataProvider implements GenericRetrievable {

@Override
public String getData(String dataSetId, String metaCollectionName, String filter, int max, String sort) throws ServiceException {
public String getData(String dataSetId, String metaCollectionName, String filter, int max, String sort, String options) throws ServiceException {
MongoDBHelper ds = null;
MongoDatabase db = null;

Expand Down Expand Up @@ -67,6 +74,18 @@ public String getData(String dataSetId, String metaCollectionName, String filter
}
}

//read new options parameter that contains geo-spatial filter
if (options != null && options.length()>0) {
BasicDBObject qo = getQueryOptions(options);
if (qo !=null) {
if (desc.getOptions().getLocationField() == null || desc.getOptions().getLocationField().length() == 0) {
throw new ServiceException("No locationField option specified for dataset " + dataSetId);
}
//add geo filter to query
appendGeoFilter(q, qo, desc.getOptions().getLocationField());
}
}

FindIterable<Document> cur = c.find(q);

//determine sort order
Expand Down Expand Up @@ -121,6 +140,38 @@ public String getData(String dataSetId, String metaCollectionName, String filter
}


private void appendGeoFilter(BasicDBObject q, BasicDBObject geoFilter, String locationField) {
//this only works if you have a location field
BasicDBObject geo = (BasicDBObject) JSON.parse("{ \"" + locationField + "\": { \"$geoWithin\": { \"$geometry\": " + geoFilter.toString() + "} } }");
if (q.containsField("$and")) {
//add to ANDed conditions
BasicDBList a = (BasicDBList) q.get("$and");

a.add(geo);
} else {
BasicDBObject t = new BasicDBObject();
BasicDBList a = new BasicDBList();

a.add(q);
a.add(geo);
t.put("$and", a);
q = t;
}

}


private BasicDBObject getQueryOptions(String options) {
BasicDBObject o = (BasicDBObject) JSON.parse(options);

if (o.containsField("geoFilter")) {
return (BasicDBObject) o.get("geoFilter");
}

return null;
}


private String getFeature(Document doc2, OpenGridDataset desc) {

String s = "{\"type\": \"Feature\", \"properties\": ";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ public class DatasetOptions {

//property to contain default sort info
private String defaultSort;

//field name of the location field to use with $geoWithin operator, if supported
private String locationField;

public Rendition getRendition() {
return rendition;
Expand Down Expand Up @@ -52,4 +55,12 @@ public String getDefaultSort() {
public void setDefaultSort(String defaultSort) {
this.defaultSort = defaultSort;
}

public String getLocationField() {
return locationField;
}

public void setLocationField(String locationField) {
this.locationField = locationField;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.opengrid.security;

import javax.annotation.Resource;
import javax.ws.rs.HttpMethod;

import org.opengrid.security.impl.MongoTokenAuthenticationService;
import org.opengrid.util.PropertiesManager;
Expand Down Expand Up @@ -57,7 +58,10 @@ protected void configure(HttpSecurity http) throws Exception {
.antMatchers("/favicon.ico").permitAll()
.antMatchers("**/*.html").permitAll()
.antMatchers("**/*.css").permitAll()
.antMatchers("**/*.js").permitAll()
.antMatchers("**/*.js").permitAll()

//Added to prevent CORS issue
.antMatchers(HttpMethod.OPTIONS,"/**").permitAll()

// Allow anonymous login to auth and current resources
.antMatchers("/rest/users/token").permitAll()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
Expand All @@ -25,6 +26,14 @@ public StatelessAuthenticationFilter(TokenAuthenticationService authenticationSe
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;

//Added to prevent CORS issue
HttpServletResponse httpResponse = (HttpServletResponse) response;

String s = response.toString();
httpResponse.addHeader("Access-Control-Allow-Origin", "*");
httpResponse.addHeader("Access-Control-Allow-Headers", "X-Requested-With, content-type, accept, X-AUTH-TOKEN");

Authentication authentication = authenticationService.getAuthentication(httpRequest);
SecurityContextHolder.getContext().setAuthentication(authentication);
filterChain.doFilter(request, response);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ public MongoTokenAuthenticationService() {
public void addAuthentication(HttpServletResponse response, Authentication authentication) {
final org.opengrid.security.impl.User user = (org.opengrid.security.impl.User) authentication.getDetails();
response.addHeader(AUTH_HEADER_NAME, tokenHandler.createTokenForUser(user));

//fix CORS issue
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Expose-Headers", AUTH_HEADER_NAME);
}

public Authentication getAuthentication(HttpServletRequest request) {
Expand Down Expand Up @@ -62,6 +66,10 @@ public void renewAuthentication(HttpServletRequest request, HttpServletResponse

//replace old token with new one
response.setHeader(AUTH_HEADER_NAME, newToken);

//fix CORS issue
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Expose-Headers", AUTH_HEADER_NAME);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,17 @@
import javax.ws.rs.core.*;

import org.apache.cxf.jaxrs.ext.MessageContext;
import org.apache.cxf.rs.security.cors.CorsHeaderConstants;

import org.opengrid.data.ServiceCapabilities;
import org.opengrid.exception.ServiceException;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;

import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;

@Path("/")
public interface OpenGridService {

Expand Down Expand Up @@ -47,7 +53,8 @@ public interface OpenGridService {
public String executeOpenGridQueryWithParams(@PathParam("datasetId") final String datasetId,
@QueryParam("q") final String filter,
@QueryParam("n") final int max,
@QueryParam("s") final String sort
@QueryParam("s") final String sort,
@QueryParam("opts") final String options
);

//lists queries meeting specified filter
Expand Down Expand Up @@ -166,4 +173,15 @@ public String updateOpenGridgroup(@PathParam("groupId") final String groupId,
@Path("/groups/{groupId}")
public void deleteOpenGridGroup(@PathParam("groupId") final String groupId);


//returns capabilities flags
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/capabilities")
public ServiceCapabilities getServiceCapabilities();

@OPTIONS
@Path("{path : .*}")
public Response options();

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
import io.jsonwebtoken.Claims;

import org.apache.cxf.jaxrs.ext.MessageContext;
import org.apache.cxf.rs.security.cors.CorsHeaderConstants;
import org.opengrid.data.KeyValuePair;
import org.opengrid.data.ListOfValuesDataProvider;
import org.opengrid.data.GenericRetrievable;
import org.opengrid.data.Retrievable;
import org.opengrid.data.ServiceCapabilities;
import org.opengrid.data.Updatable;
import org.opengrid.exception.ServiceException;
import org.opengrid.security.RoleAccessValidator;
Expand All @@ -26,6 +28,9 @@
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;

import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;

@Component("OpenGridServiceBean")
public class OpenGridMongoService implements OpenGridService, AutoCompleteService {

Expand Down Expand Up @@ -94,13 +99,14 @@ public void deleteOpenGridUser(String userId) {


@Override
public String executeOpenGridQueryWithParams(String datasetId, String filter, int max, String sort) {
public String executeOpenGridQueryWithParams(String datasetId, String filter, int max, String sort, String options) {
return omniDataProvider.getData(
datasetId,
ServiceProperties.getProperties().getStringProperty("mongo.metaCollectionName"),
filter,
max,
sort);
sort,
options);
}


Expand Down Expand Up @@ -220,4 +226,25 @@ public List<KeyValuePair> getAutoCompleteSuggestions(String listId) {
return p.getList(listId);
}


@Override
public ServiceCapabilities getServiceCapabilities() {
//customize this depending on what this service implementation support
ServiceCapabilities sc = new ServiceCapabilities();

sc.setGeoSpatialFiltering(true);
return sc;
}

@Override
public Response options() {
return Response.ok()
.header(CorsHeaderConstants.HEADER_AC_ALLOW_HEADERS, "origin, content-type, accept, authorization, X-AUTH-TOKEN")
.header(CorsHeaderConstants.HEADER_AC_ALLOW_METHODS, "GET, POST, PUT, DELETE, OPTIONS, HEAD")
//.header(CorsHeaderConstants.HEADER_AC_ALLOW_CREDENTIALS, "false")
//.header(CorsHeaderConstants.HEADER_AC_ALLOW_ORIGIN, "*")
.header(CorsHeaderConstants.HEADER_AC_EXPOSE_HEADERS, "X-AUTH-TOKEN")
.build();
}

}
Loading

0 comments on commit a4ecc54

Please sign in to comment.