revert-70aa11f8
charitha 7 years ago
commit 3fda0a1459

@ -22,13 +22,13 @@
<parent>
<artifactId>apimgt-extensions</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>org.wso2.carbon.apimgt.annotations</artifactId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<packaging>bundle</packaging>
<name>WSO2 Carbon - API Management Annotations</name>
<description>WSO2 Carbon - API Management Custom Annotation Module</description>

@ -21,12 +21,12 @@
<parent>
<artifactId>apimgt-extensions</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<artifactId>org.wso2.carbon.apimgt.application.extension.api</artifactId>
<packaging>war</packaging>
<name>WSO2 Carbon - API Application Management API</name>

@ -22,12 +22,12 @@
<parent>
<artifactId>apimgt-extensions</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<artifactId>org.wso2.carbon.apimgt.application.extension</artifactId>
<packaging>bundle</packaging>
<name>WSO2 Carbon - API Application Management</name>

@ -21,13 +21,13 @@
<parent>
<artifactId>apimgt-extensions</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>org.wso2.carbon.apimgt.handlers</artifactId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<packaging>bundle</packaging>
<name>WSO2 Carbon - API Security Handler Component</name>
<description>WSO2 Carbon - API Management Security Handler Module</description>

@ -13,13 +13,13 @@
<parent>
<artifactId>apimgt-extensions</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>org.wso2.carbon.apimgt.integration.client</artifactId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<packaging>bundle</packaging>
<name>WSO2 Carbon - API Management Integration Client</name>
<description>WSO2 Carbon - API Management Integration Client</description>

@ -13,13 +13,13 @@
<parent>
<artifactId>apimgt-extensions</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>org.wso2.carbon.apimgt.integration.generated.client</artifactId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<packaging>bundle</packaging>
<name>WSO2 Carbon - API Management Integration Generated Client</name>
<description>WSO2 Carbon - API Management Integration Client</description>

@ -22,13 +22,13 @@
<parent>
<artifactId>apimgt-extensions</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>org.wso2.carbon.apimgt.webapp.publisher</artifactId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<packaging>bundle</packaging>
<name>WSO2 Carbon - API Management Webapp Publisher</name>
<description>WSO2 Carbon - API Management Webapp Publisher</description>

@ -22,13 +22,13 @@
<parent>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>carbon-devicemgt</artifactId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>apimgt-extensions</artifactId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<packaging>pom</packaging>
<name>WSO2 Carbon - API Management Extensions Component</name>
<url>http://wso2.org</url>

@ -22,7 +22,7 @@
<parent>
<artifactId>certificate-mgt</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

@ -22,7 +22,7 @@
<parent>
<artifactId>certificate-mgt</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

@ -24,7 +24,7 @@
<parent>
<artifactId>certificate-mgt</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

@ -21,13 +21,13 @@
<parent>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>certificate-mgt</artifactId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>org.wso2.carbon.certificate.mgt.core</artifactId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<packaging>bundle</packaging>
<name>WSO2 Carbon - Certificate Management Core</name>
<description>WSO2 Carbon - Certificate Management Core</description>

@ -24,7 +24,7 @@
<parent>
<artifactId>certificate-mgt</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

@ -22,14 +22,14 @@
<parent>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>carbon-devicemgt</artifactId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>certificate-mgt</artifactId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<packaging>pom</packaging>
<name>WSO2 Carbon - Certificate Management Component</name>
<url>http://wso2.org</url>

@ -22,7 +22,7 @@
<parent>
<artifactId>device-mgt-extensions</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

@ -22,7 +22,7 @@
<parent>
<artifactId>device-mgt-extensions</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

@ -22,7 +22,7 @@
<parent>
<artifactId>device-mgt-extensions</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

@ -22,7 +22,7 @@
<parent>
<artifactId>device-mgt-extensions</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

@ -22,7 +22,7 @@
<parent>
<artifactId>device-mgt-extensions</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

@ -22,7 +22,7 @@
<parent>
<artifactId>device-mgt-extensions</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

@ -22,7 +22,7 @@
<parent>
<artifactId>carbon-devicemgt</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

@ -22,7 +22,7 @@
<parent>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>device-mgt</artifactId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

@ -22,7 +22,7 @@
<parent>
<artifactId>device-mgt</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

@ -290,11 +290,13 @@ public interface DeviceEventManagementService {
response = ErrorResponse.class)
}
)
Response getLastKnownData(@ApiParam(name = "deviceId", value = "The device ID.", required = false)
@PathParam("deviceId") String deviceId,
@ApiParam(name = "type", value = "The device type, such as android, ios, or windows.", required = false)
@PathParam("type") String deviceType);
Response getLastKnownData(@ApiParam(name = "deviceId", value = "id of the device ", required = true)
@PathParam("deviceId") String deviceId,
@ApiParam(name = "type", value = "name of the device type", required = true)
@PathParam("type") String deviceType,
@ApiParam(name = "limit", value = "limit of the records that needs to be picked up", required = false)
@QueryParam("limit") int limit);
@GET
@Path("/{type}")
@ApiOperation(
@ -348,4 +350,4 @@ public interface DeviceEventManagementService {
" ios, or windows.", required = false)
@PathParam("type")String deviceType) ;
}
}

@ -295,6 +295,60 @@ public interface GeoLocationBasedService {
required = true)
@PathParam("alertType") String alertType);
/**
* Create Geo alerts for geo clusters
*/
@POST
@Path("/alerts/{alertType}")
@ApiOperation(
consumes = "application/json",
produces = "application/json",
httpMethod = "POST",
value = "Create Geo alerts for geo clusters",
notes = "Creating geo alerts for cluster of devices",
response = Response.class,
tags = "Geo Service Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = Constants.SCOPE, value = "perm:geo-service:alerts-manage")
})
}
)
@ApiResponses(value = {
@ApiResponse(
code = 200,
message = "OK.",
response = Response.class,
responseHeaders = {
@ResponseHeader(
name = "Content-Type",
description = "The content type of the body")
}),
@ApiResponse(
code = 400,
message = "Bad Request. \n A geo alert with this name already exists.",
response = Response.class),
@ApiResponse(
code = 401,
message = "Unauthorized. \n Unauthorized request."),
@ApiResponse(
code = 500,
message = "Internal Server Error. \n Error on retrieving stats",
response = Response.class)
})
Response createGeoAlertsForGeoClusters(
@ApiParam(
name = "alert",
value = "The alert object",
required = true)
@Valid Alert alert,
@ApiParam(
name = "alertType",
value = "The alert type, such as Within, Speed, Stationary",
required = true)
@PathParam("alertType") String alertType);
/**
* Update Geo alerts
*/
@ -360,6 +414,59 @@ public interface GeoLocationBasedService {
required = true)
@PathParam("alertType") String alertType);
/**
* Update Geo alerts for geo clusters
*/
@PUT
@Path("alerts/{alertType}")
@ApiOperation(
consumes = "application/json",
produces = "application/json",
httpMethod = "GET",
value = "Update Geo alerts for geo clusters",
notes = "Updating an existing geo alert that was defined for geo clusters",
response = Response.class,
tags = "Geo Service Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = Constants.SCOPE, value = "perm:geo-service:alerts-manage")
})
}
)
@ApiResponses(value = {
@ApiResponse(
code = 200,
message = "OK.",
response = Response.class,
responseHeaders = {
@ResponseHeader(
name = "Content-Type",
description = "The content type of the body")
}),
@ApiResponse(
code = 400,
message = "Bad Request. \n Invalid Device Identifiers found.",
response = Response.class),
@ApiResponse(
code = 401,
message = "Unauthorized. \n Unauthorized request."),
@ApiResponse(
code = 500,
message = "Internal Server Error. \n Error on retrieving stats",
response = Response.class)
})
Response updateGeoAlertsForGeoClusters(
@ApiParam(
name = "alert",
value = "The alert object",
required = true)
@Valid Alert alert,
@ApiParam(
name = "alertType",
value = "The alert type, such as Within, Speed, Stationary",
required = true)
@PathParam("alertType") String alertType);
/**
* Retrieve Geo alerts
*/
@ -424,6 +531,59 @@ public interface GeoLocationBasedService {
required = true)
@PathParam("alertType") String alertType);
/**
* Retrieve Geo alerts for geo clusters
*/
@GET
@Path("alerts/{alertType}")
@ApiOperation(
consumes = "application/json",
produces = "application/json",
httpMethod = "GET",
value = "Retrieve Geo alerts for geo clusters",
notes = "Retrieve all the defined alerts for a specific alert type",
response = Response.class,
tags = "Geo Service Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = Constants.SCOPE, value = "perm:geo-service:alerts-manage")
})
}
)
@ApiResponses(value = {
@ApiResponse(
code = 200,
message = "OK.",
response = Response.class,
responseHeaders = {
@ResponseHeader(
name = "Content-Type",
description = "The content type of the body"),
@ResponseHeader(
name = "Last-Modified",
description = "Date and time the resource was last modified.\n" +
"Used by caches, or in conditional requests.")
}),
@ApiResponse(
code = 400,
message = "Bad Request. \n Invalid Device Identifiers found.",
response = Response.class),
@ApiResponse(
code = 401,
message = "Unauthorized. \n Unauthorized request."),
@ApiResponse(
code = 500,
message = "Internal Server Error. \n Error on retrieving stats",
response = Response.class)
})
Response getGeoAlertsForGeoClusters(
@ApiParam(
name = "alertType",
value = "The alert type, such as Within, Speed, Stationary",
required = true)
@PathParam("alertType") String alertType);
/**
* Retrieve Geo alerts history
*/
@ -493,6 +653,68 @@ public interface GeoLocationBasedService {
required = true)
@QueryParam("to") long to);
/**
* Retrieve Geo alerts history for geo clusters
*/
@GET
@Path("alerts/history")
@ApiOperation(
consumes = "application/json",
produces = "application/json",
httpMethod = "GET",
value = "Retrieve Geo alerts history for geo clusters",
notes = "Retrieving geo alert history of all defined alerts for geo clusters",
response = Response.class,
tags = "Geo Service Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = Constants.SCOPE, value = "perm:geo-service:alerts-manage")
})
}
)
@ApiResponses(value = {
@ApiResponse(
code = 200,
message = "OK.",
response = Response.class,
responseHeaders = {
@ResponseHeader(
name = "Content-Type",
description = "The content type of the body"),
@ResponseHeader(
name = "Last-Modified",
description = "Date and time the resource was last modified.\n" +
"Used by caches, or in conditional requests.")
}),
@ApiResponse(
code = 400,
message = "Bad Request. \n Invalid Device Identifiers found.",
response = Response.class),
@ApiResponse(
code = 401,
message = "Unauthorized. \n Unauthorized request."),
@ApiResponse(
code = 500,
message = "Internal Server Error. \n Error on retrieving stats",
response = Response.class)
})
Response getGeoAlertsHistoryForGeoClusters(
@ApiParam(
name = "from",
value = "Get stats from what time",
required = true)
@QueryParam("from") long from,
@ApiParam(
name = "to",
value = "Get stats up to what time",
required = true)
@QueryParam("to") long to);
/**
* Remove geo alerts
*/
@DELETE
@Path("alerts/{alertType}/{deviceType}/{deviceId}")
@ApiOperation(
@ -553,5 +775,59 @@ public interface GeoLocationBasedService {
" here.",
required = true)
@QueryParam("queryName") String queryName);
/**
* Remove geo alerts for geo clusters
*/
@DELETE
@Path("alerts/{alertType}")
@ApiOperation(
consumes = "application/json",
produces = "application/json",
httpMethod = "DELETE",
value = "Deletes Geo alerts for geo clusters",
notes = "Deleting any type of a geo alert that was defined for geo clusters",
response = Response.class,
tags = "Geo Service Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = Constants.SCOPE, value = "perm:geo-service:alerts-manage")
})
}
)
@ApiResponses(value = {
@ApiResponse(
code = 200,
message = "OK.",
response = Response.class,
responseHeaders = {
@ResponseHeader(
name = "Content-Type",
description = "The content type of the body")
}),
@ApiResponse(
code = 400,
message = "Bad Request. \n Invalid Device Identifiers found.",
response = Response.class),
@ApiResponse(
code = 401,
message = "Unauthorized. \n Unauthorized request."),
@ApiResponse(
code = 500,
message = "Internal Server Error. \n Error on retrieving stats",
response = Response.class)
})
Response removeGeoAlertsForGeoClusters(
@ApiParam(
name = "alertType",
value = "The alert type, such as Within, Speed, Stationary",
required = true)
@PathParam("alertType") String alertType,
@ApiParam(
name = "queryName",
value = "The query name.",
required = true)
@QueryParam("queryName") String queryName);
}

