blob: 4f646ed14620f2c9eccae7d962e5397d97087126 [file] [log] [blame]
/*
* Copyright (c) 2020 Kentyou.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Kentyou - initial API and implementation
*/
package org.eclipse.sensinact.gateway.nthbnd.filter.geojson.internal;
import org.eclipse.sensinact.gateway.common.bundle.Mediator;
import org.eclipse.sensinact.gateway.core.Filtering;
import org.eclipse.sensinact.gateway.core.LocationResource;
import org.eclipse.sensinact.gateway.core.Resource;
import org.eclipse.sensinact.gateway.util.LocationUtils;
import org.eclipse.sensinact.gateway.util.json.JSONObjectStatement;
import org.eclipse.sensinact.gateway.util.json.JSONTokenerStatement;
import org.eclipse.sensinact.gateway.util.json.JSONValidator;
import org.eclipse.sensinact.gateway.util.json.JSONValidator.JSONToken;
import org.eclipse.sensinact.gateway.util.location.Segment;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* {@link Filtering} implementation allowing to apply a location discrimination
* to the result object to be filtered
*
* @author <a href="mailto:christophe.munilla@cea.fr">Christophe Munilla</a>
*/
public class GeoJSONFiltering implements Filtering {
//********************************************************************//
// NESTED DECLARATIONS //
//********************************************************************//
//********************************************************************//
// ABSTRACT DECLARATIONS //
//********************************************************************//
//********************************************************************//
// STATIC DECLARATIONS //
//********************************************************************//
private static final JSONObjectStatement STATEMENT =
new JSONObjectStatement(new JSONTokenerStatement(
"{" +
" \"type\": \"Feature\"," +
" \"properties\": {" +
" \"name\": $(name)" +
" }," +
" \"geometry\": {" +
" \"type\": \"Point\"," +
" \"coordinates\": [ $(longitude),$(latitude)] " +
" }" +
"}"));
//********************************************************************//
// INSTANCE DECLARATIONS //
//********************************************************************//
private Mediator mediator;
/**
* Constructor
*
* @param mediator the {@link Mediator} allowing the
* GeoJSONFiltering to be instantiated to interact with
* the OSGi host environment
*/
public GeoJSONFiltering(Mediator mediator) {
this.mediator = mediator;
}
/**
* @inheritDoc
* @see org.eclipse.sensinact.gateway.core.Filtering#handle(java.lang.String)
*/
@Override
public boolean handle(String type) {
return "geojson".equals(type);
}
/**
* @inheritDoc
* @see org.eclipse.sensinact.gateway.core.Filtering#apply(java.lang.String, java.lang.Object)
*/
@Override
public String apply(String definition, Object result) {
JSONObject obj = new JSONObject(definition);
boolean output = obj.optBoolean("output");
if (!output) {
return String.valueOf(result);
}
JSONValidator validator = new JSONValidator(String.valueOf(result));
StringBuilder builder = new StringBuilder();
builder.append("{\"type\": \"FeatureCollection\", \"features\": [");
int count = 0;
int index = 0;
Set<String> names = new HashSet<String>();
Map<Integer, String> locationMap = new HashMap<Integer, String>();
Map<Integer, String> nameMap = new HashMap<Integer, String>();
while (true) {
JSONToken token = validator.nextToken();
if (token == null) {
break;
}
if (token.ordinal() == JSONToken.JSON_OBJECT_OPENING.ordinal()) {
count++;
}
if (token.ordinal() == JSONToken.JSON_OBJECT_CLOSING.ordinal()) {
Integer ind = new Integer(count);
nameMap.remove(ind);
locationMap.remove(ind);
count--;
}
if (token.ordinal() == JSONToken.JSON_OBJECT_ITEM.ordinal() && token.getContext().key.equals(Resource.NAME)) {
Integer ind = new Integer(count);
String name = (String) token.getContext().value;
if (name != null) {
nameMap.put(ind, name);
}
String location = null;
if ((location = locationMap.get(ind)) != null && !names.contains(name) && writeLocation(name, location, index, builder)) {
index++;
}
}
if (token.ordinal() == JSONToken.JSON_OBJECT_ITEM.ordinal() && token.getContext().key.equals(LocationResource.LOCATION)) {
Integer ind = new Integer(count);
String location = (String) token.getContext().value;
if (location != null) {
locationMap.put(ind, location);
}
String name = null;
if ((name = nameMap.get(ind)) != null && !names.contains(name) && writeLocation(name, location, index, builder)) {
index++;
}
}
}
builder.append("]}");
return builder.toString();
}
boolean writeLocation(String name, String location, int index, StringBuilder builder) {
try {
String[] locationElements = location.split(":");
double latitude = Double.parseDouble(locationElements[0]);
double longitude = Double.parseDouble(locationElements[1]);
STATEMENT.apply("latitude", latitude);
STATEMENT.apply("longitude", longitude);
STATEMENT.apply("name", name);
if (index > 0) {
builder.append(",");
}
builder.append(STATEMENT.toString());
return true;
} catch (Exception e) {
mediator.error(e);
} finally {
STATEMENT.reset();
}
return false;
}
/**
* @inheritDoc
* @see org.eclipse.sensinact.gateway.core.Filtering#getLDAPComponent()
*/
@Override
public String getLDAPComponent(String definition) {
String ldapFilter = null;
try {
JSONObject obj = new JSONObject(definition);
double lat = obj.getDouble("latitude");
double lng = obj.getDouble("longitude");
double distance = obj.getDouble("distance");
Segment rad0 = null;
Segment rad90 = null;
if (distance < 200) {
rad0 = LocationUtils.getSphericalEarthModelCoordinates(lat, lng, 0, distance);
rad90 = LocationUtils.getSphericalEarthModelCoordinates(lat, lng, 90, distance);
} else {
rad0 = LocationUtils.getElipsoidEarthModelCoordinates(lat, lng, 0, distance);
rad90 = LocationUtils.getElipsoidEarthModelCoordinates(lat, lng, 90, distance);
}
double diffLat = Math.abs((rad0.getLat1() - rad0.getLat2()));
double diffLng = Math.abs((rad90.getLng1() - rad90.getLng2()));
ldapFilter = String.format("(&(latitude <= %s)(latitude >= %s)(longitude <= %s)(longitude >= %s))", (lat + diffLat), (lat - diffLat), (lng + diffLng), (lng - diffLng));
} catch (JSONException e) {
return null;
}
return ldapFilter;
}
}