I am encountering the following issue:
I am trying to grab the users that are within x [miles/km] from the user’s cell
phone. I am using the datastore api for google app engine, I cant figure out
what is the problem. The issue is that when i fetch the record using the
itiration – an error appears telling me i cant use diffeant properties in the
combination filter.
package com.linkedlive.business;
import java.io.IOException;
import java.util.Iterator;
import javax.servlet.http.*;
import org.json.JSONArray;
import org.json.JSONObject;
import com.biomedica.server.geolocation.GeoLocation;
import com.biomedica.server.searchtools.SearchForGeolocEntitiy;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.KeyFactory;
#SuppressWarnings("serial")
public class Venue extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
this.doPost(req, resp);
}
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
DatastoreService datastore =
DatastoreServiceFactory.getDatastoreService();
String cmd=req.getParameter("cmd");
if(cmd.equals("venuenearby"))
{
GeoLocation geo=new GeoLocation();
SearchForGeolocEntitiy search=new
SearchForGeolocEntitiy("accounts");// this is a class that i created to set the
query filters see bellow
// get request parameters
float lat=Float.valueOf(req.getParameter("lat"));
float lng=Float.valueOf(req.getParameter("lng"));
float rad=Float.valueOf(req.getParameter("rad"));
// calculate the distance
Iterable<Entity>
ent=search.GetJSONForEntitiyNearByUsingBounds(lat,
lng,geo.getGeoLocationBounds(lat, lng, rad) );
Iterator<Entity> i=ent.iterator();
JSONObject json=new JSONObject();
JSONArray injson=new JSONArray();
json.put("result", "venuenearby");
while(i.hasNext())
{
try {
JSONObject j=new JSONObject();
Entity t=i.next();
j.put("key",
KeyFactory.keyToString(t.getKey()));
j.put("userid",
t.getProperty("userid"));
j.put("filepath",
t.getProperty("filepath"));
injson.put(j);
} catch (NullPointerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
json.put("body",injson);
resp.getWriter().write(json.toString());
}
}
}
///////////////////////////////////////////////////////////////////////////////
////////////////////
////////////////////////// SearchForGeolocEntitiy
////////////////////////////////////
package com.biomedica.server.searchtools;
import java.lang.reflect.Array;
import java.util.Arrays;
import com.biomedica.server.geolocation.GeoLocation;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.CompositeFilterOperator;
import com.google.appengine.api.datastore.Query.Filter;
import com.google.appengine.api.datastore.Query.FilterOperator;
import com.google.appengine.api.datastore.Query.FilterPredicate;
import com.google.appengine.api.datastore.Query.CompositeFilter;
public class SearchForGeolocEntitiy {
private String EntitiyName;
private Query q;
public SearchForGeolocEntitiy(String name)
{
EntitiyName=name;
q=new Query(name);
}
public Iterable<Entity> GetJSONForEntitiyNearBy(double lang,double
lat,double rad,int max_result)
{
DatastoreService datastore =
DatastoreServiceFactory.getDatastoreService();
// decleeraing filter object
Filter filter_min_lngt=new
FilterPredicate("lng", FilterOperator.GREATER_THAN, lang-rad);
Filter filter_max_lngt=new
FilterPredicate("lng", FilterOperator.LESS_THAN, lang+rad);
Filter filter_min_lat=new
FilterPredicate("lat", FilterOperator.GREATER_THAN, lat-rad);
Filter filter_max_lat=new
FilterPredicate("lat", FilterOperator.LESS_THAN, lat+rad);
Filter filter_lng=new
CompositeFilter(CompositeFilterOperator.AND,Arrays.asList(filter_min_lngt,filte
r_max_lngt));
Filter filter_lat=new
CompositeFilter(CompositeFilterOperator.AND,Arrays.asList(filter_min_lat,filter
_max_lat));
Filter filter=new
CompositeFilter(CompositeFilterOperator.AND,Arrays.asList(filter_lng,filter_lat
));
q.setFilter(filter);
PreparedQuery pq = datastore.prepare(q);
return pq.asIterable();
}
public Iterable<Entity> GetJSONForEntitiyNearByUsingSSID(String
EntityName,String entityID,String SSID)
{
DatastoreService datastore =
DatastoreServiceFactory.getDatastoreService();
// decleeraing filter object
Filter filter_entityID=new FilterPredicate(EntityName,
FilterOperator.EQUAL, entityID);
Filter filter_min_lngt=new
FilterPredicate("lng", FilterOperator.EQUAL, SSID);
Filter filter=new
CompositeFilter(CompositeFilterOperator.AND,Arrays.asList(filter_entityID,filte
r_min_lngt));
q.setFilter(filter);
PreparedQuery pq = datastore.prepare(q);
return pq.asIterable();
}
public Iterable<Entity> GetJSONForEntitiyNearByUsingBounds(float
lng,float lat,GeoLocation.GeoLocationBoundry bound)
{
DatastoreService datastore =
DatastoreServiceFactory.getDatastoreService();
Filter filter_min_lngt=new FilterPredicate("lng",
FilterOperator.LESS_THAN, bound.lng1);
Filter filter_max_lngt=new FilterPredicate("lng",
FilterOperator.LESS_THAN, bound.lng2);
Filter filter_min_lat=new FilterPredicate("lat",
FilterOperator.GREATER_THAN, bound.lat1);
Filter filter_max_lat=new FilterPredicate("lat",
FilterOperator.LESS_THAN, bound.lat2);
Filter filter_lng=new
CompositeFilter(CompositeFilterOperator.AND,Arrays.asList(filter_min_lngt,filte
r_max_lngt));
Filter filter_lat=new
CompositeFilter(CompositeFilterOperator.AND,Arrays.asList(filter_min_lat,filter
_max_lat));
Filter filter=new
CompositeFilter(CompositeFilterOperator.AND,Arrays.asList(filter_lng,filter_lat
));
q.setFilter(filter);
PreparedQuery pq = datastore.prepare(q);
return pq.asIterable();
}
}
You're hitting a limitation of the datastore. Inequality filters can only be on one property.
https://developers.google.com/appengine/docs/java/datastore/queries#Restrictions_on_Queries
The easiest way around this is to use the Search API. Otherwise, you need to build your own geohashing like mechanism to search within a range without using multiple inequality filters.
Related
I was create a soap web service at java. When called from java working fine, but when called from c# its not working, would you please help me? How to call getHelloWorldAsString method from c# with header authentication. Thanks in advance
Here is the java code:
package com.mkyong.ws;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import javax.jws.WebService;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.handler.MessageContext;
//Service Implementation Bean
#WebService(endpointInterface = "com.mkyong.ws.HelloWorld")
public class HelloWorldImpl implements HelloWorld{
#Resource
WebServiceContext wsctx;
#Override
public String getHelloWorldAsString() {
MessageContext mctx = wsctx.getMessageContext();
//get detail from request headers
Map<?,?> http_headers = (Map<?,?>) mctx.get(MessageContext.HTTP_REQUEST_HEADERS);
List<?> userList = (List<?>) http_headers.get("Username");
List<?> passList = (List<?>) http_headers.get("Password");
String username = "";
String password = "";
if(userList!=null){
//get username
username = userList.get(0).toString();
}
if(passList!=null){
//get password
password = passList.get(0).toString();
}
//Should validate username and password
if (username.equals("abcd") && password.equals("abcd123")){
return "Hello World JAX-WS - Valid User!";
}else{
return "Unknown User!";
}
}
#Override
public String getSum() {
return "10";
}
}
Here is the java calling (this is working):
package com.mkyong.client;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.namespace.QName;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.Service;
import javax.xml.ws.handler.MessageContext;
import com.mkyong.ws.HelloWorld;
public class HelloWorldClient{
private static final String WS_URL ="http://localhost:8080/ws/HelloWorld?wsdl";
public static void main(String[] args) throws Exception {
try {
URL url = new URL(WS_URL);
QName qname = new QName("http://ws.mkyong.com/", "HelloWorldImplService");
Service service = Service.create(url, qname);
HelloWorld hello = service.getPort(HelloWorld.class);
/*******************UserName & Password ******************************/
Map<String, Object> req_ctx = ((BindingProvider)hello).getRequestContext();
req_ctx.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, WS_URL);
Map<String, List<String>> headers = new HashMap<String, List<String>>();
headers.put("Username", Collections.singletonList("abcd"));
headers.put("Password", Collections.singletonList("abcd123"));
req_ctx.put(MessageContext.HTTP_REQUEST_HEADERS, headers);
/**********************************************************************/
System.out.println(hello.getHelloWorldAsString());
System.out.println(hello.getSum());
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
C# Client Call:
After adding wsdl to the windows application web service,written following C# code,
webService.HelloWorldImplService ws = new webService.HelloWorldImplService(); Console.WriteLine(ws.getHelloWorldAsString());
I am trying to retrieve Map content via WFS Geoserver connection in Java with Geotools 18.4. But I am getting the following error: Content type is required for org.geotools.data.ows.Response.
The idea is that i want to map features (Position and Heartrate of a running person) of a WFS Layer with the java processing library.
I would be very grateful if someone can help me with this error.
here is the code:
`
import java.io.IOException;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import org.geotools.data.DataStore;
import org.geotools.data.wfs.WFSDataStoreFactory;
public class Heartrate2 {
public static void main(String[] args) throws IOException {
Heartrate2 me = new Heartrate2();
DataStore ds = me.dataStoreWFS();
for (String n:ds.getTypeNames()) {
System.out.println(n);
}
}
public DataStore dataStoreWFS() {
DataStore dataStore = null;
try {
Map<String, Serializable> connectionParameters = new HashMap<>();
String getCapabilities = "http://webgis.regione.sardegna.it/geoserver/ows?service=WFS&request=GetCapabilities";
String variableCapabilities = "WFSDataStoreFactory:GET_CAPABILITIES_URL";
connectionParameters.put(variableCapabilities, getCapabilities);
dataStore = (new WFSDataStoreFactory()).createDataStore(connectionParameters);
} catch (IOException e) {
e.printStackTrace();
}
return dataStore;
}
}
`
I searched on net, found similar issues. As I'm newbie to LDAP, had to reach out for help.
Right now code brings all the groups for a user. When user1 logins, it brings Group A.
New Requirement is:
If Group A is member of Group B, we need to retrieve Group B as well along with Group A.
I'm trying to achieve this by tweaking query. I read about some matching rules OID 1.2.840.113556.1.4.1941 & LDAP_MATCHING_RULE_IN_CHAIN. But couldn't figure out how to implement in my code.
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Hashtable;
import java.util.List;
public abstract class SAPSecurityFilter implements Filter {
protected abstract SAPPrincipal buildGroups(SAPPrincipal principal, NamingEnumeration<SearchResult> results) throws NamingException;
private static final String SECURE_ENTERPRISE_DIRECTORY = "ldaps://ldap.abc.com:636/o=abc.com";
private static final String PRINCIPAL_NAME = "SAPPrincipal";
private static final String ENTERPRISE_DIRECTORY = "ldap://ldap.abc.com:389/o=abc.com";
private static final String USER_KEY = "HTTP_SM_USER";
private static final String BASE = "ou=Groups";
private static final String GROUP_QUERY = "(member=uid=%s,ou=People,o=abc.com)";
private final CacheManager cacheManager;
private List<String> excludeUrlPatterns = new ArrayList<String>();
public SAPSecurityFilter() {
// Setup Cache for principals
// cache Manager
URL url = getClass().getResource("/data-cache.xml");
cacheManager = new CacheManager(url);
}
public void destroy() {
// TODO Auto-generated method stub
}
/**
* doFilter
* <p/>
* Read the request headers for the HTTP_SM_USER value
* This value is the users email address.
* Using the email address lookup the users values in Enterprise directory
* Populate the principal and place it in request scope.
*/
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
//SAPt the request into HttpServletRequest
String path = ((HttpServletRequest) request).getPathInfo();
if (patternExcluded(path) || "OPTIONS".equalsIgnoreSAPe(((HttpServletRequest) request).getMethod())) {
chain.doFilter(request, response);
} else {
String smUser = ((HttpServletRequest) request).getRemoteUser();
HttpSession session = ((HttpServletRequest) request).getSession();
if (smUser == null) throw new ServletException("USER TOKEN MISSING");
// use the smUser to get the data needed to build a principal
LdapContext ctx = null;
// build SAP principal //
SAPPrincipal principal = new SAPPrincipal();
principal.setName(smUser);
//Cache cache = cacheManager.getCache("principalCache");
//Element element = cache.get(smUser);
// Cache miss for user
if (session.getAttribute(PRINCIPAL_NAME) == null) {
try {
ctx = getLdapContext(smUser);
SearchControls constraints = new SearchControls();
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
String[] attrs = {"cn"};
constraints.setReturningAttributes(attrs);
String filter = String.format(GROUP_QUERY, smUser);
NamingEnumeration<SearchResult> results = ctx.search(BASE, filter, constraints);
principal = buildGroups(principal, results);
//cache.put(new Element(smUser, principal));
session.setAttribute(PRINCIPAL_NAME, principal);
} catch (NamingException ne) {
throw new ServletException(ne);
} finally {
try {
if (ctx != null) ctx.close();
} catch (NamingException ne) {
// swallow on purpose
}
}
// Cache Hit for user
} else {
principal = (SAPPrincipal) session.getAttribute(PRINCIPAL_NAME);
}
// add principal to securityContext and SAPContext//
SAPContext.setPrincipal(principal);
chain.doFilter(new SecurityRequestWrapper(principal, (HttpServletRequest) request), response);
}
}
Your filter needs to be something like:
(member:1.2.840.113556.1.4.1941:=(CN=UserName,CN=Users,DC=YOURDOMAIN,DC=NET))
form:http://ldapwiki.willeke.com/wiki/Active%20Directory%20User%20Related%20Searches
-jim
Creating the entity and setting the property
package pack.exp;
import java.io.IOException;
import javax.servlet.http.*;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
#SuppressWarnings("serial")
public class IkaiLanServlet extends HttpServlet
{
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws...
{
Entity alice = new Entity("Person", "Alice");
alice.setProperty("gender", "female");
alice.setProperty("age", 20);
Key bobKey = KeyFactory.createKey("Person", "Bob");
Entity bob = new Entity(bobKey);
bob.setProperty("gender", "male");
bob.setProperty("age", "23");
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
datastore.put(alice);
datastore.put(bob);
resp.setContentType("text/plain");
resp.getWriter().println("Bye Bye");
}
}
In the same package creating another servlet
package pack.exp;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
public class Read extends HttpServlet
{
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws...
{
// TODO Auto-generated method stub
super.doGet(req, resp);
Key bobKey = KeyFactory.createKey("Person", "Bob");
Key aliceKey = KeyFactory.createKey("Person", "Alice");
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
Entity alice, bob;
try {
alice = datastore.get(aliceKey);
bob = datastore.get(bobKey);
Long aliceAge = (Long) alice.getProperty("age");
Long bobAge = (Long) bob.getProperty("age");
System.out.println("Alice’s age: " + aliceAge);
System.out.println("Bob’s age: " + bobAge);
}
catch (EntityNotFoundException e)
{
// Alice or Bob doesn't exist!
}
}
}
When I am deploying the app the output is "Bye Bye". Why it is not reading the entity.
Please help me i am new to google app engine datastore..
When you go to whatever URL you have mapped to IkaiLanServlet, it will respond with "Bye Bye" because you called resp.getWriter().println("Bye Bye"). To read the entity, change
System.out.println("Alice’s age: " + aliceAge);
System.out.println("Bob’s age: " + bobAge);
to
resp.setContentType("text/plain");
resp.getWriter().println("Alice’s age: " + aliceAge);
resp.getWriter().println("Bob’s age: " + bobAge);
According to the docs (https://developers.google.com/appengine/docs/java/#Java_Logging):
Everything the servlet writes to the standard output stream (System.out) and standard error stream (System.err) is captured by App Engine and recorded in the application logs. Lines written to the standard output stream are logged at the "INFO" level, and lines written to the standard error stream are logged at the "WARNING" level.
To see the output in your browser, you must use resp.
Also, be sure that you visit the URL's for IkaiLanServlet and then Read, in that order, to ensure the entities are in the datastore.
I wrote this code that will pull everything from my entity "ContactInfo" from the app engine datastore and place it into a string.
My question is how do I make specific queries in the android endpoint. I only want to display the items in the entity that are a certain name or zipcode for example. Here is what I have to put the entire entity into a string.
package com.indeeditis;
import java.io.IOException;
import java.util.Date;
import org.json.JSONException;
import android.os.AsyncTask;
import android.content.Context;
import android.content.Intent;
import com.indeeditis.MainActivity.EndpointsTask;
import com.indeeditis.contactinfoendpoint.Contactinfoendpoint;
import com.indeeditis.contactinfoendpoint.model.CollectionResponseContactInfo;
import com.indeeditis.contactinfoendpoint.model.ContactInfo;
import com.google.api.client.extensions.android.http.AndroidHttp;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.json.jackson.JacksonFactory;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import android.app.Activity;
import android.view.View.OnClickListener;
public class FinderActivity extends Activity implements OnClickListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.finder);
Button start = (Button)findViewById(R.id.button9000);
start.setOnClickListener(this);
}
public class EndpointsTask extends AsyncTask<Context, Integer, Long> {
protected Long doInBackground(Context... contexts) {
Contactinfoendpoint.Builder endpointBuilder = new Contactinfoendpoint.Builder(
AndroidHttp.newCompatibleTransport(),
new JacksonFactory(),
new HttpRequestInitializer() {
public void initialize(HttpRequest httpRequest) { }
});
Contactinfoendpoint endpoint = CloudEndpointUtils.updateBuilder(
endpointBuilder).build();
try {
String apples = endpoint.listContactInfo().execute().toString();
Log.w("myApp", apples);
} catch (IOException e) {
e.printStackTrace();
}
return (long) 0;
}
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
new EndpointsTask().execute(getApplicationContext());
}
}
For applying filters while sending a query request from android through cloud endpoints, you need to add options to set parameters. I will explain with a short example
1, Assume your contactinfo endpoint has 2 properties
name = ndb.StringProperty()
contacttype = ndb.StringProperty() // assume this can have values personal or business
2, Now if you need to query for a particular contacttype, then your app engine code should have a query method that filters based on the property contacttype.
Your endpoint should call this query method by passing on the input parameter from the user.
3, Now to send the required parameter from android , your class Listcontactinfo where you would define the REST Path and method type, should include an option to the set the contacttype parameter
#com.google.api.client.util.Key
private String contacttype;
public String getContacttype() {
return contacttype;
}
public Listcontactinfo setContacttype(String contacttype) {
this.contacttype = contacttype;
return this;
}
4, Finally while calling the endpoint method from your android code, you should pass a value using the setContacttype, which will be something like:
String apples = endpoint.listContactInfo().setContacttype("personal").execute().toString();
This is for an example case where you want to query entities having contacttype with value "personal"