@ -76,8 +76,47 @@ public class DeviceEventManagementServiceImpl implements DeviceEventManagementSe
private static final String MQTT_CONTENT_VALIDATOR = "default";
private static final String TIMESTAMP_FIELD_NAME = "_timestamp";
private static AnalyticsDataAPI getAnalyticsDataAPI() {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
AnalyticsDataAPI analyticsDataAPI =
(AnalyticsDataAPI) ctx.getOSGiService(AnalyticsDataAPI.class, null);
if (analyticsDataAPI == null) {
String msg = "Analytics api service has not initialized.";
log.error(msg);
throw new IllegalStateException(msg);
}
return analyticsDataAPI;
}
private static EventRecords getAllEventsForDevice(String tableName, String query, List<SortByField> sortByFields
, int offset, int limit) throws AnalyticsException {
int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
AnalyticsDataAPI analyticsDataAPI = getAnalyticsDataAPI();
EventRecords eventRecords = new EventRecords();
int eventCount = analyticsDataAPI.searchCount(tenantId, tableName, query);
if (eventCount == 0) {
eventRecords.setCount(0);
}
List<SearchResultEntry> resultEntries = analyticsDataAPI.search(tenantId, tableName, query, offset, limit,
sortByFields);
List<String> recordIds = getRecordIds(resultEntries);
AnalyticsDataResponse response = analyticsDataAPI.get(tenantId, tableName, 1, null, recordIds);
eventRecords.setCount(eventCount);
eventRecords.setList(AnalyticsDataAPIUtil.listRecords(analyticsDataAPI, response));
return eventRecords;
}
private static List<String> getRecordIds(List<SearchResultEntry> searchResults) {
List<String> ids = new ArrayList<>();
for (SearchResultEntry searchResult : searchResults) {
ids.add(searchResult.getId());
}
return ids;
}
/**
* Retrieves the stream definition from das for the given device type.
*
* @return dynamic event attribute list
*/
@GET
@ -196,7 +235,7 @@ public class DeviceEventManagementServiceImpl implements DeviceEventManagementSe
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
} catch (EventStreamPersistenceAdminServiceEventStreamPersistenceAdminServiceExceptionException e) {
log.error("Failed to create event store for, tenantDomain: " + tenantDomain + " deviceType" + deviceType,
e);
e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
}
}
@ -229,9 +268,11 @@ public class DeviceEventManagementServiceImpl implements DeviceEventManagementSe
}
eventStreamAdminServiceStub.removeEventStreamDefinition(streamName, Constants.DEFAULT_STREAM_VERSION);
EventReceiverAdminServiceCallbackHandler eventReceiverAdminServiceCallbackHandler =
new EventReceiverAdminServiceCallbackHandler() {};
new EventReceiverAdminServiceCallbackHandler() {
};
EventPublisherAdminServiceCallbackHandler eventPublisherAdminServiceCallbackHandler =
new EventPublisherAdminServiceCallbackHandler() {};
new EventPublisherAdminServiceCallbackHandler() {
};
String eventReceiverName = getReceiverName(deviceType, tenantDomain, TransportType.MQTT);
@ -254,7 +295,7 @@ public class DeviceEventManagementServiceImpl implements DeviceEventManagementSe
tenantBasedEventReceiverAdminServiceStub = DeviceMgtAPIUtils.getEventReceiverAdminServiceStub();
tenantBasedEventStreamAdminServiceStub = DeviceMgtAPIUtils.getEventStreamAdminServiceStub();
tenantBasedEventStreamAdminServiceStub.removeEventStreamDefinition(streamName,
Constants.DEFAULT_STREAM_VERSION);
Constants.DEFAULT_STREAM_VERSION);
tenantBasedEventReceiverAdminServiceStub.startundeployInactiveEventReceiverConfiguration(
eventReceiverName, eventReceiverAdminServiceCallbackHandler);
@ -298,7 +339,7 @@ public class DeviceEventManagementServiceImpl implements DeviceEventManagementSe
@Override
public Response getData(@PathParam("deviceId") String deviceId, @QueryParam("from") long from,
@QueryParam("to") long to, @PathParam("type") String deviceType, @QueryParam("offset")
int offset, @QueryParam("limit") int limit) {
int offset, @QueryParam("limit") int limit) {
if (from == 0 || to == 0) {
String errorMessage = "Invalid values for from/to";
return Response.status(Response.Status.BAD_REQUEST).entity(errorMessage).build();
@ -340,12 +381,13 @@ public class DeviceEventManagementServiceImpl implements DeviceEventManagementSe
}
/**
* Returns the last know data point of the device type.
* Returns last known data points up to the limit if limit is specified. Otherwise returns last known data point.
* Limit parameter needs to be zero or positive.
*/
@GET
@Path("/last-known/{type}/{deviceId}")
@Override
public Response getLastKnownData(@PathParam("deviceId") String deviceId, @PathParam("type") String deviceType) {
public Response getLastKnownData(@PathParam("deviceId") String deviceId, @PathParam("type") String deviceType, @QueryParam("limit") int limit) {
String query = DEFAULT_META_DEVICE_ID_ATTRIBUTE + ":" + deviceId;
String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain();
String sensorTableName = getTableName(DeviceMgtAPIUtils.getStreamDefinition(deviceType, tenantDomain));
@ -363,8 +405,16 @@ public class DeviceEventManagementServiceImpl implements DeviceEventManagementSe
List<SortByField> sortByFields = new ArrayList<>();
SortByField sortByField = new SortByField(TIMESTAMP_FIELD_NAME, SortType.DESC);
sortByFields.add(sortByField);
EventRecords eventRecords = getAllEventsForDevice(sensorTableName, query, sortByFields, 0, 1);
return Response.status(Response.Status.OK.getStatusCode()).entity(eventRecords).build();
if (limit == 0) {
EventRecords eventRecords = getAllEventsForDevice(sensorTableName, query, sortByFields, 0, 1);
return Response.status(Response.Status.OK.getStatusCode()).entity(eventRecords).build();
} else if (limit > 0) {
EventRecords eventRecords = getAllEventsForDevice(sensorTableName, query, sortByFields, 0, limit);
return Response.status(Response.Status.OK.getStatusCode()).entity(eventRecords).build();
} else {
String errorMessage = "Invalid limit value";
return Response.status(Response.Status.BAD_REQUEST).entity(errorMessage).build();
}
} catch (AnalyticsException e) {
String errorMsg = "Error on retrieving stats on table " + sensorTableName + " with query " + query;
log.error(errorMsg);
@ -393,7 +443,8 @@ public class DeviceEventManagementServiceImpl implements DeviceEventManagementSe
.getActiveEventReceiverConfiguration(eventRecieverNameTobeRemoved);
if (eventReceiverConfigurationDto != null) {
EventReceiverAdminServiceCallbackHandler eventReceiverAdminServiceCallbackHandler =
new EventReceiverAdminServiceCallbackHandler() {};
new EventReceiverAdminServiceCallbackHandler() {
};
receiverAdminServiceStub.startundeployActiveEventReceiverConfiguration(eventRecieverNameTobeRemoved
, eventReceiverAdminServiceCallbackHandler);
}
@ -468,7 +519,7 @@ public class DeviceEventManagementServiceImpl implements DeviceEventManagementSe
private void publishEventStore(String streamName, String version, EventAttributeList eventAttributes)
throws RemoteException, UserStoreException, JWTClientException,
EventStreamPersistenceAdminServiceEventStreamPersistenceAdminServiceExceptionException {
EventStreamPersistenceAdminServiceEventStreamPersistenceAdminServiceExceptionException {
EventStreamPersistenceAdminServiceStub eventStreamPersistenceAdminServiceStub =
DeviceMgtAPIUtils.getEventStreamPersistenceAdminServiceStub();
try {
@ -539,44 +590,6 @@ public class DeviceEventManagementServiceImpl implements DeviceEventManagementSe
return deviceType.replace(" ", "_").trim() + "-" + tenantDomain + "-" + transportType.toString() + "-receiver";
}
private static AnalyticsDataAPI getAnalyticsDataAPI() {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
AnalyticsDataAPI analyticsDataAPI =
(AnalyticsDataAPI) ctx.getOSGiService(AnalyticsDataAPI.class, null);
if (analyticsDataAPI == null) {
String msg = "Analytics api service has not initialized.";
log.error(msg);
throw new IllegalStateException(msg);
}
return analyticsDataAPI;
}
private static EventRecords getAllEventsForDevice(String tableName, String query, List<SortByField> sortByFields
, int offset, int limit) throws AnalyticsException {
int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
AnalyticsDataAPI analyticsDataAPI = getAnalyticsDataAPI();
EventRecords eventRecords = new EventRecords();
int eventCount = analyticsDataAPI.searchCount(tenantId, tableName, query);
if (eventCount == 0) {
eventRecords.setCount(0);
}
List<SearchResultEntry> resultEntries = analyticsDataAPI.search(tenantId, tableName, query, offset, limit,
sortByFields);
List<String> recordIds = getRecordIds(resultEntries);
AnalyticsDataResponse response = analyticsDataAPI.get(tenantId, tableName, 1, null, recordIds);
eventRecords.setCount(eventCount);
eventRecords.setList(AnalyticsDataAPIUtil.listRecords(analyticsDataAPI, response));
return eventRecords;
}
private static List<String> getRecordIds(List<SearchResultEntry> searchResults) {
List<String> ids = new ArrayList<>();
for (SearchResultEntry searchResult : searchResults) {
ids.add(searchResult.getId());
}
return ids;
}
private void cleanup(Stub stub) {
if (stub != null) {
try {

@ -185,6 +185,28 @@ public class GeoLocationBasedServiceImpl implements GeoLocationBasedService {
}
}
@Path("alerts/{alertType}")
@POST
@Consumes("application/json")
@Produces("application/json")
public Response createGeoAlertsForGeoClusters(Alert alert, @PathParam("alertType") String alertType) {
try {
GeoLocationProviderService geoService = DeviceMgtAPIUtils.getGeoService();
geoService.createGeoAlert(alert, alertType);
return Response.ok().build();
} catch (GeoLocationBasedServiceException e) {
String error = "Error occurred while creating " + alertType + " alert";
log.error(error, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(error).build();
} catch (AlertAlreadyExistException e) {
String error = "A geo alert with this name already exists.";
log.error(error,e);
return Response.status(Response.Status.BAD_REQUEST).entity(error).build();
}
}
@Path("alerts/{alertType}/{deviceType}/{deviceId}")
@PUT
@Consumes("application/json")
@ -222,6 +244,26 @@ public class GeoLocationBasedServiceImpl implements GeoLocationBasedService {
}
}
@Path("alerts/{alertType}")
@PUT
@Consumes("application/json")
@Produces("application/json")
public Response updateGeoAlertsForGeoClusters(Alert alert, @PathParam("alertType") String alertType) {
try {
GeoLocationProviderService geoService = DeviceMgtAPIUtils.getGeoService();
geoService.updateGeoAlert(alert, alertType);
return Response.ok().build();
} catch (GeoLocationBasedServiceException e) {
String error = "Error occurred while updating the geo alert for geo clusters";
log.error(error, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(error).build();
} catch (AlertAlreadyExistException e) {
String error = "A geo alert with this name already exists.";
log.error(error,e);
return Response.status(Response.Status.BAD_REQUEST).entity(error).build();
}
}
@Path("alerts/{alertType}/{deviceType}/{deviceId}")
@DELETE
@Consumes("application/json")
@ -256,6 +298,22 @@ public class GeoLocationBasedServiceImpl implements GeoLocationBasedService {
}
}
@Path("alerts/{alertType}")
@DELETE
@Consumes("application/json")
@Produces("application/json")
public Response removeGeoAlertsForGeoClusters(@PathParam("alertType") String alertType, @QueryParam("queryName") String queryName) {
try {
GeoLocationProviderService geoService = DeviceMgtAPIUtils.getGeoService();
geoService.removeGeoAlert(alertType, queryName);
return Response.ok().build();
} catch (GeoLocationBasedServiceException e) {
String error = "Error occurred while removing the geo alert for geo clusters";
log.error(error, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(error).build();
}
}
@Path("alerts/{alertType}/{deviceType}/{deviceId}")
@GET
@Consumes("application/json")
@ -308,6 +366,47 @@ public class GeoLocationBasedServiceImpl implements GeoLocationBasedService {
}
}
@Path("alerts/{alertType}")
@GET
@Consumes("application/json")
@Produces("application/json")
public Response getGeoAlertsForGeoClusters(@PathParam("alertType") String alertType) {
try {
GeoLocationProviderService geoService = DeviceMgtAPIUtils.getGeoService();
List<GeoFence> alerts = null;
String result = null;
switch (alertType) {
case GeoServices.ALERT_TYPE_WITHIN:
alerts = geoService.getWithinAlerts();
break;
case GeoServices.ALERT_TYPE_EXIT:
alerts = geoService.getExitAlerts();
break;
case GeoServices.ALERT_TYPE_STATIONARY:
alerts = geoService.getStationaryAlerts();
break;
case GeoServices.ALERT_TYPE_TRAFFIC:
alerts = geoService.getTrafficAlerts();
break;
case GeoServices.ALERT_TYPE_SPEED:
result = geoService.getSpeedAlerts();
return Response.ok().entity(result).build();
case GeoServices.ALERT_TYPE_PROXIMITY:
result = geoService.getProximityAlerts();
return Response.ok().entity(result).build();
default:
throw new GeoLocationBasedServiceException("Invalid Alert Type");
}
return Response.ok().entity(alerts).build();
} catch (GeoLocationBasedServiceException e) {
String error = "Error occurred while getting the geo alerts for " + alertType + " alert";
log.error(error, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(error).build();
}
}
@Path("alerts/history/{deviceType}/{deviceId}")
@GET
@Consumes("application/json")
@ -358,6 +457,45 @@ public class GeoLocationBasedServiceImpl implements GeoLocationBasedService {
}
}
@Path("alerts/history")
@GET
@Consumes("application/json")
@Produces("application/json")
public Response getGeoAlertsHistoryForGeoClusters(@QueryParam("from") long from, @QueryParam("to") long to) {
String tableName = "IOT_PER_DEVICE_STREAM_GEO_ALERTNOTIFICATIONS";
String fromDate = String.valueOf(from);
String toDate = String.valueOf(to);
String query = "";
if (from != 0 || to != 0) {
query = "timeStamp : [" + fromDate + " TO " + toDate + "]";
}
try {
List<SortByField> sortByFields = new ArrayList<>();
SortByField sortByField = new SortByField("timeStamp", SortType.ASC);
sortByFields.add(sortByField);
// this is the user who initiates the request
String authorizedUser = MultitenantUtils.getTenantAwareUsername(
CarbonContext.getThreadLocalCarbonContext().getUsername());
String tenantDomain = MultitenantUtils.getTenantDomain(authorizedUser);
int tenantId = DeviceMgtAPIUtils.getRealmService().getTenantManager().getTenantId(tenantDomain);
AnalyticsDataAPI analyticsDataAPI = DeviceMgtAPIUtils.getAnalyticsDataAPI();
List<SearchResultEntry> searchResults = analyticsDataAPI.search(tenantId, tableName, query,
0,
100,
sortByFields);
List<Event> events = getEventBeans(analyticsDataAPI, tenantId, tableName, new ArrayList<String>(),
searchResults);
return Response.ok().entity(events).build();
} catch (AnalyticsException | UserStoreException e) {
log.error("Failed to perform search on table: " + tableName + " : " + e.getMessage(), e);
throw DeviceMgtUtil.buildBadRequestException(
Constants.ErrorMessages.STATUS_BAD_REQUEST_MESSAGE_DEFAULT);
}
}
private List<Event> getEventBeans(AnalyticsDataAPI analyticsDataAPI, int tenantId, String tableName,
List<String> columns,
List<SearchResultEntry> searchResults) throws AnalyticsException {

@ -46,10 +46,10 @@ public class GeoLocationBasedServiceImplTest {
List<GeoCluster> geoClusters = new ArrayList<>();
geoClusters.add(new GeoCluster(new GeoCoordinate(1.5, 80.7),
new GeoCoordinate(1.1, 79.5), new GeoCoordinate(1.9, 82.1), 3,
"tb32", "aegtew234", "android"));
"tb32", "aegtew234", "android", "1234"));
geoClusters.add(new GeoCluster(new GeoCoordinate(10.2, 86.1),
new GeoCoordinate(9.8, 84.7), new GeoCoordinate(11.1, 88.1), 4,
"t1gd", "swerty12s", "android"));
"t1gd", "swerty12s", "android", "1234"));
Mockito.doReturn(geoClusters).when(deviceManagementProviderService)
.findGeoClusters(Mockito.any(GeoCoordinate.class), Mockito.any(GeoCoordinate.class), Mockito.anyInt());
Response response = geoLocationBasedService.getGeoDeviceLocations(0.4, 15, 75.6,

@ -21,7 +21,7 @@
<parent>
<artifactId>device-mgt</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

@ -30,22 +30,43 @@ public interface GeoLocationProviderService {
List<GeoFence> getWithinAlerts(DeviceIdentifier identifier) throws GeoLocationBasedServiceException;
List<GeoFence> getWithinAlerts() throws GeoLocationBasedServiceException;
List<GeoFence> getExitAlerts(DeviceIdentifier identifier) throws GeoLocationBasedServiceException;
List<GeoFence> getExitAlerts() throws GeoLocationBasedServiceException;
boolean createGeoAlert(Alert alert, DeviceIdentifier identifier, String alertType)
throws GeoLocationBasedServiceException, AlertAlreadyExistException;
boolean createGeoAlert(Alert alert, String alertType)
throws GeoLocationBasedServiceException,AlertAlreadyExistException;
boolean updateGeoAlert(Alert alert, DeviceIdentifier identifier, String alertType)
throws GeoLocationBasedServiceException, AlertAlreadyExistException;
boolean updateGeoAlert(Alert alert, String alertType)
throws GeoLocationBasedServiceException,AlertAlreadyExistException;
boolean removeGeoAlert(String alertType, DeviceIdentifier identifier, String queryName)
throws GeoLocationBasedServiceException;
boolean removeGeoAlert(String alertType, String queryName)
throws GeoLocationBasedServiceException;
String getSpeedAlerts(DeviceIdentifier identifier) throws GeoLocationBasedServiceException;
String getSpeedAlerts() throws GeoLocationBasedServiceException;
String getProximityAlerts(DeviceIdentifier identifier) throws GeoLocationBasedServiceException;
String getProximityAlerts() throws GeoLocationBasedServiceException;
List<GeoFence> getStationaryAlerts(DeviceIdentifier identifier) throws GeoLocationBasedServiceException;
List<GeoFence> getStationaryAlerts() throws GeoLocationBasedServiceException;
List<GeoFence> getTrafficAlerts(DeviceIdentifier identifier) throws GeoLocationBasedServiceException;
List<GeoFence> getTrafficAlerts() throws GeoLocationBasedServiceException;
}

@ -22,7 +22,7 @@
<parent>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>device-mgt</artifactId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

@ -1076,7 +1076,8 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
" MAX(DEVICE_LOCATION.LONGITUDE) AS MAX_LONGITUDE," +
" SUBSTRING(DEVICE_LOCATION.GEO_HASH,1,?) AS GEOHASH_PREFIX, COUNT(*) AS COUNT," +
" MIN(DEVICE.DEVICE_IDENTIFICATION) AS DEVICE_IDENTIFICATION," +
" MIN(DEVICE_TYPE.NAME) AS TYPE " +
" MIN(DEVICE_TYPE.NAME) AS TYPE, " +
" MIN(DEVICE.LAST_UPDATED_TIMESTAMP) AS LAST_UPDATED_TIMESTAMP " +
"FROM DM_DEVICE_LOCATION AS DEVICE_LOCATION,DM_DEVICE AS DEVICE, DM_DEVICE_TYPE AS DEVICE_TYPE " +
"WHERE DEVICE_LOCATION.LATITUDE BETWEEN ? AND ? AND " +
"DEVICE_LOCATION.LONGITUDE BETWEEN ? AND ? AND " +
@ -1100,11 +1101,12 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
double max_longitude = rs.getDouble("MAX_LONGITUDE");
String device_identification = rs.getString("DEVICE_IDENTIFICATION");
String device_type=rs.getString("TYPE");
String last_seen = rs.getString("LAST_UPDATED_TIMESTAMP");
long count = rs.getLong("COUNT");
String geohashPrefix = rs.getString("GEOHASH_PREFIX");
geoClusters.add(new GeoCluster(new GeoCoordinate(latitude, longitude),
new GeoCoordinate(min_latitude,min_longitude), new GeoCoordinate(max_latitude,max_longitude),
count, geohashPrefix,device_identification,device_type));
count, geohashPrefix,device_identification,device_type,last_seen));
}
} catch (SQLException e) {
throw new DeviceManagementDAOException("Error occurred while retrieving information of " +

@ -10,11 +10,11 @@ public class GeoCluster {
private String geohashPrefix;
private String deviceIdentification;
private String deviceType;
private String lastSeen;
public GeoCluster(GeoCoordinate coordinates, GeoCoordinate southWestBound, GeoCoordinate northEastBound, long count,
String geohashPrefix, String deviceIdentification, String deviceType){
String geohashPrefix, String deviceIdentification, String deviceType, String lastSeen){
this.coordinates=coordinates;
this.southWestBound=southWestBound;
this.northEastBound=northEastBound;
@ -22,6 +22,7 @@ public class GeoCluster {
this.geohashPrefix=geohashPrefix;
this.deviceIdentification=deviceIdentification;
this.deviceType=deviceType;
this.lastSeen = lastSeen;
}
@ -51,4 +52,8 @@ public class GeoCluster {
public String getDeviceType() { return deviceType;
}
public String getLastSeen() {
return lastSeen;
}
}

@ -55,6 +55,7 @@ import org.wso2.carbon.registry.api.Resource;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import javax.persistence.EntityExistsException;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
@ -72,6 +73,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Collections;
import static org.wso2.carbon.device.mgt.common.DeviceManagementConstants.GeoServices.DAS_PORT;
import static org.wso2.carbon.device.mgt.common.DeviceManagementConstants.GeoServices.DEFAULT_HTTP_PROTOCOL;
@ -159,6 +161,53 @@ public class GeoLocationProviderServiceImpl implements GeoLocationProviderServic
}
}
@Override
public List<GeoFence> getWithinAlerts() throws GeoLocationBasedServiceException {
Registry registry = getGovernanceRegistry();
String registryPath = GeoServices.REGISTRY_PATH_FOR_ALERTS +
GeoServices.ALERT_TYPE_WITHIN + "/";
Resource resource;
try {
resource = registry.get(registryPath);
} catch (RegistryException e) {
log.error("Error while reading the registry path: " + registryPath);
return Collections.emptyList();
}
try {
List<GeoFence> fences = new ArrayList<>();
if (resource != null) {
Object contentObj = resource.getContent();
if (contentObj instanceof String[]) {
String[] content = (String[]) contentObj;
for (String res : content) {
Resource childRes = registry.get(res);
Properties props = childRes.getProperties();
GeoFence geoFence = new GeoFence();
InputStream inputStream = childRes.getContentStream();
StringWriter writer = new StringWriter();
IOUtils.copy(inputStream, writer, "UTF-8");
geoFence.setGeoJson(writer.toString());
List queryNameObj = (List) props.get(GeoServices.QUERY_NAME);
geoFence.setQueryName(queryNameObj != null ? queryNameObj.get(0).toString() : null);
List areaNameObj = (List) props.get(GeoServices.AREA_NAME);
geoFence.setAreaName(areaNameObj != null ? areaNameObj.get(0).toString() : null);
geoFence.setCreatedTime(childRes.getCreatedTime().getTime());
fences.add(geoFence);
}
}
}
return fences;
} catch (RegistryException | IOException e) {
throw new GeoLocationBasedServiceException(
"Error occurred while getting the geo alerts" , e);
}
}
@Override
public List<GeoFence> getExitAlerts(DeviceIdentifier identifier) throws GeoLocationBasedServiceException {
@ -207,18 +256,184 @@ public class GeoLocationProviderServiceImpl implements GeoLocationProviderServic
}
}
@Override
public List<GeoFence> getExitAlerts() throws GeoLocationBasedServiceException {
Registry registry = getGovernanceRegistry();
String registryPath = GeoServices.REGISTRY_PATH_FOR_ALERTS +
GeoServices.ALERT_TYPE_EXIT + "/";
Resource resource;
try {
resource = registry.get(registryPath);
} catch (RegistryException e) {
log.error("Error while reading the registry path: " + registryPath);
return Collections.emptyList();
}
try {
List<GeoFence> fences = new ArrayList<>();
if (resource != null) {
Object contentObj = resource.getContent();
if (contentObj instanceof String[]) {
String[] content = (String[]) contentObj;
for (String res : content) {
Resource childRes = registry.get(res);
Properties props = childRes.getProperties();
GeoFence geoFence = new GeoFence();
InputStream inputStream = childRes.getContentStream();
StringWriter writer = new StringWriter();
IOUtils.copy(inputStream, writer, "UTF-8");
geoFence.setGeoJson(writer.toString());
List queryNameObj = (List) props.get(GeoServices.QUERY_NAME);
geoFence.setQueryName(queryNameObj != null ? queryNameObj.get(0).toString() : null);
List areaNameObj = (List) props.get(GeoServices.AREA_NAME);
geoFence.setAreaName(areaNameObj != null ? areaNameObj.get(0).toString() : null);
geoFence.setCreatedTime(childRes.getCreatedTime().getTime());
fences.add(geoFence);
}
}
}
return fences;
} catch (RegistryException | IOException e) {
throw new GeoLocationBasedServiceException(
"Error occurred while getting the geo alerts", e);
}
}
@Override
public boolean createGeoAlert(Alert alert, DeviceIdentifier identifier, String alertType)
throws GeoLocationBasedServiceException, AlertAlreadyExistException {
return saveGeoAlert(alert, identifier, alertType, false);
}
@Override
public boolean createGeoAlert(Alert alert, String alertType)
throws GeoLocationBasedServiceException,AlertAlreadyExistException {
return saveGeoAlert(alert, alertType, false);
}
@Override
public boolean updateGeoAlert(Alert alert, DeviceIdentifier identifier, String alertType)
throws GeoLocationBasedServiceException, AlertAlreadyExistException {
return saveGeoAlert(alert, identifier, alertType, true);
}
@Override
public boolean updateGeoAlert(Alert alert, String alertType)
throws GeoLocationBasedServiceException,AlertAlreadyExistException {
return saveGeoAlert(alert, alertType, true);
}
public boolean saveGeoAlert(Alert alert, String alertType, boolean isUpdate)
throws GeoLocationBasedServiceException,AlertAlreadyExistException {
Type type = new TypeToken<Map<String, String>>() {
}.getType();
Gson gson = new Gson();
Map<String, String> parseMap = gson.fromJson(alert.getParseData(), type);
Map<String, String> options = new HashMap<>();
Object content = null;
if (GeoServices.ALERT_TYPE_WITHIN.equals(alertType)) {
options.put(GeoServices.QUERY_NAME, alert.getQueryName());
options.put(GeoServices.AREA_NAME, alert.getCustomName());
content = parseMap.get(GeoServices.GEO_FENCE_GEO_JSON);
} else if (GeoServices.ALERT_TYPE_EXIT.equals(alertType)) {
options.put(GeoServices.QUERY_NAME, alert.getQueryName());
options.put(GeoServices.AREA_NAME, alert.getCustomName());
content = parseMap.get(GeoServices.GEO_FENCE_GEO_JSON);
} else if (GeoServices.ALERT_TYPE_SPEED.equals(alertType)) {
content = parseMap.get(GeoServices.SPEED_ALERT_VALUE);
} else if (GeoServices.ALERT_TYPE_PROXIMITY.equals(alertType)) {
options.put(GeoServices.PROXIMITY_DISTANCE, alert.getProximityDistance());
options.put(GeoServices.PROXIMITY_TIME, alert.getProximityTime());
content = alert.getParseData();
} else if (GeoServices.ALERT_TYPE_STATIONARY.equals(alertType)) {
options.put(GeoServices.QUERY_NAME, alert.getQueryName());
options.put(GeoServices.AREA_NAME, alert.getCustomName());
options.put(GeoServices.STATIONARY_TIME, alert.getStationeryTime());
options.put(GeoServices.FLUCTUATION_RADIUS, alert.getFluctuationRadius());
content = alert.getParseData();
} else if (GeoServices.ALERT_TYPE_TRAFFIC.equals(alertType)) {
content = parseMap.get(GeoServices.GEO_FENCE_GEO_JSON);
} else {
throw new GeoLocationBasedServiceException(
"Unrecognized execution plan type: " + alertType + " while creating geo alert");
}
//deploy alert into event processor
EventProcessorAdminServiceStub eventprocessorStub = null;
String action = (isUpdate ? "updating" : "creating");
try {
ExecutionPlanConfigurationDto[] allActiveExecutionPlanConfigs = null;
String activeExecutionPlan = null;
String executionPlanName = getExecutionPlanName(alertType, alert.getQueryName());
eventprocessorStub = getEventProcessorAdminServiceStub();
String parsedTemplate = parseTemplateForGeoClusters(alertType, parseMap);
String validationResponse = eventprocessorStub.validateExecutionPlan(parsedTemplate);
if (validationResponse.equals("success")) {
allActiveExecutionPlanConfigs = eventprocessorStub.getAllActiveExecutionPlanConfigurations();
if (isUpdate) {
for (ExecutionPlanConfigurationDto activeExectionPlanConfig:allActiveExecutionPlanConfigs) {
activeExecutionPlan = activeExectionPlanConfig.getExecutionPlan();
if (activeExecutionPlan.contains(executionPlanName)) {
eventprocessorStub.editActiveExecutionPlan(parsedTemplate, executionPlanName);
return true;
}
}
eventprocessorStub.deployExecutionPlan(parsedTemplate);
} else {
for (ExecutionPlanConfigurationDto activeExectionPlanConfig:allActiveExecutionPlanConfigs) {
activeExecutionPlan = activeExectionPlanConfig.getExecutionPlan();
if (activeExecutionPlan.contains(executionPlanName)) {
throw new AlertAlreadyExistException("Execution plan already exists with name "
+ executionPlanName);
}
}
updateRegistry(getRegistryPath(alertType, alert.getQueryName()),content,options);
eventprocessorStub.deployExecutionPlan(parsedTemplate);
}
} else {
if (validationResponse.startsWith(
"'within' is neither a function extension nor an aggregated attribute extension"
)) {
log.error("GPL Siddhi Geo Extension is not configured. Please execute maven script " +
"`siddhi-geo-extention-deployer.xml` in $IOT_HOME/analytics/scripts");
} else {
log.error("Execution plan validation failed: " + validationResponse);
}
throw new GeoLocationBasedServiceException(
"Error occurred while " + action + " geo " + alertType);
}
return true;
} catch (AxisFault axisFault) {
throw new GeoLocationBasedServiceException(
"Event processor admin service initialization failed while " + action + " geo alert '" +
alertType, axisFault
);
} catch (IOException e) {
throw new GeoLocationBasedServiceException(
"Event processor admin service failed while " + action + " geo alert '" +
alertType, e);
} catch (JWTClientException e) {
throw new GeoLocationBasedServiceException(
"JWT token creation failed while " + action + " geo alert '" + alertType, e);
} finally {
cleanup(eventprocessorStub);
}
}
public boolean saveGeoAlert(Alert alert, DeviceIdentifier identifier, String alertType, boolean isUpdate)
throws GeoLocationBasedServiceException, AlertAlreadyExistException {
@ -301,7 +516,7 @@ public class GeoLocationProviderServiceImpl implements GeoLocationProviderServic
"'within' is neither a function extension nor an aggregated attribute extension"
)) {
log.error("GPL Siddhi Geo Extension is not configured. Please execute maven script " +
"`siddhi-geo-extention-deployer.xml` in $IOT_HOME/analytics/scripts");
"`siddhi-geo-extention-deployer.xml` in $IOT_HOME/analytics/scripts");
} else {
log.error("Execution plan validation failed: " + validationResponse);
}
@ -358,16 +573,53 @@ public class GeoLocationProviderServiceImpl implements GeoLocationProviderServic
return path;
}
private String getRegistryPath(String alertType, String queryName)
throws GeoLocationBasedServiceException {
String path = "";
if (GeoServices.ALERT_TYPE_WITHIN.equals(alertType)) {
path = GeoServices.REGISTRY_PATH_FOR_ALERTS + GeoServices.ALERT_TYPE_WITHIN +
"/" + "/" + queryName;
} else if (GeoServices.ALERT_TYPE_EXIT.equals(alertType)) {
path = GeoServices.REGISTRY_PATH_FOR_ALERTS + GeoServices.ALERT_TYPE_EXIT +
"/" + queryName;
} else if (GeoServices.ALERT_TYPE_SPEED.equals(alertType)) {
path = GeoServices.REGISTRY_PATH_FOR_ALERTS + GeoServices.ALERT_TYPE_SPEED +
"/" ;
} else if (GeoServices.ALERT_TYPE_PROXIMITY.equals(alertType)) {
path = GeoServices.REGISTRY_PATH_FOR_ALERTS + GeoServices.ALERT_TYPE_PROXIMITY +
"/" + queryName;
} else if (GeoServices.ALERT_TYPE_STATIONARY.equals(alertType)) {
path = GeoServices.REGISTRY_PATH_FOR_ALERTS + GeoServices.ALERT_TYPE_STATIONARY +
"/" + queryName;
} else if (GeoServices.ALERT_TYPE_TRAFFIC.equals(alertType)) {
path = GeoServices.REGISTRY_PATH_FOR_ALERTS + GeoServices.ALERT_TYPE_TRAFFIC +
"/" + queryName;
} else {
throw new GeoLocationBasedServiceException(
"Unrecognized execution plan type: " + alertType);
}
return path;
}
private String getExecutionPlanName(String alertType, String queryName, String deviceId) {
if ("Traffic".equals(alertType)) {
return "Geo-ExecutionPlan-Traffic_" + queryName + "_alert";
} else if ("Speed".equals(alertType)) {
return "Geo-ExecutionPlan-" + alertType + "---" + deviceId + "_alert";
} else {
return "Geo-ExecutionPlan-" + alertType + "_" + queryName + "---_" + deviceId + "_alert";
}
}
private String getExecutionPlanName(String alertType, String queryName) {
if ("Traffic".equals(alertType)) {
return "Geo-ExecutionPlan-Traffic_" + queryName + "_alert";
} else {
if ("Speed".equals(alertType)) {
return "Geo-ExecutionPlan-" + alertType + "---" + "_alert";
}
return "Geo-ExecutionPlan-" + alertType + "_" + queryName + "---" + "_alert";
}
}
@Override
public boolean removeGeoAlert(String alertType, DeviceIdentifier identifier, String queryName)
throws GeoLocationBasedServiceException {
@ -396,6 +648,32 @@ public class GeoLocationProviderServiceImpl implements GeoLocationProviderServic
}
}
@Override
public boolean removeGeoAlert(String alertType, String queryName)
throws GeoLocationBasedServiceException {
removeFromRegistry(alertType, queryName);
String executionPlanName = getExecutionPlanName(alertType, queryName);
EventProcessorAdminServiceStub eventprocessorStub = null;
try {
eventprocessorStub = getEventProcessorAdminServiceStub();
eventprocessorStub.undeployActiveExecutionPlan(executionPlanName);
return true;
} catch (IOException e) {
throw new GeoLocationBasedServiceException(
"Event processor admin service stub invocation failed while removing geo alert '" +
alertType +
"': " + executionPlanName, e
);
} catch (JWTClientException e) {
throw new GeoLocationBasedServiceException(
"JWT token creation failed while removing geo alert '" + alertType + "': " +
executionPlanName, e
);
} finally {
cleanup(eventprocessorStub);
}
}
private void removeFromRegistry(String alertType, DeviceIdentifier identifier, String queryName)
throws GeoLocationBasedServiceException {
String path = "unknown";
@ -409,6 +687,18 @@ public class GeoLocationProviderServiceImpl implements GeoLocationProviderServic
}
}
private void removeFromRegistry(String alertType, String queryName)
throws GeoLocationBasedServiceException {
String path = "unknown";
try {
path = getRegistryPath(alertType, queryName);
getGovernanceRegistry().delete(path);
} catch (RegistryException e) {
throw new GeoLocationBasedServiceException(
"Error occurred while removing " + alertType + " alert " + " from the path: " + path);
}
}
protected EventProcessorAdminServiceStub getEventProcessorAdminServiceStub() throws JWTClientException {
//send alert to event-processing
String eventProcessorAdminServiceWSUrl = Utils.replaceSystemProperty(GeoServices.DAS_URL) +
@ -473,6 +763,24 @@ public class GeoLocationProviderServiceImpl implements GeoLocationProviderServic
}
}
@Override
public String getSpeedAlerts() throws GeoLocationBasedServiceException {
try {
Registry registry = getGovernanceRegistry();
Resource resource = registry.get(GeoServices.REGISTRY_PATH_FOR_ALERTS +
GeoServices.ALERT_TYPE_SPEED);
if (resource == null) {
return "{'content': false}";
}
InputStream inputStream = resource.getContentStream();
StringWriter writer = new StringWriter();
IOUtils.copy(inputStream, writer, "UTF-8");
return "{'speedLimit':" + writer.toString() + "}";
} catch (RegistryException | IOException e) {
return "{'content': false}";
}
}
@Override
public String getProximityAlerts(DeviceIdentifier identifier) throws GeoLocationBasedServiceException {
try {
@ -497,6 +805,30 @@ public class GeoLocationProviderServiceImpl implements GeoLocationProviderServic
}
}
@Override
public String getProximityAlerts() throws GeoLocationBasedServiceException {
try {
Registry registry = getGovernanceRegistry();
Resource resource = registry.get(GeoServices.REGISTRY_PATH_FOR_ALERTS +
GeoServices.ALERT_TYPE_PROXIMITY);
if (resource != null) {
Properties props = resource.getProperties();
List proxDisObj = (List) props.get(GeoServices.PROXIMITY_DISTANCE);
List proxTimeObj = (List) props.get(GeoServices.PROXIMITY_TIME);
return String.format("{proximityDistance:\"%s\", proximityTime:\"%s\"}",
proxDisObj != null ? proxDisObj.get(0).toString() : "",
proxTimeObj != null ? proxTimeObj.get(0).toString() : "");
} else {
return "{'content': false}";
}
} catch (RegistryException e) {
return "{'content': false}";
}
}
@Override
public List<GeoFence> getStationaryAlerts(DeviceIdentifier identifier) throws GeoLocationBasedServiceException {
@ -549,6 +881,57 @@ public class GeoLocationProviderServiceImpl implements GeoLocationProviderServic
}
}
@Override
public List<GeoFence> getStationaryAlerts() throws GeoLocationBasedServiceException {
Registry registry = getGovernanceRegistry();
String registryPath = GeoServices.REGISTRY_PATH_FOR_ALERTS +
GeoServices.ALERT_TYPE_STATIONARY + "/";
Resource resource;
try {
resource = registry.get(registryPath);
} catch (RegistryException e) {
log.error("Error while reading the registry path: " + registryPath);
return Collections.emptyList();
}
try {
List<GeoFence> fences = new ArrayList<>();
if (resource != null) {
Object contentObj = resource.getContent();
if (contentObj instanceof String[]) {
String[] content = (String[]) contentObj;
for (String res : content) {
Resource childRes = registry.get(res);
Properties props = childRes.getProperties();
GeoFence geoFence = new GeoFence();
InputStream inputStream = childRes.getContentStream();
StringWriter writer = new StringWriter();
IOUtils.copy(inputStream, writer, "UTF-8");
geoFence.setGeoJson(writer.toString());
List queryNameObj = (List) props.get(GeoServices.QUERY_NAME);
geoFence.setQueryName(queryNameObj != null ? queryNameObj.get(0).toString() : null);
List areaNameObj = (List) props.get(GeoServices.AREA_NAME);
geoFence.setAreaName(areaNameObj != null ? areaNameObj.get(0).toString() : null);
List sTimeObj = (List) props.get(GeoServices.STATIONARY_TIME);
geoFence.setStationaryTime(sTimeObj != null ? sTimeObj.get(0).toString() : null);
List fluctRadiusObj = (List) props.get(GeoServices.FLUCTUATION_RADIUS);
geoFence.setFluctuationRadius(fluctRadiusObj != null ? fluctRadiusObj.get(0).toString() : null);
geoFence.setCreatedTime(childRes.getCreatedTime().getTime());
fences.add(geoFence);
}
}
}
return fences;
} catch (RegistryException | IOException e) {
throw new GeoLocationBasedServiceException(
"Error occurred while getting the geo alerts", e);
}
}
@Override
public List<GeoFence> getTrafficAlerts(DeviceIdentifier identifier) throws GeoLocationBasedServiceException {
Registry registry = getGovernanceRegistry();
@ -596,6 +979,52 @@ public class GeoLocationProviderServiceImpl implements GeoLocationProviderServic
}
}
@Override
public List<GeoFence> getTrafficAlerts() throws GeoLocationBasedServiceException {
Registry registry = getGovernanceRegistry();
String registryPath = GeoServices.REGISTRY_PATH_FOR_ALERTS +
GeoServices.ALERT_TYPE_STATIONARY + "/";
Resource resource;
try {
resource = registry.get(registryPath);
} catch (RegistryException e) {
log.error("Error while reading the registry path: " + registryPath);
return Collections.emptyList();
}
try {
List<GeoFence> fences = new ArrayList<>();
if (resource != null) {
Object contentObj = resource.getContent();
if (contentObj instanceof String[]) {
String[] content = (String[]) contentObj;
for (String res : content) {
Resource childRes = registry.get(res);
Properties props = childRes.getProperties();
GeoFence geoFence = new GeoFence();
InputStream inputStream = childRes.getContentStream();
StringWriter writer = new StringWriter();
IOUtils.copy(inputStream, writer, "UTF-8");
geoFence.setGeoJson(writer.toString());
List queryNameObj = (List) props.get(GeoServices.QUERY_NAME);
geoFence.setQueryName(queryNameObj != null ? queryNameObj.get(0).toString() : null);
List sNameObj = (List) props.get(GeoServices.STATIONARY_NAME);
geoFence.setAreaName(sNameObj != null ? sNameObj.get(0).toString() : null);
geoFence.setCreatedTime(childRes.getCreatedTime().getTime());
fences.add(geoFence);
}
}
}
return fences;
} catch (RegistryException | IOException e) {
throw new GeoLocationBasedServiceException(
"Error occurred while getting the geo alerts", e);
}
}
private Registry getGovernanceRegistry() throws GeoLocationBasedServiceException {
try {
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId();
@ -631,6 +1060,28 @@ public class GeoLocationProviderServiceImpl implements GeoLocationProviderServic
}
}
private String parseTemplateForGeoClusters(String alertType, Map<String, String> parseMap) throws
GeoLocationBasedServiceException {
String templatePath = "alerts/Geo-ExecutionPlan-" + alertType + "_alert_for_GeoClusters.siddhiql";
InputStream resource = getClass().getClassLoader().getResourceAsStream(templatePath);
if (resource == null) {
throw new GeoLocationBasedServiceException("Could not find template in path : " + templatePath);
}
try {
//Read template
String template = IOUtils.toString(resource, StandardCharsets.UTF_8.toString());
//Replace variables
for (Map.Entry<String, String> parseEntry : parseMap.entrySet()) {
String find = "\\$" + parseEntry.getKey();
template = template.replaceAll(find, parseEntry.getValue());
}
return template;
} catch (IOException e) {
throw new GeoLocationBasedServiceException(
"Error occurred while populating the template for the Within Alert", e);
}
}
private void updateRegistry(String path, DeviceIdentifier identifier, Object content, Map<String, String> options)
throws GeoLocationBasedServiceException {
try {
@ -650,6 +1101,24 @@ public class GeoLocationProviderServiceImpl implements GeoLocationProviderServic
}
}
private void updateRegistry(String path, Object content, Map<String, String> options)
throws GeoLocationBasedServiceException {
try {
Registry registry = getGovernanceRegistry();
Resource newResource = registry.newResource();
newResource.setContent(content);
newResource.setMediaType("application/json");
for (Map.Entry<String, String> option : options.entrySet()) {
newResource.addProperty(option.getKey(), option.getValue());
}
registry.put(path, newResource);
} catch (RegistryException e) {
throw new GeoLocationBasedServiceException(
"Error occurred while setting the Within Alert", e);
}
}
/**
* Loads the keystore.
*

@ -13,7 +13,7 @@ define stream dataIn (id string, latitude double, longitude double, timeStamp lo
define stream dataOut (id string, latitude double, longitude double, timeStamp long, type string ,speed float, heading float, eventId string, state string, information string);
from dataIn[geo:within(longitude,latitude,"$geoFenceGeoJSON")==false and id == "$deviceId"]#geodashboard:subscribe()
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId , "ALERTED" as state, "This device is outside $areaName area!!!" as information
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId , "ALERTED" as state, str:concat(str:concat(str:concat(type," device "),id), " is outside $areaName area!!!") as information
insert into dataOut;
from dataIn[geo:within(longitude,latitude,"$geoFenceGeoJSON")!=false and id == "$deviceId"]
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId , "NORMAL" as state, "" as information

@ -0,0 +1,21 @@
/* Enter a unique ExecutionPlan */
@Plan:name('$executionPlanName')
/* Enter a unique description for ExecutionPlan */
-- @Plan:description('ExecutionPlan')
/* define streams/tables and write queries here ... */
@Import('org.wso2.geo.StandardSpatialEvents:1.0.0')
define stream dataIn (id string, latitude double, longitude double, timeStamp long, type string ,speed float, heading float, eventId string);
@Export('org.wso2.geo.ProcessedSpatialEvents:1.0.0')
define stream dataOut (id string, latitude double, longitude double, timeStamp long, type string ,speed float, heading float, eventId string, state string, information string);
from dataIn[geo:within(longitude,latitude,"$geoFenceGeoJSON")==false]#geodashboard:subscribe()
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId , "ALERTED" as state, str:concat(str:concat(str:concat(type," device "),id), " is outside $areaName area!!!") as information
insert into dataOut;
from dataIn[geo:within(longitude,latitude,"$geoFenceGeoJSON")!=false]
select id, latitude, longitude,timeStamp, type, speed, heading ,eventId , "NORMAL" as state, "" as information
insert into dataOut;

@ -0,0 +1,140 @@
/* Enter a unique ExecutionPlan */
@Plan:name('Geo-ExecutionPlan-Proximity_alert')
/* Enter a unique description for ExecutionPlan */
-- @Plan:description('ExecutionPlan')
/* define streams/tables and write queries here ... */
@Import('org.wso2.geo.StandardSpatialEvents:1.0.0')
define stream dataIn (id string, latitude double, longitude double, timeStamp long, type string, speed float, heading float, eventId string );
@Export('org.wso2.geo.ProcessedSpatialEvents:1.0.0')
define stream dataOut ( id string, latitude double, longitude double, timeStamp long, type string, speed float, heading float, eventId string, state string, information string );
@IndexBy('id')
define table ProximityTable(id string, timeStamp long);
@IndexBy('id')
define table AlertsTable(id string , proximityWith string, eventId string);
from dataIn#geodashboard:subscribe()
select id, latitude, longitude, timeStamp, type, speed, heading, eventId
insert into initialStream;
from initialStream[type == 'STOP']
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId , "" as proximityInfo ,"false" as isProximity
insert into dataOutStream;
from initialStream[type != 'STOP']
select *
insert into objectInitialStream;
from objectInitialStream#geo:proximity(id,longitude,latitude, $proximityDistance)
select id, latitude, longitude, timeStamp, type, speed, heading, eventId,inCloseProximity,proximityWith
insert into proxymityStream;
from proxymityStream[AlertsTable.id == proxymityStream.id in AlertsTable]
select id, latitude, longitude, timeStamp, type, speed, heading, eventId,inCloseProximity,proximityWith,true as inAlertTable
insert into innerStreamOne;
from proxymityStream[not(AlertsTable.id == proxymityStream.id in AlertsTable)]
select id, latitude, longitude, timeStamp, type, speed, heading, eventId,inCloseProximity,proximityWith,false as inAlertTable
insert into innerStreamOne;
from proxymityStream[AlertsTable.id == proxymityStream.proximityWith in AlertsTable]
select id, latitude, longitude, timeStamp, type, speed, heading, eventId,inCloseProximity,proximityWith,true as inAlertTable
insert into innerStreamSeven;
from proxymityStream[not(AlertsTable.id == proxymityStream.proximityWith in AlertsTable)]
select id, latitude, longitude, timeStamp, type, speed, heading, eventId,inCloseProximity,proximityWith,false as inAlertTable
insert into innerStreamSeven;
from innerStreamOne[inCloseProximity == true AND not(inAlertTable)]
select id,str:concat(",",proximityWith) as proximityWith , eventId
insert into AlertsTable;
from innerStreamSeven[inCloseProximity == true AND not(inAlertTable)]
select proximityWith as id,str:concat(",",id) as proximityWith , eventId
insert into AlertsTable;
from innerStreamOne[innerStreamOne.inCloseProximity == true AND inAlertTable]#window.length(0) join AlertsTable
on innerStreamOne.id == AlertsTable.id
select innerStreamOne.id as id, str:concat(",", innerStreamOne.proximityWith, AlertsTable.proximityWith) as proximityWith, innerStreamOne.eventId as eventId
insert into updateStream;
from innerStreamSeven[innerStreamSeven.inCloseProximity == true AND inAlertTable]#window.length(0) join AlertsTable
on innerStreamSeven.proximityWith == AlertsTable.id
select innerStreamSeven.proximityWith as id, str:concat(",", innerStreamSeven.id, AlertsTable.proximityWith) as proximityWith, innerStreamSeven.eventId as eventId
insert into updateStream;
from innerStreamOne[innerStreamOne.inCloseProximity == false AND inAlertTable]#window.length(0) join AlertsTable
on innerStreamOne.id == AlertsTable.id
select innerStreamOne.id as id, str:replaceAll(AlertsTable.proximityWith, str:concat(",", innerStreamOne.proximityWith), "") as proximityWith, innerStreamOne.eventId as eventId
insert into updateStream;
from innerStreamSeven[innerStreamSeven.inCloseProximity == false AND inAlertTable]#window.length(0) join AlertsTable
on innerStreamSeven.proximityWith == AlertsTable.id
select innerStreamSeven.proximityWith as id, str:replaceAll(AlertsTable.proximityWith, str:concat(",", innerStreamSeven.id), "") as proximityWith, innerStreamSeven.eventId as eventId
insert into updateStream;
from updateStream
select *
update AlertsTable
on id== AlertsTable.id;
from updateStream[proximityWith == ""]
delete AlertsTable
on id== AlertsTable.id;
from objectInitialStream[AlertsTable.id == objectInitialStream.id in AlertsTable]
select id, latitude, longitude, timeStamp, type, speed, heading, eventId, true as inAlertTable
insert into publishStream;
from objectInitialStream[not(AlertsTable.id == objectInitialStream.id in AlertsTable)]
select id, latitude, longitude, timeStamp, type, speed, heading, eventId, false as inAlertTable
insert into publishStream;
from publishStream[inAlertTable == true]#window.length(0) join AlertsTable
on publishStream.id== AlertsTable.id
select publishStream.id as id, publishStream.latitude as latitude, publishStream.longitude as longitude, publishStream.timeStamp as timeStamp, publishStream.type as type, publishStream.speed as speed, publishStream.heading as heading, publishStream.eventId as eventId, AlertsTable.proximityWith as proximityInfo
insert into innerStreamTwo;
from publishStream[inAlertTable == false]
delete ProximityTable on ProximityTable.id==id;
from publishStream[inAlertTable == false]
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId , "" as proximityInfo ,"false" as isProximity
insert into dataOutStream;
from innerStreamTwo[ProximityTable.id == innerStreamTwo.id in ProximityTable]
insert into innerStreamThree;
from innerStreamThree#window.length(0) join ProximityTable
on innerStreamThree.id == ProximityTable.id
select innerStreamThree.id , innerStreamThree.latitude, innerStreamThree.longitude,innerStreamThree.timeStamp, innerStreamThree.type, innerStreamThree.speed, innerStreamThree.heading ,innerStreamThree.eventId, ProximityTable.timeStamp as storedTime, innerStreamThree.proximityInfo as proximityInfo
insert into innerStreamFour;
from innerStreamFour[(timeStamp - storedTime) >= $proximityTime]
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId ,proximityInfo,"true" as isProximity
insert into dataOutStream;
from innerStreamFour[(timeStamp - storedTime) < $proximityTime]
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId , proximityInfo ,"false" as isProximity
insert into dataOutStream;
from innerStreamTwo[not(ProximityTable.id == innerStreamTwo.id in ProximityTable)]
select innerStreamTwo.id, innerStreamTwo.timeStamp
insert into ProximityTable;
from innerStreamTwo[not(ProximityTable.id == innerStreamTwo.id in ProximityTable)]
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId , "" as proximityInfo ,"false" as isProximity
insert into dataOutStream;
from dataOutStream[isProximity == 'true']
select id, latitude, longitude, timeStamp, type, speed, heading, eventId,"WARNING" as state,str:concat("Proximity with "," ",proximityInfo) as information
insert into dataOut;
from dataOutStream[isProximity == 'false']
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId ,"NORMAL" as state,"" as information
insert into dataOut;

@ -13,10 +13,10 @@ define stream dataIn (id string, latitude double, longitude double, timeStamp lo
define stream dataOut (id string, latitude double, longitude double, timeStamp long, type string, speed float, heading float, eventId string, state string, information string);
from dataIn[speed >= $speedAlertValue and id == "$deviceId"]#geodashboard:subscribe()
select id , latitude, longitude,timeStamp, type ,speed, heading ,eventId , "ALERTED" as state, "This device movement is not normal!!" as information
select id , latitude, longitude,timeStamp, type ,speed, heading ,eventId , "ALERTED" as state, str:concat(str:concat(str:concat(str:concat("Movement of ",type), " device "), id), " is not normal!!") as information
insert into dataOut;
from dataIn[speed < $speedAlertValue and id == "$deviceId"]
select id , latitude, longitude,timeStamp, type ,speed, heading ,eventId , "NORMAL" as state, "This device movement is normal" as information
select id , latitude, longitude,timeStamp, type ,speed, heading ,eventId , "NORMAL" as state, str:concat(str:concat(str:concat(str:concat("Movement of ",type), " device "), id), " is normal") as information
insert into dataOut;
from dataIn[id != "$deviceId"]
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId , "NORMAL" as state, "" as information

@ -0,0 +1,21 @@
/* Enter a unique ExecutionPlan */
@Plan:name('Geo-ExecutionPlan-Speed---_alert')
/* Enter a unique description for ExecutionPlan */
-- @Plan:description('ExecutionPlan')
/* define streams/tables and write queries here ... */
@Import('org.wso2.geo.StandardSpatialEvents:1.0.0')
define stream dataIn (id string, latitude double, longitude double, timeStamp long, type string, speed float, heading float, eventId string);
@Export('org.wso2.geo.ProcessedSpatialEvents:1.0.0')
define stream dataOut (id string, latitude double, longitude double, timeStamp long, type string, speed float, heading float, eventId string, state string, information string);
from dataIn[speed >= $speedAlertValue]#geodashboard:subscribe()
select id , latitude, longitude,timeStamp, type ,speed, heading ,eventId , "ALERTED" as state, str:concat(str:concat(str:concat(str:concat("Movement of ",type), " device "), id), " is not normal!!") as information
insert into dataOut;
from dataIn[speed < $speedAlertValue]
select id , latitude, longitude,timeStamp, type ,speed, heading ,eventId , "NORMAL" as state, str:concat(str:concat(str:concat(str:concat("Movement of ",type), " device "), id), " is normal") as information
insert into dataOut;

@ -81,7 +81,7 @@ select id , latitude, longitude,timeStamp, type, speed, heading ,eventId ,"false
insert into dataOutStream;
from dataOutStream[isStationary == 'true']
select id ,latitude, longitude,timeStamp, type, speed, heading ,eventId ,"ALERTED" as state, "This device is in $stationeryName area!!!" as information
select id ,latitude, longitude,timeStamp, type, speed, heading ,eventId ,"ALERTED" as state, str:concat(str:concat(str:concat(type," device "),id),"is in $stationeryName area!!!") as information
insert into dataOut;
from dataOutStream[isStationary == 'false']

@ -0,0 +1,89 @@
/* Enter a unique ExecutionPlan */
@Plan:name('$executionPlanName')
/* Enter a unique description for ExecutionPlan */
-- @Plan:description('ExecutionPlan')
/* define streams/tables and write queries here ... */
@Import('org.wso2.geo.StandardSpatialEvents:1.0.0')
define stream dataIn (id string, latitude double, longitude double, timeStamp long, type string ,speed float, heading float, eventId string);
@Export('org.wso2.geo.ProcessedSpatialEvents:1.0.0')
define stream dataOut (id string, latitude double, longitude double, timeStamp long, type string ,speed float, heading float, eventId string, state string, information string);
@IndexBy('id')
define table StationeryTable(id string, timeStamp long);
@IndexBy('id')
define table AlertsTable(id string, stationary bool);
from dataIn#geodashboard:subscribe()
select id, latitude, longitude, timeStamp, type, speed, heading, eventId,geo:within(longitude,latitude,"$geoFenceGeoJSON") as isWithin
insert into innerStreamOne;
from innerStreamOne[isWithin == false]
delete StationeryTable on StationeryTable.id==id;
from innerStreamOne[isWithin == false]
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId , "false" as isStationary
insert into dataOutStream;
from innerStreamOne[isWithin == true]#geo:stationary(id,longitude,latitude, $fluctuationRadius)
select id, latitude, longitude, timeStamp, type, speed, heading, eventId,stationary
insert into innerStreamTwo;
from innerStreamTwo[innerStreamTwo.stationary == true]
select innerStreamTwo.id, innerStreamTwo.stationary
insert into AlertsTable;
from innerStreamTwo[innerStreamTwo.stationary == false]
delete AlertsTable on AlertsTable.id==id;
from innerStreamTwo[innerStreamTwo.stationary == false]
delete StationeryTable on StationeryTable.id==id;
from innerStreamOne[isWithin == true AND not(AlertsTable.id == innerStreamOne.id in AlertsTable)]
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId , "false" as isStationary
insert into dataOutStream;
from innerStreamOne[isWithin == true AND AlertsTable.id == innerStreamOne.id in AlertsTable]
insert into innerStreamThree;
from innerStreamThree#window.length(0) join AlertsTable
on innerStreamThree.id == AlertsTable.id
select innerStreamThree.id , innerStreamThree.latitude, innerStreamThree.longitude,innerStreamThree.timeStamp, innerStreamThree.type, innerStreamThree.speed, innerStreamThree.heading ,innerStreamThree.eventId
insert into innerStreamFour;
from innerStreamFour[not(StationeryTable.id == innerStreamFour.id in StationeryTable)]
select innerStreamFour.id, innerStreamFour.timeStamp
insert into StationeryTable;
from innerStreamOne[isWithin == true AND not(StationeryTable.id == innerStreamOne.id in StationeryTable)]
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId , "false" as isStationary
insert into dataOutStream;
from innerStreamOne[isWithin == true AND StationeryTable.id == innerStreamOne.id in StationeryTable]
insert into innerStreamFive;
from innerStreamFive#window.length(0) join StationeryTable
on innerStreamFive.id == StationeryTable.id
select innerStreamFive.id , innerStreamFive.latitude, innerStreamFive.longitude,innerStreamFive.timeStamp, innerStreamFive.type, innerStreamFive.speed, innerStreamFive.heading ,innerStreamFive.eventId, StationeryTable.timeStamp as storedTime
insert into innerStreamSix;
from innerStreamSix[(timeStamp - storedTime) >= $stationeryTime]
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId ,"true" as isStationary
insert into dataOutStream;
from innerStreamSix[(timeStamp - storedTime) < $stationeryTime]
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId ,"false" as isStationary
insert into dataOutStream;
from dataOutStream[isStationary == 'true']
select id ,latitude, longitude,timeStamp, type, speed, heading ,eventId ,"ALERTED" as state, str:concat(str:concat(str:concat(type," device "),id),"is in $stationeryName area!!!") as information
insert into dataOut;
from dataOutStream[isStationary == 'false']
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId ,"NORMAL" as state,"" as information
insert into dataOut;

@ -0,0 +1,17 @@
/* Enter a unique ExecutionPlan */
@Plan:name('$executionPlanName')
/* Enter a unique description for ExecutionPlan */
-- @Plan:description('ExecutionPlan')
/* define streams/tables and write queries here ... */
@Import('rawGeoStream:1.0.0')
define stream dataIn (id string, timeStamp long, geometry string, state string, information string);
@Export('AlertsNotifications:1.0.0')
define stream dataOut (id string, state string, information string, timeStamp long, latitude double, longitude double);
from dataIn[geo:intersects(geometry, "$geoFenceGeoJSON")==true and geodashboard:needToNotify(id, str:concat(information, state), "sendFirst") == true]
select id, state, str:concat("Traffic alert in $areaName. State: ", state, " ", information) as information, timeStamp, 0.0 as latitude, 0.0 as longitude
insert into dataOut

@ -13,7 +13,7 @@ define stream dataIn (id string, latitude double, longitude double, timeStamp lo
define stream dataOut (id string, latitude double, longitude double, timeStamp long, type string ,speed float, heading float, eventId string, state string, information string);
from dataIn[geo:within(longitude,latitude,"$geoFenceGeoJSON")==true and id == "$deviceId"]#geodashboard:subscribe()
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId , "ALERTED" as state, "This device is in $areaName restricted area!!!" as information
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId , "ALERTED" as state, str:concat(str:concat(str:concat(type," device "), id), " is in $areaName restricted area!!!") as information
insert into dataOut;
from dataIn[geo:within(longitude,latitude,"$geoFenceGeoJSON")!=true and id == "$deviceId"]
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId , "NORMAL" as state, "" as information

@ -0,0 +1,20 @@
/* Enter a unique ExecutionPlan */
@Plan:name('$executionPlanName')
/* Enter a unique description for ExecutionPlan */
-- @Plan:description('ExecutionPlan')
/* define streams/tables and write queries here ... */
@Import('org.wso2.geo.StandardSpatialEvents:1.0.0')
define stream dataIn (id string, latitude double, longitude double, timeStamp long, type string ,speed float, heading float, eventId string);
@Export('org.wso2.geo.ProcessedSpatialEvents:1.0.0')
define stream dataOut (id string, latitude double, longitude double, timeStamp long, type string ,speed float, heading float, eventId string, state string, information string);
from dataIn[geo:within(longitude,latitude,"$geoFenceGeoJSON")==true]#geodashboard:subscribe()
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId , "ALERTED" as state, str:concat(str:concat(str:concat(type," device "), id), " is in $areaName restricted area!!!") as information
insert into dataOut;
from dataIn[geo:within(longitude,latitude,"$geoFenceGeoJSON")!=true]
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId , "NORMAL" as state, "" as information
insert into dataOut;

@ -30,6 +30,7 @@ import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import org.wso2.carbon.device.mgt.common.DeviceManagementConstants;
import org.wso2.carbon.device.mgt.common.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.geo.service.Alert;
import org.wso2.carbon.device.mgt.common.geo.service.AlertAlreadyExistException;
import org.wso2.carbon.device.mgt.common.geo.service.GeoFence;
import org.wso2.carbon.device.mgt.common.geo.service.GeoLocationBasedServiceException;
import org.wso2.carbon.device.mgt.common.geo.service.AlertAlreadyExistException;

@ -22,7 +22,7 @@
<parent>
<artifactId>device-mgt</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

@ -22,7 +22,7 @@
<parent>
<artifactId>device-mgt</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

@ -39,30 +39,30 @@ function loadGeoFencing() {
function openTools(id) {
lastId = id;
if (drawControl) {
try{
map.removeControl(drawControl);
} catch(e) {
console.log("error: " + e.message);
}
console.log("removed drawControl");
if (drawControl) {
try{
map.removeControl(drawControl);
} catch(e) {
console.log("error: " + e.message);
}
console.log("removed drawControl");
}
if (removeAllControl) {
try {
map.removeControl(removeAllControl);
} catch(e) {
console.log("error: " + e.message);
}
console.log("removed removeAllControl");
try {
map.removeControl(removeAllControl);
} catch(e) {
console.log("error: " + e.message);
}
console.log("removed removeAllControl");
}
if (drawnItems) {
try{
map.removeLayer(drawnItems);
console.log("removing layer");
} catch(e) {
console.log("error: " + e.message);
}
console.log("removed drawnItems");
try{
map.removeLayer(drawnItems);
console.log("removing layer");
} catch(e) {
console.log("error: " + e.message);
}
console.log("removed drawnItems");
}
closeAll();
@ -84,7 +84,7 @@ function openTools(id) {
drawnItems.clearLayers();
if(id == "Prediction"){
$('#predictionResults').animate({width: ['toggle','swing']},200);
toggeled = false;
toggeled = false;
}
});
@ -108,7 +108,7 @@ function openTools(id) {
// Initialise the FeatureGroup to store editable layers
drawnItems = new L.FeatureGroup();
map.addLayer(drawnItems);
if (id=="WithIn") {
// Initialise the draw control and pass it the FeatureGroup of editable layers
drawControl = new L.Control.Draw({
@ -139,30 +139,30 @@ function openTools(id) {
} else if (id=="Exit") {
// Initialise the draw control and pass it the FeatureGroup of editable layers
drawControl = new L.Control.Draw({
draw: {
polygon: {
allowIntersection: false, // Restricts shapes to simple polygons
drawError: {
color: '#e1e100', // Color the shape will turn when intersects
message: '<strong>Oh snap!<strong> you can\'t draw that!' // Message that will show when intersect
},
shapeOptions: {
color: '#ff0043'
}
},
rectangle: {
shapeOptions: {
color: '#002bff'
}
},
polyline: false,
circle: false, // Turns off this drawing tool
marker: false // Markers are not applicable for within geo fencing
},
edit: {
featureGroup: drawnItems
}
});
draw: {
polygon: {
allowIntersection: false, // Restricts shapes to simple polygons
drawError: {
color: '#e1e100', // Color the shape will turn when intersects
message: '<strong>Oh snap!<strong> you can\'t draw that!' // Message that will show when intersect
},
shapeOptions: {
color: '#ff0043'
}
},
rectangle: {
shapeOptions: {
color: '#002bff'
}
},
polyline: false,
circle: false, // Turns off this drawing tool
marker: false // Markers are not applicable for within geo fencing
},
edit: {
featureGroup: drawnItems
}
});
} else if(id=="Stationery"){
// Initialise the draw control and pass it the FeatureGroup of editable layers
drawControl = new L.Control.Draw({
@ -220,9 +220,9 @@ function openTools(id) {
}
},
marker: {
shapeOptions: {
color: '#ff0043'
}
shapeOptions: {
color: '#ff0043'
}
}
},
edit: {
@ -230,16 +230,16 @@ function openTools(id) {
}
});
} else if (id =="Prediction") {
drawControl = new L.Control.Draw({
drawControl = new L.Control.Draw({
draw: {
polygon: false,
rectangle: false,
polyline: false,
circle: false,
marker: {
shapeOptions: {
color: '#ff0043'
}
shapeOptions: {
color: '#ff0043'
}
}
},
edit: {
@ -266,10 +266,10 @@ function createPopup(layer,id) {
popupTemplate.find('#addTrafficAlert').attr('leaflet_id', layer._leaflet_id);
//console.log(">>got here " + id + " " + popupTemplate.find('#addTrafficAlert') + " " + layer._leaflet_id);
} else if (id=="Prediction") {
getPrediction(layer._leaflet_id);
return;
getPrediction(layer._leaflet_id);
return;
}
popupTemplate.find('.exportGeoJson').attr('leaflet_id', layer._leaflet_id);
popupTemplate.find('.editGeoJson').attr('leaflet_id', layer._leaflet_id);
@ -362,9 +362,9 @@ function viewFence(geoFenceElement,id) {
color: '#ff0043'
};
geometryShape= new L.circle([geoJson.coordinates[1],geoJson.coordinates[0]], geoJson.radius,circleOptions);
// var marker=new L.marker([geoJson.coordinates[1],geoJson.coordinates[0]]);
// var marker=new L.marker([geoJson.coordinates[1],geoJson.coordinates[0]]);
map.addLayer(geometryShape);
// map.addLayer(marker);
// map.addLayer(marker);
} else if (geoJson.type=="Polygon") {
geoJson.coordinates[0].pop(); // popout the last coordinate set(lat,lng pair) due to circular chain
var leafletLatLngs = [];
@ -493,4 +493,3 @@ function viewFenceByData(geoJson, queryName, areaName, stationeryTime, id) {
}
closeAll();
}

@ -281,7 +281,7 @@ function setWithinAlert(leafletId) {
responseHandler, function (xhr) {
responseHandler(xhr.responseText, xhr.statusText, xhr);
});
viewFenceByData(selectedAreaGeoJson, queryName, areaName, null, 'Within');
viewFenceByData(selectedAreaGeoJson, queryName, areaName, null, 'WithIn');
}
}
@ -414,7 +414,7 @@ function setStationeryAlert(leafletId) {
responseHandler, function (xhr) {
responseHandler(xhr.responseText, xhr.statusText, xhr);
});
viewFenceByData(selectedProcessedAreaGeoJson, queryName, areaName, time, 'Stationery');
viewFenceByData(selectedProcessedAreaGeoJson, queryName, stationeryName, time, 'Stationery');
}
@ -563,8 +563,8 @@ function getAlertsHistory(deviceType, deviceId, timeFrom, timeTo) {
if (val.values) {
val = val.values;
}
var msg = deviceType.charAt(0).toUpperCase() + deviceType.slice(1) +
" " + deviceId + " " + val.information.replace("Alerts: ,", "") + " - " + timeSince(val.timeStamp);
var msg = val.information.replace("Alerts: ,", "").charAt(0).toUpperCase() +
val.information.replace("Alerts: ,", "").slice(1) + " - " + timeSince(val.timeStamp);
switch (val.state) {
case "NORMAL":
return;

@ -27,10 +27,853 @@
{{css "css/leaflet.awesome-markers.css" combine=false}}
{{/zone}}
<div class="tab-actions">
<div class="action-btn-container" id="location-action-bar">
</div>
</div>
{{#if geoServicesEnabled}}
<br>
<br>
<br>
{{/if}}
<span id="geo-charts" data-ws-endpoint="{{wsEndpoint}}" data-ws-token="{{wsToken}}" data-geo-public-uri="{{@unit.publicUri}}"
data-device-location="{{lastLocation}}"></span>
<div class="map-wrapper">
<div id="" style="height: 80vh;">
<div id="map"></div>
{{#if geoServicesEnabled}}
<div id="" style="height: 75vh;">
<div id="map"></div>
<div id="ws-alerts">
<i id="ws-alert-stream" class="fw fw-circle text-muted"></i> Alerts Stream&nbsp;
<i id="ws-spatial-stream" class="fw fw-circle text-muted"></i> Spatial Stream
</div>
</div>
{{else}}
<div id="" style="height: 80vh;">
<div id="map"></div>
</div>
{{/if}}
<div id="predictionResults" style="background: darkgray;display: none;border-radius: 13px;height: 94%;padding: 0"
class="col-md-2 pull-right">
<div class="panel-heading text-center">
<h4> Prediction Results For: <span id="predictionResultsID" class="text-info"></span>
<i id="objectInfoCloseButton" class="fa fa-times pull-right"
onclick="$('#predictionResults').animate({width: ['toggle','swing']},200);toggeled = false;spatialObject = currentSpatialObjects[selectedSpatialObject];spatialObject.removePath();spatialObject.marker.closePopup();selectedSpatialObject = null;">
</i>
</h4>
</div>
<br>
<div class="panel panel-default" style="overflow: auto;box-shadow: 0 0 8px 0 #635749">
<div class="panel-heading text-center"><h4>Prediction</h4>
</div>
<br>
<div class="panel-body">
<div style="max-height: 100%;margin: 0;border: none;margin-left: -25px" id="prediction_chart_div"></div>
</div>
</div>
</div>
<div id="loading">
<div class="loading-indicator">
<div class="progress progress-striped active">
<div class="progress-bar progress-bar-info" style="width: 100%"></div>
</div>
</div>
</div>
<div class="modal" id="aboutModal" tabindex="-1" role="dialog">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button class="close" type="button" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">Welcome to the BootLeaf template!</h4>
</div>
<div class="modal-body">
<ul class="nav nav-tabs" id="aboutTabs">
<li class="active"><a href="#about" data-toggle="tab"><i class="fa fa-question-circle"></i>&nbsp;About
the project</a></li>
<li><a href="#contact" data-toggle="tab"><i class="fa fa-envelope"></i>&nbsp;Contact us</a></li>
<li><a href="#disclaimer" data-toggle="tab"><i class="fa fa-exclamation-circle"></i>&nbsp;Disclaimer</a>
</li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown"><i class="fa fa-globe"></i>&nbsp;Metadata
<b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a href="#boroughs-tab" data-toggle="tab">Boroughs</a></li>
<li><a href="#subway-lines-tab" data-toggle="tab">Subway Lines</a></li>
<li><a href="#theaters-tab" data-toggle="tab">Theaters</a></li>
<li><a href="#museums-tab" data-toggle="tab">Museums</a></li>
</ul>
</li>
</ul>
<div class="tab-content" id="aboutTabsContent" style="padding-top: 10px;">
<div class="tab-pane fade active in" id="about">
<p>A simple, responsive template for building web mapping applications with <a
href="http://getbootstrap.com/">Bootstrap 3</a>, <a href="http://leafletjs.com/"
target="_blank">Leaflet</a>, and <a
href="http://twitter.github.io/typeahead.js/" target="_blank">typeahead.js</a>. Open
source, MIT licensed, and available on <a href="https://github.com/bmcbride/bootleaf"
target="_blank">GitHub</a>.</p>
<div class="panel panel-primary">
<div class="panel-heading">Features</div>
<ul class="list-group">
<li class="list-group-item">Fullscreen mobile-friendly map template with responsive
navbar and modal placeholders
</li>
<li class="list-group-item">jQuery loading of external GeoJSON files</li>
<li class="list-group-item">Logical multiple layer marker clustering via the <a
href="https://github.com/Leaflet/Leaflet.markercluster" target="_blank">leaflet
marker cluster plugin</a></li>
<li class="list-group-item">Elegant client-side multi-layer feature search with
autocomplete using <a href="http://twitter.github.io/typeahead.js/" target="_blank">typeahead.js</a>
</li>
<li class="list-group-item">Responsive sidebar feature list with sorting and filtering
via <a href="http://listjs.com/" target="_blank">list.js</a></li>
<li class="list-group-item">Marker icons included in grouped layer control via the <a
href="https://github.com/ismyrnow/Leaflet.groupedlayercontrol" target="_blank">grouped
layer control plugin</a></li>
</ul>
</div>
</div>
<div id="disclaimer" class="tab-pane fade text-danger">
<p>The data provided on this site is for informational and planning purposes only.</p>
<p>Absolutely no accuracy or completeness guarantee is implied or intended. All information on
this map is subject to such variations and corrections as might result from a complete title
search and/or accurate field survey.</p>
</div>
<div class="tab-pane fade" id="contact">
<form id="contact-form">
<div class="well well-sm">
<div class="row">
<div class="col-md-4">
<div class="form-group">
<label for="first-name">First Name:</label>
<input type="text" class="form-control" id="first-name">
</div>
<div class="form-group">
<label for="last-email">Last Name:</label>
<input type="text" class="form-control" id="last-email">
</div>
<div class="form-group">
<label for="email">Email:</label>
<input type="text" class="form-control" id="email">
</div>
</div>
<div class="col-md-8">
<label for="message">Message:</label>
<textarea class="form-control" rows="8" id="message"></textarea>
</div>
<div class="col-md-12">
<p>
<button type="submit" class="btn btn-primary pull-right"
data-dismiss="modal">Submit
</button>
</p>
</div>
</div>
</div>
</form>
</div>
<div class="tab-pane fade" id="boroughs-tab">
<p>Borough data courtesy of <a
href="http://www.nyc.gov/html/dcp/html/bytes/meta_dis_nyboroughwi.shtml"
target="_blank">New York City Department of City Planning</a></p>
</div>
<div class="tab-pane fade" id="subway-lines-tab">
<p><a href="http://spatialityblog.com/2010/07/08/mta-gis-data-update/#datalinks"
target="_blank">MTA Subway data</a> courtesy of the <a
href="http://www.urbanresearch.org/about/cur-components/cuny-mapping-service"
target="_blank">CUNY Mapping Service at the Center for Urban Research</a></p>
</div>
<div class="tab-pane fade" id="theaters-tab">
<p>Theater data courtesy of <a
href="https://data.cityofnewyork.us/Recreation/Theaters/kdu2-865w" target="_blank">NYC
Department of Information & Telecommunications (DoITT)</a></p>
</div>
<div class="tab-pane fade" id="museums-tab">
<p>Museum data courtesy of <a
href="https://data.cityofnewyork.us/Recreation/Museums-and-Galleries/sat5-adpb"
target="_blank">NYC Department of Information & Telecommunications (DoITT)</a></p>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<div class="modal" id="attributionModal" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button class="close" type="button" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 id = "title" class="modal-title">
WSO2 Geo Dashboard
</h4>
</div>
<div class="modal-body">
<div id="attribution"></div>
</div>
</div>
</div>
</div>
<div class="modal" id="addTileServer" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content" style="width:50%; margin:0 auto;">
<div class="modal-header"
style="cursor: move;background: #f9f9f9;-webkit-box-shadow: inset 0px 0px 14px 1px rgba(0,0,0,0.2);-moz-box-shadow: inset 0px 0px 14px 1px rgba(0,0,0,0.2);box-shadow: inset 0px 0px 14px 1px rgba(0,0,0,0.2);">
<button class="close" type="button" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">
&lt;!&ndash; TODO: Trigger bootstrap tooltip $('#aboutTileUrl').tooltip(); to enable tooltip &ndash;&gt;
Add tiler server URL <sup id="aboutTileUrl" style="cursor: pointer;" data-toggle="tooltip"
title="What is a tile URL?"><i class="fa fa-question" style="color: #39F;"
data-toggle="collapse"
data-target="#collapseOne"></i></sup>
</h4>
</div>
<div class="modal-body">
<div id="urlInput">
<div style="height: 0px;" id="collapseOne" class="panel-collapse collapse">
<div class="panel-body">
<p>A string of the following form:</p>
<pre><code class="javascript"><span class="string">'http://{s}.somedomain.com/blabla/{z}/{x}/{y}.png'</span></code></pre>
<p><code class="javascript">{s}</code> means one of the available subdomains (used
sequentially to help with browser parallel requests per domain limitation; subdomain
values are specified in options; <code class="javascript">a</code>, <code
class="javascript">b</code> or <code class="javascript">c</code> by default, can
be omitted), <code class="javascript">{z}</code> — zoom level, <code class="javascript">{x}</code>
and <code class="javascript">{y}</code> — tile coordinates.</p>
<p>You can use custom keys in the template, which will be <a
href="#util-template">evaluated</a> from TileLayer options, like this:</p>
<pre><code class="javascript">L.tileLayer(<span class="string">'http://{s}.somedomain.com/{foo}/{z}/{x}/{y}.png'</span>,
{foo: <span class="string">'bar'</span>});</code></pre>
</div>
</div>
<div class="input-group input-group-sm">
<span class="input-group-addon"><i class="fa fa-italic"></i></span>
<input autofocus="enable" id="tileName" type="text" class="form-control"
placeholder="Tile URL name">
</div>
<br>
<div class="input-group input-group-sm">
<span class="input-group-addon"><i class="fa fa-globe"></i></span>
<input id="tileUrl" class="form-control" type="text"
placeholder="http://{s}.somedomain.com/blabla/{z}/{x}/{y}.png">
<span class="input-group-btn">
<button class="btn btn-info" type="button" onclick="addTileUrl()"><i class="fa fa-plus"></i>
</button>
</span>
</div>
<br/>
<div class="panel panel-default" style="width: 80%;">
<div>
<h4 class="panel-title" style="font-size: 12px;line-height: 1.5;">
<button style="text-align: left;" class="btn btn-default btn-xs btn-block collapsed"
onclick="$('.fa-chevron-right').toggleClass('fa-rotate-90')"
data-toggle="collapse" data-parent="#accordion" href="#tileUrlOptions">
<i class="fa fa-chevron-right"></i> Options
</button>
</h4>
</div>
<div style="height: 0px;" id="tileUrlOptions" class="panel-collapse collapse">
<div class="panel-body">
<div class="input-group input-group-sm col-sm-9">
<small class="text-primary">
<label class="col-sm-2 control-label" for="sub_domains">Sub-domains</label>
</small>
<input id="sub_domains" type="text" class="form-control"
placeholder="Enter sub-domains in CSV format">
</div>
<br/>
<div class="input-group input-group-sm col-sm-9">
<small class="text-primary">
<label class="col-sm-9 control-label" for="maxzoom">Max zoom level</label>
</small>
<input id="maxzoom" type="text" class="form-control"
placeholder="Number between(around) 1~19">
</div>
<br/>
<div class="input-group input-group-sm col-sm-9">
<small class="text-primary">
<label class="col-sm-2 control-label" for="data_attribution">Attribution</label>
</small>
<input id="data_attribution" type="text" class="form-control"
placeholder="Enter attribution">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal" id="addWmsUrl" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content" style="width:50%; margin:0 auto;">
<div class="modal-header"
style="cursor: move;background: #f9f9f9;-webkit-box-shadow: inset 0px 0px 14px 1px rgba(0,0,0,0.2);-moz-box-shadow: inset 0px 0px 14px 1px rgba(0,0,0,0.2);box-shadow: inset 0px 0px 14px 1px rgba(0,0,0,0.2);">
<button class="close" type="button" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">
<sup id="aboutWms" style="cursor: pointer;" data-toggle="tooltip"
title="What WMS end-point"><i class="fa fa-question"
style="color: #39F;"
data-toggle="collapse"
data-target="#wmsOverview"></i></sup>
</h4>
</div>
<div class="modal-body">
<div>
<div style="height: 0px;" id="wmsOverview" class="panel-collapse collapse">
<div class="panel-body">
The OpenGIS® Web Map Service Interface Standard (WMS) provides a simple HTTP interface for
requesting geo-registered map images from one or more distributed geospatial databases.
A WMS request defines the geographic layer(s) and area of interest to be processed.
The response to the request is one or more geo-registered map images (returned as JPEG, PNG,
etc) that can be displayed in a browser application.
The interface also supports the ability to specify whether the returned images should be
transparent so that layers from multiple servers can be combined or not.
</div>
</div>
<div class="input-group input-group-sm">
<span class="input-group-addon"><i class="fa fa-italic"></i></span>
<input autofocus="enable" id="serviceName" type="text" class="form-control"
placeholder="Service provider name">
</div>
<br>
<div class="input-group input-group-sm">
<span class="input-group-addon"><i class="fa fa-align-justify"></i></span>
<input autofocus="enable" id="layers" type="text" class="form-control"
placeholder="Service layers as comma seperated values">
</div>
<br>
<div class="input-group input-group-sm">
<span class="input-group-addon">V.</span>
<input autofocus="enable" id="wmsVersion" type="text" class="form-control"
placeholder="WMS version (i.e: 1.1.1 or 1.3.0)">
</div>
<br>
<div class="input-group input-group-sm">
<span class="input-group-addon"><i class="fa fa-globe"></i></span>
<input id="serviceEndPoint" class="form-control" type="text"
placeholder="http(s)://sedac.ciesin.columbia.edu/geoserver/wms">
<span class="input-group-btn">
<button class="btn btn-info" type="button" onclick="addWmsEndPoint()"><i
class="fa fa-plus"></i>
</button>
</span>
</div>
<br/>
<div class="panel panel-default" style="width: 80%;">
<div>
<h4 class="panel-title" style="font-size: 12px;line-height: 1.5;">
<button style="text-align: left;" class="btn btn-default btn-xs btn-block collapsed"
onclick="$('.fa-chevron-right').toggleClass('fa-rotate-90')"
data-toggle="collapse" data-parent="#accordion" href="#wmsOptions">
<i class="fa fa-chevron-right"></i> Options
</button>
</h4>
</div>
<div style="height: 0px;" id="wmsOptions" class="panel-collapse collapse">
<div class="panel-body">
<div class="input-group input-group-sm col-sm-11">
<small class="text-primary">
<label class="col-sm-6 control-label" for="outputFormat">Output format</label>
</small>
<input id="outputFormat" type="text" class="form-control"
placeholder="Output format (i.e: image/png, image/jpeg, image/svg)">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal" id="modalExit" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button class="close" type="button" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">
<div class="col-lg-5 col-md-6 col-centered">
<h4>
Set 'Exit Fence' alerts
<br>
</h4>
</div>
</h4>
</div>
<div class="modal-body">
<div class="row">
<div class="col-lg-8 col-md-8 col-centered">
<div class="">
<table class="table table-hover" id="exit-alert">
<thead>
<tr>
<th>Fence Name</th>
<th>Query Name</th>
<th>Created On</th>
<th></th>
</tr>
</thead>
<tbody>
<div class="alert alert-info fence-not-exist" role="alert">
<strong>Oh snap!</strong> Can't find any geofence area, please draw a new area or try again.
</div>
</tbody>
</table>
</div>
<div class="pull-left">
<button style="background-color: #f4f4f4; float: left" type="button" class="btn btn-default"
onclick="viewAll('Exit')">View All
</button>
</div>
<div class="pull-right">
<button style="background-color: #f4f4f4;" type="button" class="btn btn-default"
onclick="openTools('Exit')">Draw area
</button>
<button style="background-color: #f4f4f4;" type="button" class="btn btn-default"
onclick="$('#editExitGeoJSON').modal('toggle')">Enter area
</button>
<br/>
<br/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal" id="modalWithin" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button class="close" type="button" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">
<div class="col-lg-5 col-md-6 col-centered">
<h4>
Set 'Within' alerts
<br>
</h4>
</div>
</h4>
</div>
<div class="modal-body">
<div class="row">
<div class="col-lg-8 col-md-8 col-centered">
<div class="">
<table class="table table-hover" id="within-alert">
<thead>
<tr>
<th>Fence Name</th>
<th>Query Name</th>
<th>Created On</th>
<th></th>
</tr>
</thead>
<tbody>
<div class="alert alert-info fence-not-exist" role="alert">
<strong>Oh snap!</strong> Can't find any geofence area, please draw a new area or try again.
</div>
</tbody>
</table>
</div>
<div class="pull-left">
<button style="background-color: #f4f4f4; float: left" type="button" class="btn btn-default"
onclick="viewAll('WithIn')">View All
</button>
</div>
<div class="pull-right">
<button style="background-color: #f4f4f4;" type="button" class="btn btn-default"
onclick="openTools('WithIn')">Draw area
</button>
<button style="background-color: #f4f4f4;" type="button" class="btn btn-default"
onclick="$('#editWithinGeoJSON').modal('toggle')">Enter area
</button>
<br/>
<br/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal" id="modalStationery" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button class="close" type="button" data-dismiss="modal" aria-hidden="true">&times;</button>
<div class="col-lg-5 col-md-6 col-centered">
<h4>
Set 'Stationary' alerts
<br>
</h4>
</div>
</div>
<div class="modal-body">
<div class="row">
<div class="col-lg-8 col-md-8 col-centered">
<div class="">
<table class="table table-hover" id="stationary-alert-table">
<thead>
<tr>
<th>Stationary Name</th>
<th>Stationary Time</th>
<th>Fluctuation Radius</th>
<th>Query Name</th>
<th>Created On</th>
<th></th>
</tr>
</thead>
<tbody>
<div class="alert alert-info fence-not-exist" role="alert">
<strong>Oh snap!</strong> Can't find any geofence area, please draw a new area or try again.
</div>
</tbody>
</table>
</div>
<div class="pull-left">
<button style="background-color: #f4f4f4; float: left" type="button" class="btn btn-default"
onclick="viewAll('Stationery')">View All
</button>
</div>
<div class="pull-right">
<button style="background-color: #f4f4f4;" type="button" class="btn btn-default"
onclick="openTools('Stationery')">Draw area
</button>
<button style="background-color: #f4f4f4;" type="button" class="btn btn-default"
onclick="$('#editWithinGeoJSON').modal('toggle')">Enter area
</button>
</div>
<br/>
<br/>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal" id="modalSpeed" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button class="close" type="button" data-dismiss="modal" aria-hidden="true">&times;</button>
<div class="col-lg-5 col-md-6 col-centered">
<h4>
Setup global speed limit
<br>
</h4>
</div>
</div>
<div class="modal-body">
<div class="row">
<div class="col-lg-5 col-md-6 col-centered">
<div class="input-group input-group-sm">
<input autofocus="enable" id="speedAlertValue" type="number" min="0" class="form-control" placeholder="Speed alert value " autocomplete="off">
<span class="input-group-addon">km/h</span>
</div>
<br>
<button type="button" class="btn btn-default pull-right btn-sm" onclick="closeAll()">Cancel</button>
<button type="button" class="btn btn-info pull-right btn-sm" onclick="setSpeedAlert()" style="margin-right: 10px;">Set speed alert</button>
<br><br>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal" id="editWithinGeoJSON" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button class="close" type="button" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">
</h4>
<div class="col-lg-5 col-md-6 col-centered">
<h4>
Adding GeoJson
<br>
</h4>
</div>
</div>
<div class="modal-body">
<div class="col-lg-8 col-md-8 col-centered">
<div>
<label for="importGeoJsonFile">Import GeoJson</label>
<input id="importGeoJsonFile" type="file">
<hr />
<label for="enterGeoJson">Enter GeoJson</label>
<textarea id="enterGeoJson" class="form-control" rows="10"></textarea>
</div>
<div class="pull-right">
<button id="updateGeoJson" class="btn btn-primary" onclick="importGeoJson()">Import</button>
<button type="button" class="btn btn-default" onclick="closeAll()">Cancel</button>
<br />
<br />
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal" id="editExitGeoJSON" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button class="close" type="button" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">
</h4>
<div class="col-lg-5 col-md-6 col-centered">
<h4>
Adding GeoJson
<br>
</h4>
</div>
</div>
<div class="modal-body">
<div class="col-lg-8 col-md-8 col-centered">
<div>
<label for="importGeoJsonFile">Import GeoJson</label>
<input id="importGeoJsonFile" type="file">
<hr />
<label for="enterGeoJson">Enter GeoJson</label>
<textarea id="enterGeoJson" class="form-control" rows="10"></textarea>
</div>
<div class="pull-right">
<button id="updateGeoJson" class="btn btn-primary" onclick="importGeoJson()">Import</button>
<button type="button" class="btn btn-default" onclick="closeAll()">Cancel</button>
<br />
<br />
</div>
</div>
</div>
</div>
</div>
</div>
<div style="display: none">
<div id="markerPopup" class="popover top">
<div class="arrow"></div>
<h3 class="popover-title">ID <span id="objectId"></span></h3>
<div class="popover-content">
<h6>Information</h6>
<p id="information" class="bg-primary" style="margin: 0px;padding: 0px;"></p>
{{#if geoServicesEnabled}}
<h6>Speed<span class="label label-primary pull-right"><span id="speed"></span> km/h</span></h6>
<h6>Heading<span id="heading" class="label label-primary pull-right"></span></h6>
<button type="button" class="btn btn-info btn-xs" onClick="toggleSpeedGraph();return false;">Speed Graph</button>
<button type="button" class="btn btn-info btn-xs" onClick="showRecentAlertsHistory();return false;">Recent History</button>
<button type="button" class="btn btn-info btn-xs" onClick="popupDateRange();">Full History</button>
{{/if}}
</div>
</div>
<div id="dateRangePopup">
<div class="form-horizontal">
<div class="form-group">
<label class="col-sm-3">From:</label>
<div class="col-sm-9">
<input id="timeFromCal" type="text">
</div>
</div>
<div class="form-group">
<label class="col-sm-3">To:</label>
<div class="col-sm-9">
<input id="timeToCal" type="text">
</div>
</div>
</div>
<button type="button" class="btn btn-info btn-xs" onClick="showAlertsHistory(document.getElementById('timeFromCal').value, document.getElementById('timeToCal').value);return false;">Full History</button>
</div>
<div id="markerPopupStop" class="popover top">
<div class="arrow"></div>
<h3 class="popover-title">ID <span id="objectId"></span></h3>
<div class="popover-content">
<h6>Information</h6>
<p id="information" class="bg-primary" style="margin: 0px;padding: 0px;"></p>
</div>
</div>
<div id="areaPopup" class="popover top">
<div class="arrow"></div>
<h3 class="popover-title">ID <span id="objectId"></span></h3>
<div class="popover-content">
<h6>Severity</h6>
<p id="severity" class="bg-primary" style="margin: 0px;padding: 0px;"></p>
</div>
<div class="popover-content">
<h6>Information</h6>
<p id="information" class="bg-primary" style="margin: 0px;padding: 0px;"></p>
</div>
</div>
<div id="setWithinAlert">
<form role="form" style="width: auto;">
<div class="form-group">
<label class="text-primary" for="withinAlertAreaName">Fence name</label>
<input class="form-control" id="withinAlertAreaName" placeholder="Fence name" type="text">
<span class="help-block">Name of the selected area(e.g. colombo)</span>
</div>
<div>
<div class="btn-group btn-group-sm btn-group-justified">
<div class="btn-group">
<button id="addWithinAlert" onclick="setWithinAlert($(this).attr('leaflet_id'))" type="button"
class="btn btn-info btn-xs" data-toggle="tooltip" data-placement="left"
title="Save selected area for alerts">Save
</button>
</div>
<div class="btn-group">
<button onclick="$('#editWithinGeoJSON #updateGeoJson').attr('leaflet_id',$(this).attr('leaflet_id'));$('#editWithinGeoJSON textarea').text(JSON.stringify(map._layers[$(this).attr('leaflet_id')].toGeoJSON(),null, '\t'));$('#editWithinGeoJSON').modal('toggle')"
type="button" class="btn btn-default btn-xs editGeoJson">Edit
</button>
</div>
<div class="btn-group">
<a id="exportGeoJson" download="geoJson.json" href="#"
onclick="exportToGeoJSON(this, JSON.stringify(map._layers[$(this).attr('leaflet_id')].toGeoJSON(),null, '\t'))"
class="btn btn-default btn-xs" data-toggle="tooltip" data-placement="left"
title="Export selected area as a geoJson file">Export</a>
</div>
</div>
</div>
</form>
</div>
<div id="setExitAlert">
<form role="form" style="width: auto;">
<div class="form-group">
<label class="text-primary" for="exitAlertAreaName">Fence name</label>
<input class="form-control" id="exitAlertAreaName" placeholder="Fence name" type="text">
<span class="help-block">Name of the selected area(e.g. colombo)</span>
</div>
<div>
<div class="btn-group btn-group-sm btn-group-justified">
<div class="btn-group">
<button id="addExitAlert" onclick="setExitAlert($(this).attr('leaflet_id'))" type="button"
class="btn btn-info btn-xs" data-toggle="tooltip" data-placement="left"
title="Save selected area for alerts">Save
</button>
</div>
<div class="btn-group">
<button onclick="$('#editExitGeoJSON #updateGeoJson').attr('leaflet_id',$(this).attr('leaflet_id'));$('#editExitGeoJSON textarea').text(JSON.stringify(map._layers[$(this).attr('leaflet_id')].toGeoJSON(),null, '\t'));$('#editExitGeoJSON').modal('toggle')"
type="button" class="btn btn-default btn-xs editGeoJson">Edit
</button>
</div>
<div class="btn-group">
<a id="exportGeoJson" download="geoJson.json" href="#"
onclick="exportToGeoJSON(this, JSON.stringify(map._layers[$(this).attr('leaflet_id')].toGeoJSON(),null, '\t'))"
class="btn btn-default btn-xs" data-toggle="tooltip" data-placement="left"
title="Export selected area as a geoJson file">Export</a>
</div>
</div>
</div>
</form>
</div>
<div id="templateLoader"></div>
<div id="setStationeryAlert">
<form role="form" style="width: auto;">
<div class="form-group">
<label class="text-primary" for="stationaryAlertAreaName">Fence name</label>
<input class="form-control" id="stationaryAlertAreaName" placeholder="Stationery name" type="text">
<span class="help-block">Name of the selected area(e.g. colombo)</span>
<label class="text-primary" for="fRadius">Fluctuation radius</label>
<input class="form-control" id="fRadius" onblur="reformatRadius(this.form.fRadius.value);" placeholder="m" type="text">
<label class="text-primary" for="time">Time</label>
<input class="form-control" id="time" placeholder="Seconds" type="text">
</div>
<div>
<div class="btn-group btn-group-sm btn-group-justified">
<div class="btn-group">
<button id="addStationeryAlert" onclick="setStationeryAlert($(this).attr('leaflet_id'))" type="button"
class="btn btn-info btn-xs" data-toggle="tooltip" data-placement="left"
title="Save selected area for alerts">Save
</button>
</div>
<div class="btn-group">
<button onclick="$('#editWithinGeoJSON #updateGeoJson').attr('leaflet_id',$(this).attr('leaflet_id'));$('#editWithinGeoJSON textarea').text(JSON.stringify(map._layers[$(this).attr('leaflet_id')].toGeoJSON(),null, '\t'));$('#editWithinGeoJSON').modal('toggle')"
type="button" class="btn btn-default btn-xs editGeoJson">Edit
</button>
</div>
<div class="btn-group">
<a id="exportGeoJson" download="geoJson.json" href="#"
onclick="exportToGeoJSON(this, JSON.stringify(map._layers[$(this).attr('leaflet_id')].toGeoJSON(),null, '\t'))"
class="btn btn-default btn-xs" data-toggle="tooltip" data-placement="left"
title="Export selected area as a geoJson file">Export</a>
</div>
</div>
</div>
</form>
</div>
<div id="setTrafficAlert">
<form role="form" style="width: auto;">
<div class="form-group">
<label class="text-primary" for="trafficAlertAreaName">Fence name</label>
<input class="form-control" id="trafficAlertAreaName" placeholder="Area Name" type="text">
<span class="help-block">Name of the selected area(e.g. colombo)</span>
</div>
<div>
<div class="btn-group btn-group-sm btn-group-justified">
<div class="btn-group">
<button id="addTrafficAlert" onclick="setTrafficAlert($(this).attr('leaflet_id'))" type="button"
class="btn btn-info btn-xs" data-toggle="tooltip" data-placement="left"
title="Save selected area for alerts">Save
</button>
</div>
<div class="btn-group">
<button onclick="$('#editTrafficGeoJSON #updateGeoJson').attr('leaflet_id',$(this).attr('leaflet_id'));$('#editTrafficGeoJSON textarea').text(JSON.stringify(map._layers[$(this).attr('leaflet_id')].toGeoJSON(),null, '\t'));$('#editTrafficGeoJSON').modal('toggle')"
type="button" class="btn btn-default btn-xs editGeoJson">Edit
</button>
</div>
<div class="btn-group">
<a id="exportGeoJson" download="geoJson.json" href="#"
onclick="exportToGeoJSON(this, JSON.stringify(map._layers[$(this).attr('leaflet_id')].toGeoJSON(),null, '\t'))"
class="btn btn-default btn-xs" data-toggle="tooltip" data-placement="left"
title="Export selected area as a geoJson file">Export</a>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
@ -39,6 +882,7 @@
{{js "js/leaflet/leaflet.markercluster.js" }}
{{js "js/leaflet/L.Control.Locate.js" }}
{{js "js/leaflet/L.Control.Focus.js" }}
{{js "js/leaflet/L.Control.GeoAlerts.js" }}
{{js "js/leaflet/leaflet.groupedlayercontrol.js" }}
{{js "js/leaflet/Leaflet.fullscreen.min.js" }}
{{js "js/leaflet/Marker.Rotate.js" }}
@ -47,9 +891,68 @@
{{js "js/typeahead.bundle.min.js" }}
{{js "js/geo_remote.js" }}
{{js "js/app.js" }}
{{js "js/geo_exit_fence.js" }}
{{js "js/geo_within.js" }}
{{js "js/geo_stationary.js" }}
{{js "js/geo_speed.js" }}
{{!js "js/jquery/jquery-ui.min.js" }}
<!-- Leaflet plugins libries -->
{{js "js/firstTemp.js" }}
<!-- C3 charting library using D3 core -->
{{js "js/d3/d3.min.js" }}
{{js "js/d3/c3.min.js" }}
{{js "js/application_options.js" }}
{{js "js/secondTemp.js" }}
{{js "js/show_alert_in_map.js" }}
{{js "js/websocket.js" }}
{{js "js/geo_fencing.js" }}
<script type="text/javascript">
$(document).ready(function () {
initialLoad(false);
initializeGeoLocation({{geoServicesEnabled}});
geoPublicUri = $("#geo-charts").data("geo-public-uri");
{{#if geoServicesEnabled}}
var geoToolsMenu = $('#location-action-bar');
var refreshMap = createGeoToolListItem('javascript:void(0);', 'Refresh', 'fw fw-refresh', geoToolsMenu, true);
refreshMap.addClass("geo-tools");
refreshMap.on("click", function(){enableRealTime({{geoServicesEnabled}});});
var viewAll = createGeoToolListItem('javascript:void(0);', 'View All', 'glyphicon glyphicon-th-list', geoToolsMenu, true);
viewAll.addClass("geo-tools");
viewAll.on("click", function(){viewAllFences();});
var realTime = createGeoToolListItem('javascript:void(0);', 'Return to Real Time View', 'fw fw-undo', geoToolsMenu, true);
realTime.addClass("geo-tools");
realTime.on("click", function(){enableRealTime({{geoServicesEnabled}});});
realTime.css("display", "none");
realTime.attr("id", "realTimeShow");
var exitAlert = createGeoToolListItem('#', 'Add Geofence Exit Alert', 'glyphicon glyphicon-log-out', geoToolsMenu,'Exit');
exitAlert.addClass("geo-alert");
exitAlert.on("click", function(){initializeExit();});
var withinAlert = createGeoToolListItem('#', 'Add Geofence Enter Alert', 'glyphicon glyphicon-log-in', geoToolsMenu,'Within');
withinAlert.addClass("geo-alert");
withinAlert.on("click", function(){initializeWithin();});
var stationaryAlert = createGeoToolListItem('#', 'Add Stationary Alert', 'glyphicon glyphicon-link', geoToolsMenu,'Stationery');
stationaryAlert.addClass("geo-alert");
stationaryAlert.on("click", function(){initStationaryAlert();});
var speedAlert = createGeoToolListItem('#', 'Set Speed Alert', 'glyphicon glyphicon-dashboard', geoToolsMenu,'Speed');
speedAlert.addClass("geo-alert");
speedAlert.on("click", function(){initializeSpeed();});
{{/if}}
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
$('#dateRangePopup.ui-dialog-content').dialog('close');
});
});
</script>
{{/zone}}

@ -0,0 +1,58 @@
/*
* Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
function onRequest(context) {
var log = new Log("geo-devices.js");
var devicemgtProps = require("/app/modules/conf-reader/main.js")["conf"];
var viewModel = {};
var carbonServer = require("carbon").server;
var device = context.unit.params.device;
var constants = require("/app/modules/constants.js");
var wsEndpoint = null;
var jwtService = carbonServer.osgiService(
'org.wso2.carbon.identity.jwt.client.extension.service.JWTClientManagerService');
var jwtClient = jwtService.getJWTClient();
var encodedClientKeys = session.get(constants["ENCODED_TENANT_BASED_WEB_SOCKET_CLIENT_CREDENTIALS"]);
var tokenPair = null;
var token = "";
if (encodedClientKeys) {
var tokenUtil = require("/app/modules/oauth/token-handler-utils.js")["utils"];
var resp = tokenUtil.decode(encodedClientKeys).split(":");
if (context.user.domain == "carbon.super") {
tokenPair = jwtClient.getAccessToken(resp[0], resp[1], context.user.username,"default", {});
if (tokenPair) {
token = tokenPair.accessToken;
wsEndpoint = devicemgtProps["wssURL"].replace("https", "wss") + "/secured-websocket/";
}
} else {
tokenPair = jwtClient.getAccessToken(resp[0], resp[1], context.user.username + "@" + context.user.domain,"default", {});
if (tokenPair) {
token = tokenPair.accessToken;
wsEndpoint = devicemgtProps["wssURL"].replace("https", "wss") + "/secured-websocket/t/"+context.user.domain+"/";
}
}
}
viewModel.device = device;
viewModel.wsToken = token;
viewModel.wsEndpoint = wsEndpoint;
viewModel.geoServicesEnabled = devicemgtProps.serverConfig.geoLocationConfiguration.enabled;
return viewModel;
}

@ -0,0 +1,95 @@
<!--~ Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
~
~ WSO2 Inc. licenses this file to you under the Apache License,
~ Version 2.0 (the "License"); you may not use this file except
~ in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing,
~ software distributed under the License is distributed on an
~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
~ KIND, either express or implied. See the License for the
~ specific language governing permissions and limitations
~ under the License.-->
<!DOCTYPE html>
<html>
<head lang="en">
<link href="/portal/store/carbon.super/fs/gadget/geo-devices/css/leaflet/L.Grid.css" rel="stylesheet" type="text/css"/>
<link href="/portal/store/carbon.super/fs/gadget/geo-devices/css/main.css" rel="stylesheet" type="text/css"/>
<script src="/portal/store/carbon.super/fs/gadget/geo-devices/js/leaflet/L.Grid.js"></script>
<script src="/portal/store/carbon.super/fs/gadget/geo-devices/js/leaflet/L.MeasuringTool.js"></script>
<style>
.leaflet-grid-label .lng {
margin-left: 8px;
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
}
.measuring-line-for-look {
stroke-dasharray: 3, 20;
}
.measuring-label-tooltip .leaflet-popup-content-wrapper {
border-radius: 4px 4px 4px 4px;
opacity: 0.7;
padding: 1px;
text-align: center;
}
.measuring-label-tooltip .leaflet-popup-content {
margin: 0 5px;
/*width: 0;*/
}
.measuring-label-tooltip .leaflet-popup-tip-container {
display: none;
}
</style>
</head>
<body>
<div class="modal-header"
style="cursor: move;background: #f9f9f9;-webkit-box-shadow: inset 0px 0px 14px 1px rgba(0,0,0,0.2);-moz-box-shadow: inset 0px 0px 14px 1px rgba(0,0,0,0.2);box-shadow: inset 0px 0px 14px 1px rgba(0,0,0,0.2);">
<button class="close" type="button" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">
<!-- TODO: Trigger bootstrap tooltip $('#aboutTileUrl').tooltip(); to enable tooltip -->
Define proximity
</h4>
</div>
<div class="modal-body">
<div id="proximityMap" style="height: 50%; margin: 0 auto;"></div>
<div class="row">
<div class="row">
<div class="col-md-10 col-md-offset-1">
<form class="form-inline" role="form">
<div class="input-group input-group-sm">
<input type="text" id="proximityDistance" class="form-control" placeholder="Distance" >
<span class="input-group-addon">m</span>
</div>
<div class="input-group input-group-sm">
<input autofocus="enable" id="proximityTime" type="number" class="form-control"
placeholder="Close time in S" >
<span class="input-group-addon">Seconds</span>
</div>
</form>
</div>
</div>
<div style="margin-bottom: -15px" class="btn-group btn-group-justified">
<div class="btn-group">
<button style="background-color: #f4f4f4;" type="button" class="btn btn-default"
onclick="setProximityAlert()">Set Proximity
</button>
</div>
<div class="btn-group">
<button style="background-color: #f4f4f4;" type="button" class="btn btn-default"
onclick="closeAll()">Cancel
</button>
</div>
</div>
</div>
</div>
<script src="/portal/store/carbon.super/fs/gadget/geo-devices/js/geo_proximity.js"></script>
</body>
</html>

@ -0,0 +1,106 @@
<!--~ Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
~
~ WSO2 Inc. licenses this file to you under the Apache License,
~ Version 2.0 (the "License"); you may not use this file except
~ in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing,
~ software distributed under the License is distributed on an
~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
~ KIND, either express or implied. See the License for the
~ specific language governing permissions and limitations
~ under the License.-->
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
.fa-trash-o:hover {
color: red;
}
</style>
<script>
$(".removeGeoFence").tooltip();
$('.viewGeoFenceRow td:not(:last-child)').click(function () {
viewFence(this.parentElement, 'Traffic');
});
</script>
</head>
<body>
<div class="modal-header"
style="cursor: move;background: #f9f9f9;-webkit-box-shadow: inset 0px 0px 14px 1px rgba(0,0,0,0.2);-moz-box-shadow: inset 0px 0px 14px 1px rgba(0,0,0,0.2);box-shadow: inset 0px 0px 14px 1px rgba(0,0,0,0.2);">
<button class="close" type="button" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">
<!-- TODO: Trigger bootstrap tooltip $('#aboutTileUrl').tooltip(); to enable tooltip -->
Set <i>traffic</i> alerts
</h4>
</div>
<div class="modal-body">
<div class="row">
<p class="text-info text-center">View current fences</p>
<div class="">
<table class="table table-hover">
<thead>
<tr>
<th>Query Name</th>
<th>Traffic Congestion Area Name</th>
<th></th>
</tr>
</thead>
<tbody>
<%
var alerts = get('traffic');
if(alerts){
for each(var alert in alerts){
%>
<tr class="viewGeoFenceRow" style="cursor: pointer" data-areaName='<%= alert.areaName %>'
data-queryName='<%= alert.queryName %>' data-geoJson='<%= alert.geoJson %>'>
<td><%= alert.queryName %></td>
<td><%= alert.areaName %></td>
<td onClick="removeGeoFence(this.parentElement,'Traffic')" class="removeGeoFence"
data-toggle="tooltip" title="Remove fence"><i class="fa fa-trash-o"></i></td>
</tr>
<%
}
}
else{
%>
<div class="alert alert-danger" role="alert">
<strong>Oh snap!</strong> Can't find any geofence area, please draw a new area or try again.
</div>
<%
}
%>
</tbody>
</table>
</div>
<p class="text-info text-center">Select Interested Area</p>
<div style="margin-bottom: -15px" class="btn-group btn-group-justified">
<div class="btn-group">
<button style="background-color: #f4f4f4;" type="button" class="btn btn-default"
onclick="openTools('Traffic')">Draw area
</button>
</div>
<div class="btn-group">
<button style="background-color: #f4f4f4;" type="button" class="btn btn-default"
onclick="$('#editWithinGeoJSON').modal('toggle')">Enter area
</button>
</div>
</div>
</div>
</div>
</body>
</html>

@ -0,0 +1,52 @@
<!--~ Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
~
~ WSO2 Inc. licenses this file to you under the Apache License,
~ Version 2.0 (the "License"); you may not use this file except
~ in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing,
~ software distributed under the License is distributed on an
~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
~ KIND, either express or implied. See the License for the
~ specific language governing permissions and limitations
~ under the License.-->
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="viewExitAlert" >
<h3 class="popover-title" id="viewAreaName"></h3>
<div class="popover-content">
<form role="form" style="width: auto" id="exitAlertForm">
<button type="button" id="exportGeoJson" download="geoJson.json" onclick="exportToGeoJSON(this,JSON.stringify(map._layers[$(this).attr('leaflet_id')].toGeoJSON(),null, '\t'))" class="btn btn-info btn-xs" data-toggle="tooltip" data-placement="left" title="Export selected area as a geoJson file">Export</button>
<button type="button" id="hideViewFence" class="btn btn-info btn-xs" data-toggle="tooltip" data-placement="left" title="Hide this fence" onclick="map.removeLayer(map._layers[$(this).attr('leaflet_id')])" >Hide</button>
</form>
</div>
</div>
<div id="viewWithinAlert" >
<h3 class="popover-title" id="viewAreaName"></h3>
<div class="popover-content">
<form role="form" style="width: auto" class="" id="withinAlertForm">
<button type="button" id="exportGeoJson" download="geoJson.json" onclick="exportToGeoJSON(this,JSON.stringify(map._layers[$(this).attr('leaflet_id')].toGeoJSON(),null, '\t'))" class="btn btn-info btn-xs" data-toggle="tooltip" data-placement="left" title="Export selected area as a geoJson file">Export</button>
<button type="button" id="hideViewFence" class="btn btn-info btn-xs" data-toggle="tooltip" data-placement="left" title="Hide this fence" onclick="map.removeLayer(map._layers[$(this).attr('leaflet_id')])" >Hide</button>
</form>
</div>
</div>
<div id="viewStationeryAlert" >
<h3 class="popover-title" id="viewAreaName"></h3>
<div class="popover-content">
<form role="form" style="width: auto" id="stationaryAlertForm">
<h6>Stationery time(Seconds)<span id="viewAreaTime" class="label label-primary pull-right">N/A</span></h6>
<button type="button" id="exportGeoJson" download="geoJson.json" onclick="exportToGeoJSON(this,JSON.stringify(map._layers[$(this).attr('leaflet_id')].toGeoJSON(),null, '\t'))" class="btn btn-info btn-xs" data-toggle="tooltip" data-placement="left" title="Export selected area as a geoJson file">Export</button>
<button type="button" id="hideViewFence" class="btn btn-info btn-xs" data-toggle="tooltip" data-placement="left" title="Hide this fence" onclick="map.removeLayer(map._layers[$(this).attr('leaflet_id')])" >Hide</button>
</form>
</div>
</div>
</body>
</html>

@ -0,0 +1,20 @@
/* Enter a unique ExecutionPlan */
@Plan:name('$executionPlanName')
/* Enter a unique description for ExecutionPlan */
-- @Plan:description('ExecutionPlan')
/* define streams/tables and write queries here ... */
@Import('org.wso2.geo.StandardSpatialEvents:1.0.0')
define stream dataIn (id string, latitude double, longitude double, timeStamp long, type string ,speed float, heading float, eventId string);
@Export('org.wso2.geo.ProcessedSpatialEvents:1.0.0')
define stream dataOut (id string, latitude double, longitude double, timeStamp long, type string ,speed float, heading float, eventId string, state string, information string);
from dataIn[geo:within(longitude,latitude,"$geoFenceGeoJSON")==false and id == "$deviceId"]#geodashboard:subscribe()
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId , "ALERTED" as state, "This device is in $areaName restricted area!!!" as information
insert into dataOut;
from dataIn[geo:within(longitude,latitude,"$geoFenceGeoJSON")!=false and id == "$deviceId"]
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId , "NORMAL" as state, "" as information
insert into dataOut;

@ -0,0 +1,140 @@
/* Enter a unique ExecutionPlan */
@Plan:name('Geo-ExecutionPlan-Proximity_alert')
/* Enter a unique description for ExecutionPlan */
-- @Plan:description('ExecutionPlan')
/* define streams/tables and write queries here ... */
@Import('org.wso2.geo.StandardSpatialEvents:1.0.0')
define stream dataIn (id string, latitude double, longitude double, timeStamp long, type string, speed float, heading float, eventId string );
@Export('org.wso2.geo.ProcessedSpatialEvents:1.0.0')
define stream dataOut ( id string, latitude double, longitude double, timeStamp long, type string, speed float, heading float, eventId string, state string, information string );
@IndexBy('id')
define table ProximityTable(id string, timeStamp long);
@IndexBy('id')
define table AlertsTable(id string , proximityWith string, eventId string);
from dataIn#geodashboard:subscribe()
select id, latitude, longitude, timeStamp, type, speed, heading, eventId
insert into initialStream;
from initialStream[type == 'STOP']
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId , "" as proximityInfo ,"false" as isProximity
insert into dataOutStream;
from initialStream[type != 'STOP']
select *
insert into objectInitialStream;
from objectInitialStream#geo:proximity(id,longitude,latitude, $proximityDistance)
select id, latitude, longitude, timeStamp, type, speed, heading, eventId,inCloseProximity,proximityWith
insert into proxymityStream;
from proxymityStream[AlertsTable.id == proxymityStream.id in AlertsTable]
select id, latitude, longitude, timeStamp, type, speed, heading, eventId,inCloseProximity,proximityWith,true as inAlertTable
insert into innerStreamOne;
from proxymityStream[not(AlertsTable.id == proxymityStream.id in AlertsTable)]
select id, latitude, longitude, timeStamp, type, speed, heading, eventId,inCloseProximity,proximityWith,false as inAlertTable
insert into innerStreamOne;
from proxymityStream[AlertsTable.id == proxymityStream.proximityWith in AlertsTable]
select id, latitude, longitude, timeStamp, type, speed, heading, eventId,inCloseProximity,proximityWith,true as inAlertTable
insert into innerStreamSeven;
from proxymityStream[not(AlertsTable.id == proxymityStream.proximityWith in AlertsTable)]
select id, latitude, longitude, timeStamp, type, speed, heading, eventId,inCloseProximity,proximityWith,false as inAlertTable
insert into innerStreamSeven;
from innerStreamOne[inCloseProximity == true AND not(inAlertTable)]
select id,str:concat(",",proximityWith) as proximityWith , eventId
insert into AlertsTable;
from innerStreamSeven[inCloseProximity == true AND not(inAlertTable)]
select proximityWith as id,str:concat(",",id) as proximityWith , eventId
insert into AlertsTable;
from innerStreamOne[innerStreamOne.inCloseProximity == true AND inAlertTable]#window.length(0) join AlertsTable
on innerStreamOne.id == AlertsTable.id
select innerStreamOne.id as id, str:concat(",", innerStreamOne.proximityWith, AlertsTable.proximityWith) as proximityWith, innerStreamOne.eventId as eventId
insert into updateStream;
from innerStreamSeven[innerStreamSeven.inCloseProximity == true AND inAlertTable]#window.length(0) join AlertsTable
on innerStreamSeven.proximityWith == AlertsTable.id
select innerStreamSeven.proximityWith as id, str:concat(",", innerStreamSeven.id, AlertsTable.proximityWith) as proximityWith, innerStreamSeven.eventId as eventId
insert into updateStream;
from innerStreamOne[innerStreamOne.inCloseProximity == false AND inAlertTable]#window.length(0) join AlertsTable
on innerStreamOne.id == AlertsTable.id
select innerStreamOne.id as id, str:replaceAll(AlertsTable.proximityWith, str:concat(",", innerStreamOne.proximityWith), "") as proximityWith, innerStreamOne.eventId as eventId
insert into updateStream;
from innerStreamSeven[innerStreamSeven.inCloseProximity == false AND inAlertTable]#window.length(0) join AlertsTable
on innerStreamSeven.proximityWith == AlertsTable.id
select innerStreamSeven.proximityWith as id, str:replaceAll(AlertsTable.proximityWith, str:concat(",", innerStreamSeven.id), "") as proximityWith, innerStreamSeven.eventId as eventId
insert into updateStream;
from updateStream
select *
update AlertsTable
on id== AlertsTable.id;
from updateStream[proximityWith == ""]
delete AlertsTable
on id== AlertsTable.id;
from objectInitialStream[AlertsTable.id == objectInitialStream.id in AlertsTable]
select id, latitude, longitude, timeStamp, type, speed, heading, eventId, true as inAlertTable
insert into publishStream;
from objectInitialStream[not(AlertsTable.id == objectInitialStream.id in AlertsTable)]
select id, latitude, longitude, timeStamp, type, speed, heading, eventId, false as inAlertTable
insert into publishStream;
from publishStream[inAlertTable == true]#window.length(0) join AlertsTable
on publishStream.id== AlertsTable.id
select publishStream.id as id, publishStream.latitude as latitude, publishStream.longitude as longitude, publishStream.timeStamp as timeStamp, publishStream.type as type, publishStream.speed as speed, publishStream.heading as heading, publishStream.eventId as eventId, AlertsTable.proximityWith as proximityInfo
insert into innerStreamTwo;
from publishStream[inAlertTable == false]
delete ProximityTable on ProximityTable.id==id;
from publishStream[inAlertTable == false]
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId , "" as proximityInfo ,"false" as isProximity
insert into dataOutStream;
from innerStreamTwo[ProximityTable.id == innerStreamTwo.id in ProximityTable]
insert into innerStreamThree;
from innerStreamThree#window.length(0) join ProximityTable
on innerStreamThree.id == ProximityTable.id
select innerStreamThree.id , innerStreamThree.latitude, innerStreamThree.longitude,innerStreamThree.timeStamp, innerStreamThree.type, innerStreamThree.speed, innerStreamThree.heading ,innerStreamThree.eventId, ProximityTable.timeStamp as storedTime, innerStreamThree.proximityInfo as proximityInfo
insert into innerStreamFour;
from innerStreamFour[(timeStamp - storedTime) >= $proximityTime]
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId ,proximityInfo,"true" as isProximity
insert into dataOutStream;
from innerStreamFour[(timeStamp - storedTime) < $proximityTime]
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId , proximityInfo ,"false" as isProximity
insert into dataOutStream;
from innerStreamTwo[not(ProximityTable.id == innerStreamTwo.id in ProximityTable)]
select innerStreamTwo.id, innerStreamTwo.timeStamp
insert into ProximityTable;
from innerStreamTwo[not(ProximityTable.id == innerStreamTwo.id in ProximityTable)]
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId , "" as proximityInfo ,"false" as isProximity
insert into dataOutStream;
from dataOutStream[isProximity == 'true']
select id, latitude, longitude, timeStamp, type, speed, heading, eventId,"WARNING" as state,str:concat("Proximity with "," ",proximityInfo) as information
insert into dataOut;
from dataOutStream[isProximity == 'false']
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId ,"NORMAL" as state,"" as information
insert into dataOut;

@ -0,0 +1,20 @@
/* Enter a unique ExecutionPlan */
@Plan:name('Geo-ExecutionPlan-Speed---$deviceId_alert')
/* Enter a unique description for ExecutionPlan */
-- @Plan:description('ExecutionPlan')
/* define streams/tables and write queries here ... */
@Import('org.wso2.geo.StandardSpatialEvents:1.0.0')
define stream dataIn (id string, latitude double, longitude double, timeStamp long, type string, speed float, heading float, eventId string);
@Export('org.wso2.geo.ProcessedSpatialEvents:1.0.0')
define stream dataOut (id string, latitude double, longitude double, timeStamp long, type string, speed float, heading float, eventId string, state string, information string);
from dataIn[speed >= $speedAlertValue and id == "$deviceId"]#geodashboard:subscribe()
select id , latitude, longitude,timeStamp, type ,speed, heading ,eventId , "ALERTED" as state, "This device movement is not normal!!" as information
insert into dataOut;
from dataIn[speed < $speedAlertValue and id == "$deviceId"]
select id , latitude, longitude,timeStamp, type ,speed, heading ,eventId , "NORMAL" as state, "This device movement is normal" as information
insert into dataOut;

@ -0,0 +1,89 @@
/* Enter a unique ExecutionPlan */
@Plan:name('$executionPlanName')
/* Enter a unique description for ExecutionPlan */
-- @Plan:description('ExecutionPlan')
/* define streams/tables and write queries here ... */
@Import('org.wso2.geo.StandardSpatialEvents:1.0.0')
define stream dataIn (id string, latitude double, longitude double, timeStamp long, type string ,speed float, heading float, eventId string);
@Export('org.wso2.geo.ProcessedSpatialEvents:1.0.0')
define stream dataOut (id string, latitude double, longitude double, timeStamp long, type string ,speed float, heading float, eventId string, state string, information string);
@IndexBy('id')
define table StationeryTable(id string, timeStamp long);
@IndexBy('id')
define table AlertsTable(id string, stationary bool);
from dataIn#geodashboard:subscribe()
select id, latitude, longitude, timeStamp, type, speed, heading, eventId,geo:within(longitude,latitude,"$geoFenceGeoJSON") as isWithin
insert into innerStreamOne;
from innerStreamOne[isWithin == false]
delete StationeryTable on StationeryTable.id==id;
from innerStreamOne[isWithin == false]
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId , "false" as isStationary
insert into dataOutStream;
from innerStreamOne[isWithin == true]#geo:stationary(id,longitude,latitude, $fluctuationRadius)
select id, latitude, longitude, timeStamp, type, speed, heading, eventId,stationary
insert into innerStreamTwo;
from innerStreamTwo[innerStreamTwo.stationary == true]
select innerStreamTwo.id, innerStreamTwo.stationary
insert into AlertsTable;
from innerStreamTwo[innerStreamTwo.stationary == false]
delete AlertsTable on AlertsTable.id==id;
from innerStreamTwo[innerStreamTwo.stationary == false]
delete StationeryTable on StationeryTable.id==id;
from innerStreamOne[isWithin == true AND not(AlertsTable.id == innerStreamOne.id in AlertsTable)]
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId , "false" as isStationary
insert into dataOutStream;
from innerStreamOne[isWithin == true AND AlertsTable.id == innerStreamOne.id in AlertsTable]
insert into innerStreamThree;
from innerStreamThree#window.length(0) join AlertsTable
on innerStreamThree.id == AlertsTable.id
select innerStreamThree.id , innerStreamThree.latitude, innerStreamThree.longitude,innerStreamThree.timeStamp, innerStreamThree.type, innerStreamThree.speed, innerStreamThree.heading ,innerStreamThree.eventId
insert into innerStreamFour;
from innerStreamFour[not(StationeryTable.id == innerStreamFour.id in StationeryTable)]
select innerStreamFour.id, innerStreamFour.timeStamp
insert into StationeryTable;
from innerStreamOne[isWithin == true AND not(StationeryTable.id == innerStreamOne.id in StationeryTable)]
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId , "false" as isStationary
insert into dataOutStream;
from innerStreamOne[isWithin == true AND StationeryTable.id == innerStreamOne.id in StationeryTable]
insert into innerStreamFive;
from innerStreamFive#window.length(0) join StationeryTable
on innerStreamFive.id == StationeryTable.id
select innerStreamFive.id , innerStreamFive.latitude, innerStreamFive.longitude,innerStreamFive.timeStamp, innerStreamFive.type, innerStreamFive.speed, innerStreamFive.heading ,innerStreamFive.eventId, StationeryTable.timeStamp as storedTime
insert into innerStreamSix;
from innerStreamSix[(timeStamp - storedTime) >= $stationeryTime]
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId ,"true" as isStationary
insert into dataOutStream;
from innerStreamSix[(timeStamp - storedTime) < $stationeryTime]
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId ,"false" as isStationary
insert into dataOutStream;
from dataOutStream[isStationary == 'true']
select id ,latitude, longitude,timeStamp, type, speed, heading ,eventId ,"ALERTED" as state, "This device is in $stationeryName area!!!" as information
insert into dataOut;
from dataOutStream[isStationary == 'false']
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId ,"NORMAL" as state,"" as information
insert into dataOut;

@ -0,0 +1,17 @@
/* Enter a unique ExecutionPlan */
@Plan:name('$executionPlanName')
/* Enter a unique description for ExecutionPlan */
-- @Plan:description('ExecutionPlan')
/* define streams/tables and write queries here ... */
@Import('rawGeoStream:1.0.0')
define stream dataIn (id string, timeStamp long, geometry string, state string, information string);
@Export('AlertsNotifications:1.0.0')
define stream dataOut (id string, state string, information string, timeStamp long, latitude double, longitude double);
from dataIn[geo:intersects(geometry, "$geoFenceGeoJSON")==true and geodashboard:needToNotify(id, str:concat(information, state), "sendFirst") == true and id == $deviceId]
select id, state, str:concat("Traffic alert in $areaName. State: ", state, " ", information) as information, timeStamp, 0.0 as latitude, 0.0 as longitude
insert into dataOut

@ -0,0 +1,20 @@
/* Enter a unique ExecutionPlan */
@Plan:name('$executionPlanName')
/* Enter a unique description for ExecutionPlan */
-- @Plan:description('ExecutionPlan')
/* define streams/tables and write queries here ... */
@Import('org.wso2.geo.StandardSpatialEvents:1.0.0')
define stream dataIn (id string, latitude double, longitude double, timeStamp long, type string ,speed float, heading float, eventId string);
@Export('org.wso2.geo.ProcessedSpatialEvents:1.0.0')
define stream dataOut (id string, latitude double, longitude double, timeStamp long, type string ,speed float, heading float, eventId string, state string, information string);
from dataIn[geo:within(longitude,latitude,"$geoFenceGeoJSON")==true and id == "$deviceId"]#geodashboard:subscribe()
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId , "ALERTED" as state, "This device is in $areaName restricted area!!!" as information
insert into dataOut;
from dataIn[geo:within(longitude,latitude,"$geoFenceGeoJSON")!=true and id == "$deviceId"]
select id , latitude, longitude,timeStamp, type, speed, heading ,eventId , "NORMAL" as state, "" as information
insert into dataOut;

@ -128,6 +128,25 @@ input[type="radio"], input[type="checkbox"] {
padding: 5px 10px;
}
.tab-actions .action-btn.filter.geo-alert {
padding: 10px 15px;
background-color: #ebebeb;
float: left;
cursor: pointer;
position: relative;
margin-left: 10px;
margin-bottom: 10px;
}
.tab-actions .action-btn.filter.geo-tools {
padding: 10px 15px;
background-color: #ebebeb;
float: right;
cursor: pointer;
position: relative;
margin-left: 10px;
margin-bottom: 10px;
}
/*

@ -33,16 +33,22 @@ var map;
var geoClusters;
var markersLayer = new L.LayerGroup();
var popupContent;
var clusterLat;
var clusterLong;
var lastSeen;
var geoFencingEnabled;
var zoomLevel = 15;
var tileSet = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png";
var attribution = "&copy; <a href='https://openstreetmap.org/copyright'>OpenStreetMap</a> contributors";
function initialLoad() {
function initialLoad(geoFencingEnabled) {
window.geoFencingEnabled = geoFencingEnabled;
if (document.getElementById('map') == null) {
setTimeout(initialLoad, 500); // give everything some time to render
} else {
initializeMap();
processAfterInitializationMap();
$("#loading").hide();
}
}
@ -65,6 +71,7 @@ function initializeMap() {
maxNativeZoom: 18
});
L.tileLayer(tileSet, {attribution: attribution}).addTo(map);
markersLayer.clearLayers();
markersLayer.addTo(map);
showMarkersOnChange();
@ -86,6 +93,39 @@ function initializeMap() {
$("a[href='#left_side_pannel']").trigger('click');
}
function processAfterInitializationMap() {
attributionControl = L.control({
position: "bottomright"
});
attributionControl.onAdd = function (map) {
var div = L.DomUtil.create("div", "leaflet-control-attribution");
div.innerHTML = "<a href='#' onclick='$(\"#attributionModal\").modal(\"show\"); return false;'>Attribution</a>";
return div;
};
map.addControl(L.control.fullscreen({position: 'bottomright'}));
geoAlertsBar = L.control.geoAlerts({position: 'topright'});
if (geoFencingEnabled) {
map.addControl(geoAlertsBar);
}
groupedOverlays = {
"Web Map Service layers": {}
};
layerControl = L.control.groupedLayers(baseLayers, groupedOverlays, {
collapsed: true,
position: 'bottomleft'
}).addTo(map);
if (geoFencingEnabled) {
var alertsFromDate = new Date();
var toDate = new Date();
alertsFromDate.setHours(alertsFromDate.getHours() - 24); //last 24 hours
getAlertsHistory(alertsFromDate.valueOf(), toDate.valueOf());
};
}
var showMarkesOnZoomEnd = function (zoomLevel) {
if(map.getZoom()===zoomLevel){
@ -127,14 +167,17 @@ function geoGridControl(){
geoClusterMarker(count,cluster.coordinates.latitude,cluster.coordinates.longitude,
cluster.southWestBound.latitude,
cluster.northEastBound.latitude,cluster.southWestBound.longitude,cluster.northEastBound.longitude,
cluster.deviceIdentification,cluster.deviceType);
cluster.deviceIdentification,cluster.deviceType, cluster.lastSeen);
}
}
}
function geoClusterMarker(count, clusterLat, clusterLong, minLat, maxLat, minLong, maxLong,deviceIdentification,
deviceType) {
deviceType, lastSeen) {
window.clusterLat = clusterLat;
window.clusterLong = clusterLong;
window.lastSeen = lastSeen;
var deviceMarker = L.AwesomeMarkers.icon({
icon: ' ',
markerColor: 'blue'
@ -180,17 +223,32 @@ function handleMarkerEvents(event,extra_data,marker) {
}
var devicePopupManagement= function(deviceName, deviceType, deviceIdentifier,deviceStatus,deviceOwner){
var devicePopupManagement= function(deviceName, deviceType, deviceIdentifier,deviceStatus,deviceOwner) {
if (!geoFencingEnabled) {
var deviceMgtUrl = "/devicemgt/device/";
var html1 = '<div>';
var html2 = '<p><h3>' + '<a href="' + deviceMgtUrl + deviceType + '?id=' + deviceIdentifier + '" target="_blank">' + deviceName + '</a>' + '</h3></p>';
var html3 = '<p>' + 'Type : ' + deviceType + '</p>';
var html4 = '<p>' + 'Status : ' + deviceStatus + '</p>';
var html5 = '<p>' + 'Owner : ' + deviceOwner + '</p>';
var html6 = '</div>';
var html = html1 + html2 + html3 + html4 + html5 + html6;
return html;
}
var popupTemplate = $('#markerPopup');
var fromDate = new Date();
fromDate.setHours(fromDate.getHours() - 2);
var toDate = new Date();
var tableData = getAnalyticsData(deviceIdentifier,deviceType,fromDate.valueOf(),toDate.valueOf());
var data = tableData[tableData.length-1];
var deviceMgtUrl= "/devicemgt/device/";
var html1='<div>';
var html2 = '<p><h3>'+'<a href="' + deviceMgtUrl +deviceType+'?id='+deviceIdentifier+ '" target="_blank">' + deviceName + '</a>'+'</h3></p>' ;
var html3 = '<p>'+'Type : '+ deviceType+'</p>';
var html4 = '<p>'+'Status : '+deviceStatus+'</p>';
var html5 = '<p>'+ 'Owner : ' + deviceOwner + '</p>';
var html6='</div>';
var html=html1+html2+html3+html4+html5+html6;
return html;
popupTemplate.find('#objectId').html(deviceIdentifier);
popupTemplate.find('#information').html(data.values.information);
popupTemplate.find('#speed').html(Math.round(data.values.speed * 10) / 10);
popupTemplate.find('#heading').html(angleToHeading(data.values.heading));
return popupTemplate.html();
};
var devicePopupContentBackEndCall = function(type,deviceIdentification,marker,callback){
@ -212,3 +270,196 @@ var successCallBackDeviceDetails=function(device){
popupContent = devicePopupManagement(deviceName,deviceType,deviceIdentifier,deviceStatus,deviceOwner);
}
function getAnalyticsData(deviceId, deviceType, timeFrom, timeTo) {
var tableData = [];
var serviceUrl = '/api/device-mgt/v1.0/geo-services/stats/' + deviceType + '/' + deviceId + '?from=' + timeFrom + '&to=' + timeTo;
invokerUtil.get(serviceUrl,
function (data) {
if(data === "") {
showCurrentLocation(deviceId, deviceType, tableData);
}
tableData = JSON.parse(data);
if (tableData.length === 0) {
showCurrentLocation(deviceId, deviceType, tableData);
}
}, function (message) {
showCurrentLocation(deviceId, deviceType, tableData);
});
return tableData;
}
function showRecentAlertsHistory() {
if (geoFencingEnabled) {
var alertsFromDate = new Date();
var toDate = new Date();
alertsFromDate.setHours(alertsFromDate.getHours() - 2); //last 24 hours
getAlertsHistory(alertsFromDate.valueOf(), toDate.valueOf());
}
if (speedGraphControl) {
setTimeout(function () {
createChart();
chart.load({columns: [0]}); //TODO: Somehow get device speed history here
}, 100);
}
noty({text: "Showing last two hours geo history", type: "information"});
}
function showAlertsHistory(timeFrom, timeTo) {
if (!timeFrom) {
notifyError('No start time provided to show history. Please provide a suitable value' + timeFrom);
} else if (!timeTo) {
notifyError('No end time provided to show history. Please provide a suitable value' + timeTo);
} else {
$('#dateRangePopup').dialog('close');
disableRealTime();
isBatchModeOn = true;
getAlertsHistory(new Date($('#timeFromCal').val()).getTime(), new Date($('#timeToCal').val()).getTime());
if (speedGraphControl) {
setTimeout(function () {
createChart();
chart.load({columns: [0]}); //TODO: Somehow get device speed history here
}, 100);
}
}
}
function createGeoToolListItem(link, text, icon, menuRoot, alert) {
var listItem = $("<div/>", { class: 'action-btn filter'}).appendTo(menuRoot);
var anchor = $("<a/>", {href: link, text: ' ' + text}).appendTo(listItem);
if (alert == 'Exit') {
anchor.attr('data-toggle', 'modal');
anchor.attr('data-target', '#modalExit');
} else if (alert == 'Within') {
anchor.attr('data-toggle', 'modal');
anchor.attr('data-target', '#modalWithin');
} else if (alert == 'Stationery') {
anchor.attr('data-toggle', 'modal');
anchor.attr('data-target', '#modalStationery');
} else if (alert == 'Speed') {
anchor.attr('data-toggle', 'modal');
anchor.attr('data-target', '#modalSpeed');
}
$("<i/>", {class: icon}).prependTo(anchor);
return listItem;
}
var chart;
function createChart() {
chart = c3.generate({
bindto: '#chart_div',
data: {
columns: [
['speed']
]
},
subchart: {
show: true
},
axis: {
y: {
label: {
text: 'Speed',
position: 'outer-middle'
}
}
},
legend: {
show: false
}
});
}
function notifyError(message) {
noty({text: message, type: "error"});
}
function enableRealTime(geoFencingEnabled) {
$("#realTimeShow").hide();
$(".geo-alert").show();
isBatchModeOn = false;
initializeGeoLocation(geoFencingEnabled);
}
function disableRealTime(){
$(".geo-alert").hide();
$("#realTimeShow").show();
}
function showCurrentLocation(tableData){
var location = {};
location.latitude = clusterLat;
location.longitude = clusterLong;
location.updatedTime = lastSeen;
location.id = deviceId;
location.values = {};
location.values.id = deviceId;
location.values.information = "Last seen " + timeSince(new Date(location.updatedTime));
location.values.notify = false;
location.values.speed = 0;
location.values.heading = 0;
location.values.state = "NORMAL";
location.values.longitude = location.longitude;
location.values.latitude = location.latitude;
location.timestamp = location.updatedTime;
location.values.timeStamp = location.updatedTime;
location.values.type = deviceType;
location._version = "1.0.0";
tableData.push(location);
}
function formatDate(date) {
var hours = date.getHours();
var minutes = date.getMinutes();
var ampm = hours >= 12 ? 'pm' : 'am';
hours = hours % 12;
hours = hours ? hours : 12; // the hour '0' should be '12'
minutes = minutes < 10 ? '0' + minutes : minutes;
var strTime = hours + ':' + minutes + ' ' + ampm;
return date.getDate() + "/" + date.getMonth() + 1 + "/" + date.getFullYear() + " " + strTime;
}
function timeSince(date) {
if (!date) {
return "time is unknown";
}
var seconds = Math.floor((new Date() - date) / 1000);
var intervalType;
var interval = Math.floor(seconds / 31536000);
if (interval >= 1) {
intervalType = 'year';
} else {
interval = Math.floor(seconds / 2592000);
if (interval >= 1) {
intervalType = 'month';
} else {
interval = Math.floor(seconds / 86400);
if (interval >= 1) {
intervalType = 'day';
} else {
interval = Math.floor(seconds / 3600);
if (interval >= 1) {
intervalType = "hour";
} else {
interval = Math.floor(seconds / 60);
if (interval >= 1) {
intervalType = "minute";
} else {
interval = seconds;
intervalType = "second";
}
}
}
}
}
if (interval > 1 || interval === 0) {
intervalType += 's';
}
return interval + ' ' + intervalType + ' ago';
}

@ -0,0 +1,77 @@
/*
* Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
var ApplicationOptions = {
colors: {
states: {
NORMAL: 'blue',
WARNING: 'blue',
OFFLINE: 'grey',
ALERTED: 'red',
UNKNOWN: 'black'
},
application: {
header: 'grey'
}
},
constance:{
CEP_WEB_SOCKET_OUTPUT_ADAPTOR_NAME: 'iot.per.device.stream.geo.FusedSpatialEvent',
CEP_ON_ALERT_WEB_SOCKET_OUTPUT_ADAPTOR_NAME: 'org.wso2.geo.AlertsNotifications',
CEP_Traffic_STREAM_WEB_SOCKET_OUTPUT_ADAPTOR_NAME: 'DefaultWebsocketOutputAdaptorOnTrafficStream',
CEP_WEB_SOCKET_OUTPUT_ADAPTOR_WEBAPP_NAME: 'secured-websocket',
TENANT_INDEX: 't',
COLON : ':',
PATH_SEPARATOR : '/',
VERSION: '1.0.0',
SPEED_HISTORY_COUNT: 20,
NOTIFY_INFO_TIMEOUT: 1000,
NOTIFY_SUCCESS_TIMEOUT: 1000,
NOTIFY_WARNING_TIMEOUT: 3000,
NOTIFY_DANGER_TIMEOUT: 5000
},
messages:{
app:{
}
},
leaflet: {
iconUrls: {
//TODO path needs to be changed
normalMovingIcon: '/img/markers/object-types/default/moving/alerted.png',
alertedMovingIcon: '/img/markers/moving/arrow_alerted.png',
offlineMovingIcon: '/img/markers/moving/arrow_offline.png',
warningMovingIcon: '/img/markers/moving/arrow_warning.png',
defaultMovingIcon: '/img/markers/moving/arrow_normal.png',
normalNonMovingIcon: '/img/markers/non_moving/dot_normal.png',
alertedNonMovingIcon: '/img/markers/non_moving/dot_alerted.png',
offlineNonMovingIcon: '/img/markers/non_moving/dot_offline.png',
warningNonMovingIcon: '/img/markers/non_moving/dot_warning.png',
defaultNonMovingIcon: '/img/markers/non_moving/dot_normal.png',
normalPlaceIcon: '/img/markers/places/marker-icon.png',
alertedPlaceIcon: '/img/markers/places/redMarker.png',
offlinePlaceIcon: '/img/markers/places/ashMarker.png',
warningPlaceIcon: '/img/markers/places/pinkMarker.png',
defaultPlaceIcon: '/img/markers/places/marker-icon.png',
defaultIcon: '/img/markers/moving/default_icons/marker-icon.png',
resizeIcon: '/img/markers/resize.png',
stopIcon: '/img/markers/stopIcon.png'
}
}
};

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2013 Masayuki Tanaka
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

@ -0,0 +1,26 @@
Copyright (c) 2010-2014, Michael Bostock
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* The name Michael Bostock may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

@ -0,0 +1,26 @@
/*
* Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
$(function() {
$("#timeFromCal").datepicker({
orientation: 'top'
});
$("#timeToCal").datepicker({
orientation: 'top'
});
});

@ -0,0 +1,48 @@
/*
* Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
function initializeExit() {
$(".removeGeoFence").tooltip();
$("#exit-alert > tbody").empty();
var serverUrl = "/api/device-mgt/v1.0/geo-services/alerts/Exit";
invokerUtil.get(serverUrl, function (response) {
if (response) {
response = JSON.parse(response);
}
if (response && response.length) {
$(".fence-not-exist").hide();
$("#exit-alert").show();
for (var index in response) {
var alertBean = response[index];
$("#exit-alert > tbody").append(
"<tr class='viewGeoFenceRow' style='cursor: pointer' data-areaName='" + alertBean.areaName +
"' data-queryName='" + alertBean.queryName + "'data-geoJson="+ alertBean.geoJson +"><td>" + alertBean.areaName + "</td>" +
"<td>" + alertBean.queryName + "</td><td>" + formatDate(new Date(alertBean.createdTime)) + "</td>" +
"<td onClick=removeGeoFence(this.parentElement,'Exit') class='removeGeoFence'" +
" data-toggle='tooltip' title='Remove fence' ><i class='fa fa-trash-o'></i></td></tr>");
}
} else {
$(".fence-not-exist").show();
$("#exit-alert").hide();
}
$('.viewGeoFenceRow td:not(:last-child)').click(function () {
viewFence(this.parentElement,'Exit');
});
});
}
initializeExit();

@ -0,0 +1,570 @@
/*
* Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
var drawControl;
var speedGraphControl;
var removeAllControl;
var drawnItems;
var lastId;
var controlDiv;
var deleteLayers;
var deleteLayersCount;
loadGeoFencing();
function loadGeoFencing() {
if (map == null) {
setTimeout(loadGeoFencing, 1000); // give everything some time to render
} else {
map.on('draw:created', function (e) {
var type = e.layerType, layer = e.layer;
drawnItems.addLayer(layer);
createPopup(layer,lastId);
});
}
}
function openTools(id) {
lastId = id;
if (drawControl) {
try{
map.removeControl(drawControl);
} catch(e) {
console.log("error: " + e.message);
}
}
if (removeAllControl) {
try {
map.removeControl(removeAllControl);
} catch(e) {
console.log("error: " + e.message);
}
}
if (drawnItems) {
try{
map.removeLayer(drawnItems);
console.log("removing layer");
} catch(e) {
console.log("error: " + e.message);
}
}
closeAll();
noty({text: "Please draw the required area on the map", type: "information"});
L.Control.RemoveAll = L.Control.extend(
{
options: {
position: 'topleft'
},
onAdd: function (map) {
controlDiv = L.DomUtil.create('div', 'leaflet-draw-toolbar leaflet-bar');
L.DomEvent
.addListener(controlDiv, 'click', L.DomEvent.stopPropagation)
.addListener(controlDiv, 'click', L.DomEvent.preventDefault)
.addListener(controlDiv, 'click', function () {
controlDiv.remove();
drawControl.removeFrom(map);
drawnItems.clearLayers();
if(id == "Prediction"){
$('#predictionResults').animate({width: ['toggle','swing']},200);
toggeled = false;
}
});
var controlUI = L.DomUtil.create('a', 'fa fa-times fa-lg drawControlCloseButton', controlDiv);
$(controlUI).css("background-image", "none"); // Remove default control icon
// TODO: bad usage of .hover() use CSS instead
$(controlUI).mouseenter(function () {
$(this).css("color", "red");
}).mouseleave(function () {
$(this).css("color", "black")
});
controlUI.title = 'Close drawer tools';
controlUI.href = '#';
return controlDiv;
}
});
removeAllControl = new L.Control.RemoveAll();
map.addControl(removeAllControl);
// Initialise the FeatureGroup to store editable layers
drawnItems = new L.FeatureGroup();
map.addLayer(drawnItems);
if (id=="WithIn") {
// Initialise the draw control and pass it the FeatureGroup of editable layers
drawControl = new L.Control.Draw({
draw: {
polygon: {
allowIntersection: false, // Restricts shapes to simple polygons
drawError: {
color: '#002bff', // Color the shape will turn when intersects
message: '<strong>Oh snap!<strong> you can\'t draw that!' // Message that will show when intersect
},
shapeOptions: {
color: '#002bff'
}
},
rectangle: {
shapeOptions: {
color: '#002bff'
}
},
polyline: false,
circle: false, // Turns off this drawing tool
marker: false // Markers are not applicable for within geo fencing
},
edit: {
featureGroup: drawnItems
}
});
} else if (id=="Exit") {
// Initialise the draw control and pass it the FeatureGroup of editable layers
drawControl = new L.Control.Draw({
draw: {
polygon: {
allowIntersection: false, // Restricts shapes to simple polygons
drawError: {
color: '#ff0043', // Color the shape will turn when intersects
message: '<strong>Oh snap!<strong> you can\'t draw that!' // Message that will show when intersect
},
shapeOptions: {
color: '#ff0043'
}
},
rectangle: {
shapeOptions: {
color: '#ff0043'
}
},
polyline: false,
circle: false, // Turns off this drawing tool
marker: false // Markers are not applicable for within geo fencing
},
edit: {
featureGroup: drawnItems
}
});
} else if(id=="Stationery"){
// Initialise the draw control and pass it the FeatureGroup of editable layers
drawControl = new L.Control.Draw({
draw: {
polygon: {
allowIntersection: false, // Restricts shapes to simple polygons
drawError: {
color: '#e1e100', // Color the shape will turn when intersects
message: '<strong>Oh snap!<strong> you can\'t draw that!' // Message that will show when intersect
},
shapeOptions: {
color: '#e1e100'
}
},
rectangle: {
shapeOptions: {
color: '#e1e100'
}
},
polyline: false,
circle: {
shapeOptions: {
color: '#e1e100'
}
},
marker: false // Markers are not applicable for within geo fencing
},
edit: {
featureGroup: drawnItems
}
});
} else if (id=="Traffic") {
// Initialise the draw control and pass it the FeatureGroup of editable layers
drawControl = new L.Control.Draw({
draw: {
polygon: {
allowIntersection: false, // Restricts shapes to simple polygons
drawError: {
color: '#e1e100', // Color the shape will turn when intersects
message: '<strong>Oh snap!<strong> you can\'t draw that!' // Message that will show when intersect
},
shapeOptions: {
color: '#ff0043'
}
},
rectangle: {
shapeOptions: {
color: '#002bff'
}
},
polyline: false,
circle: {
shapeOptions: {
color: '#ff0043'
}
},
marker: {
shapeOptions: {
color: '#ff0043'
}
}
},
edit: {
featureGroup: drawnItems
}
});
} else if (id =="Prediction") {
drawControl = new L.Control.Draw({
draw: {
polygon: false,
rectangle: false,
polyline: false,
circle: false,
marker: {
shapeOptions: {
color: '#ff0043'
}
}
},
edit: {
featureGroup: drawnItems
}
});
console.log("prediction tool opened");
}
map.addControl(drawControl);
map.on('draw:created', function (e) {
var type = e.layerType, layer = e.layer;
drawnItems.addLayer(layer);
createPopup(layer,lastId);
});
}
function createPopup(layer,id) {
if (id=="WithIn") {
var popupTemplate = $('#setWithinAlert');
popupTemplate.find('#addWithinAlert').attr('leaflet_id', layer._leaflet_id);
} else if (id=="Exit") {
var popupTemplate = $('#setExitAlert');
popupTemplate.find('#addExitAlert').attr('leaflet_id', layer._leaflet_id);
} else if (id=="Stationery") {
var popupTemplate = $('#setStationeryAlert');
popupTemplate.find('#addStationeryAlert').attr('leaflet_id', layer._leaflet_id);
} else if (id=="Traffic") {
var popupTemplate = $('#setTrafficAlert');
popupTemplate.find('#addTrafficAlert').attr('leaflet_id', layer._leaflet_id);
} else if (id=="Prediction") {
getPrediction(layer._leaflet_id);
return;
}
popupTemplate.find('.exportGeoJson').attr('leaflet_id', layer._leaflet_id);
popupTemplate.find('.editGeoJson').attr('leaflet_id', layer._leaflet_id);
layer.bindPopup(popupTemplate.html(), {closeOnClick: false, closeButton: false}).openPopup();
$(layer._popup._container.childNodes[0]).css("background", "rgba(255,255,255,0.8)");
}
function toggleSpeedGraph() {
if (speedGraphControl) {
try {
map.removeControl(speedGraphControl);
speedGraphControl = null;
} catch (e) {
console.log("error: " + e.message);
}
} else {
speedGraphControl = new L.control.speedChart({'position' : 'topright'});
map.addControl(speedGraphControl);
}
}
function closeTools(leafletId) {
map.removeLayer(map._layers[leafletId]);
map.removeControl(drawControl);
controlDiv.remove();
}
/* Export selected area on the map as a json encoded geoJson standard file, no back-end calls simple HTML5 trick ;) */
function exportToGeoJSON(element, content) {
// HTML5 features has been used here
var geoJsonData = 'data:application/json;charset=utf-8,' + encodeURIComponent(content);
// TODO: replace closest() by using persistence id for templates, template id prefixed by unique id(i.e leaflet_id)
var fileName = $(element).closest('form').attr('area-name') || 'geoJson';
var link = document.createElement("a");
link.download = fileName + '.json'; // Use the fence name given by the user as the file name of the JSON file;
link.href = geoJsonData;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
delete link;
}
$(function () {
$("#importGeoJsonFile").change(function () {
var importedFile = this.files[0];
var reader = new FileReader();
reader.readAsText(importedFile);
reader.onload = function (e) {
$("#enterGeoJson").text(e.target.result.toString());
};
});
});
function importGeoJson() {
var updatedGeoJson;
updatedGeoJson = $('#enterGeoJson').val();
updateDrawing(updatedGeoJson);
}
function updateDrawing(updatedGeoJson) {
updatedGeoJson = JSON.parse(updatedGeoJson);
// Pop the last LatLng pair because according to the geoJSON standard it use complete round LatLng set to store polygon coordinates
updatedGeoJson.geometry.coordinates[0].pop();
var leafletLatLngs = [];
$.each(updatedGeoJson.geometry.coordinates[0], function (idx, pItem) {
leafletLatLngs.push({lat: pItem[1], lng: pItem[0]});
});
var polygon = new L.Polygon(leafletLatLngs);
polygon.editing.enable();
map.addLayer(polygon);
createPopup(polygon);
closeAll();
}
var prevLayers = [];
function clearPrevLayers() {
for(var i =0; i < prevLayers.length; i++) {
var prevLayer = prevLayers[i];
map.removeLayer(prevLayer);
}
prevLayers.length = 0;
}
function viewFence(geoFenceElement,id) {
if (deleteLayers && !deleteLayersCount) {
clearPrevLayers();
deleteLayersCount = true;
deleteLayers = false;
}
var geoJson = $(geoFenceElement).attr('data-geoJson');
var matchResults = /(?:"geoFenceGeoJSON"):"{(.*)}"/g.exec(geoJson);
if (matchResults && matchResults.length > 1) {
geoJson = "{" + matchResults[1] + "}";
}
geoJson = JSON.parse(geoJson.replace(/'/g, '"'));
var queryName = $(geoFenceElement).attr('data-queryName');
var areaName = $(geoFenceElement).attr('data-areaName');
var geometryShape;
var circleOptions = {color: null};
var polygonOptions = {color: null};
if (id == "Exit") {
circleOptions.color = '#ff0043';
polygonOptions.color = '#ff0043';
} else if (id == "WithIn") {
circleOptions.color = '#002bff';
polygonOptions.color = '#002bff';
} else {
circleOptions.color = '#e1e100';
polygonOptions.color = '#e1e100';
}
if (geoJson.type=="Point") {
geometryShape= new L.circle([geoJson.coordinates[1],geoJson.coordinates[0]], geoJson.radius,circleOptions);
map.addLayer(geometryShape);
prevLayers.push(geometryShape);
} else if (geoJson.type=="Polygon") {
geoJson.coordinates[0].pop(); // popout the last coordinate set(lat,lng pair) due to circular chain
var leafletLatLngs = [];
$.each(geoJson.coordinates[0], function (idx, pItem) {
leafletLatLngs.push({lat: pItem[1], lng: pItem[0]});
});
geometryShape = new L.Polygon(leafletLatLngs,polygonOptions);
map.addLayer(geometryShape);
prevLayers.push(geometryShape);
}
var geoPublicUri = $("#geo-charts").data("geo-public-uri");
if (id=="Stationery") {
var stationeryTime=$(geoFenceElement).attr('data-stationeryTime');
$('#templateLoader').load(geoPublicUri + "/assets/html_templates/view_fence_popup.html #viewStationeryAlert", function () {
var popupTemplate = $('#templateLoader').find('#viewStationeryAlert');
popupTemplate.find('#exportGeoJson').attr('leaflet_id', geometryShape._leaflet_id);
popupTemplate.find('#hideViewFence').attr('leaflet_id', geometryShape._leaflet_id);
popupTemplate.find('#viewAreaName').html(areaName);
popupTemplate.find('#stationaryAlertForm').attr('area-name', areaName);
popupTemplate.find('#stationaryAlertForm').attr('query-name', queryName);
popupTemplate.find('#viewAreaTime').html(stationeryTime);
geometryShape.bindPopup(popupTemplate.html(), {closeButton: true}).openPopup();
$(geometryShape._popup._container.childNodes[0]).css("background", "rgba(255,255,255,0.8)");
});
} else if (id=="WithIn") {
$('#templateLoader').load(geoPublicUri + "/assets/html_templates/view_fence_popup.html #viewWithinAlert", function () {
var popupTemplate = $('#templateLoader').find('#viewWithinAlert');
popupTemplate.find('#exportGeoJson').attr('leaflet_id', geometryShape._leaflet_id);
popupTemplate.find('#hideViewFence').attr('leaflet_id', geometryShape._leaflet_id);
popupTemplate.find('#viewAreaName').html(areaName);
popupTemplate.find('#withinAlertForm').attr('area-name', areaName);
popupTemplate.find('#withinAlertForm').attr('query-name', queryName);
geometryShape.bindPopup(popupTemplate.html(), {closeButton: true}).openPopup();
$(geometryShape._popup._container.childNodes[0]).css("background", "rgba(255,255,255,0.8)");
});
} else if (id=="Exit") {
$('#templateLoader').load(geoPublicUri + "/assets/html_templates/view_fence_popup.html #viewExitAlert", function () {
var popupTemplate = $('#templateLoader').find('#viewExitAlert');
popupTemplate.find('#exportGeoJson').attr('leaflet_id', geometryShape._leaflet_id);
popupTemplate.find('#hideViewFence').attr('leaflet_id', geometryShape._leaflet_id);
popupTemplate.find('#viewAreaName').html(areaName);
popupTemplate.find('#exitAlertForm').attr('area-name', areaName);
popupTemplate.find('#exitAlertForm').attr('query-name', queryName);
geometryShape.bindPopup(popupTemplate.html(), {closeButton: true}).openPopup();
$(geometryShape._popup._container.childNodes[0]).css("background", "rgba(255,255,255,0.8)");
});
}
closeAll();
}
// view all defined fence areas of a particular alert type
function viewAll(id) {
deleteLayers = true;
deleteLayersCount = false;
var table = null;
if (id == "Exit") {
table = $("#exit-alert > tbody");
} else if (id == "WithIn") {
table = $("#within-alert > tbody");
} else {
table = $("#stationary-alert-table > tbody");
}
table.find('tr').each(function (i, el) {
viewFence(this,id);
});
}
// View all defined fence areas of all alert types
function viewAllFences() {
deleteLayers = true;
deleteLayersCount = false;
initializeExit();
initializeWithin();
initStationaryAlert();
initializeSpeed();
var table = $("#exit-alert > tbody");
table.find('tr').each(function (i, el) {
viewFence(this,'Exit');
});
table = $("#within-alert > tbody");
table.find('tr').each(function (i, el) {
viewFence(this,'WithIn');
});
table = $("#stationary-alert-table > tbody");
table.find('tr').each(function (i, el) {
viewFence(this,'Stationery');
});
}
function viewFenceByData(geoJson, queryName, areaName, stationeryTime, id) {
var matchResults = /(?:"geoFenceGeoJSON"):"{(.*)}"/g.exec(geoJson);
if (matchResults && matchResults.length > 1) {
geoJson = "{" + matchResults[1] + "}";
}
geoJson = JSON.parse(geoJson.replace(/'/g, '"'));
var geometryShape;
var circleOptions = {color: null};
var polygonOptions = {color: null};
if (id == "Exit") {
circleOptions.color = '#ff0043';
polygonOptions.color = '#ff0043';
} else if (id == "WithIn") {
circleOptions.color = '#002bff';
polygonOptions.color = '#002bff';
} else {
circleOptions.color = '#e1e100';
polygonOptions.color = '#e1e100';
}
if (geoJson.type=="Point") {
geometryShape= new L.circle([geoJson.coordinates[1],geoJson.coordinates[0]], geoJson.radius,circleOptions);
// var marker=new L.marker([geoJson.coordinates[1],geoJson.coordinates[0]]);
map.addLayer(geometryShape);
// map.addLayer(marker);
} else if (geoJson.type=="Polygon") {
geoJson.coordinates[0].pop(); // popout the last coordinate set(lat,lng pair) due to circular chain
var leafletLatLngs = [];
$.each(geoJson.coordinates[0], function (idx, pItem) {
leafletLatLngs.push({lat: pItem[1], lng: pItem[0]});
});
geometryShape = new L.Polygon(leafletLatLngs,polygonOptions);
map.addLayer(geometryShape);
}
var geoPublicUri = $("#geo-charts").data("geo-public-uri");
if (id=="Stationery") {
$('#templateLoader').load(geoPublicUri + "/assets/html_templates/view_fence_popup.html #viewStationeryAlert", function () {
var popupTemplate = $('#templateLoader').find('#viewStationeryAlert');
popupTemplate.find('#exportGeoJson').attr('leaflet_id', geometryShape._leaflet_id);
popupTemplate.find('#hideViewFence').attr('leaflet_id', geometryShape._leaflet_id);
popupTemplate.find('#viewAreaTime').html(stationeryTime);
geometryShape.bindPopup(popupTemplate.html(), {closeButton: true}).openPopup();
// transparent the layer .leaflet-popup-content-wrapper
$(geometryShape._popup._container.childNodes[0]).css("background", "rgba(255,255,255,0.8)");
});
} else if (id=="WithIn") {
$('#templateLoader').load(geoPublicUri + "/assets/html_templates/view_fence_popup.html #viewWithinAlert", function () {
var popupTemplate = $('#templateLoader').find('#viewWithinAlert');
popupTemplate.find('#exportGeoJson').attr('leaflet_id', geometryShape._leaflet_id);
popupTemplate.find('#hideViewFence').attr('leaflet_id', geometryShape._leaflet_id);
popupTemplate.find('#viewAreaName').html(areaName);
popupTemplate.find('#withinAlertForm').attr('area-name', areaName);
popupTemplate.find('#withinAlertForm').attr('query-name', queryName);
geometryShape.bindPopup(popupTemplate.html(), {closeButton: true}).openPopup();
// transparent the layer .leaflet-popup-content-wrapper
$(geometryShape._popup._container.childNodes[0]).css("background", "rgba(255,255,255,0.8)");
});
} else if (id=="Exit") {
$('#templateLoader').load(geoPublicUri + "/assets/html_templates/view_fence_popup.html #viewExitAlert", function () {
var popupTemplate = $('#templateLoader').find('#viewExitAlert');
popupTemplate.find('#exportGeoJson').attr('leaflet_id', geometryShape._leaflet_id);
popupTemplate.find('#hideViewFence').attr('leaflet_id', geometryShape._leaflet_id);
popupTemplate.find('#viewAreaName').html(areaName);
popupTemplate.find('#exitAlertForm').attr('area-name', areaName);
popupTemplate.find('#exitAlertForm').attr('query-name', queryName);
geometryShape.bindPopup(popupTemplate.html(), {closeButton: true}).openPopup();
// transparent the layer .leaflet-popup-content-wrapper
$(geometryShape._popup._container.childNodes[0]).css("background", "rgba(255,255,255,0.8)");
});
}
closeAll();
}

@ -0,0 +1,88 @@
/*
* Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
var centerLocation = new L.LatLng(6.999833130825296, 79.99855044297874);
var resizeIconLocation = new L.LatLng(6.99847, 80.14412);
var proximityMap = L.map("proximityMap", {
zoom: 10,
center: centerLocation,
zoomControl: false,
attributionControl: false,
maxZoom: 20
});
var proximityDistance = $("#proximityDistance");
var serverUrl = "/api/device-mgt/v1.0/geo-services/alerts/Proximity";
invokerUtil.get(serverUrl, function (response) {
response = JSON.parse(response);
proximityDistance.val(response.proximityDistance);
$("#proximityTime").val(response.proximityTime);
});
L.grid({
redraw: 'move'
}).addTo(proximityMap);
proximityMap.scrollWheelZoom.disable();
var marker = L.marker(centerLocation).setIcon(normalMovingIcon);
marker.addTo(proximityMap);
var resizeIcon = L.icon({
iconUrl: ApplicationOptions.leaflet.iconUrls.resizeIcon,
iconAnchor: [24, 24]
});
var resizeMarker = L.marker(resizeIconLocation, {icon: resizeIcon, draggable: 'true'}).addTo(proximityMap);
resizeMarker.on('drag', updateRuler);
var measureLine = new L.Polyline(
[centerLocation, resizeIconLocation ],
{ color: "black", opacity: 0.5, stroke: true });
proximityMap.addLayer(measureLine);
measureLine._path.setAttribute("class", 'measuring-line-for-look');
var options = {
minWidth: 50,
autoPan: false,
closeButton: true, // should the popups have a close option?
displayTotalDistance: true,
displayPartialDistance: false,
className: 'measuring-label-tooltip' /*css label class name*/
};
var initialDistance = centerLocation.distanceTo(resizeIconLocation);
var measureCircle = L.circle(centerLocation, initialDistance).addTo(proximityMap);
function updateRuler(e) {
var target = e.target;
resizeIconLocation = target.getLatLng();
measureLine.setLatLngs([centerLocation, resizeIconLocation]);
setDistancePopup(centerLocation, resizeIconLocation)
}
function setDistancePopup(startLatLng, endLatLng) {
var centerPos = new L.LatLng((startLatLng.lat + endLatLng.lat) / 2,
(startLatLng.lng + endLatLng.lng) / 2),
distance = startLatLng.distanceTo(endLatLng);
proximityDistance.val(distance.toFixed(2));
measureCircle.setRadius(distance);
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
* Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
@ -91,8 +91,498 @@ function getTileServers() {
});
}
function addWmsEndPoint() {
serviceName = $('#serviceName').val();
layers = $('#layers').val();
wmsVersion = $('#wmsVersion').val();
serviceEndPoint = $('#serviceEndPoint').val();
outputFormat = $('#outputFormat').val();
var validated = false;
if (serviceName === undefined || serviceName == "" || serviceName == null) {
var message = "Service Provider name cannot be empty.";
noty({text: '<span style="color: red">' + message + '</span>', type: 'error'});
}
if (validated) {
wmsLayer = L.tileLayer.wms(serviceEndPoint, {
layers: layers.split(','),
format: outputFormat ? outputFormat : 'image/png',
version: wmsVersion,
transparent: true,
opacity: 0.4
});
layerControl.addOverlay(wmsLayer, serviceName, "Web Map Service layers");
map.addLayer(wmsLayer);
var data = {
'serviceName': serviceName,
'layers': layers,
'wmsVersion': wmsVersion,
'serviceEndPoint': serviceEndPoint,
'outputFormat': outputFormat
};
var serverUrl = "/api/controllers/wms_endpoints";
// TODO: If failure happens notify user about the error message
$.post(serverUrl, data, function (response) {
noty({
text: '<span style="color: dodgerblue">' + response + '</span>',
type: 'success'
});
closeAll();
});
}
}
function loadWms() {
// For refference {"wmsServerId" : 1, "serviceUrl" : "http://{s}.somedomain.com/blabla/{z}/{x}/{y}.png", "name" : "Sample server URL", "layers" : "asdsad,sd,adasd,asd", "version" : "1.0.2", "format" : "sadasda/asdas"}
$.getJSON("/api/controllers/wms_endpoints?serverId=all", function (data) {
$.each(data, function (key, val) {
wmsLayer = L.tileLayer.wms(val.SERVICEURL, {
layers: val.LAYERS.split(','),
format: val.FORMAT ? val.FORMAT : 'image/png',
version: val.VERSION,
transparent: true,
opacity: 0.4
});
layerControl.addOverlay(wmsLayer, val.NAME, "Web Map Service layers");
});
});
}
function setSpeedAlert() {
//TODO: get the device Id from the URL
var speedAlertValue = $("#speedAlertValue").val();
if (!speedAlertValue) {
var message = "Speed cannot be empty.";
noty({text: message, type: 'error'});
} else {
data = {
'parseData': JSON.stringify({'speedAlertValue': speedAlertValue, 'deviceId': deviceId}), // parseKey : parseValue pair , this key pair is replace with the key in the template file
'executionPlan': 'Speed',
'customName': null,
'cepAction': 'edit',
'deviceId': deviceId
};
var serviceUrl = '/api/device-mgt/v1.0/geo-services/alerts/Speed';
var responseHandler = function (data, textStatus, xhr) {
closeAll();
if (xhr.status == 200) {
noty({text: 'Successfully added alert', type: 'success'});
} else {
var ptrn = /(?:<am\:description>)(.*)(?:<\/am\:description>)/g;
var result = (ptrn.exec(data));
var errorTxt;
if (result) {
errorTxt = result.length > 1 ? result[1] : data;
} else {
errorTxt = data;
}
noty({text: textStatus + ' : ' + errorTxt, type: 'error'});
}
};
invokerUtil.put(serviceUrl,
data,
responseHandler, function (xhr) {
responseHandler(xhr.responseText, xhr.statusText, xhr);
});
}
}
var lastToolLeafletId = null;
function setWithinAlert(leafletId) {
/*
* TODO: replace double quote to single quote because of a conflict when deploying execution plan in CEP
* this is against JSON standards so has been re-replaced when getting the data from governance registry
* (look in get_alerts for .replace() method)
* */
var selectedAreaGeoJson = JSON.stringify(map._layers[leafletId].toGeoJSON().geometry).replace(/"/g, "'");
var areaName = $("#withinAlertAreaName").val();
var queryName = areaName;
if (areaName == null || areaName === undefined || areaName == "") {
var message = "Area Name cannot be empty.";
noty({text: message, type: 'error'});
} else if ($.trim(areaName).indexOf(" ") > -1) {
var message = "Area Name cannot contain spaces.";
noty({text: message, type: 'error'});
} else {
areaName = $.trim(areaName);
var data = {
'parseData': JSON.stringify({
'geoFenceGeoJSON': selectedAreaGeoJson,
'executionPlanName': createExecutionPlanName(queryName, "WithIn", deviceId),
'areaName': areaName,
'deviceId': deviceId
}),
'executionPlan': 'Within',
'customName': areaName, // TODO: fix , When template copies there can be two queryName and areaName id elements in the DOM
'queryName': queryName,
'cepAction': 'deploy',
'deviceId': deviceId
};
var serviceUrl = '/api/device-mgt/v1.0/geo-services/alerts/Within';
var responseHandler = function (data, textStatus, xhr) {
closeTools(leafletId);
if (xhr.status == 200) {
noty({text: 'Successfully added alert', type: 'success'});
} else {
var ptrn = /(?:<am\:description>)(.*)(?:<\/am\:description>)/g;
var errorTxt;
var result = (ptrn.exec(data));
if (result) {
errorTxt = result.length > 1 ? result[1] : data;
} else {
errorTxt = data;
}
noty({text: textStatus + ' : ' + errorTxt, type: 'error'});
}
};
invokerUtil.post(serviceUrl,
data,
responseHandler, function (xhr) {
responseHandler(xhr.responseText, xhr.statusText, xhr);
});
viewFenceByData(selectedAreaGeoJson, queryName, areaName, null, 'WithIn');
}
}
function setExitAlert(leafletId) {
/*
* TODO: replace double quote to single quote because of a conflict when deploying execution plan in CEP
* this is against JSON standards so has been re-replaced when getting the data from governance registry
* (look in get_alerts for .replace() method)
* */
var selectedAreaGeoJson = JSON.stringify(map._layers[leafletId].toGeoJSON().geometry).replace(/"/g, "'");
var areaName = $("#exitAlertAreaName").val();
var queryName = areaName;
if (areaName == null || areaName === undefined || areaName == "") {
var message = "Area Name cannot be empty.";
noty({text: message, type: 'error'});
} else if ($.trim(areaName).indexOf(" ") > -1) {
var message = "Area Name cannot contain spaces.";
noty({text: message, type: 'error'});
} else {
areaName = $.trim(areaName);
var data = {
'parseData': JSON.stringify({
'geoFenceGeoJSON': selectedAreaGeoJson,
'executionPlanName': createExecutionPlanName(queryName, "Exit", deviceId),
'areaName': areaName,
'deviceId': deviceId
}),
'executionPlan': 'Exit',
'customName': areaName, // TODO: fix , When template copies there can be two queryName and areaName id elements in the DOM
'queryName': queryName,
'cepAction': 'deploy',
'deviceId': deviceId
};
var serviceUrl = '/api/device-mgt/v1.0/geo-services/alerts/Exit';
var responseHandler = function (data, textStatus, xhr) {
closeTools(leafletId);
if (xhr.status == 200) {
noty({text: 'Successfully added alert', type: 'success'});
} else {
var ptrn = /(?:<am\:description>)(.*)(?:<\/am\:description>)/g;
var errorTxt;
var result = (ptrn.exec(data));
if (result) {
errorTxt = result.length > 1 ? result[1] : data;
} else {
errorTxt = data;
}
noty({text: textStatus + ' : ' + errorTxt, type: 'error'});
}
};
invokerUtil.post(serviceUrl,
data,
responseHandler, function (xhr) {
responseHandler(xhr.responseText, xhr.statusText, xhr);
});
viewFenceByData(selectedAreaGeoJson, queryName, areaName, null, 'Exit');
}
}
function setStationeryAlert(leafletId) {
var selectedAreaGeoJson = map._layers[leafletId].toGeoJSON().geometry;
//if a circle is drawn adding radius for the object
if (selectedAreaGeoJson.type == "Point") {
var radius = map._layers[leafletId]._mRadius;
selectedAreaGeoJson["radius"] = radius;
}
var selectedProcessedAreaGeoJson = JSON.stringify(selectedAreaGeoJson).replace(/"/g, "'");
var stationeryName = $("#stationaryAlertAreaName").val();
var queryName = stationeryName;
var fluctuationRadius = $("#fRadius").val();
var time = $("#time").val();
if (stationeryName == null || stationeryName === undefined || stationeryName == "") {
var message = "Stationery Name cannot be empty.";
noty({text: message, type: 'error'});
} else if ($.trim(stationeryName).indexOf(" ") > -1) {
var message = "Stationery Name cannot contain spaces.";
noty({text: message, type: 'error'});
} else if (fluctuationRadius == null || fluctuationRadius === undefined || fluctuationRadius == "") {
var message = "Fluctuation Radius cannot be empty.";
noty({text: message, type: 'error'});
} else if (time == null || time === undefined || time == "") {
var message = "Time cannot be empty.";
noty({text: message, type: 'error'});
} else {
stationeryName = $.trim(stationeryName);
var data = {
'parseData': JSON.stringify({
'geoFenceGeoJSON': selectedProcessedAreaGeoJson,
'executionPlanName': createExecutionPlanName(queryName, "Stationery", deviceId),
'stationeryName': stationeryName,
'stationeryTime': time,
'fluctuationRadius': fluctuationRadius
}),
'stationeryTime': time,
'fluctuationRadius': fluctuationRadius,
'executionPlan': 'Stationery',
'customName': stationeryName, // TODO: fix , When template copies there can be two queryName and areaName id elements in the DOM
'queryName': queryName,
'cepAction': 'deploy',
'deviceId': deviceId
};
var serviceUrl = '/api/device-mgt/v1.0/geo-services/alerts/Stationery';
var responseHandler = function (data, textStatus, xhr) {
closeTools(leafletId);
if (xhr.status == 200) {
noty({text: 'Successfully added alert', type: 'success'});
} else {
var ptrn = /(?:<am\:description>)(.*)(?:<\/am\:description>)/g;
var errorTxt;
var result = (ptrn.exec(data));
if (result) {
errorTxt = result.length > 1 ? result[1] : data;
} else {
errorTxt = data;
}
noty({text: textStatus + ' : ' + errorTxt, type: 'error'});
}
};
invokerUtil.post(serviceUrl,
data,
responseHandler, function (xhr) {
responseHandler(xhr.responseText, xhr.statusText, xhr);
});
viewFenceByData(selectedProcessedAreaGeoJson, queryName, stationeryName, time, 'Stationery');
}
}
var toggeled = false;
function setTrafficAlert(leafletId) {
/*
* TODO: replace double quote to single quote because of a conflict when deploying execution plan in CEP
* this is against JSON standards so has been re-replaced when getting the data from governance registry
* (look in get_alerts for .replace() method)
* */
var selectedAreaGeoJson = map._layers[leafletId].toGeoJSON().geometry;
//if a circle is drawn adding radius for the object
if (selectedAreaGeoJson.type == "Point") {
var radius = map._layers[leafletId]._mRadius;
selectedAreaGeoJson["radius"] = radius;
}
var selectedProcessedAreaGeoJson = JSON.stringify(selectedAreaGeoJson).replace(/"/g, "'");
var areaName = $("#trafficAlertAreaName").val();
var queryName = areaName;
//var time = $("#time").val();
if (areaName == null || areaName === undefined || areaName == "") {
var message = "Area Name cannot be empty.";
noty({text: message, type: 'error'});
} else if ($.trim(areaName).indexOf(" ") > -1) {
var message = "Area Name cannot contain spaces.";
noty({text: message, type: 'error'});
} else {
areaName = $.trim(areaName);
var data = {
'parseData': JSON.stringify({
'geoFenceGeoJSON': selectedProcessedAreaGeoJson,
'executionPlanName': createExecutionPlanName(queryName, "Traffic", deviceId),
'areaName': areaName
}),
'executionPlan': 'Traffic',
'customName': areaName, // TODO: fix , When template copies there can be two queryName and areaName id elements in the DOM
'queryName': queryName,
'cepAction': 'deploy',
'deviceId': deviceId
};
var serviceUrl = '/api/device-mgt/v1.0/geo-services/alerts/Traffic';
var responseHandler = function (data, textStatus, xhr) {
closeTools(leafletId);
if (xhr.status == 200) {
noty({text: 'Successfully added alert', type: 'success'});
} else {
var ptrn = /(?:<am\:description>)(.*)(?:<\/am\:description>)/g;
var errorTxt;
var result = (ptrn.exec(data));
if (result) {
errorTxt = result.length > 1 ? result[1] : data;
} else {
errorTxt = data;
}
noty({text: textStatus + ' : ' + errorTxt, type: 'error'});
}
};
invokerUtil.post(serviceUrl,
data,
responseHandler, function (xhr) {
responseHandler(xhr.responseText, xhr.statusText, xhr);
});
}
}
function removeGeoFence(geoFenceElement, id) {
var queryName = $(geoFenceElement).attr('data-queryName');
var areaName = $(geoFenceElement).attr('data-areaName');
var serviceUrl = '/api/device-mgt/v1.0/geo-services/alerts/' + id + '?queryName='
+ queryName;
invokerUtil.delete(serviceUrl, function (response) {
noty({
text: 'Successfully removed ' + id + ' alert',
type: 'success'
});
closeAll();
},
function (xhr) {
noty({
text: 'Could not remove ' + id + ' alert',
type: 'error'
})
});
}
function getAlertsHistory(timeFrom, timeTo) {
var timeRange = '';
if (timeFrom && timeTo) {
timeRange = '?from=' + timeFrom + '&to=' + timeTo;
}
var serviceUrl = '/api/device-mgt/v1.0/geo-services/alerts/history' + timeRange;
invokerUtil.get(serviceUrl,
function (data) {
geoAlertsBar.clearAllAlerts();
var alerts = JSON.parse(data);
$.each(alerts, function (key, val) {
if (val.values) {
val = val.values;
}
var msg = val.information.replace("Alerts: ,", "").charAt(0).toUpperCase() +
val.information.replace("Alerts: ,", "").slice(1) + " - " + timeSince(val.timeStamp);
switch (val.state) {
case "NORMAL":
return;
case "WARNING":
geoAlertsBar.addAlert('warn', msg, val);
break;
case "ALERTED":
geoAlertsBar.addAlert('danger', msg, val);
break;
case "OFFLINE":
geoAlertsBar.addAlert('info', msg, val);
break;
}
});
}, function (message) {
});
}
function setProximityAlert() {
var proximityDistance = $("#proximityDistance").val();
var proximityTime = $("#proximityTime").val();
if (proximityDistance == null || proximityDistance === undefined || proximityDistance == "") {
var message = "Proximity distance cannot be empty.";
noty({text: message, type: 'error'});
} else if (proximityTime == null || proximityTime === undefined || proximityTime == "") {
var message = "Proximity Time cannot be empty.";
noty({text: message, type: 'error'});
} else {
var data = {
'parseData': JSON.stringify({
'proximityTime': proximityTime,
'proximityDistance': proximityDistance
}),
'proximityTime': proximityTime,
'proximityDistance': proximityDistance,
'executionPlan': 'Proximity',
'customName': null,
'cepAction': 'edit',
'deviceId': deviceId
};
var serviceUrl = '/api/device-mgt/v1.0/geo-services/alerts/Proximity';
var responseHandler = function (data, textStatus, xhr) {
closeAll();
if (xhr.status == 200) {
noty({text: 'Successfully added alert', type: 'success'});
} else {
var ptrn = /(?:<am\:description>)(.*)(?:<\/am\:description>)/g;
var errorTxt;
var result = (ptrn.exec(data));
if (result) {
errorTxt = result.length > 1 ? result[1] : data;
} else {
errorTxt = data;
}
noty({text: textStatus + ' : ' + errorTxt, type: 'error'});
}
};
invokerUtil.put(serviceUrl,
data,
responseHandler, function (xhr) {
responseHandler(xhr.responseText, xhr.statusText, xhr);
});
}
}
// TODO:this is not a remote call , move this to application.js
function createExecutionPlanName(queryName, id) {
if (id == "WithIn") {
return 'Geo-ExecutionPlan-Within' + (queryName ? '_' + queryName : '') + "---" + '_alert'; // TODO: value of the `queryName` can't be empty, because it will cause name conflicts in CEP, have to do validation(check not empty String)
} else if (id == "Exit") {
return 'Geo-ExecutionPlan-Exit' + (queryName ? '_' + queryName : '') + "---" + '_alert'; // TODO: value of the `queryName` can't be empty, because it will cause name conflicts in CEP, have to do validation(check not empty String)
} else if (id == "Stationery") {
return 'Geo-ExecutionPlan-Stationery' + (queryName ? '_' + queryName : '') + "---" + '_alert'; // TODO: value of the `queryName` can't be empty, because it will cause name conflicts in CEP, have to do validation(check not empty String)
} else if (id == "Traffic") {
return 'Geo-ExecutionPlan-Traffic' + (queryName ? '_' + queryName : '') + '_alert'; // TODO: value of the `queryName` can't be empty, because it will cause name conflicts in CEP, have to do validation(check not empty String)
}
}
// TODO:this is not a remote call , move this to application.js
function closeAll() {

@ -0,0 +1,29 @@
/*
* Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
function initializeSpeed() {
var serverUrl = "/api/device-mgt/v1.0/geo-services/alerts/Speed";
// var serverUrl = "/portal/store/carbon.super/fs/gadget/geo-dashboard/controllers/get_alerts.jag?executionPlanType=Speed&deviceId=" + deviceId;
invokerUtil.get(serverUrl, function (response) {
response = JSON.parse(response);
if (response) {
$("#speedAlertValue").val(response.speedLimit);
}
});
}
initializeSpeed();

@ -0,0 +1,52 @@
/*
* Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
function initStationaryAlert() {
// var serverUrl = "/portal/store/carbon.super/fs/gadget/geo-dashboard/controllers/get_alerts.jag?executionPlanType=Stationery&deviceId=" + deviceId;
var serverUrl = "/api/device-mgt/v1.0/geo-services/alerts/Stationery";
$(".removeGeoFence").tooltip();
$("#stationary-alert-table > tbody").empty();
invokerUtil.get(serverUrl, function (response) {
if (response) {
response = JSON.parse(response);
}
if (response && response.length) {
$(".fence-not-exist").hide();
$("#stationary-alert-table").show();
for (var index in response) {
var alert = response[index];
$("#stationary-alert-table > tbody").append(
"<tr class='viewGeoFenceRow'style='cursor: pointer' data-stationeryTime='" + alert.stationaryTime +
"'data-fluctuationRadius='" + alert.fluctuationRadius + "'data-areaName='" + alert.areaName +
"'data-queryName='" + alert.queryName + "'data-geoJson=" + alert.geoJson + ">" +
"<td>" + alert.areaName + "</td><td>" + alert.stationaryTime + "</td><td>" + alert.fluctuationRadius +
"<td>" + alert.queryName + "</td><td>" + formatDate(new Date(alert.createdTime)) + "</td><td" +
" onClick=removeGeoFence(this.parentElement,'Stationery') data-toggle=" +
" 'tooltip' title='Remove fence' ><i class='fa fa-trash-o'></i></td></tr>")
}
} else {
$(".fence-not-exist").show();
$("#stationary-alert-table").hide();
}
$('.viewGeoFenceRow td:not(:last-child)').click(function () {
viewFence(this.parentElement,'Stationery');
});
});
}
initStationaryAlert();

@ -0,0 +1,48 @@
/*
* Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
function initializeWithin() {
$(".removeGeoFence").tooltip();
$("#within-alert > tbody").empty();
var serverUrl = "/api/device-mgt/v1.0/geo-services/alerts/Within";
invokerUtil.get(serverUrl, function (response) {
if (response) {
response = JSON.parse(response);
}
if (response && response.length) {
$(".fence-not-exist").hide();
$("#within-alert").show();
for (var index in response) {
var alertBean = response[index];
$("#within-alert > tbody").append(
"<tr class='viewGeoFenceRow' style='cursor: pointer' data-areaName='" + alertBean.areaName +
"' data-queryName='" + alertBean.queryName + "'data-geoJson="+ alertBean.geoJson +"><td>" + alertBean.areaName + "</td>" +
"<td>" + alertBean.queryName + "</td><td>" + formatDate(new Date(alertBean.createdTime)) + "</td>" +
"<td onClick=removeGeoFence(this.parentElement,'Within') class='removeGeoFence'" +
" data-toggle='tooltip' title='Remove fence' ><i class='fa fa-trash-o'></i></td></tr>");
}
} else{
$(".fence-not-exist").show();
$("#within-alert").hide();
}
$('.viewGeoFenceRow td:not(:last-child)').click(function () {
viewFence(this.parentElement,'WithIn');
});
});
}
initializeWithin();

@ -0,0 +1,27 @@
/*
* Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
function reformatRadius(val){
if(val != "" && !isNaN(val)){
$("#fRadius" ).val(parseFloat(Math.round(val * 100) / 100).toFixed(2));
} else{
var message = "Invalid Fluctuation Radius Provided.";
noty({text: message, type: 'error'});
}
}

@ -0,0 +1,42 @@
/*
* Copyright (c) 2005-2010, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
function showAlertInMap(alertData) {
clearFocus();
var id = $(alertData).attr("data-id");
var latitude = $(alertData).attr("data-latitude");
var longitude = $(alertData).attr("data-longitude");
var state = $(alertData).attr("data-state");
var information = $(alertData).attr("data-information");
var alertLatLngPoint = L.latLng(latitude,longitude);
var alertOccouredArea = L.circle(alertLatLngPoint, 10, {
color: '#FF9900',
fillColor: '#FF00FF',
fillOpacity: 0.5
}).addTo(map);
alertOccouredArea.bindPopup("Id: <b>"+id+"</b><br>"+
"State: <b>"+state+"</b><br>"+
"Information: <b>"+information+"</b><br>"
).openPopup();
$(alertOccouredArea._popup._closeButton).on("click",function(){map.removeLayer(alertOccouredArea)});
map.setView(alertLatLngPoint,18);
/* TODO: for reference <Update lib or remove if not in use>: This `R`(RaphaelLayer: https://github.com/dynmeth/RaphaelLayer) library is dam buggy can't use it reliably */
}

@ -0,0 +1,277 @@
/*
* Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
var debugObject; // assign object and debug from browser console, this is for debugging purpose , unless this var is unused
var showPathFlag = false; // Flag to hold the status of draw objects path
var currentSpatialObjects = {};
var selectedSpatialObject; // This is set when user search for an object from the search box
var spatialWebsocket;
var onAlertWebsocket;
var onTrafficStreamWebsocket;
var currentPredictions = {};
// Make the function wait until the connection is made...
var waitTime = 1000;
var webSocketURL, alertWebSocketURL, trafficStreamWebSocketURL;
var deviceId;
var deviceType;
var isBatchModeOn = false;
var wsToken;
var geoPublicUri;
var initLoading = true;
function processPointMessage(geoJsonFeature) {
if (geoJsonFeature.id in currentSpatialObjects) {
var excitingObject = currentSpatialObjects[geoJsonFeature.id];
excitingObject.update(geoJsonFeature);
}
else {
var receivedObject = new SpatialObject(geoJsonFeature);
receivedObject.update(geoJsonFeature);
currentSpatialObjects[receivedObject.id] = receivedObject;
currentSpatialObjects[receivedObject.id].addTo(map);
}
}
window.onbeforeunload = function () {
disconnect();
};
function initializeSpatialStreamWebSocket() {
spatialWebsocket = new WebSocket(webSocketURL);
spatialWebsocket.onopen = webSocketSpatialOnOpen;
spatialWebsocket.onmessage = webSocketSpatialOnMessage;
spatialWebsocket.onclose = webSocketSpatialOnClose;
spatialWebsocket.onerror = webSocketSpatialOnError;
}
function initializeOnAlertWebSocket() {
onAlertWebsocket = new WebSocket(alertWebSocketURL);
onAlertWebsocket.onmessage = webSocketOnAlertMessage;
onAlertWebsocket.onclose = webSocketOnAlertClose;
onAlertWebsocket.onerror = webSocketOnAlertError;
onAlertWebsocket.onopen = webSocketOnAlertOpen;
}
function initializeGeoLocation(geoFencingEnabled) {
if (true) {
var geoCharts = $("#geo-charts");
var wsEndPoint = geoCharts.data("ws-endpoint");
wsToken = geoCharts.data("ws-token");
geoPublicUri = geoCharts.data("geo-public-uri");
geoPublicUri = geoCharts.data("geo-public-uri");
webSocketURL = wsEndPoint + "iot.per.device.stream.geo.FusedSpatialEvent/1.0.0?" + "&websocketToken=" + wsToken;
alertWebSocketURL = wsEndPoint + "iot.per.device.stream.geo.AlertsNotifications/1.0.0?" + "&websocketToken=" + wsToken;
$("#proximity_alert").hide();
if (geoFencingEnabled) {
disconnect();
initializeSpatialStreamWebSocket();
initializeOnAlertWebSocket();
}
initialLoad(geoFencingEnabled);
} else {
noty({text: 'Invalid Access! No device information provided to track!', type: 'error'});
}
}
function disconnect(){
if (spatialWebsocket && spatialWebsocket.readyState == spatialWebsocket.OPEN){
spatialWebsocket.close();
}
if (onAlertWebsocket && onAlertWebsocket.readyState == onAlertWebsocket.OPEN){
onAlertWebsocket.close();
}
}
function popupDateRange() {
$('#dateRangePopup').attr('title', 'Device ID - ' + deviceId + " Device Type - " + deviceType).dialog();
}
var headings = ["North", "NorthEast", "East", "SouthEast", "South", "SouthWest", "West", "NorthWest"];
function angleToHeading(angle) {
var angle = (angle + 360 + 22.5 ) % 360;
angle = Math.floor(angle / 45);
return headings[angle];
}
function processTrafficMessage(json) {
if (json.id in currentSpatialObjects) {
var existingObject = currentSpatialObjects[json.id];
existingObject.update(json);
}
else {
var receivedObject = new GeoAreaObject(json);
currentSpatialObjects[json.id] = receivedObject;
currentSpatialObjects[json.id].addTo(map);
}
}
function processAlertMessage(json) {
if (json.state != "NORMAL" && json.state != "MINIMAL") {
notifyAlert("Object ID: <span style='color: blue;cursor: pointer' onclick='focusOnSpatialObject(" + json.id + ")'>" + json.id + "</span> change state to: <span style='color: red'>" + json.state + "</span> Info : " + json.information);
}
}
function processPredictionMessage(json) {
setPropertySafe(currentPredictions, json.day, json.hour, json.longitude, json.latitude, json.traffic - 1);
}
WebSocket.prototype.set_opened = function () {
this._opened = true;
};
WebSocket.prototype.get_opened = function () {
return this._opened || false;
};
function GeoAreaObject(json) {
this.id = json.id;
this.type = "area";
var myStyle = {
"color": "#000001",
"weight": 5,
"opacity": 0,
"fillOpacity": 0.75
};
switch (json.properties.state) {
case "Moderate":
myStyle["color"] = "#ffb13b";
break;
case "Severe":
myStyle["color"] = "#ff3f3f";
break;
case "Minimal":
return null;
}
this.geoJson = L.geoJson(json, {style: myStyle});
this.marker = this.geoJson.getLayers()[0];
this.marker.options.title = this.id;
this.popupTemplate = $('#areaPopup');
this.popupTemplate.find('#objectId').html(this.id);
this.popupTemplate.find('#severity').html(json.properties.state);
this.popupTemplate.find('#information').html(json.properties.information);
this.marker.bindPopup(this.popupTemplate.html());
return this;
}
GeoAreaObject.prototype.addTo = function (map) {
this.geoJson.addTo(map);
};
GeoAreaObject.prototype.focusOn = function (map) {
map.fitBounds(this.geoJson);
};
GeoAreaObject.prototype.removeFromMap = function () {
map.removeLayer(this.geoJson);
};
GeoAreaObject.prototype.update = function (geoJSON) {
this.information = geoJSON.properties.information;
this.type = geoJSON.properties.type;
// Update the spatial object leaflet marker
this.marker.setLatLng([this.latitude, this.longitude]);
this.marker.setIconAngle(this.heading);
this.marker.setIcon(this.stateIcon());
// TODO: use general popup DOM
this.popupTemplate.find('#objectId').html(this.id);
this.popupTemplate.find('#information').html(this.information);
this.marker.setPopupContent(this.popupTemplate.html())
};
function notifyAlert(message) {
noty({text: "Alert: " + message, type: 'warning'});
}
function Alert(type, message, level) {
this.type = type;
this.message = message;
if (level)
this.level = level;
else
this.level = 'information';
this.notify = function () {
noty({text: this.type + ' ' + this.message, type: level});
}
}
var webSocketOnAlertOpen = function () {
$('#ws-alert-stream').removeClass('text-muted text-danger text-success').addClass('text-success');
};
var webSocketOnAlertMessage = function processMessage(message) {
if (!isBatchModeOn) {
var json = $.parseJSON(message.data);
if (json.messageType == "Alert") {
processAlertMessage(json);
}else {
console.log("Message type not supported.");
}
}
};
var webSocketOnAlertClose = function (e) {
};
var webSocketOnAlertError = function (e) {
var wsURL = alertWebSocketURL;
wsURL = wsURL.replace("wss://","https://");
var uriParts = wsURL.split("/");
wsURL = uriParts[0] + "//" + uriParts[2];
noty({text: 'Something went wrong when trying to connect to <b>' + wsURL + '<b/>', type: 'error'});
};
var webSocketSpatialOnOpen = function () {
if (initLoading) {
initLoading = false;
}
$('#ws-spatial-stream').removeClass('text-muted text-danger text-success').addClass('text-success');
};
var webSocketSpatialOnMessage = function (message) {
if (!isBatchModeOn) {
var json = $.parseJSON(message.data);
if (json.messageType == "Point") {
processPointMessage(json);
} else if (json.messageType == "Prediction") {
//processPredictionMessage(json);
}
}
};
var webSocketSpatialOnClose = function (e) {
};
var webSocketSpatialOnError = function (err) {
var wsURL = webSocketURL;
wsURL = wsURL.replace("wss://","https://");
var uriParts = wsURL.split("/");
wsURL = uriParts[0] + "//" + uriParts[2];
noty({text: 'Something went wrong when trying to connect to <b>' + wsURL + '<b/>', type: 'error'});
};

@ -120,6 +120,13 @@
Certificate Configurations
</a>
</li>
{{#if iosPluginFlag}}
<li>
<a href="{{@app.context}}/dep/devices"><i class="fw fw-apple"></i>
DEP Configurations
</a>
</li>
{{/if}}
</ul>
</li>

@ -28,6 +28,7 @@ function onRequest(context) {
}
});
var userModule = require("/app/modules/business-controllers/user.js")["userModule"];
var deviceModule = require("/app/modules/business-controllers/device.js")["deviceModule"];
var mdmProps = require("/app/modules/conf-reader/main.js")["conf"];
var constants = require("/app/modules/constants.js");
var uiPermissions = userModule.getUIPermissions();
@ -41,6 +42,17 @@ function onRequest(context) {
"device-mgt": []
};
var typesListResponse = deviceModule.getDeviceTypesConfig();
var temp = [];
temp = typesListResponse["content"];
var iosPluginFlag = false;
temp.forEach(function(element) {
if (element["name"] == "ios") {
iosPluginFlag = true;
}
});
context["iosPluginFlag"] = iosPluginFlag;
// following context.link value comes here based on the value passed at the point
// where units are attached to a page zone.
// eg: {{unit "appbar" pageLink="users" title="User Management"}}

@ -6998,6 +6998,7 @@ header.header-default {
.tooltip-overflow-fix {
overflow: visible !important;
}
.editable-input select {
height: 35px !important;

@ -23,7 +23,7 @@
<parent>
<artifactId>device-mgt</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

@ -22,7 +22,7 @@
<parent>
<artifactId>device-mgt</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

@ -185,6 +185,33 @@ public class GeoLocationBasedServiceImpl implements GeoLocationBasedService {
}
}
@Path("alerts/{alertType}")
@POST
@Consumes("application/json")
@Produces("application/json")
public Response createGeoAlertsForGeoClusters(Alert alert, @PathParam("alertType") String alertType) {
try {
// this is the user who initiates the request
String authorizedUser = MultitenantUtils.getTenantAwareUsername(
CarbonContext.getThreadLocalCarbonContext().getUsername()
);
GeoLocationProviderService geoService = DeviceMgtAPIUtils.getGeoService();
geoService.createGeoAlert(alert, alertType);
return Response.ok().build();
} catch (GeoLocationBasedServiceException e) {
String error = "Error occurred while creating " + alertType + " alert";
log.error(error, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(error).build();
} catch (AlertAlreadyExistException e) {
String error = "A geo alert with this name already exists.";
log.error(error,e);
return Response.status(Response.Status.BAD_REQUEST).entity(error).build();
}
}
@Path("alerts/{alertType}/{deviceType}/{deviceId}")
@PUT
@Consumes("application/json")
@ -222,6 +249,31 @@ public class GeoLocationBasedServiceImpl implements GeoLocationBasedService {
}
}
@Path("alerts/{alertType}")
@PUT
@Consumes("application/json")
@Produces("application/json")
public Response updateGeoAlertsForGeoClusters(Alert alert, @PathParam("alertType") String alertType) {
try {
// this is the user who initiates the request
String authorizedUser = MultitenantUtils.getTenantAwareUsername(
CarbonContext.getThreadLocalCarbonContext().getUsername()
);
GeoLocationProviderService geoService = DeviceMgtAPIUtils.getGeoService();
geoService.updateGeoAlert(alert, alertType);
return Response.ok().build();
} catch (GeoLocationBasedServiceException e) {
String error = "Error occurred while updating the geo alert for geo clusters";
log.error(error, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(error).build();
} catch (AlertAlreadyExistException e) {
String error = "A geo alert with this name already exists.";
log.error(error,e);
return Response.status(Response.Status.BAD_REQUEST).entity(error).build();
}
}
@Path("alerts/{alertType}/{deviceType}/{deviceId}")
@DELETE
@Consumes("application/json")
@ -256,6 +308,27 @@ public class GeoLocationBasedServiceImpl implements GeoLocationBasedService {
}
}
@Path("alerts/{alertType}")
@DELETE
@Consumes("application/json")
@Produces("application/json")
public Response removeGeoAlertsForGeoClusters(@PathParam("alertType") String alertType, @QueryParam("queryName") String queryName) {
try {
// this is the user who initiates the request
String authorizedUser = MultitenantUtils.getTenantAwareUsername(
CarbonContext.getThreadLocalCarbonContext().getUsername()
);
GeoLocationProviderService geoService = DeviceMgtAPIUtils.getGeoService();
geoService.removeGeoAlert(alertType, queryName);
return Response.ok().build();
} catch (GeoLocationBasedServiceException e) {
String error = "Error occurred while removing the geo alert for geo clusters";
log.error(error, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(error).build();
}
}
@Path("alerts/{alertType}/{deviceType}/{deviceId}")
@GET
@Consumes("application/json")
@ -308,6 +381,47 @@ public class GeoLocationBasedServiceImpl implements GeoLocationBasedService {
}
}
@Path("alerts/{alertType}")
@GET
@Consumes("application/json")
@Produces("application/json")
public Response getGeoAlertsForGeoClusters(@PathParam("alertType") String alertType) {
try {
// this is the user who initiates the request
String authorizedUser = MultitenantUtils.getTenantAwareUsername(
CarbonContext.getThreadLocalCarbonContext().getUsername()
);
GeoLocationProviderService geoService = DeviceMgtAPIUtils.getGeoService();
if (GeoServices.ALERT_TYPE_WITHIN.equals(alertType)) {
List<GeoFence> alerts = geoService.getWithinAlerts();
return Response.ok().entity(alerts).build();
} else if (GeoServices.ALERT_TYPE_EXIT.equals(alertType)) {
List<GeoFence> alerts = geoService.getExitAlerts();
return Response.ok().entity(alerts).build();
} else if (GeoServices.ALERT_TYPE_SPEED.equals(alertType)) {
String result = geoService.getSpeedAlerts();
return Response.ok().entity(result).build();
} else if (GeoServices.ALERT_TYPE_PROXIMITY.equals(alertType)) {
String result = geoService.getProximityAlerts();
return Response.ok().entity(result).build();
} else if (GeoServices.ALERT_TYPE_STATIONARY.equals(alertType)) {
List<GeoFence> alerts = geoService.getStationaryAlerts();
return Response.ok().entity(alerts).build();
} else if (GeoServices.ALERT_TYPE_TRAFFIC.equals(alertType)) {
List<GeoFence> alerts = geoService.getTrafficAlerts();
return Response.ok().entity(alerts).build();
}
return null;
} catch (GeoLocationBasedServiceException e) {
String error = "Error occurred while getting the geo alerts for " + alertType + " alert";
log.error(error, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(error).build();
}
}
@Path("alerts/history/{deviceType}/{deviceId}")
@GET
@Consumes("application/json")
@ -358,6 +472,49 @@ public class GeoLocationBasedServiceImpl implements GeoLocationBasedService {
}
}
@Path("alerts/history")
@GET
@Consumes("application/json")
@Produces("application/json")
public Response getGeoAlertsHistoryForGeoClusters(@QueryParam("from") long from, @QueryParam("to") long to) {
String tableName = "IOT_PER_DEVICE_STREAM_GEO_ALERTNOTIFICATIONS";
String fromDate = String.valueOf(from);
String toDate = String.valueOf(to);
String query = "";
if (from != 0 || to != 0) {
query = "timeStamp : [" + fromDate + " TO " + toDate + "]";
}
try {
List<SortByField> sortByFields = new ArrayList<>();
SortByField sortByField = new SortByField("timeStamp", SortType.ASC);
sortByFields.add(sortByField);
// this is the user who initiates the request
String authorizedUser = MultitenantUtils.getTenantAwareUsername(
CarbonContext.getThreadLocalCarbonContext().getUsername());
try {
String tenantDomain = MultitenantUtils.getTenantDomain(authorizedUser);
int tenantId = DeviceMgtAPIUtils.getRealmService().getTenantManager().getTenantId(tenantDomain);
AnalyticsDataAPI analyticsDataAPI = DeviceMgtAPIUtils.getAnalyticsDataAPI();
List<SearchResultEntry> searchResults = analyticsDataAPI.search(tenantId, tableName, query,
0,
100,
sortByFields);
List<Event> events = getEventBeans(analyticsDataAPI, tenantId, tableName, new ArrayList<String>(),
searchResults);
return Response.ok().entity(events).build();
} catch (AnalyticsException | UserStoreException e) {
log.error("Failed to perform search on table: " + tableName + " : " + e.getMessage(), e);
throw DeviceMgtUtil.buildBadRequestException(
Constants.ErrorMessages.STATUS_BAD_REQUEST_MESSAGE_DEFAULT);
}
} catch (Exception e) {
log.error(e.getMessage());
return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build();
}
}
private List<Event> getEventBeans(AnalyticsDataAPI analyticsDataAPI, int tenantId, String tableName,
List<String> columns,
List<SearchResultEntry> searchResults) throws AnalyticsException {

@ -65,10 +65,10 @@ public class GeoLocationBasedServiceImplTest {
List<GeoCluster> geoClusters = new ArrayList<>();
geoClusters.add(new GeoCluster(new GeoCoordinate(1.5, 80.7),
new GeoCoordinate(1.1, 79.5), new GeoCoordinate(1.9, 82.1), 3,
"tb32", "aegtew234", "android"));
"tb32", "aegtew234", "android", "1234"));
geoClusters.add(new GeoCluster(new GeoCoordinate(10.2, 86.1),
new GeoCoordinate(9.8, 84.7), new GeoCoordinate(11.1, 88.1), 4,
"t1gd", "swerty12s", "android"));
"t1gd", "swerty12s", "android", "1234"));
Mockito.doReturn(geoClusters).when(deviceManagementProviderService)
.findGeoClusters(Mockito.any(GeoCoordinate.class), Mockito.any(GeoCoordinate.class), Mockito.anyInt());
Response response = geoLocationBasedService.getGeoDeviceLocations(0.4, 15, 75.6,

@ -22,7 +22,7 @@
<parent>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>carbon-devicemgt</artifactId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

@ -22,7 +22,7 @@
<parent>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>email-sender</artifactId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

@ -22,7 +22,7 @@
<parent>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>carbon-devicemgt</artifactId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

@ -22,13 +22,13 @@
<parent>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>identity-extensions</artifactId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>org.wso2.carbon.device.mgt.oauth.extensions</artifactId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<packaging>bundle</packaging>
<name>WSO2 Carbon - OAuth Extensions</name>
<url>http://wso2.org</url>

@ -21,7 +21,7 @@
<parent>
<artifactId>identity-extensions</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

@ -22,7 +22,7 @@
<parent>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>identity-extensions</artifactId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

@ -22,7 +22,7 @@
<parent>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>carbon-devicemgt</artifactId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

@ -22,14 +22,14 @@
<parent>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>policy-mgt</artifactId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.complex.policy.decision.point</artifactId>
<version>3.1.6-SNAPSHOT</version>
<version>3.1.7-SNAPSHOT</version>
<packaging>bundle</packaging>
<name>WSO2 Carbon - Policy Decision Point</name>
<description>WSO2 Carbon - Policy Decision Point</description>

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save