diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.api/pom.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.api/pom.xml index d9cff3eee8..52489251bb 100644 --- a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.api/pom.xml +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.api/pom.xml @@ -179,6 +179,11 @@ org.wso2.carbon.apimgt.webapp.publisher provided + + org.wso2.carbon.analytics + org.wso2.carbon.analytics.api + provided + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/service/impl/AndroidSenseControllerServiceImpl.java b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/service/impl/AndroidSenseControllerServiceImpl.java index 3d0dfa7f30..312a9d9aa3 100644 --- a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/service/impl/AndroidSenseControllerServiceImpl.java +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/service/impl/AndroidSenseControllerServiceImpl.java @@ -20,26 +20,26 @@ package org.wso2.carbon.device.mgt.iot.androidsense.service.impl; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.analytics.dataservice.commons.SORT; +import org.wso2.carbon.analytics.dataservice.commons.SortByField; +import org.wso2.carbon.analytics.datasource.commons.exception.AnalyticsException; import org.wso2.carbon.context.PrivilegedCarbonContext; -import org.wso2.carbon.device.mgt.analytics.data.publisher.AnalyticsDataRecord; import org.wso2.carbon.device.mgt.analytics.data.publisher.exception.DataPublisherConfigurationException; -import org.wso2.carbon.device.mgt.analytics.data.publisher.exception.DeviceManagementAnalyticsException; -import org.wso2.carbon.device.mgt.analytics.data.publisher.service.DeviceAnalyticsService; +import org.wso2.carbon.device.mgt.analytics.data.publisher.service.EventsPublisherService; import org.wso2.carbon.device.mgt.iot.androidsense.service.impl.transport.AndroidSenseMQTTConnector; +import org.wso2.carbon.device.mgt.iot.androidsense.service.impl.util.APIUtil; import org.wso2.carbon.device.mgt.iot.androidsense.service.impl.util.DeviceData; import org.wso2.carbon.device.mgt.iot.androidsense.service.impl.util.SensorData; +import org.wso2.carbon.device.mgt.iot.androidsense.service.impl.util.SensorRecord; import org.wso2.carbon.device.mgt.iot.androidsense.plugin.constants.AndroidSenseConstants; import org.wso2.carbon.device.mgt.iot.controlqueue.mqtt.MqttConfig; import org.wso2.carbon.device.mgt.iot.exception.DeviceControllerException; import org.wso2.carbon.device.mgt.iot.sensormgt.SensorDataManager; -import org.wso2.carbon.device.mgt.iot.sensormgt.SensorRecord; import org.wso2.carbon.device.mgt.iot.service.IoTServerStartupListener; import org.wso2.carbon.device.mgt.iot.transport.TransportHandlerException; import javax.ws.rs.core.Response; import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; import java.util.List; /** @@ -100,8 +100,8 @@ public class AndroidSenseControllerServiceImpl implements AndroidSenseController public Response addSensorData(DeviceData dataMsg) { PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); - DeviceAnalyticsService deviceAnalyticsService = (DeviceAnalyticsService) ctx - .getOSGiService(DeviceAnalyticsService.class, null); + EventsPublisherService deviceAnalyticsService = (EventsPublisherService) ctx + .getOSGiService(EventsPublisherService.class, null); SensorData[] sensorData = dataMsg.values; String streamDef = null; Object payloadData[] = null; @@ -202,7 +202,7 @@ public class AndroidSenseControllerServiceImpl implements AndroidSenseController public Response getLightData(String deviceId) { try { - SensorRecord sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, AndroidSenseConstants + org.wso2.carbon.device.mgt.iot.sensormgt.SensorRecord sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, AndroidSenseConstants .SENSOR_LIGHT); return Response.ok().entity(sensorRecord).build(); } catch (DeviceControllerException e) { @@ -212,7 +212,7 @@ public class AndroidSenseControllerServiceImpl implements AndroidSenseController public Response getBattery(String deviceId) { try { - SensorRecord sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, AndroidSenseConstants + org.wso2.carbon.device.mgt.iot.sensormgt.SensorRecord sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, AndroidSenseConstants .SENSOR_BATTERY); return Response.ok().entity(sensorRecord).build(); } catch (DeviceControllerException e) { @@ -222,7 +222,7 @@ public class AndroidSenseControllerServiceImpl implements AndroidSenseController public Response getGPS(String deviceId) { try { - SensorRecord sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, AndroidSenseConstants + org.wso2.carbon.device.mgt.iot.sensormgt.SensorRecord sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, AndroidSenseConstants .SENSOR_GPS); return Response.ok().entity(sensorRecord).build(); } catch (DeviceControllerException e) { @@ -232,7 +232,7 @@ public class AndroidSenseControllerServiceImpl implements AndroidSenseController public Response readMagnetic(String deviceId) { try { - SensorRecord sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, AndroidSenseConstants + org.wso2.carbon.device.mgt.iot.sensormgt.SensorRecord sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, AndroidSenseConstants .SENSOR_MAGNETIC); return Response.ok().entity(sensorRecord).build(); } catch (DeviceControllerException e) { @@ -242,7 +242,7 @@ public class AndroidSenseControllerServiceImpl implements AndroidSenseController public Response readAccelerometer(String deviceId) { try { - SensorRecord sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, + org.wso2.carbon.device.mgt.iot.sensormgt.SensorRecord sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, AndroidSenseConstants.SENSOR_ACCELEROMETER); return Response.ok().entity(sensorRecord).build(); } catch (DeviceControllerException e) { @@ -252,7 +252,7 @@ public class AndroidSenseControllerServiceImpl implements AndroidSenseController public Response readRotation(String deviceId) { try { - SensorRecord sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, + org.wso2.carbon.device.mgt.iot.sensormgt.SensorRecord sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, AndroidSenseConstants.SENSOR_ROTATION); return Response.ok().entity(sensorRecord).build(); } catch (DeviceControllerException e) { @@ -262,7 +262,7 @@ public class AndroidSenseControllerServiceImpl implements AndroidSenseController public Response readProximity(String deviceId) { try { - SensorRecord sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, + org.wso2.carbon.device.mgt.iot.sensormgt.SensorRecord sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, AndroidSenseConstants.SENSOR_PROXIMITY); return Response.ok().entity(sensorRecord).build(); } catch (DeviceControllerException e) { @@ -272,7 +272,7 @@ public class AndroidSenseControllerServiceImpl implements AndroidSenseController public Response readGyroscope(String deviceId) { try { - SensorRecord sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, + org.wso2.carbon.device.mgt.iot.sensormgt.SensorRecord sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, AndroidSenseConstants.SENSOR_GYROSCOPE); return Response.ok().entity(sensorRecord).build(); } catch (DeviceControllerException e) { @@ -282,7 +282,7 @@ public class AndroidSenseControllerServiceImpl implements AndroidSenseController public Response readPressure(String deviceId) { try { - SensorRecord sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, + org.wso2.carbon.device.mgt.iot.sensormgt.SensorRecord sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, AndroidSenseConstants.SENSOR_PRESSURE); return Response.ok().entity(sensorRecord).build(); } catch (DeviceControllerException e) { @@ -292,7 +292,7 @@ public class AndroidSenseControllerServiceImpl implements AndroidSenseController public Response readGravity(String deviceId) { try { - SensorRecord sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, + org.wso2.carbon.device.mgt.iot.sensormgt.SensorRecord sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, AndroidSenseConstants.SENSOR_GRAVITY); return Response.ok().entity(sensorRecord).build(); } catch (DeviceControllerException e) { @@ -302,8 +302,8 @@ public class AndroidSenseControllerServiceImpl implements AndroidSenseController public Response getWords(String deviceId, String sessionId) { try { - SensorRecord sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, - AndroidSenseConstants.SENSOR_WORDCOUNT); + org.wso2.carbon.device.mgt.iot.sensormgt.SensorRecord sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, + AndroidSenseConstants.SENSOR_WORDCOUNT); return Response.ok().entity(sensorRecord).build(); } catch (DeviceControllerException e) { return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build(); @@ -344,55 +344,27 @@ public class AndroidSenseControllerServiceImpl implements AndroidSenseController String fromDate = String.valueOf(from); String toDate = String.valueOf(to); String user = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername(); - List sensorDatas = new ArrayList<>(); - PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); - DeviceAnalyticsService deviceAnalyticsService = (DeviceAnalyticsService) ctx - .getOSGiService(DeviceAnalyticsService.class, null); String query = "owner:" + user + " AND deviceId:" + deviceId + " AND deviceType:" + AndroidSenseConstants.DEVICE_TYPE + " AND time : [" + fromDate + " TO " + toDate + "]"; if (sensor.equals(AndroidSenseConstants.SENSOR_WORDCOUNT)) { query = "owner:" + user + " AND deviceId:" + deviceId; } String sensorTableName = getSensorEventTableName(sensor); + List sensorDatas; try { - List records = deviceAnalyticsService.getAllEventsForDevice(sensorTableName, query); if (sensor.equals(AndroidSenseConstants.SENSOR_WORDCOUNT)) { - for (AnalyticsDataRecord record : records) { - SensorData sensorData = new SensorData(); - sensorData.setKey((String) record.getValue("word")); - sensorData.setTime((long) record.getValue("occurence")); - sensorData.setValue((String) record.getValue("sessionId")); - sensorDatas.add(sensorData); - } + List sortByFields = new ArrayList<>(); + SortByField sortByField = new SortByField("time", SORT.ASC, false); + sortByFields.add(sortByField); + sensorDatas = APIUtil.getAllEventsForDevice(sensorTableName, query, sortByFields); } else { - Collections.sort(records, new Comparator() { - @Override - public int compare(AnalyticsDataRecord o1, AnalyticsDataRecord o2) { - long t1 = (Long) o1.getValue("time"); - long t2 = (Long) o2.getValue("time"); - if (t1 < t2) { - return -1; - } else if (t1 > t2) { - return 1; - } else { - return 0; - } - } - }); - for (AnalyticsDataRecord record : records) { - SensorData sensorData = new SensorData(); - sensorData.setTime((long) record.getValue("time")); - sensorData.setValue("" + (float) record.getValue(sensor)); - sensorDatas.add(sensorData); - } + sensorDatas = APIUtil.getAllEventsForDevice(sensorTableName, query, null); } - SensorData[] sensorDetails = sensorDatas.toArray(new SensorData[sensorDatas.size()]); - return Response.ok().entity(sensorDetails).build(); - } catch (DeviceManagementAnalyticsException e) { + return Response.ok().entity(sensorDatas).build(); + } catch (AnalyticsException e) { String errorMsg = "Error on retrieving stats on table " + sensorTableName + " with query " + query; log.error(errorMsg); - SensorData[] senserDetails = sensorDatas.toArray(new SensorData[sensorDatas.size()]); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).entity(senserDetails).build(); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).entity(errorMsg).build(); } } diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/service/impl/transport/AndroidSenseMQTTConnector.java b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/service/impl/transport/AndroidSenseMQTTConnector.java index 0b8f30e224..bd86bca260 100644 --- a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/service/impl/transport/AndroidSenseMQTTConnector.java +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/service/impl/transport/AndroidSenseMQTTConnector.java @@ -26,7 +26,7 @@ import org.eclipse.paho.client.mqttv3.MqttException; import org.eclipse.paho.client.mqttv3.MqttMessage; import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.device.mgt.analytics.data.publisher.exception.DataPublisherConfigurationException; -import org.wso2.carbon.device.mgt.analytics.data.publisher.service.DeviceAnalyticsService; +import org.wso2.carbon.device.mgt.analytics.data.publisher.service.EventsPublisherService; import org.wso2.carbon.device.mgt.common.Device; import org.wso2.carbon.device.mgt.common.DeviceIdentifier; import org.wso2.carbon.device.mgt.common.DeviceManagementException; @@ -289,8 +289,8 @@ public class AndroidSenseMQTTConnector extends MQTTTransportHandler { if (device != null) { String owner = device.getEnrolmentInfo().getOwner(); ctx.setTenantDomain(MultitenantUtils.getTenantDomain(owner), true); - DeviceAnalyticsService deviceAnalyticsService = (DeviceAnalyticsService) ctx - .getOSGiService(DeviceAnalyticsService.class, null); + EventsPublisherService deviceAnalyticsService = (EventsPublisherService) ctx + .getOSGiService(EventsPublisherService.class, null); if (deviceAnalyticsService != null) { Object metaData[] = {owner, AndroidSenseConstants.DEVICE_TYPE, deviceId, time}; if (streamDefinition != null && payloadData != null && payloadData.length > 0) { diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/service/impl/util/APIUtil.java b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/service/impl/util/APIUtil.java index 73287696e4..c8d90a1c17 100644 --- a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/service/impl/util/APIUtil.java +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/service/impl/util/APIUtil.java @@ -2,9 +2,23 @@ package org.wso2.carbon.device.mgt.iot.androidsense.service.impl.util; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.analytics.api.AnalyticsDataAPI; +import org.wso2.carbon.analytics.dataservice.commons.AnalyticsDataResponse; +import org.wso2.carbon.analytics.dataservice.commons.AnalyticsDrillDownRequest; +import org.wso2.carbon.analytics.dataservice.commons.SearchResultEntry; +import org.wso2.carbon.analytics.dataservice.commons.SortByField; +import org.wso2.carbon.analytics.dataservice.core.AnalyticsDataServiceUtils; +import org.wso2.carbon.analytics.datasource.commons.Record; +import org.wso2.carbon.analytics.datasource.commons.exception.AnalyticsException; +import org.wso2.carbon.context.CarbonContext; import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + /** * This class provides utility functions used by REST-API. */ @@ -33,4 +47,84 @@ public class APIUtil { } return deviceManagementProviderService; } + + public 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; + } + + public static List getAllEventsForDevice(String tableName, String query, List sortByFields) throws AnalyticsException { + int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId(); + AnalyticsDataAPI analyticsDataAPI = getAnalyticsDataAPI(); + int eventCount = analyticsDataAPI.searchCount(tenantId, tableName, query); + if (eventCount == 0) { + return null; + } + AnalyticsDrillDownRequest drillDownRequest = new AnalyticsDrillDownRequest(); + drillDownRequest.setQuery(query); + drillDownRequest.setTableName(tableName); + drillDownRequest.setRecordCount(eventCount); + if (sortByFields != null) { + drillDownRequest.setSortByFields(sortByFields); + } + List resultEntries = analyticsDataAPI.drillDownSearch(tenantId, drillDownRequest); + List recordIds = getRecordIds(resultEntries); + AnalyticsDataResponse response = analyticsDataAPI.get(tenantId, tableName, 1, null, recordIds); + Map sensorDatas = createSensorData(AnalyticsDataServiceUtils.listRecords( + analyticsDataAPI, response)); + List sortedSensorData = getSortedSensorData(sensorDatas, resultEntries); + return sortedSensorData; + } + + private static List getRecordIds(List searchResults) { + List ids = new ArrayList<>(); + for (SearchResultEntry searchResult : searchResults) { + ids.add(searchResult.getId()); + } + return ids; + } + + public static List getSortedSensorData(Map sensorDatas, + List searchResults) { + List sortedRecords = new ArrayList<>(); + for (SearchResultEntry searchResultEntry : searchResults) { + sortedRecords.add(sensorDatas.get(searchResultEntry.getId())); + } + return sortedRecords; + } + + /** + * Creates the SensorDatas from records. + * + * @param records the records + * @return the Map of SensorRecord + */ + public static Map createSensorData(List records) { + Map sensorDatas = new HashMap<>(); + for (Record record : records) { + SensorRecord sensorData = createSensorData(record); + sensorDatas.put(sensorData.getId(), sensorData); + } + return sensorDatas; + } + + /** + * Create a SensorRecord object out of a Record object + * + * @param record the record object + * @return SensorRecord object + */ + public static SensorRecord createSensorData(Record record) { + SensorRecord recordBean = new SensorRecord(); + recordBean.setId(record.getId()); + recordBean.setValues(record.getValues()); + return recordBean; + } } diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/service/impl/util/SensorData.java b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/service/impl/util/SensorData.java index becd170856..67890f2f0f 100644 --- a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/service/impl/util/SensorData.java +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/service/impl/util/SensorData.java @@ -12,33 +12,32 @@ import javax.xml.bind.annotation.XmlRootElement; @JsonIgnoreProperties(ignoreUnknown = true) public class SensorData { - @XmlElement public Long time; - @XmlElement public String key; + @XmlElement public Long time; + @XmlElement public String key; + @XmlElement public String value; - public String getValue() { - return value; - } + public String getValue() { + return value; + } - public void setValue(String value) { - this.value = value; - } + public void setValue(String value) { + this.value = value; + } - public String getKey() { - return key; - } + public String getKey() { + return key; + } - public void setKey(String key) { - this.key = key; - } + public void setKey(String key) { + this.key = key; + } - public Long getTime() { - return time; - } + public Long getTime() { + return time; + } - public void setTime(Long time) { - this.time = time; - } - - @XmlElement public String value; + public void setTime(Long time) { + this.time = time; + } } diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/service/impl/util/SensorRecord.java b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/service/impl/util/SensorRecord.java new file mode 100644 index 0000000000..2159a0830a --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/service/impl/util/SensorRecord.java @@ -0,0 +1,68 @@ +package org.wso2.carbon.device.mgt.iot.androidsense.service.impl.util; + +import org.codehaus.jackson.annotate.JsonIgnoreProperties; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementWrapper; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@XmlRootElement +/** + * This stores sensor event data for android sense. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class SensorRecord { + + @XmlElementWrapper(required = true, name = "values") + private Map values; + + /** The id. */ + @XmlElement(required = false, name = "id") + private String id; + + /** + * Gets the values. + * @return the values + */ + public Map getValues() { + return values; + } + + /** + * Sets the values. + * @param values the values + */ + public void setValues(Map values) { + this.values = values; + } + + /** + * Sets the id. + * @param id the new id + */ + public void setId(String id) { + this.id = id; + } + + /** + * Gets the id. + * @return the id + */ + public String getId() { + return id; + } + + @Override + public String toString(){ + List valueList = new ArrayList(); + for (Map.Entry entry : values.entrySet()) { + valueList.add(entry.getKey() + ":" + entry.getValue()); + } + return valueList.toString(); + + } + +} diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.api/pom.xml b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.api/pom.xml index 7d698874aa..77142701b7 100644 --- a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.api/pom.xml +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.api/pom.xml @@ -160,6 +160,11 @@ org.wso2.carbon.apimgt.webapp.publisher provided + + org.wso2.carbon.analytics + org.wso2.carbon.analytics.api + provided + diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.api/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/service/impl/ArduinoControllerServiceImpl.java b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.api/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/service/impl/ArduinoControllerServiceImpl.java index 0b7de4e640..98ae9de0ea 100644 --- a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.api/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/service/impl/ArduinoControllerServiceImpl.java +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.api/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/service/impl/ArduinoControllerServiceImpl.java @@ -20,23 +20,21 @@ package org.wso2.carbon.device.mgt.iot.arduino.service.impl; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.analytics.dataservice.commons.SORT; +import org.wso2.carbon.analytics.dataservice.commons.SortByField; +import org.wso2.carbon.analytics.datasource.commons.exception.AnalyticsException; import org.wso2.carbon.context.PrivilegedCarbonContext; -import org.wso2.carbon.device.mgt.analytics.data.publisher.AnalyticsDataRecord; -import org.wso2.carbon.device.mgt.analytics.data.publisher.exception.DeviceManagementAnalyticsException; -import org.wso2.carbon.device.mgt.analytics.data.publisher.service.DeviceAnalyticsService; import org.wso2.carbon.device.mgt.iot.arduino.service.impl.dto.DeviceData; -import org.wso2.carbon.device.mgt.iot.arduino.service.impl.dto.SensorData; +import org.wso2.carbon.device.mgt.iot.arduino.service.impl.dto.SensorRecord; +import org.wso2.carbon.device.mgt.iot.arduino.service.impl.util.APIUtil; import org.wso2.carbon.device.mgt.iot.arduino.service.impl.util.ArduinoServiceUtils; import org.wso2.carbon.device.mgt.iot.arduino.plugin.constants.ArduinoConstants; import org.wso2.carbon.device.mgt.iot.exception.DeviceControllerException; import org.wso2.carbon.device.mgt.iot.sensormgt.SensorDataManager; -import org.wso2.carbon.device.mgt.iot.sensormgt.SensorRecord; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.core.Response; import java.util.ArrayList; import java.util.Calendar; -import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -83,10 +81,9 @@ public class ArduinoControllerServiceImpl implements ArduinoControllerService { @Override public Response requestTemperature(String deviceId, String protocol) { - try { - SensorRecord sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, - ArduinoConstants.SENSOR_TEMPERATURE); + org.wso2.carbon.device.mgt.iot.sensormgt.SensorRecord sensorRecord = + SensorDataManager.getInstance().getSensorRecord(deviceId, ArduinoConstants.SENSOR_TEMPERATURE); return Response.status(Response.Status.OK.getStatusCode()).entity(sensorRecord).build(); } catch (DeviceControllerException e) { return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build(); @@ -157,43 +154,19 @@ public class ArduinoControllerServiceImpl implements ArduinoControllerService { public Response getArduinoTemperatureStats(String deviceId, long from, long to) { String fromDate = String.valueOf(from); String toDate = String.valueOf(to); - List sensorDatas = new ArrayList<>(); - PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); - DeviceAnalyticsService deviceAnalyticsService = (DeviceAnalyticsService) ctx - .getOSGiService(DeviceAnalyticsService.class, null); String query = "deviceId:" + deviceId + " AND deviceType:" + ArduinoConstants.DEVICE_TYPE + " AND time : [" + fromDate + " TO " + toDate + "]"; String sensorTableName = ArduinoConstants.TEMPERATURE_EVENT_TABLE; - SensorData[] sensorDetails; try { - List records = deviceAnalyticsService.getAllEventsForDevice(sensorTableName, query); - Collections.sort(records, new Comparator() { - @Override - public int compare(AnalyticsDataRecord o1, AnalyticsDataRecord o2) { - long t1 = (Long) o1.getValue("time"); - long t2 = (Long) o2.getValue("time"); - if (t1 < t2) { - return -1; - } else if (t1 > t2) { - return 1; - } else { - return 0; - } - } - }); - for (AnalyticsDataRecord record : records) { - SensorData sensorData = new SensorData(); - sensorData.setTime((long) record.getValue("time")); - sensorData.setValue("" + (float) record.getValue(ArduinoConstants.SENSOR_TEMPERATURE)); - sensorDatas.add(sensorData); - } - sensorDetails = sensorDatas.toArray(new SensorData[sensorDatas.size()]); - return Response.status(Response.Status.OK.getStatusCode()).entity(sensorDetails).build(); - } catch (DeviceManagementAnalyticsException e) { + List sortByFields = new ArrayList<>(); + SortByField sortByField = new SortByField("time", SORT.ASC, false); + sortByFields.add(sortByField); + List sensorRecords = APIUtil.getAllEventsForDevice(sensorTableName, query, sortByFields); + return Response.status(Response.Status.OK.getStatusCode()).entity(sensorRecords).build(); + } catch (AnalyticsException e) { String errorMsg = "Error on retrieving stats on table " + sensorTableName + " with query " + query; log.error(errorMsg); - sensorDetails = sensorDatas.toArray(new SensorData[sensorDatas.size()]); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).entity(sensorDetails).build(); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).entity(errorMsg).build(); } } diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.api/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/service/impl/ArduinoManagerServiceImpl.java b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.api/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/service/impl/ArduinoManagerServiceImpl.java index 3ef8971287..fa7566b228 100644 --- a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.api/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/service/impl/ArduinoManagerServiceImpl.java +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.api/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/service/impl/ArduinoManagerServiceImpl.java @@ -34,7 +34,6 @@ import org.wso2.carbon.device.mgt.iot.exception.DeviceControllerException; import org.wso2.carbon.device.mgt.iot.util.ZipArchive; import org.wso2.carbon.device.mgt.iot.util.ZipUtil; import org.wso2.carbon.identity.jwt.client.extension.JWTClient; -import org.wso2.carbon.identity.jwt.client.extension.JWTClientManager; import org.wso2.carbon.identity.jwt.client.extension.dto.AccessTokenInfo; import org.wso2.carbon.identity.jwt.client.extension.exception.JWTClientException; import org.wso2.carbon.user.api.UserStoreException; @@ -184,14 +183,14 @@ public class ArduinoManagerServiceImpl implements ArduinoManagerService { apiApplicationKey = apiManagementProviderService.generateAndRetrieveApplicationKeys( ArduinoConstants.DEVICE_TYPE, tags, KEY_TYPE, applicationUsername, true); } - JWTClient jwtClient = JWTClientManager.getInstance().getJWTClient(); + JWTClient jwtClient = APIUtil.getJWTClientManagerService().getJWTClient(); String scopes = "device_type_" + ArduinoConstants.DEVICE_TYPE + " device_" + deviceId; AccessTokenInfo accessTokenInfo = jwtClient.getAccessToken(apiApplicationKey.getConsumerKey(), apiApplicationKey.getConsumerSecret(), owner, scopes); //create token - String accessToken = accessTokenInfo.getAccess_token(); - String refreshToken = accessTokenInfo.getRefresh_token(); + String accessToken = accessTokenInfo.getAccessToken(); + String refreshToken = accessTokenInfo.getRefreshToken(); //Register the device with CDMF boolean status = register(deviceId, deviceName); if (!status) { diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.api/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/service/impl/dto/SensorData.java b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.api/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/service/impl/dto/SensorData.java deleted file mode 100644 index 9e46a7cad1..0000000000 --- a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.api/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/service/impl/dto/SensorData.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.wso2.carbon.device.mgt.iot.arduino.service.impl.dto; - -import org.codehaus.jackson.annotate.JsonIgnoreProperties; - -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; - -@XmlRootElement -/** - * This stores sensor event data for the device type. - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class SensorData { - - @XmlElement public Long time; - @XmlElement public String key; - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - public String getKey() { - return key; - } - - public void setKey(String key) { - this.key = key; - } - - public Long getTime() { - return time; - } - - public void setTime(Long time) { - this.time = time; - } - - @XmlElement public String value; - -} diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.api/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/service/impl/dto/SensorRecord.java b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.api/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/service/impl/dto/SensorRecord.java new file mode 100644 index 0000000000..2593ed83b2 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.api/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/service/impl/dto/SensorRecord.java @@ -0,0 +1,68 @@ +package org.wso2.carbon.device.mgt.iot.arduino.service.impl.dto; + +import org.codehaus.jackson.annotate.JsonIgnoreProperties; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementWrapper; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@XmlRootElement +/** + * This stores sensor event data for android sense. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class SensorRecord { + + @XmlElementWrapper(required = true, name = "values") + private Map values; + + /** The id. */ + @XmlElement(required = false, name = "id") + private String id; + + /** + * Gets the values. + * @return the values + */ + public Map getValues() { + return values; + } + + /** + * Sets the values. + * @param values the values + */ + public void setValues(Map values) { + this.values = values; + } + + /** + * Sets the id. + * @param id the new id + */ + public void setId(String id) { + this.id = id; + } + + /** + * Gets the id. + * @return the id + */ + public String getId() { + return id; + } + + @Override + public String toString(){ + List valueList = new ArrayList(); + for (Map.Entry entry : values.entrySet()) { + valueList.add(entry.getKey() + ":" + entry.getValue()); + } + return valueList.toString(); + + } + +} diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.api/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/service/impl/util/APIUtil.java b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.api/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/service/impl/util/APIUtil.java index fb759f25a3..44ce396e58 100644 --- a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.api/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/service/impl/util/APIUtil.java +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.api/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/service/impl/util/APIUtil.java @@ -2,9 +2,25 @@ package org.wso2.carbon.device.mgt.iot.arduino.service.impl.util; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.analytics.api.AnalyticsDataAPI; +import org.wso2.carbon.analytics.dataservice.commons.AnalyticsDataResponse; +import org.wso2.carbon.analytics.dataservice.commons.AnalyticsDrillDownRequest; +import org.wso2.carbon.analytics.dataservice.commons.SearchResultEntry; +import org.wso2.carbon.analytics.dataservice.commons.SortByField; +import org.wso2.carbon.analytics.dataservice.core.AnalyticsDataServiceUtils; +import org.wso2.carbon.analytics.datasource.commons.Record; +import org.wso2.carbon.analytics.datasource.commons.exception.AnalyticsException; import org.wso2.carbon.apimgt.application.extension.APIManagementProviderService; +import org.wso2.carbon.context.CarbonContext; import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; +import org.wso2.carbon.device.mgt.iot.arduino.service.impl.dto.SensorRecord; +import org.wso2.carbon.identity.jwt.client.extension.service.JWTClientManagerService; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** * This class provides utility functions used by REST-API. @@ -23,12 +39,6 @@ public class APIUtil { return username; } - public static String getTenantDomainOftheUser() { - PrivilegedCarbonContext threadLocalCarbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext(); - String tenantDomain = threadLocalCarbonContext.getTenantDomain(); - return tenantDomain; - } - public static DeviceManagementProviderService getDeviceManagementService() { PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); DeviceManagementProviderService deviceManagementProviderService = @@ -41,6 +51,86 @@ public class APIUtil { return deviceManagementProviderService; } + public 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; + } + + public static List getAllEventsForDevice(String tableName, String query, List sortByFields) throws AnalyticsException { + int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId(); + AnalyticsDataAPI analyticsDataAPI = getAnalyticsDataAPI(); + int eventCount = analyticsDataAPI.searchCount(tenantId, tableName, query); + if (eventCount == 0) { + return null; + } + AnalyticsDrillDownRequest drillDownRequest = new AnalyticsDrillDownRequest(); + drillDownRequest.setQuery(query); + drillDownRequest.setTableName(tableName); + drillDownRequest.setRecordCount(eventCount); + if (sortByFields != null) { + drillDownRequest.setSortByFields(sortByFields); + } + List resultEntries = analyticsDataAPI.drillDownSearch(tenantId, drillDownRequest); + List recordIds = getRecordIds(resultEntries); + AnalyticsDataResponse response = analyticsDataAPI.get(tenantId, tableName, 1, null, recordIds); + Map sensorDatas = createSensorData(AnalyticsDataServiceUtils.listRecords( + analyticsDataAPI, response)); + List sortedSensorData = getSortedSensorData(sensorDatas, resultEntries); + return sortedSensorData; + } + + private static List getRecordIds(List searchResults) { + List ids = new ArrayList<>(); + for (SearchResultEntry searchResult : searchResults) { + ids.add(searchResult.getId()); + } + return ids; + } + + public static List getSortedSensorData(Map sensorDatas, + List searchResults) { + List sortedRecords = new ArrayList<>(); + for (SearchResultEntry searchResultEntry : searchResults) { + sortedRecords.add(sensorDatas.get(searchResultEntry.getId())); + } + return sortedRecords; + } + + /** + * Creates the SensorDatas from records. + * + * @param records the records + * @return the Map of SensorRecord + */ + public static Map createSensorData(List records) { + Map sensorDatas = new HashMap<>(); + for (Record record : records) { + SensorRecord sensorData = createSensorData(record); + sensorDatas.put(sensorData.getId(), sensorData); + } + return sensorDatas; + } + + /** + * Create a SensorRecord object out of a Record object + * + * @param record the record object + * @return SensorRecord object + */ + public static SensorRecord createSensorData(Record record) { + SensorRecord recordBean = new SensorRecord(); + recordBean.setId(record.getId()); + recordBean.setValues(record.getValues()); + return recordBean; + } + public static APIManagementProviderService getAPIManagementProviderService() { PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); APIManagementProviderService apiManagementProviderService = @@ -52,4 +142,21 @@ public class APIUtil { } return apiManagementProviderService; } + + public static JWTClientManagerService getJWTClientManagerService() { + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + JWTClientManagerService jwtClientManagerService = + (JWTClientManagerService) ctx.getOSGiService(JWTClientManagerService.class, null); + if (jwtClientManagerService == null) { + String msg = "JWT Client manager service has not initialized."; + log.error(msg); + throw new IllegalStateException(msg); + } + return jwtClientManagerService; + } + + public static String getTenantDomainOftheUser() { + PrivilegedCarbonContext threadLocalCarbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + return threadLocalCarbonContext.getTenantDomain(); + } } diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.api/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/service/impl/util/ArduinoServiceUtils.java b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.api/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/service/impl/util/ArduinoServiceUtils.java index 421541c41c..fcf49a80eb 100644 --- a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.api/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/service/impl/util/ArduinoServiceUtils.java +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.api/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/service/impl/util/ArduinoServiceUtils.java @@ -27,7 +27,7 @@ import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; import org.apache.http.impl.nio.client.HttpAsyncClients; import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.device.mgt.analytics.data.publisher.exception.DataPublisherConfigurationException; -import org.wso2.carbon.device.mgt.analytics.data.publisher.service.DeviceAnalyticsService; +import org.wso2.carbon.device.mgt.analytics.data.publisher.service.EventsPublisherService; import org.wso2.carbon.device.mgt.common.DeviceManagementException; import org.wso2.carbon.device.mgt.iot.arduino.plugin.constants.ArduinoConstants; import javax.ws.rs.HttpMethod; @@ -193,8 +193,8 @@ public class ArduinoServiceUtils { String owner = ctx.getUsername(); Object metdaData[] = {owner, ArduinoConstants.DEVICE_TYPE, deviceId, System.currentTimeMillis()}; Object payloadData[] = {temperature}; - DeviceAnalyticsService deviceAnalyticsService = (DeviceAnalyticsService) ctx - .getOSGiService(DeviceAnalyticsService.class, null); + EventsPublisherService deviceAnalyticsService = (EventsPublisherService) ctx + .getOSGiService(EventsPublisherService.class, null); if (deviceAnalyticsService != null) { try { deviceAnalyticsService.publishEvent(TEMPERATURE_STREAM_DEFINITION, "1.0.0", metdaData, diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/pom.xml b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/pom.xml new file mode 100644 index 0000000000..1c27e77a1d --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/pom.xml @@ -0,0 +1,165 @@ + + + + + das-extensions + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + org.wso2.carbon.event.input.adapter.extensions + bundle + WSO2 Carbon - Event Input MQTT Adapter Module + This provides the capability of connecting to existing broker that supports OAUTH + http://wso2.org + + + + org.wso2.carbon.analytics-common + org.wso2.carbon.event.input.adapter.core + + + org.wso2.carbon + org.wso2.carbon.logging + + + org.wso2.carbon + org.wso2.carbon.core + + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + + + org.apache.httpcomponents.wso2 + httpcore + + + org.wso2.orbit.org.apache.httpcomponents + httpclient + + + com.googlecode.json-simple.wso2 + json-simple + + + org.wso2.carbon.devicemgt + org.wso2.carbon.identity.jwt.client.extension + + + com.jayway.jsonpath.wso2 + json-path + + + org.wso2.carbon.identity + org.wso2.carbon.identity.oauth.stub + + + + + + + org.apache.felix + maven-scr-plugin + + + generate-scr-descriptor + + scr + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + org.apache.felix + maven-bundle-plugin + true + + + ${project.artifactId} + ${project.artifactId} + + org.wso2.carbon.event.input.adapter.extensions.internal, + org.wso2.carbon.event.input.adapter.extensions.internal.* + + + !org.wso2.carbon.event.input.adapter.extensions.internal, + !org.wso2.carbon.event.input.adapter.extensions.internal.*, + org.wso2.carbon.event.input.adapter.extensions.* + + + org.wso2.carbon.event.input.adapter.core, + org.wso2.carbon.event.input.adapter.core.*, + javax.xml.namespace; version=0.0.0, + org.eclipse.paho.client.mqttv3.*, + org.apache.http;version="${httpclient.version.range}", + org.apache.http.message;version="${httpclient.version.range}", + org.apache.http.client;version="${httpclient.version.range}", + org.apache.http.impl;version="${httpclient.version.range}", + org.apache.http.conn.*;version="${httpclient.version.range}", + org.apache.http.util;version="${httpclient.version.range}", + org.apache.http.client.entity;version="${httpclient.version.range}", + org.apache.http.client.methods;version="${httpclient.version.range}", + org.apache.http.impl.client;version="${httpclient.version.range}", + org.json.simple.*, + org.wso2.carbon.identity.jwt.client.extension.*, + com.jayway.jsonpath.*, + javax.net.ssl, + org.apache.commons.logging, + org.apache.http.entity, + org.osgi.framework, + org.osgi.service.component, + org.wso2.carbon.context, + org.wso2.carbon.core, + javax.servlet, + javax.servlet.http, + org.apache.axiom.om.util, + org.osgi.service.http, + org.wso2.carbon.user.api, + org.wso2.carbon.user.core.service, + org.wso2.carbon.user.core.tenant, + org.wso2.carbon.utils, + org.wso2.carbon.utils.multitenancy, + org.wso2.carbon.identity.oauth2.stub;version="${carbon.identity.version.range}", + org.wso2.carbon.identity.oauth2.stub.dto;version="${carbon.identity.version.range}", + org.apache.axis2, + org.apache.axis2.client, + org.apache.axis2.context, + org.apache.axis2.transport.http, + org.apache.commons.httpclient, + org.apache.commons.httpclient.contrib.ssl, + org.apache.commons.httpclient.params, + org.apache.commons.httpclient.protocol, + org.apache.commons.pool, + org.apache.commons.pool.impl, + org.apache.log4j + + + + + + + + \ No newline at end of file diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/ContentInfo.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/ContentInfo.java new file mode 100644 index 0000000000..0cd60b993d --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/ContentInfo.java @@ -0,0 +1,55 @@ +/* +* Copyright (c) 2016, 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. +*/ + +package org.wso2.carbon.event.input.adapter.extensions; + +/** + * This is the return type of the ContentValidator. + */ +public class ContentInfo { + /** + * true if the content is valid if not when false then content will not be published. + */ + private boolean isValidContent; + /** + * msgText to be returned. eg: if the content is encrypted then we can decrypt the content and then validate and + * return it. + */ + private String msgText; + + public ContentInfo(boolean isValidContent, String msgText) { + this.isValidContent = isValidContent; + this.msgText = msgText; + } + + public boolean isValidContent() { + return isValidContent; + } + + public void setIsValidContent(boolean isValidContent) { + this.isValidContent = isValidContent; + } + + public String getMsgText() { + return msgText; + } + + public void setMsgText(String msgText) { + this.msgText = msgText; + } +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/ContentValidator.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/ContentValidator.java new file mode 100644 index 0000000000..8a0ca50ad4 --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/ContentValidator.java @@ -0,0 +1,33 @@ +/* +* Copyright (c) 2016, 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. +*/ + +package org.wso2.carbon.event.input.adapter.extensions; + +import java.util.Map; + +/** + * This interface will be triggered to validate the stream content before publishing. + */ +public interface ContentValidator { + /** + * + * @param params that related to input adapter to identify the client and the content + * @return + */ + ContentInfo validate(Map params); +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/http/HTTPEventAdapter.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/http/HTTPEventAdapter.java new file mode 100644 index 0000000000..1c8c7f3314 --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/http/HTTPEventAdapter.java @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * Licensed 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. + */ + +package org.wso2.carbon.event.input.adapter.extensions.http; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.osgi.service.http.HttpService; +import org.osgi.service.http.NamespaceException; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.event.input.adapter.core.InputEventAdapter; +import org.wso2.carbon.event.input.adapter.core.InputEventAdapterConfiguration; +import org.wso2.carbon.event.input.adapter.core.InputEventAdapterListener; +import org.wso2.carbon.event.input.adapter.core.exception.InputEventAdapterException; +import org.wso2.carbon.event.input.adapter.core.exception.InputEventAdapterRuntimeException; +import org.wso2.carbon.event.input.adapter.core.exception.TestConnectionNotSupportedException; +import org.wso2.carbon.event.input.adapter.extensions.http.util.HTTPEventAdapterConstants; +import org.wso2.carbon.event.input.adapter.extensions.internal.EventAdapterServiceDataHolder; +import org.wso2.carbon.utils.multitenancy.MultitenantConstants; + +import javax.servlet.ServletException; +import java.util.Hashtable; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +public final class HTTPEventAdapter implements InputEventAdapter { + + private final InputEventAdapterConfiguration eventAdapterConfiguration; + private final Map globalProperties; + private InputEventAdapterListener eventAdaptorListener; + private final String id = UUID.randomUUID().toString(); + public static ExecutorService executorService; + private static final Log log = LogFactory.getLog(HTTPEventAdapter.class); + private boolean isConnected = false; + + public HTTPEventAdapter(InputEventAdapterConfiguration eventAdapterConfiguration, + Map globalProperties) { + this.eventAdapterConfiguration = eventAdapterConfiguration; + this.globalProperties = globalProperties; + } + + @Override + public void init(InputEventAdapterListener eventAdaptorListener) throws InputEventAdapterException { + this.eventAdaptorListener = eventAdaptorListener; + + //ThreadPoolExecutor will be assigned if it is null + if (executorService == null) { + int minThread; + int maxThread; + long defaultKeepAliveTime; + int jobQueueSize; + + //If global properties are available those will be assigned else constant values will be assigned + if (globalProperties.get(HTTPEventAdapterConstants.ADAPTER_MIN_THREAD_POOL_SIZE_NAME) != null) { + minThread = Integer + .parseInt(globalProperties.get(HTTPEventAdapterConstants.ADAPTER_MIN_THREAD_POOL_SIZE_NAME)); + } else { + minThread = HTTPEventAdapterConstants.ADAPTER_MIN_THREAD_POOL_SIZE; + } + + if (globalProperties.get(HTTPEventAdapterConstants.ADAPTER_MAX_THREAD_POOL_SIZE_NAME) != null) { + maxThread = Integer + .parseInt(globalProperties.get(HTTPEventAdapterConstants.ADAPTER_MAX_THREAD_POOL_SIZE_NAME)); + } else { + maxThread = HTTPEventAdapterConstants.ADAPTER_MAX_THREAD_POOL_SIZE; + } + + if (globalProperties.get(HTTPEventAdapterConstants.ADAPTER_KEEP_ALIVE_TIME_NAME) != null) { + defaultKeepAliveTime = Integer + .parseInt(globalProperties.get(HTTPEventAdapterConstants.ADAPTER_KEEP_ALIVE_TIME_NAME)); + } else { + defaultKeepAliveTime = HTTPEventAdapterConstants.DEFAULT_KEEP_ALIVE_TIME_IN_MILLS; + } + + if (globalProperties.get(HTTPEventAdapterConstants.ADAPTER_EXECUTOR_JOB_QUEUE_SIZE_NAME) != null) { + jobQueueSize = Integer + .parseInt(globalProperties.get(HTTPEventAdapterConstants.ADAPTER_EXECUTOR_JOB_QUEUE_SIZE_NAME)); + } else { + jobQueueSize = HTTPEventAdapterConstants.ADAPTER_EXECUTOR_JOB_QUEUE_SIZE; + } + + RejectedExecutionHandler rejectedExecutionHandler = new RejectedExecutionHandler() { + @Override + public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { + try { + executor.getQueue().put(r); + } catch (InterruptedException e) { + log.error("Exception while adding event to executor queue : " + e.getMessage(), e); + } + } + + }; + + executorService = new ThreadPoolExecutor(minThread, maxThread, defaultKeepAliveTime, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue(jobQueueSize), rejectedExecutionHandler); + + } + } + + @Override + public void testConnect() throws TestConnectionNotSupportedException { + throw new TestConnectionNotSupportedException("not-supported"); + } + + @Override + public void connect() { + registerDynamicEndpoint(eventAdapterConfiguration.getName()); + isConnected = true; + } + + @Override + public void disconnect() { + if (isConnected){ + isConnected = false; + unregisterDynamicEndpoint(eventAdapterConfiguration.getName()); + } + } + + @Override + public void destroy() { + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof HTTPEventAdapter)) + return false; + + HTTPEventAdapter that = (HTTPEventAdapter) o; + + return id.equals(that.id); + + } + + @Override + public int hashCode() { + return id.hashCode(); + } + + @Override + public boolean isEventDuplicatedInCluster() { + return false; + } + + @Override + public boolean isPolling() { + return false; + } + + private void registerDynamicEndpoint(String adapterName) { + + String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(); + + String endpoint; + if (MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) { + endpoint = HTTPEventAdapterConstants.ENDPOINT_PREFIX + adapterName; + } else { + endpoint = HTTPEventAdapterConstants.ENDPOINT_PREFIX + HTTPEventAdapterConstants.ENDPOINT_TENANT_KEY + + HTTPEventAdapterConstants.ENDPOINT_URL_SEPARATOR + tenantDomain + + HTTPEventAdapterConstants.ENDPOINT_URL_SEPARATOR + adapterName; + } + + try { + HttpService httpService = EventAdapterServiceDataHolder.getHTTPService(); + if (httpService == null) { + throw new InputEventAdapterRuntimeException( + "HttpService not available, Error in registering endpoint " + endpoint); + } + httpService.registerServlet(endpoint, new HTTPMessageServlet(eventAdaptorListener, tenantId, + eventAdapterConfiguration), + new Hashtable(), httpService.createDefaultHttpContext()); + } catch (ServletException | NamespaceException e) { + throw new InputEventAdapterRuntimeException("Error in registering endpoint " + endpoint, e); + } + + } + + private void unregisterDynamicEndpoint(String adapterName) { + HttpService httpService = EventAdapterServiceDataHolder.getHTTPService(); + String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + String endpoint; + if (MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) { + endpoint = HTTPEventAdapterConstants.ENDPOINT_PREFIX + adapterName; + } else { + endpoint = HTTPEventAdapterConstants.ENDPOINT_PREFIX + HTTPEventAdapterConstants.ENDPOINT_TENANT_KEY + + HTTPEventAdapterConstants.ENDPOINT_URL_SEPARATOR + tenantDomain + + HTTPEventAdapterConstants.ENDPOINT_URL_SEPARATOR + adapterName; + } + if (httpService != null) { + httpService.unregister(endpoint); + } + + } +} \ No newline at end of file diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/http/HTTPEventAdapterFactory.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/http/HTTPEventAdapterFactory.java new file mode 100644 index 0000000000..4a810d7d60 --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/http/HTTPEventAdapterFactory.java @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2005 - 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * Licensed 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. + */ +package org.wso2.carbon.event.input.adapter.extensions.http; + + +import org.wso2.carbon.event.input.adapter.core.InputEventAdapter; +import org.wso2.carbon.event.input.adapter.core.InputEventAdapterConfiguration; +import org.wso2.carbon.event.input.adapter.core.InputEventAdapterFactory; +import org.wso2.carbon.event.input.adapter.core.MessageType; +import org.wso2.carbon.event.input.adapter.core.Property; +import org.wso2.carbon.event.input.adapter.extensions.http.util.HTTPEventAdapterConstants; +import org.wso2.carbon.utils.CarbonUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.ResourceBundle; + +/** + * The http event adapter factory class to create a http input adapter + */ +public class HTTPEventAdapterFactory extends InputEventAdapterFactory { + + private ResourceBundle resourceBundle = + ResourceBundle.getBundle("org.wso2.carbon.event.input.adapter.extensions.http.i18n.Resources", Locale.getDefault()); + private int httpPort; + private int httpsPort; + private int portOffset; + + public HTTPEventAdapterFactory() { + portOffset = getPortOffset(); + httpPort = HTTPEventAdapterConstants.DEFAULT_HTTP_PORT + portOffset; + httpsPort = HTTPEventAdapterConstants.DEFAULT_HTTPS_PORT + portOffset; + } + + @Override + public String getType() { + return HTTPEventAdapterConstants.ADAPTER_TYPE_HTTP; + } + + @Override + public List getSupportedMessageFormats() { + List supportInputMessageTypes = new ArrayList(); + supportInputMessageTypes.add(MessageType.XML); + supportInputMessageTypes.add(MessageType.JSON); + supportInputMessageTypes.add(MessageType.TEXT); + return supportInputMessageTypes; + } + + @Override + public List getPropertyList() { + + List propertyList = new ArrayList(); + + // Transport Exposed + Property exposedTransportsProperty = new Property(HTTPEventAdapterConstants.EXPOSED_TRANSPORTS); + exposedTransportsProperty.setRequired(true); + exposedTransportsProperty.setDisplayName( + resourceBundle.getString(HTTPEventAdapterConstants.EXPOSED_TRANSPORTS)); + exposedTransportsProperty.setOptions( + new String[]{HTTPEventAdapterConstants.HTTPS, HTTPEventAdapterConstants.HTTP, + HTTPEventAdapterConstants.LOCAL, HTTPEventAdapterConstants.ALL}); + exposedTransportsProperty.setDefaultValue(HTTPEventAdapterConstants.ALL); + propertyList.add(exposedTransportsProperty); + + // OAUTH validation endpoint admin service username + Property username = new Property(HTTPEventAdapterConstants.USERNAME); + username.setRequired(true); + username.setDisplayName(resourceBundle.getString(HTTPEventAdapterConstants.USERNAME)); + username.setHint(resourceBundle.getString(HTTPEventAdapterConstants.USERNAME_HINT)); + propertyList.add(username); + + // OAUTH validation endpoint admin service password + Property password = new Property(HTTPEventAdapterConstants.PASSWORD); + password.setRequired(true); + password.setDisplayName(resourceBundle.getString(HTTPEventAdapterConstants.PASSWORD)); + password.setHint(resourceBundle.getString(HTTPEventAdapterConstants.PASSWORD_HINT)); + propertyList.add(password); + + // OAUTH validation endpoint + Property tokenValidationEndpoint = new Property(HTTPEventAdapterConstants.TOKEN_VALIDATION_ENDPOINT_URL); + tokenValidationEndpoint.setRequired(true); + tokenValidationEndpoint.setDisplayName(resourceBundle.getString(HTTPEventAdapterConstants.TOKEN_VALIDATION_ENDPOINT_URL)); + tokenValidationEndpoint.setHint(resourceBundle.getString(HTTPEventAdapterConstants.TOKEN_VALIDATION_ENDPOINT_URL_HINT)); + propertyList.add(tokenValidationEndpoint); + + Property maximumHttpConnectionPerHost = new Property(HTTPEventAdapterConstants.MAXIMUM_HTTP_CONNECTION_PER_HOST); + maximumHttpConnectionPerHost.setRequired(true); + maximumHttpConnectionPerHost.setDisplayName(resourceBundle.getString( + HTTPEventAdapterConstants.MAXIMUM_HTTP_CONNECTION_PER_HOST)); + maximumHttpConnectionPerHost.setHint(resourceBundle.getString( + HTTPEventAdapterConstants.MAXIMUM_HTTP_CONNECTION_PER_HOST_HINT)); + maximumHttpConnectionPerHost.setDefaultValue(HTTPEventAdapterConstants.MAX_HTTP_CONNECTION); + propertyList.add(maximumHttpConnectionPerHost); + + Property maxTotalHttpConnection = new Property(HTTPEventAdapterConstants.MAXIMUM_TOTAL_HTTP_CONNECTION); + maxTotalHttpConnection.setRequired(true); + maxTotalHttpConnection.setDisplayName(resourceBundle.getString( + HTTPEventAdapterConstants.MAXIMUM_TOTAL_HTTP_CONNECTION)); + maxTotalHttpConnection.setHint(resourceBundle.getString( + HTTPEventAdapterConstants.MAXIMUM_TOTAL_HTTP_CONNECTION_HINT)); + maxTotalHttpConnection.setDefaultValue(HTTPEventAdapterConstants.MAX_TOTAL_HTTP_CONNECTION); + propertyList.add(maxTotalHttpConnection); + + //Content Validator details + Property contentValidator = new Property(HTTPEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_CLASSNAME); + contentValidator.setDisplayName( + resourceBundle.getString(HTTPEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_CLASSNAME)); + contentValidator.setRequired(false); + contentValidator.setHint( + resourceBundle.getString(HTTPEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_CLASSNAME_HINT)); + propertyList.add(contentValidator); + contentValidator.setDefaultValue(HTTPEventAdapterConstants.DEFAULT); + propertyList.add(contentValidator); + + //Content Validator Params details + Property contentValidatorParams = new Property(HTTPEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_PARAMS); + contentValidatorParams.setDisplayName( + resourceBundle.getString(HTTPEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_PARAMS)); + contentValidatorParams.setRequired(false); + contentValidatorParams.setHint( + resourceBundle.getString(HTTPEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_PARAMS_HINT)); + propertyList.add(contentValidatorParams); + contentValidatorParams.setDefaultValue(HTTPEventAdapterConstants.MQTT_CONTENT_VALIDATION_DEFAULT_PARAMETERS); + propertyList.add(contentValidatorParams); + return propertyList; + } + + @Override + public String getUsageTips() { + return resourceBundle.getString(HTTPEventAdapterConstants.ADAPTER_USAGE_TIPS_PREFIX) + httpPort + + resourceBundle.getString(HTTPEventAdapterConstants.ADAPTER_USAGE_TIPS_MID1) + httpsPort + + resourceBundle.getString(HTTPEventAdapterConstants.ADAPTER_USAGE_TIPS_MID2) + httpPort + + resourceBundle.getString(HTTPEventAdapterConstants.ADAPTER_USAGE_TIPS_MID3) + httpsPort + + resourceBundle.getString(HTTPEventAdapterConstants.ADAPTER_USAGE_TIPS_POSTFIX); + } + + @Override + public InputEventAdapter createEventAdapter(InputEventAdapterConfiguration eventAdapterConfiguration, + Map globalProperties) { + return new HTTPEventAdapter(eventAdapterConfiguration, globalProperties); + } + + private int getPortOffset() { + return CarbonUtils.getPortFromServerConfig(HTTPEventAdapterConstants.CARBON_CONFIG_PORT_OFFSET_NODE) + 1; + } +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/http/HTTPMessageServlet.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/http/HTTPMessageServlet.java new file mode 100644 index 0000000000..4220ec7734 --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/http/HTTPMessageServlet.java @@ -0,0 +1,339 @@ +/* + * Copyright (c) 2005 - 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * Licensed 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. + */ + +package org.wso2.carbon.event.input.adapter.extensions.http; + +import org.apache.axis2.context.ServiceContext; +import org.apache.axis2.transport.http.HTTPConstants; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.pool.impl.GenericObjectPool; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.event.input.adapter.core.InputEventAdapterConfiguration; +import org.wso2.carbon.event.input.adapter.core.InputEventAdapterListener; +import org.wso2.carbon.event.input.adapter.extensions.ContentInfo; +import org.wso2.carbon.event.input.adapter.extensions.ContentValidator; +import org.wso2.carbon.event.input.adapter.extensions.http.oauth.OAuthTokenValidaterStubFactory; +import org.wso2.carbon.event.input.adapter.extensions.http.util.AuthenticationInfo; +import org.wso2.carbon.event.input.adapter.extensions.http.util.HTTPContentValidator; +import org.wso2.carbon.event.input.adapter.extensions.http.util.HTTPEventAdapterConstants; +import org.wso2.carbon.event.input.adapter.extensions.internal.EventAdapterServiceDataHolder; +import org.wso2.carbon.identity.oauth2.stub.OAuth2TokenValidationServiceStub; +import org.wso2.carbon.identity.oauth2.stub.dto.OAuth2TokenValidationRequestDTO; +import org.wso2.carbon.identity.oauth2.stub.dto.OAuth2TokenValidationRequestDTO_OAuth2AccessToken; +import org.wso2.carbon.identity.oauth2.stub.dto.OAuth2TokenValidationResponseDTO; +import org.wso2.carbon.user.api.UserStoreException; +import org.wso2.carbon.user.core.service.RealmService; +import org.wso2.carbon.utils.multitenancy.MultitenantUtils; + +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.rmi.RemoteException; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class HTTPMessageServlet extends HttpServlet { + + private static final String AUTHORIZATION_HEADER = "Authorization"; + private static final String AUTH_MESSAGE_STORE_AUTHENTICATION_INFO = "AUTH_MESSAGE_STORE_AUTHENTICATION_INFO"; + private static final String AUTH_FAILURE_RESPONSE = "_AUTH_FAILURE_"; + private static final Pattern PATTERN = Pattern.compile("[B|b]earer\\s"); + private static final String TOKEN_TYPE = "bearer"; + private static String cookie; + private static Log log = LogFactory.getLog(HTTPMessageServlet.class); + private GenericObjectPool stubs; + + private InputEventAdapterListener eventAdaptorListener; + private int tenantId; + private String exposedTransports; + + public HTTPMessageServlet(InputEventAdapterListener eventAdaptorListener, int tenantId, + InputEventAdapterConfiguration eventAdapterConfiguration) { + this.eventAdaptorListener = eventAdaptorListener; + this.tenantId = tenantId; + this.exposedTransports = eventAdapterConfiguration.getProperties().get( + HTTPEventAdapterConstants.EXPOSED_TRANSPORTS); + this.stubs = new GenericObjectPool(new OAuthTokenValidaterStubFactory(eventAdapterConfiguration)); + } + + private String getBearerToken(HttpServletRequest request) { + String authorizationHeader = request.getHeader(AUTHORIZATION_HEADER); + if (authorizationHeader != null) { + Matcher matcher = PATTERN.matcher(authorizationHeader); + if (matcher.find()) { + authorizationHeader = authorizationHeader.substring(matcher.end()); + } + } + return authorizationHeader; + } + + private AuthenticationInfo checkAuthentication(HttpServletRequest req) { + AuthenticationInfo authenticationInfo = (AuthenticationInfo) req.getSession().getAttribute( + AUTH_MESSAGE_STORE_AUTHENTICATION_INFO); + if (authenticationInfo != null) { + return authenticationInfo; + } + String bearerToken = getBearerToken(req); + if (bearerToken == null) { + return authenticationInfo; + } + + RealmService realmService = EventAdapterServiceDataHolder.getRealmService(); + try { + authenticationInfo = validateToken(bearerToken); + boolean success = authenticationInfo.isAuthenticated(); + if (success) { + req.getSession().setAttribute(AUTH_MESSAGE_STORE_AUTHENTICATION_INFO, authenticationInfo); + } + } catch (Exception e) { + if (log.isDebugEnabled()) { + log.debug("checkAuthentication() fail: " + e.getMessage(), e); + } + } + return authenticationInfo; + } + + /** + * This method gets a string accessToken and validates it + * + * @param token which need to be validated. + * @return AuthenticationInfo with the validated results. + */ + private AuthenticationInfo validateToken(String token) { + OAuth2TokenValidationServiceStub tokenValidationServiceStub = null; + try { + Object stub = this.stubs.borrowObject(); + if (stub != null) { + tokenValidationServiceStub = (OAuth2TokenValidationServiceStub) stub; + if (cookie != null) { + tokenValidationServiceStub._getServiceClient().getOptions().setProperty( + HTTPConstants.COOKIE_STRING, cookie); + } + return getAuthenticationInfo(token, tokenValidationServiceStub); + } else { + log.warn("Stub initialization failed."); + } + } catch (RemoteException e) { + log.error("Error on connecting with the validation endpoint.", e); + } catch (Exception e) { + log.error("Error occurred in borrowing an validation stub from the pool.", e); + + } finally { + try { + if (tokenValidationServiceStub != null) { + this.stubs.returnObject(tokenValidationServiceStub); + } + } catch (Exception e) { + log.warn("Error occurred while returning the object back to the oauth token validation service " + + "stub pool.", e); + } + } + AuthenticationInfo authenticationInfo = new AuthenticationInfo(); + authenticationInfo.setAuthenticated(false); + authenticationInfo.setTenantId(-1); + return authenticationInfo; + } + + /** + * This creates an AuthenticationInfo object that is used for authorization. This method will validate the token + * and + * sets the required parameters to the object. + * + * @param token that needs to be validated. + * @param tokenValidationServiceStub stub that is used to call the external service. + * @return AuthenticationInfo This contains the information related to authenticated client. + * @throws RemoteException that triggers when failing to call the external service.. + */ + private AuthenticationInfo getAuthenticationInfo(String token, + OAuth2TokenValidationServiceStub tokenValidationServiceStub) + throws RemoteException, UserStoreException { + AuthenticationInfo authenticationInfo = new AuthenticationInfo(); + OAuth2TokenValidationRequestDTO validationRequest = new OAuth2TokenValidationRequestDTO(); + OAuth2TokenValidationRequestDTO_OAuth2AccessToken accessToken = + new OAuth2TokenValidationRequestDTO_OAuth2AccessToken(); + accessToken.setTokenType(TOKEN_TYPE); + accessToken.setIdentifier(token); + validationRequest.setAccessToken(accessToken); + boolean authenticated; + OAuth2TokenValidationResponseDTO tokenValidationResponse; + tokenValidationResponse = tokenValidationServiceStub.validate(validationRequest); + if (tokenValidationResponse == null) { + authenticationInfo.setAuthenticated(false); + return authenticationInfo; + } + authenticated = tokenValidationResponse.getValid(); + if (authenticated) { + String authorizedUser = tokenValidationResponse.getAuthorizedUser(); + String username = MultitenantUtils.getTenantAwareUsername(authorizedUser); + String tenantDomain = MultitenantUtils.getTenantDomain(authorizedUser); + authenticationInfo.setUsername(username); + authenticationInfo.setTenantDomain(tenantDomain); + RealmService realmService = EventAdapterServiceDataHolder.getRealmService(); + int tenantId = realmService.getTenantManager().getTenantId(authenticationInfo.getTenantDomain()); + authenticationInfo.setTenantId(tenantId); + } else { + if (log.isDebugEnabled()) { + log.debug("Token validation failed for token: " + token); + } + } + ServiceContext serviceContext = tokenValidationServiceStub._getServiceClient() + .getLastOperationContext().getServiceContext(); + cookie = (String) serviceContext.getProperty(HTTPConstants.COOKIE_STRING); + authenticationInfo.setAuthenticated(authenticated); + return authenticationInfo; + } + + + private String inputStreamToString(InputStream in) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + byte[] buff = new byte[1024]; + int i; + while ((i = in.read(buff)) > 0) { + out.write(buff, 0, i); + } + out.close(); + return out.toString(); + } + + @Override + protected void doPost(HttpServletRequest req, + HttpServletResponse res) throws IOException { + + String data = this.inputStreamToString(req.getInputStream()); + if (data == null) { + log.warn("Event Object is empty/null"); + return; + } + AuthenticationInfo authenticationInfo = null; + if (exposedTransports.equalsIgnoreCase(HTTPEventAdapterConstants.HTTPS)) { + if (!req.isSecure()) { + res.setStatus(403); + log.error("Only Secured endpoint is enabled for requests"); + return; + } else { + authenticationInfo = this.checkAuthentication(req); + int tenantId = authenticationInfo != null ? authenticationInfo.getTenantId() : -1; + if (tenantId == -1) { + res.getOutputStream().write(AUTH_FAILURE_RESPONSE.getBytes()); + res.setStatus(401); + log.error("Authentication failed for the request"); + return; + } else if (tenantId != this.tenantId) { + res.getOutputStream().write(AUTH_FAILURE_RESPONSE.getBytes()); + res.setStatus(401); + log.error("Authentication failed for the request"); + return; + } + } + } else if (exposedTransports.equalsIgnoreCase(HTTPEventAdapterConstants.HTTP)) { + if (req.isSecure()) { + res.setStatus(403); + log.error("Only unsecured endpoint is enabled for requests"); + return; + } + } else { + if (req.isSecure()) { + authenticationInfo = this.checkAuthentication(req); + int tenantId = authenticationInfo != null ? authenticationInfo.getTenantId() : -1; + if (tenantId == -1) { + res.getOutputStream().write(AUTH_FAILURE_RESPONSE.getBytes()); + res.setStatus(401); + log.error("Authentication failed for the request"); + return; + } else if (tenantId != this.tenantId) { + res.getOutputStream().write(AUTH_FAILURE_RESPONSE.getBytes()); + res.setStatus(401); + log.error("Authentication failed for the request"); + return; + } + } + + } + + if (log.isDebugEnabled()) { + log.debug("Message : " + data); + } + + if (authenticationInfo != null) { + Map paramMap = new HashMap<>(); + Enumeration reqParameterNames = req.getParameterNames(); + while (reqParameterNames.hasMoreElements()) { + paramMap.put(reqParameterNames.nextElement(), req.getParameter(reqParameterNames.nextElement())); + } + paramMap.put(HTTPEventAdapterConstants.USERNAME_TAG, authenticationInfo.getUsername()); + paramMap.put(HTTPEventAdapterConstants.TENANT_DOMAIN_TAG, authenticationInfo.getTenantDomain()); + paramMap.put(HTTPEventAdapterConstants.PAYLOAD_TAG, data); + ContentValidator contentValidator = new HTTPContentValidator(); + ContentInfo contentInfo = contentValidator.validate(paramMap); + if (contentInfo != null && contentInfo.isValidContent()) { + HTTPEventAdapter.executorService.submit(new HTTPRequestProcessor(eventAdaptorListener, + contentInfo.getMsgText(), tenantId)); + + } + + } + + } + + @Override + protected void doGet(HttpServletRequest req, + HttpServletResponse res) throws IOException { + doPost(req, res); + } + + public class HTTPRequestProcessor implements Runnable { + + private InputEventAdapterListener inputEventAdapterListener; + private String payload; + private int tenantId; + + public HTTPRequestProcessor(InputEventAdapterListener inputEventAdapterListener, + String payload, int tenantId) { + this.inputEventAdapterListener = inputEventAdapterListener; + this.payload = payload; + this.tenantId = tenantId; + } + + public void run() { + try { + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantId(tenantId); + + if (log.isDebugEnabled()) { + log.debug("Event received in HTTP Event Adapter - " + payload); + } + + if (payload.trim() != null) { + inputEventAdapterListener.onEvent(payload); + } else { + log.warn("Dropping the empty/null event received through http adapter"); + } + } catch (Exception e) { + log.error("Error while parsing http request for processing: " + e.getMessage(), e); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + } + +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/http/oauth/OAuthTokenValidaterStubFactory.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/http/oauth/OAuthTokenValidaterStubFactory.java new file mode 100644 index 0000000000..57962f007e --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/http/oauth/OAuthTokenValidaterStubFactory.java @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2016, 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. + */ +package org.wso2.carbon.event.input.adapter.extensions.http.oauth; + +import org.apache.axis2.AxisFault; +import org.apache.axis2.Constants; +import org.apache.axis2.client.Options; +import org.apache.axis2.client.ServiceClient; +import org.apache.axis2.transport.http.HTTPConstants; +import org.apache.axis2.transport.http.HttpTransportProperties; +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpConnectionManager; +import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager; +import org.apache.commons.httpclient.contrib.ssl.EasySSLProtocolSocketFactory; +import org.apache.commons.httpclient.params.HttpConnectionManagerParams; +import org.apache.commons.httpclient.protocol.Protocol; +import org.apache.commons.httpclient.protocol.ProtocolSocketFactory; +import org.apache.commons.pool.BasePoolableObjectFactory; +import org.apache.log4j.Logger; +import org.wso2.carbon.event.input.adapter.core.InputEventAdapterConfiguration; +import org.wso2.carbon.event.input.adapter.extensions.http.oauth.exception.OAuthTokenValidationException; +import org.wso2.carbon.event.input.adapter.extensions.http.util.HTTPEventAdapterConstants; +import org.wso2.carbon.identity.oauth2.stub.OAuth2TokenValidationServiceStub; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.security.GeneralSecurityException; + +/** + * This follows object pool pattern to manage the stub for oauth validation service. + */ +public class OAuthTokenValidaterStubFactory extends BasePoolableObjectFactory { + private static final Logger log = Logger.getLogger(OAuthTokenValidaterStubFactory.class); + private HttpClient httpClient; + InputEventAdapterConfiguration eventAdapterConfiguration; + + + public OAuthTokenValidaterStubFactory(InputEventAdapterConfiguration eventAdapterConfiguration) { + this.eventAdapterConfiguration = eventAdapterConfiguration; + this.httpClient = createHttpClient(); + } + + /** + * This creates a OAuth2TokenValidationServiceStub object to the pool. + * + * @return an OAuthValidationStub object + * @throws Exception thrown when creating the object. + */ + @Override + public Object makeObject() throws Exception { + return this.generateStub(); + } + + /** + * This is used to clean up the OAuth validation stub and releases to the object pool. + * + * @param o object that needs to be released. + * @throws Exception throws when failed to release to the pool + */ + @Override + public void passivateObject(Object o) throws Exception { + if (o instanceof OAuth2TokenValidationServiceStub) { + OAuth2TokenValidationServiceStub stub = (OAuth2TokenValidationServiceStub) o; + stub._getServiceClient().cleanupTransport(); + } + } + + /** + * This is used to create a stub which will be triggered through object pool factory, which will create an + * instance of it. + * + * @return OAuth2TokenValidationServiceStub stub that is used to call an external service. + * @throws OAuthTokenValidationException will be thrown when initialization failed. + */ + private OAuth2TokenValidationServiceStub generateStub() throws OAuthTokenValidationException { + OAuth2TokenValidationServiceStub stub; + try { + URL hostURL = new URL(eventAdapterConfiguration.getProperties().get( + HTTPEventAdapterConstants.TOKEN_VALIDATION_ENDPOINT_URL)); + if (hostURL != null) { + stub = new OAuth2TokenValidationServiceStub(hostURL.toString()); + if (stub != null) { + ServiceClient client = stub._getServiceClient(); + client.getServiceContext().getConfigurationContext().setProperty( + HTTPConstants.CACHED_HTTP_CLIENT, httpClient); + + HttpTransportProperties.Authenticator auth = + new HttpTransportProperties.Authenticator(); + auth.setPreemptiveAuthentication(true); + String username = eventAdapterConfiguration.getProperties().get(HTTPEventAdapterConstants + .USERNAME); + String password = eventAdapterConfiguration.getProperties().get(HTTPEventAdapterConstants + .PASSWORD); + auth.setPassword(username); + auth.setUsername(password); + Options options = client.getOptions(); + options.setProperty(HTTPConstants.AUTHENTICATE, auth); + options.setProperty(HTTPConstants.REUSE_HTTP_CLIENT, Constants.VALUE_TRUE); + client.setOptions(options); + if (hostURL.getProtocol().equals("https")) { + // set up ssl factory since axis2 https transport is used. + EasySSLProtocolSocketFactory sslProtocolSocketFactory = + createProtocolSocketFactory(); + Protocol authhttps = new Protocol(hostURL.getProtocol(), + (ProtocolSocketFactory) sslProtocolSocketFactory, + hostURL.getPort()); + Protocol.registerProtocol(hostURL.getProtocol(), authhttps); + options.setProperty(HTTPConstants.CUSTOM_PROTOCOL_HANDLER, authhttps); + } + } else { + String errorMsg = "OAuth Validation instanization failed."; + throw new OAuthTokenValidationException(errorMsg); + } + } else { + String errorMsg = "host url is invalid"; + throw new OAuthTokenValidationException(errorMsg); + } + } catch (AxisFault axisFault) { + throw new OAuthTokenValidationException( + "Error occurred while creating the OAuth2TokenValidationServiceStub.", axisFault); + } catch (MalformedURLException e) { + throw new OAuthTokenValidationException( + "Error occurred while parsing token endpoint URL", e); + } + + return stub; + } + + /** + * This is required to create a trusted connection with the external entity. + * Have to manually configure it since we use CommonHTTPTransport(axis2 transport) in axis2. + * + * @return an EasySSLProtocolSocketFactory for SSL communication. + */ + private EasySSLProtocolSocketFactory createProtocolSocketFactory() throws OAuthTokenValidationException { + try { + EasySSLProtocolSocketFactory easySSLPSFactory = new EasySSLProtocolSocketFactory(); + return easySSLPSFactory; + } catch (IOException e) { + String errorMsg = "Failed to initiate EasySSLProtocolSocketFactory."; + throw new OAuthTokenValidationException(errorMsg, e); + } catch (GeneralSecurityException e) { + String errorMsg = "Failed to set the key material in easy ssl factory."; + throw new OAuthTokenValidationException(errorMsg, e); + } + } + + /** + * This created httpclient pool that can be used to connect to external entity. This connection can be configured + * via broker.xml by setting up the required http connection parameters. + * + * @return an instance of HttpClient that is configured with MultiThreadedHttpConnectionManager + */ + private HttpClient createHttpClient() { + HttpConnectionManagerParams params = new HttpConnectionManagerParams(); + params.setDefaultMaxConnectionsPerHost(Integer.parseInt(eventAdapterConfiguration.getProperties().get( + HTTPEventAdapterConstants.MAXIMUM_HTTP_CONNECTION_PER_HOST))); + params.setMaxTotalConnections(Integer.parseInt(eventAdapterConfiguration.getProperties().get( + HTTPEventAdapterConstants.MAXIMUM_TOTAL_HTTP_CONNECTION))); + HttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager(); + connectionManager.setParams(params); + return new HttpClient(connectionManager); + } +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/http/oauth/exception/OAuthTokenValidationException.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/http/oauth/exception/OAuthTokenValidationException.java new file mode 100644 index 0000000000..d7b7b5797f --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/http/oauth/exception/OAuthTokenValidationException.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2016, 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. + */ +package org.wso2.carbon.event.input.adapter.extensions.http.oauth.exception; + +/** + * This Exception will be thrown, when there any interference with token validation flow. + */ +public class OAuthTokenValidationException extends Exception { + private String errMessage; + + public OAuthTokenValidationException(String msg, Exception nestedEx) { + super(msg, nestedEx); + setErrorMessage(msg); + } + + public OAuthTokenValidationException(String message, Throwable cause) { + super(message, cause); + setErrorMessage(message); + } + + public OAuthTokenValidationException(String msg) { + super(msg); + setErrorMessage(msg); + } + + public OAuthTokenValidationException() { + super(); + } + + public OAuthTokenValidationException(Throwable cause) { + super(cause); + } + + public String getErrorMessage() { + return errMessage; + } + + public void setErrorMessage(String errMessage) { + this.errMessage = errMessage; + } +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/http/util/AuthenticationInfo.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/http/util/AuthenticationInfo.java new file mode 100644 index 0000000000..7e64cd36e0 --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/http/util/AuthenticationInfo.java @@ -0,0 +1,52 @@ +package org.wso2.carbon.event.input.adapter.extensions.http.util; + +public class AuthenticationInfo { + + /** + * this variable is used to check whether the client is authenticated. + */ + private boolean authenticated; + private String username; + private String tenantDomain; + private int tenantId; + /** + * returns whether the client is authenticated + */ + public boolean isAuthenticated() { + return authenticated; + } + + public void setAuthenticated(boolean authenticated) { + this.authenticated = authenticated; + } + + /** + * returns the authenticated client username + */ + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + /** + * return the authenticated client tenant domain + */ + public String getTenantDomain() { + return tenantDomain; + } + + public void setTenantDomain(String tenantDomain) { + this.tenantDomain = tenantDomain; + } + + public int getTenantId() { + return tenantId; + } + + public void setTenantId(int tenantId) { + this.tenantId = tenantId; + } +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/http/util/HTTPContentValidator.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/http/util/HTTPContentValidator.java new file mode 100644 index 0000000000..d6a163e87a --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/http/util/HTTPContentValidator.java @@ -0,0 +1,45 @@ +/* +* Copyright (c) 2016, 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. +*/ + +package org.wso2.carbon.event.input.adapter.extensions.http.util; + +import com.jayway.jsonpath.JsonPath; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.event.input.adapter.extensions.ContentInfo; +import org.wso2.carbon.event.input.adapter.extensions.ContentValidator; + +import java.util.Map; + +public class HTTPContentValidator implements ContentValidator { + private static final Log log = LogFactory.getLog(HTTPContentValidator.class); + + @Override + public ContentInfo validate(Map paramMap) { + String deviceId = paramMap.get("deviceId"); + + String msg = paramMap.get(HTTPEventAdapterConstants.PAYLOAD_TAG); + String deviceIdJsonPath = paramMap.get(HTTPEventAdapterConstants.DEVICE_ID_JSON_PATH); + Object res = JsonPath.read(msg, deviceIdJsonPath); + String deviceIdFromContent = (res != null) ? res.toString() : ""; + if (deviceIdFromContent.equals(deviceId)) { + return new ContentInfo(true, msg); + } + return new ContentInfo(false, msg); + } +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/http/util/HTTPEventAdapterConstants.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/http/util/HTTPEventAdapterConstants.java new file mode 100644 index 0000000000..a03112c77d --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/http/util/HTTPEventAdapterConstants.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * Licensed 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. + */ +package org.wso2.carbon.event.input.adapter.extensions.http.util; + + +public final class HTTPEventAdapterConstants { + + private HTTPEventAdapterConstants() { + } + + public static final String ADAPTER_TYPE_HTTP = "oauth-http"; + public static final String ADAPTER_USAGE_TIPS_PREFIX = "http.usage.tips_prefix"; + public static final String ADAPTER_USAGE_TIPS_MID1 = "http.usage.tips_mid1"; + public static final String ADAPTER_USAGE_TIPS_MID2 = "http.usage.tips_mid2"; + public static final String ADAPTER_USAGE_TIPS_MID3 = "http.usage.tips_mid3"; + public static final String ADAPTER_USAGE_TIPS_POSTFIX = "http.usage.tips_postfix"; + public static final int ADAPTER_MIN_THREAD_POOL_SIZE = 8; + public static final int ADAPTER_MAX_THREAD_POOL_SIZE = 100; + public static final int ADAPTER_EXECUTOR_JOB_QUEUE_SIZE = 10000; + public static final long DEFAULT_KEEP_ALIVE_TIME_IN_MILLS = 20000; + public static final String ENDPOINT_PREFIX = "/endpoints/"; + public static final String ENDPOINT_URL_SEPARATOR = "/"; + public static final String ENDPOINT_TENANT_KEY = "t"; + public static final String ADAPTER_MIN_THREAD_POOL_SIZE_NAME = "minThread"; + public static final String ADAPTER_MAX_THREAD_POOL_SIZE_NAME = "maxThread"; + public static final String ADAPTER_KEEP_ALIVE_TIME_NAME = "keepAliveTimeInMillis"; + public static final String ADAPTER_EXECUTOR_JOB_QUEUE_SIZE_NAME = "jobQueueSize"; + public static final String EXPOSED_TRANSPORTS = "transports"; + public static final String HTTPS = "https"; + public static final String HTTP = "http"; + public static final String LOCAL = "local"; + public static final String ALL = "all"; + public static final String CARBON_CONFIG_PORT_OFFSET_NODE = "Ports.Offset"; + public static final int DEFAULT_HTTP_PORT = 9763; + public static final int DEFAULT_HTTPS_PORT = 9443; + public static final String MAXIMUM_TOTAL_HTTP_CONNECTION = "maximumTotalHttpConnection"; + public static final String MAXIMUM_TOTAL_HTTP_CONNECTION_HINT = "maximumTotalHttpConnection.hint"; + public static final String MAXIMUM_HTTP_CONNECTION_PER_HOST = "maximumHttpConnectionPerHost"; + public static final String MAXIMUM_HTTP_CONNECTION_PER_HOST_HINT = "maximumHttpConnectionPerHost.hint"; + public static final String TOKEN_VALIDATION_ENDPOINT_URL = "tokenValidationEndpointUrl"; + public static final String TOKEN_VALIDATION_ENDPOINT_URL_HINT = "tokenValidationEndpointUrl.hint"; + public static final String USERNAME = "username"; + public static final String USERNAME_HINT = "username.hint"; + public static final String PASSWORD = "password"; + public static final String PASSWORD_HINT = "password.hint"; + public static final String DEFAULT_STRING = "default"; + public static final String MAX_HTTP_CONNECTION = "2"; + public static final String MAX_TOTAL_HTTP_CONNECTION = "100"; + public static final String TENANT_DOMAIN_TAG = "tenantDomain"; + public static final String USERNAME_TAG = "username"; + public static final String PAYLOAD_TAG = "payload"; + public static final String DEVICE_ID_JSON_PATH = "device_id_json_path"; + public static final String ADAPTER_CONF_CONTENT_VALIDATOR_CLASSNAME = "contentValidation"; + public static final String ADAPTER_CONF_CONTENT_VALIDATOR_CLASSNAME_HINT = "contentValidation.hint"; + public static final String ADAPTER_CONF_CONTENT_VALIDATOR_PARAMS = "contentValidationParams"; + public static final String ADAPTER_CONF_CONTENT_VALIDATOR_PARAMS_HINT = "contentValidationParams.hint"; + public static final String DEFAULT = "default"; + public static final String MQTT_CONTENT_VALIDATION_DEFAULT_PARAMETERS = + "device_id_json_path:meta_deviceId"; +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/internal/EventAdapterServiceComponent.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/internal/EventAdapterServiceComponent.java new file mode 100644 index 0000000000..397487ab54 --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/internal/EventAdapterServiceComponent.java @@ -0,0 +1,77 @@ +/* +* Copyright (c) 2015, 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. +*/ +package org.wso2.carbon.event.input.adapter.extensions.internal; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.http.HttpService; +import org.wso2.carbon.event.input.adapter.core.InputEventAdapterFactory; +import org.wso2.carbon.event.input.adapter.extensions.http.HTTPEventAdapterFactory; +import org.wso2.carbon.event.input.adapter.extensions.mqtt.MQTTEventAdapterFactory; +import org.wso2.carbon.user.core.service.RealmService; + +/** + * @scr.component component.name="input.iot.Mqtt.AdapterService.component" immediate="true" + */ + +/** + * @scr.component name="org.wso2.carbon.event.input.adapter.extension.EventAdapterServiceComponent" immediate="true" + * @scr.reference name="user.realmservice.default" + * interface="org.wso2.carbon.user.core.service.RealmService" cardinality="1..1" + * policy="dynamic" bind="setRealmService" unbind="unsetRealmService" + * @scr.reference name="http.service" interface="org.osgi.service.http.HttpService" + * cardinality="1..1" policy="dynamic" bind="setHttpService" unbind="unsetHttpService" + */ +public class EventAdapterServiceComponent { + + private static final Log log = LogFactory.getLog(EventAdapterServiceComponent.class); + + protected void activate(ComponentContext context) { + try { + InputEventAdapterFactory mqttEventAdapterFactory = new MQTTEventAdapterFactory(); + context.getBundleContext().registerService(InputEventAdapterFactory.class.getName(), + mqttEventAdapterFactory, null); + InputEventAdapterFactory httpEventEventAdapterFactory = new HTTPEventAdapterFactory(); + context.getBundleContext().registerService(InputEventAdapterFactory.class.getName(), + httpEventEventAdapterFactory, null); + if (log.isDebugEnabled()) { + log.debug("Successfully deployed the input IoT-MQTT adapter service"); + } + } catch (RuntimeException e) { + log.error("Can not create the input IoT-MQTT adapter service ", e); + } + } + + protected void setRealmService(RealmService realmService) { + EventAdapterServiceDataHolder.registerRealmService(realmService); + } + + protected void unsetRealmService(RealmService realmService) { + EventAdapterServiceDataHolder.registerRealmService(null); + } + + protected void setHttpService(HttpService httpService) { + EventAdapterServiceDataHolder.registerHTTPService(httpService); + } + + protected void unsetHttpService(HttpService httpService) { + EventAdapterServiceDataHolder.registerHTTPService(null); + } + +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/internal/EventAdapterServiceDataHolder.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/internal/EventAdapterServiceDataHolder.java new file mode 100644 index 0000000000..324196bf9b --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/internal/EventAdapterServiceDataHolder.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * Licensed 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. + */ +package org.wso2.carbon.event.input.adapter.extensions.internal; + +import org.osgi.service.http.HttpService; +import org.wso2.carbon.user.core.service.RealmService; + +/** + * common place to hold some OSGI service references. + */ +public final class EventAdapterServiceDataHolder { + + private static RealmService realmService; + private static HttpService httpService; + + private EventAdapterServiceDataHolder() { + } + + public static void registerRealmService( + RealmService realmService) { + EventAdapterServiceDataHolder.realmService = realmService; + } + + public static RealmService getRealmService() { + return realmService; + } + + public static void registerHTTPService( + HttpService httpService) { + EventAdapterServiceDataHolder.httpService = httpService; + } + + public static HttpService getHTTPService() { + return httpService; + } + + +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/mqtt/Constants.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/mqtt/Constants.java new file mode 100644 index 0000000000..284397cb12 --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/mqtt/Constants.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016, 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. + */ +package org.wso2.carbon.event.input.adapter.extensions.mqtt; + +/** + * This holds the constants related to MQTT input adapter. + */ +public class Constants { + public static final String EMPTY_STRING = ""; + public static final String GRANT_TYPE = "urn:ietf:params:oauth:grant-type:jwt-bearer refresh_token"; + public static final String TOKEN_SCOPE = "production"; + public static final String APPLICATION_TYPE = "device"; + public static final String CLIENT_ID = "client_id"; + public static final String CLIENT_SECRET = "client_secret"; + public static final String CLIENT_NAME = "client_name"; + public static final String DEFAULT = "default"; + public static final String MQTT_CONTENT_VALIDATION_DEFAULT_PARAMETERS = + "device_id_json_path:meta_deviceId,device_id_topic_hierarchy_index:2"; + public static final String TOPIC = "topic"; + public static final String PAYLOAD = "payload"; + public static final String DEVICE_ID_JSON_PATH = "device_id_json_path"; + public static final String DEVICE_ID_TOPIC_HIERARCHY_INDEX = "device_id_topic_hierarchy_index"; +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/mqtt/MQTTEventAdapter.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/mqtt/MQTTEventAdapter.java new file mode 100644 index 0000000000..c273e5af03 --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/mqtt/MQTTEventAdapter.java @@ -0,0 +1,147 @@ +/* +* Copyright (c) 2015, 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. +*/ +package org.wso2.carbon.event.input.adapter.extensions.mqtt; + +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.event.input.adapter.core.InputEventAdapter; +import org.wso2.carbon.event.input.adapter.core.InputEventAdapterConfiguration; +import org.wso2.carbon.event.input.adapter.core.InputEventAdapterListener; +import org.wso2.carbon.event.input.adapter.core.exception.InputEventAdapterException; +import org.wso2.carbon.event.input.adapter.core.exception.TestConnectionNotSupportedException; +import org.wso2.carbon.event.input.adapter.extensions.mqtt.util.MQTTAdapterListener; +import org.wso2.carbon.event.input.adapter.extensions.mqtt.util.MQTTBrokerConnectionConfiguration; +import org.wso2.carbon.event.input.adapter.extensions.mqtt.util.MQTTEventAdapterConstants; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +/** + * Input MQTTEventAdapter will be used to receive events with MQTT protocol using specified broker and topic. + */ +public class MQTTEventAdapter implements InputEventAdapter { + + private final InputEventAdapterConfiguration eventAdapterConfiguration; + private final Map globalProperties; + private InputEventAdapterListener eventAdapterListener; + private final String id = UUID.randomUUID().toString(); + private MQTTAdapterListener mqttAdapterListener; + private MQTTBrokerConnectionConfiguration mqttBrokerConnectionConfiguration; + + + public MQTTEventAdapter(InputEventAdapterConfiguration eventAdapterConfiguration, + Map globalProperties) { + this.eventAdapterConfiguration = eventAdapterConfiguration; + this.globalProperties = globalProperties; + } + + @Override + public void init(InputEventAdapterListener eventAdapterListener) throws InputEventAdapterException { + this.eventAdapterListener = eventAdapterListener; + try { + int keepAlive; + + //If global properties are available those will be assigned else constant values will be assigned + if (globalProperties.get(MQTTEventAdapterConstants.ADAPTER_CONF_KEEP_ALIVE) != null) { + keepAlive = Integer.parseInt((globalProperties.get(MQTTEventAdapterConstants.ADAPTER_CONF_KEEP_ALIVE))); + } else { + keepAlive = MQTTEventAdapterConstants.ADAPTER_CONF_DEFAULT_KEEP_ALIVE; + } + String contentValidationParams = eventAdapterConfiguration.getProperties().get(MQTTEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_PARAMS); + String params[] = contentValidationParams.split(","); + Map paramsMap = new HashMap<>(); + for (String param: params) { + String paramsKeyAndValue[] = param.split("/_(.+)?/"); + if (paramsKeyAndValue.length != 2) { + throw new InputEventAdapterException("Invalid parameters for content validation - " + param); + } + paramsMap.put(paramsKeyAndValue[0], paramsKeyAndValue[1]); + } + + mqttBrokerConnectionConfiguration = new MQTTBrokerConnectionConfiguration( + eventAdapterConfiguration.getProperties().get(MQTTEventAdapterConstants.ADAPTER_CONF_URL), + eventAdapterConfiguration.getProperties().get(MQTTEventAdapterConstants.ADAPTER_CONF_USERNAME), + eventAdapterConfiguration.getProperties().get(MQTTEventAdapterConstants.ADAPTER_CONF_SCOPES), + eventAdapterConfiguration.getProperties().get(MQTTEventAdapterConstants.ADAPTER_CONF_DCR_URL), + eventAdapterConfiguration.getProperties().get(MQTTEventAdapterConstants.ADAPTER_CONF_CLEAN_SESSION), + keepAlive, + eventAdapterConfiguration.getProperties().get(MQTTEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_CLASSNAME), + paramsMap + ); + + + mqttAdapterListener = new MQTTAdapterListener(mqttBrokerConnectionConfiguration, + eventAdapterConfiguration.getProperties().get(MQTTEventAdapterConstants.ADAPTER_MESSAGE_TOPIC), + eventAdapterConfiguration.getProperties().get(MQTTEventAdapterConstants.ADAPTER_CONF_CLIENTID), + eventAdapterListener, PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId()); + + } catch (Throwable t) { + throw new InputEventAdapterException(t.getMessage(), t); + } + } + + @Override + public void testConnect() throws TestConnectionNotSupportedException { + throw new TestConnectionNotSupportedException("not-supported"); + } + + @Override + public void connect() { + mqttAdapterListener.createConnection(); + } + + @Override + public void disconnect() { + if (mqttAdapterListener != null) { + mqttAdapterListener.stopListener(eventAdapterConfiguration.getName()); + } + } + + @Override + public void destroy() { + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof MQTTEventAdapter)) return false; + + MQTTEventAdapter that = (MQTTEventAdapter) o; + + if (!id.equals(that.id)) return false; + + return true; + } + + @Override + public int hashCode() { + return id.hashCode(); + } + + + @Override + public boolean isEventDuplicatedInCluster() { + return true; + } + + @Override + public boolean isPolling() { + return true; + } + +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/mqtt/MQTTEventAdapterFactory.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/mqtt/MQTTEventAdapterFactory.java new file mode 100644 index 0000000000..be1111bce2 --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/mqtt/MQTTEventAdapterFactory.java @@ -0,0 +1,153 @@ +/* +* Copyright (c) 2015, 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. +*/ +package org.wso2.carbon.event.input.adapter.extensions.mqtt; + +import org.wso2.carbon.event.input.adapter.core.*; +import org.wso2.carbon.event.input.adapter.extensions.mqtt.util.MQTTEventAdapterConstants; + +import java.util.*; + +/** + * The mqtt event adapter factory class to create a mqtt input adapter + */ +public class MQTTEventAdapterFactory extends InputEventAdapterFactory { + + private ResourceBundle resourceBundle = ResourceBundle.getBundle + ("org.wso2.carbon.event.input.adapter.extensions.mqtt.i18n.Resources", Locale.getDefault()); + + @Override + public String getType() { + return MQTTEventAdapterConstants.ADAPTER_TYPE_MQTT; + } + + @Override + public List getSupportedMessageFormats() { + List supportInputMessageTypes = new ArrayList(); + + supportInputMessageTypes.add(MessageType.TEXT); + supportInputMessageTypes.add(MessageType.JSON); + supportInputMessageTypes.add(MessageType.XML); + + return supportInputMessageTypes; + } + + @Override + public List getPropertyList() { + List propertyList = new ArrayList(); + + // set topic + Property topicProperty = new Property(MQTTEventAdapterConstants.ADAPTER_MESSAGE_TOPIC); + topicProperty.setDisplayName( + resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_MESSAGE_TOPIC)); + topicProperty.setRequired(true); + topicProperty.setHint( + resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_MESSAGE_TOPIC_HINT)); + propertyList.add(topicProperty); + + //Broker Url + Property brokerUrl = new Property(MQTTEventAdapterConstants.ADAPTER_CONF_URL); + brokerUrl.setDisplayName( + resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_URL)); + brokerUrl.setRequired(true); + brokerUrl.setHint(resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_URL_HINT)); + propertyList.add(brokerUrl); + + //DCR endpoint details + Property dcrUrl = new Property(MQTTEventAdapterConstants.ADAPTER_CONF_DCR_URL); + dcrUrl.setDisplayName( + resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_DCR_URL)); + dcrUrl.setRequired(false); + dcrUrl.setHint( + resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_DCR_URL_HINT)); + propertyList.add(dcrUrl); + + //Content Validator details + Property contentValidator = new Property(MQTTEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_CLASSNAME); + contentValidator.setDisplayName( + resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_CLASSNAME)); + contentValidator.setRequired(false); + contentValidator.setHint( + resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_CLASSNAME_HINT)); + propertyList.add(contentValidator); + contentValidator.setDefaultValue(Constants.DEFAULT); + propertyList.add(contentValidator); + + //Content Validator Params details + Property contentValidatorParams = new Property(MQTTEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_PARAMS); + contentValidatorParams.setDisplayName( + resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_PARAMS)); + contentValidatorParams.setRequired(false); + contentValidatorParams.setHint( + resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_PARAMS_HINT)); + propertyList.add(contentValidatorParams); + contentValidatorParams.setDefaultValue(Constants.MQTT_CONTENT_VALIDATION_DEFAULT_PARAMETERS); + propertyList.add(contentValidatorParams); + + //Broker Username + Property userName = new Property(MQTTEventAdapterConstants.ADAPTER_CONF_USERNAME); + userName.setDisplayName( + resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_USERNAME)); + userName.setRequired(false); + userName.setHint( + resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_USERNAME_HINT)); + propertyList.add(userName); + propertyList.add(userName); + + //Broker Required Scopes. + Property scopes = new Property(MQTTEventAdapterConstants.ADAPTER_CONF_SCOPES); + scopes.setDisplayName( + resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_SCOPES)); + scopes.setRequired(false); + scopes.setHint( + resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_SCOPES_HINT)); + propertyList.add(scopes); + + //Broker clear session + Property clearSession = new Property(MQTTEventAdapterConstants.ADAPTER_CONF_CLEAN_SESSION); + clearSession.setDisplayName( + resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_CLEAN_SESSION)); + clearSession.setRequired(false); + clearSession.setOptions(new String[]{"true", "false"}); + clearSession.setDefaultValue("true"); + clearSession.setHint( + resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_CLEAN_SESSION_HINT)); + propertyList.add(clearSession); + + // set clientId + Property clientId = new Property(MQTTEventAdapterConstants.ADAPTER_CONF_CLIENTID); + clientId.setDisplayName( + resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_CLIENTID)); + clientId.setRequired(false); + clientId.setHint( + resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_CLIENTID_HINT)); + propertyList.add(clientId); + + return propertyList; + } + + @Override + public String getUsageTips() { + return null; + } + + @Override + public InputEventAdapter createEventAdapter(InputEventAdapterConfiguration eventAdapterConfiguration, + Map globalProperties) { + return new MQTTEventAdapter(eventAdapterConfiguration, globalProperties); + } +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/mqtt/exception/MQTTContentValidatorInitializationException.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/mqtt/exception/MQTTContentValidatorInitializationException.java new file mode 100644 index 0000000000..a03cde2f98 --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/mqtt/exception/MQTTContentValidatorInitializationException.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2016, 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. + */ +package org.wso2.carbon.event.input.adapter.extensions.mqtt.exception; + +public class MQTTContentValidatorInitializationException extends RuntimeException { + private String errMessage; + + public MQTTContentValidatorInitializationException(String msg, Exception nestedEx) { + super(msg, nestedEx); + setErrorMessage(msg); + } + + public MQTTContentValidatorInitializationException(String message, Throwable cause) { + super(message, cause); + setErrorMessage(message); + } + + public MQTTContentValidatorInitializationException(String msg) { + super(msg); + setErrorMessage(msg); + } + + public MQTTContentValidatorInitializationException() { + super(); + } + + public MQTTContentValidatorInitializationException(Throwable cause) { + super(cause); + } + + public String getErrorMessage() { + return errMessage; + } + + public void setErrorMessage(String errMessage) { + this.errMessage = errMessage; + } +} \ No newline at end of file diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/mqtt/util/MQTTAdapterListener.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/mqtt/util/MQTTAdapterListener.java new file mode 100644 index 0000000000..0da5ee21d5 --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/mqtt/util/MQTTAdapterListener.java @@ -0,0 +1,280 @@ +/* +* Copyright (c) 2015, 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. +*/ +package org.wso2.carbon.event.input.adapter.extensions.mqtt.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.eclipse.paho.client.mqttv3.*; +import org.eclipse.paho.client.mqttv3.persist.MqttDefaultFilePersistence; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.core.ServerStatus; +import org.wso2.carbon.event.input.adapter.core.InputEventAdapterListener; +import org.wso2.carbon.event.input.adapter.core.exception.InputEventAdapterRuntimeException; +import org.wso2.carbon.event.input.adapter.extensions.ContentInfo; +import org.wso2.carbon.event.input.adapter.extensions.ContentValidator; +import org.wso2.carbon.event.input.adapter.extensions.mqtt.Constants; +import org.wso2.carbon.event.input.adapter.extensions.mqtt.exception.MQTTContentValidatorInitializationException; +import org.wso2.carbon.identity.jwt.client.extension.dto.AccessTokenInfo; +import org.wso2.carbon.identity.jwt.client.extension.exception.JWTClientException; +import org.wso2.carbon.identity.jwt.client.extension.service.JWTClientManagerService; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.util.Map; + +public class MQTTAdapterListener implements MqttCallback, Runnable { + private static final Log log = LogFactory.getLog(MQTTAdapterListener.class); + + private MqttClient mqttClient; + private MqttConnectOptions connectionOptions; + private boolean cleanSession; + private int keepAlive; + + private MQTTBrokerConnectionConfiguration mqttBrokerConnectionConfiguration; + private String mqttClientId; + private String topic; + private int tenantId; + private boolean connectionSucceeded = false; + ContentValidator contentValidator; + Map contentValidationParams; + + private InputEventAdapterListener eventAdapterListener = null; + + + public MQTTAdapterListener(MQTTBrokerConnectionConfiguration mqttBrokerConnectionConfiguration, + String topic, String mqttClientId, + InputEventAdapterListener inputEventAdapterListener, int tenantId) { + + if(mqttClientId == null || mqttClientId.trim().isEmpty()){ + mqttClientId = MqttClient.generateClientId(); + } + + this.mqttClientId = mqttClientId; + this.mqttBrokerConnectionConfiguration = mqttBrokerConnectionConfiguration; + this.cleanSession = mqttBrokerConnectionConfiguration.isCleanSession(); + this.keepAlive = mqttBrokerConnectionConfiguration.getKeepAlive(); + this.topic = topic; + this.eventAdapterListener = inputEventAdapterListener; + this.tenantId = tenantId; + + //SORTING messages until the server fetches them + String temp_directory = System.getProperty("java.io.tmpdir"); + MqttDefaultFilePersistence dataStore = new MqttDefaultFilePersistence(temp_directory); + + + try { + // Construct the connection options object that contains connection parameters + // such as cleanSession and LWT + connectionOptions = new MqttConnectOptions(); + connectionOptions.setCleanSession(cleanSession); + connectionOptions.setKeepAliveInterval(keepAlive); + + // Construct an MQTT blocking mode client + mqttClient = new MqttClient(this.mqttBrokerConnectionConfiguration.getBrokerUrl(), this.mqttClientId, + dataStore); + + // Set this wrapper as the callback handler + mqttClient.setCallback(this); + String contentValidatorClassName = this.mqttBrokerConnectionConfiguration.getContentValidatorClassName(); + + if (contentValidatorClassName != null && contentValidatorClassName.equals(Constants.DEFAULT)) { + contentValidator = new MQTTContentValidator(); + } else if (contentValidatorClassName != null && !contentValidatorClassName.isEmpty()) { + try { + Class contentValidatorClass = Class.forName(contentValidatorClassName) + .asSubclass(ContentValidator.class); + contentValidator = contentValidatorClass.newInstance(); + } catch (ClassNotFoundException e) { + throw new MQTTContentValidatorInitializationException( + "Unable to find the class authorizer: " + contentValidatorClassName, e); + } catch (InstantiationException e) { + throw new MQTTContentValidatorInitializationException( + "Unable to create an instance of :" + contentValidatorClassName, e); + } catch (IllegalAccessException e) { + throw new MQTTContentValidatorInitializationException("Access of the instance in not allowed.", e); + } + } + + contentValidationParams = mqttBrokerConnectionConfiguration.getContentValidatorParams(); + + } catch (MqttException e) { + log.error("Exception occurred while subscribing to MQTT broker at " + + mqttBrokerConnectionConfiguration.getBrokerUrl()); + throw new InputEventAdapterRuntimeException(e); + } catch (Throwable e) { + log.error("Exception occurred while subscribing to MQTT broker at " + + mqttBrokerConnectionConfiguration.getBrokerUrl()); + throw new InputEventAdapterRuntimeException(e); + } + + } + + public void startListener() throws MqttException { + if (this.mqttBrokerConnectionConfiguration.getBrokerUsername() != null && this.mqttBrokerConnectionConfiguration.getDcrUrl() != null) { + String username = this.mqttBrokerConnectionConfiguration.getBrokerUsername(); + String dcrUrlString = this.mqttBrokerConnectionConfiguration.getDcrUrl(); + String scopes = this.mqttBrokerConnectionConfiguration.getBrokerScopes(); + //getJWT Client Parameters. + if (dcrUrlString != null && !dcrUrlString.isEmpty()) { + try { + URL dcrUrl = new URL(dcrUrlString); + HttpClient httpClient = MQTTUtil.getHttpClient(dcrUrl.getProtocol()); + HttpPost postMethod = new HttpPost(dcrUrlString); + RegistrationProfile registrationProfile = new RegistrationProfile(); + registrationProfile.setCallbackUrl(Constants.EMPTY_STRING); + registrationProfile.setGrantType(Constants.GRANT_TYPE); + registrationProfile.setOwner(username); + registrationProfile.setTokenScope(Constants.TOKEN_SCOPE); + registrationProfile.setApplicationType(Constants.APPLICATION_TYPE); + int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true); + registrationProfile.setClientName(username + "_" + tenantId); + String jsonString = registrationProfile.toJSON(); + StringEntity requestEntity = new StringEntity(jsonString, ContentType.APPLICATION_JSON); + postMethod.setEntity(requestEntity); + HttpResponse httpResponse = httpClient.execute(postMethod); + String response = MQTTUtil.getResponseString(httpResponse); + try { + JSONParser jsonParser = new JSONParser(); + JSONObject jsonPayload = (JSONObject) jsonParser.parse(response); + String clientId = (String) jsonPayload.get(Constants.CLIENT_ID); + String clientSecret = (String) jsonPayload.get(Constants.CLIENT_SECRET); + JWTClientManagerService jwtClientManagerService = MQTTUtil.getJWTClientManagerService(); + AccessTokenInfo accessTokenInfo = jwtClientManagerService.getJWTClient().getAccessToken( + clientId, clientSecret, username, scopes); + connectionOptions.setUserName(accessTokenInfo.getAccessToken()); + } catch (ParseException e) { + String msg = "error occurred while parsing client credential payload"; + log.error(msg, e); + } catch (JWTClientException e) { + String msg = "error occurred while parsing the response from JWT Client"; + log.error(msg, e); + } + } catch (MalformedURLException e) { + log.error("Invalid dcrUrl : " + dcrUrlString); + } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException | IOException e) { + log.error("Failed to create an https connection.", e); + } + } + } + // Connect to the MQTT server + mqttClient.connect(connectionOptions); + + // Subscribe to the requested topic + // The QoS specified is the maximum level that messages will be sent to the client at. + // For instance if QoS 1 is specified, any messages originally published at QoS 2 will + // be downgraded to 1 when delivering to the client but messages published at 1 and 0 + // will be received at the same level they were published at. + mqttClient.subscribe(topic); + } + + public void stopListener(String adapterName) { + if (connectionSucceeded) { + try { + // Un-subscribe accordingly and disconnect from the MQTT server. + if (!ServerStatus.getCurrentStatus().equals(ServerStatus.STATUS_SHUTTING_DOWN) || cleanSession) { + mqttClient.unsubscribe(topic); + } + mqttClient.disconnect(3000); + } catch (MqttException e) { + log.error("Can not unsubscribe from the destination " + topic + + " with the event adapter " + adapterName, e); + } + } + //This is to stop all running reconnection threads + connectionSucceeded = true; + } + + @Override + public void connectionLost(Throwable throwable) { + log.warn("MQTT connection not reachable " + throwable); + connectionSucceeded = false; + new Thread(this).start(); + } + + @Override + public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception { + try { + String msgText = mqttMessage.toString(); + if (log.isDebugEnabled()) { + log.debug(msgText); + } + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantId(tenantId); + + if (log.isDebugEnabled()) { + log.debug("Event received in MQTT Event Adapter - " + msgText); + } + ContentInfo contentInfo; + synchronized (contentValidationParams) { + contentValidationParams.put(Constants.TOPIC, topic); + contentValidationParams.put(Constants.PAYLOAD, msgText); + contentInfo = contentValidator.validate(contentValidationParams); + contentValidationParams.remove(Constants.TOPIC); + contentValidationParams.remove(Constants.PAYLOAD); + } + if (contentValidator != null) { + if (contentInfo != null && contentInfo.isValidContent()) { + eventAdapterListener.onEvent(contentInfo.getMsgText()); + } + } else { + eventAdapterListener.onEvent(msgText); + } + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + @Override + public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) { + + } + + @Override + public void run() { + while (!connectionSucceeded) { + try { + MQTTEventAdapterConstants.initialReconnectDuration = MQTTEventAdapterConstants.initialReconnectDuration + * MQTTEventAdapterConstants.reconnectionProgressionFactor; + Thread.sleep(MQTTEventAdapterConstants.initialReconnectDuration); + startListener(); + connectionSucceeded = true; + log.info("MQTT Connection successful"); + } catch (InterruptedException e) { + log.error("Interruption occurred while waiting for reconnection", e); + } catch (MqttException e) { + log.error("MQTT Exception occurred when starting listener", e); + } + } + } + + public void createConnection() { + new Thread(this).start(); + } +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/mqtt/util/MQTTBrokerConnectionConfiguration.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/mqtt/util/MQTTBrokerConnectionConfiguration.java new file mode 100644 index 0000000000..504d46ff61 --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/mqtt/util/MQTTBrokerConnectionConfiguration.java @@ -0,0 +1,119 @@ +/* +* Copyright (c) 2015, 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. +*/ +package org.wso2.carbon.event.input.adapter.extensions.mqtt.util; + +import org.wso2.carbon.event.input.adapter.extensions.mqtt.Constants; + +import java.util.Map; + +public class MQTTBrokerConnectionConfiguration { + + private String brokerUsername = null; + private String brokerScopes = null; + private boolean cleanSession = true; + private int keepAlive; + private String brokerUrl; + private String dcrUrl; + private String contentValidatorClassName; + private Map contentValidatorParams; + + public String getBrokerScopes() { + return brokerScopes; + } + + public void setBrokerScopes(String brokerScopes) { + this.brokerScopes = brokerScopes; + } + + public String getBrokerUsername() { + return brokerUsername; + } + + public void setBrokerUsername(String brokerUsername) { + this.brokerUsername = brokerUsername; + } + + public void setCleanSession(boolean cleanSession) { + this.cleanSession = cleanSession; + } + + + public boolean isCleanSession() { + return cleanSession; + } + + public String getBrokerUrl() { + return brokerUrl; + } + + public void setBrokerUrl(String brokerUrl) { + this.brokerUrl = brokerUrl; + } + + public String getDcrUrl() { + return dcrUrl; + } + + public void setDcrUrl(String dcrUrl) { + this.dcrUrl = dcrUrl; + } + + public int getKeepAlive() { + return keepAlive; + } + + public void setKeepAlive(int keepAlive) { + this.keepAlive = keepAlive; + } + + public String getContentValidatorClassName() { + return contentValidatorClassName; + } + + public void setContentValidatorClassName(String contentValidatorClassName) { + this.contentValidatorClassName = contentValidatorClassName; + } + + public Map getContentValidatorParams() { + return contentValidatorParams; + } + + public void setContentValidatorParams(Map contentValidatorParams) { + this.contentValidatorParams = contentValidatorParams; + } + + public MQTTBrokerConnectionConfiguration(String brokerUrl, String brokerUsername, String brokerScopes, + String dcrUrl, String cleanSession, int keepAlive, + String contentValidatorClassName, Map contentValidatorParams) { + this.brokerUsername = brokerUsername; + this.brokerScopes = brokerScopes; + if (brokerScopes == null) { + this.brokerScopes = Constants.EMPTY_STRING; + } + this.brokerUrl = brokerUrl; + this.dcrUrl = dcrUrl; + this.contentValidatorClassName = contentValidatorClassName; + if (cleanSession != null) { + this.cleanSession = Boolean.parseBoolean(cleanSession); + } + this.keepAlive = keepAlive; + if (contentValidatorParams != null) { + this.contentValidatorParams = contentValidatorParams; + } + } +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/mqtt/util/MQTTContentValidator.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/mqtt/util/MQTTContentValidator.java new file mode 100644 index 0000000000..96c1eee167 --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/mqtt/util/MQTTContentValidator.java @@ -0,0 +1,53 @@ +/* +* Copyright (c) 2016, 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. +*/ + +package org.wso2.carbon.event.input.adapter.extensions.mqtt.util; + +import com.jayway.jsonpath.JsonPath; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.event.input.adapter.extensions.ContentInfo; +import org.wso2.carbon.event.input.adapter.extensions.ContentValidator; +import org.wso2.carbon.event.input.adapter.extensions.mqtt.Constants; + +import java.util.Map; + +public class MQTTContentValidator implements ContentValidator { + private static final Log log = LogFactory.getLog(MQTTContentValidator.class); + + @Override + public ContentInfo validate(Map params) { + String topic = params.get(Constants.TOPIC); + String topics[] = topic.split("/"); + + String msg = params.get(Constants.PAYLOAD); + String deviceIdJsonPath = params.get(Constants.DEVICE_ID_JSON_PATH); + String deviceIdInTopicHierarchyLevel = params.get(Constants.DEVICE_ID_TOPIC_HIERARCHY_INDEX); + int deviceIdInTopicHierarchyLevelIndex = 0; + if (deviceIdInTopicHierarchyLevel != null && !deviceIdInTopicHierarchyLevel.isEmpty()) { + deviceIdInTopicHierarchyLevelIndex = Integer.parseInt(deviceIdInTopicHierarchyLevel); + } + String deviceIdFromTopic = topics[deviceIdInTopicHierarchyLevelIndex]; + Object res = JsonPath.read(msg, deviceIdJsonPath); + String deviceIdFromContent = (res != null) ? res.toString() : ""; + if (deviceIdFromContent.equals(deviceIdFromTopic)) { + return new ContentInfo(true, msg); + } + return new ContentInfo(false, msg); + } +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/mqtt/util/MQTTEventAdapterConstants.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/mqtt/util/MQTTEventAdapterConstants.java new file mode 100644 index 0000000000..d9a564d96c --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/mqtt/util/MQTTEventAdapterConstants.java @@ -0,0 +1,46 @@ +/* +* Copyright (c) 2015, 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. +*/ +package org.wso2.carbon.event.input.adapter.extensions.mqtt.util; + +public class MQTTEventAdapterConstants { + + public static final String ADAPTER_TYPE_MQTT = "oauth-mqtt"; + public static final String ADAPTER_CONF_URL = "url"; + public static final String ADAPTER_CONF_USERNAME = "username"; + public static final String ADAPTER_CONF_USERNAME_HINT = "username.hint"; + public static final String ADAPTER_CONF_SCOPES = "scopes"; + public static final String ADAPTER_CONF_SCOPES_HINT = "scopes.hint"; + public static final String ADAPTER_CONF_URL_HINT = "url.hint"; + public static final String ADAPTER_CONF_DCR_URL = "dcrUrl"; + public static final String ADAPTER_CONF_DCR_URL_HINT = "dcrUrl.hint"; + public static final String ADAPTER_CONF_CONTENT_VALIDATOR_CLASSNAME = "contentValidation"; + public static final String ADAPTER_CONF_CONTENT_VALIDATOR_CLASSNAME_HINT = "contentValidation.hint"; + public static final String ADAPTER_CONF_CONTENT_VALIDATOR_PARAMS = "contentValidationParams"; + public static final String ADAPTER_CONF_CONTENT_VALIDATOR_PARAMS_HINT = "contentValidationParams.hint"; + public static final String ADAPTER_MESSAGE_TOPIC = "topic"; + public static final String ADAPTER_MESSAGE_TOPIC_HINT = "topic.hint"; + public static final String ADAPTER_CONF_CLIENTID = "clientId"; + public static final String ADAPTER_CONF_CLIENTID_HINT = "clientId.hint"; + public static final String ADAPTER_CONF_CLEAN_SESSION = "cleanSession"; + public static final String ADAPTER_CONF_CLEAN_SESSION_HINT = "cleanSession.hint"; + public static final String ADAPTER_CONF_KEEP_ALIVE = "keepAlive"; + public static final int ADAPTER_CONF_DEFAULT_KEEP_ALIVE = 60000; + + public static int initialReconnectDuration = 10000; + public static final int reconnectionProgressionFactor = 2; +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/mqtt/util/MQTTUtil.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/mqtt/util/MQTTUtil.java new file mode 100644 index 0000000000..29bae3583b --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/mqtt/util/MQTTUtil.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2016, 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. + */ + +package org.wso2.carbon.event.input.adapter.extensions.mqtt.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.conn.ssl.SSLContextBuilder; +import org.apache.http.conn.ssl.TrustSelfSignedStrategy; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.identity.jwt.client.extension.service.JWTClientManagerService; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; + +/** + * This is the utility class that is used for MQTT input adapater. + */ +public class MQTTUtil { + private static final String HTTPS_PROTOCOL = "https"; + private static final Log log = LogFactory.getLog(MQTTUtil.class); + /** + * Return a http client instance + * + * @param protocol- service endpoint protocol http/https + * @return + */ + public static HttpClient getHttpClient(String protocol) + throws IOException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException { + HttpClient httpclient; + if (HTTPS_PROTOCOL.equals(protocol)) { + SSLContextBuilder builder = new SSLContextBuilder(); + builder.loadTrustMaterial(null, new TrustSelfSignedStrategy()); + SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build()); + httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build(); + } else { + httpclient = HttpClients.createDefault(); + } + return httpclient; + } + + public static String getResponseString(HttpResponse httpResponse) throws IOException { + BufferedReader br = null; + try { + br = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent())); + String readLine; + String response = ""; + while (((readLine = br.readLine()) != null)) { + response += readLine; + } + return response; + } finally { + EntityUtils.consumeQuietly(httpResponse.getEntity()); + if (br != null) { + try { + br.close(); + } catch (IOException e) { + log.warn("Error while closing the connection! " + e.getMessage()); + } + } + } + } + + public static JWTClientManagerService getJWTClientManagerService() { + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + JWTClientManagerService jwtClientManagerService = + (JWTClientManagerService) ctx.getOSGiService(JWTClientManagerService.class, null); + if (jwtClientManagerService == null) { + String msg = "JWT management service has not initialized."; + log.error(msg); + throw new IllegalStateException(msg); + } + return jwtClientManagerService; + } +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/mqtt/util/RegistrationProfile.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/mqtt/util/RegistrationProfile.java new file mode 100644 index 0000000000..fec69d61b6 --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/java/org/wso2/carbon/event/input/adapter/extensions/mqtt/util/RegistrationProfile.java @@ -0,0 +1,73 @@ +package org.wso2.carbon.event.input.adapter.extensions.mqtt.util; + +/** + * This class represents the data that are required to register + * the oauth application. + */ +public class RegistrationProfile { + + private String callbackUrl; + private String clientName; + private String tokenScope; + private String owner; + private String grantType; + private String applicationType; + + private static final String TAG = RegistrationProfile.class.getSimpleName(); + + public String getCallbackUrl() { + return callbackUrl; + } + + public void setCallbackUrl(String callBackUrl) { + this.callbackUrl = callBackUrl; + } + + public String getClientName() { + return clientName; + } + + public void setClientName(String clientName) { + this.clientName = clientName; + } + + public String getTokenScope() { + return tokenScope; + } + + public void setTokenScope(String tokenScope) { + this.tokenScope = tokenScope; + } + + public String getOwner() { + return owner; + } + + public void setOwner(String owner) { + this.owner = owner; + } + + public String getGrantType() { + return grantType; + } + + public void setGrantType(String grantType) { + this.grantType = grantType; + } + + public String getApplicationType() { + return applicationType; + } + + public void setApplicationType(String applicationType) { + this.applicationType = applicationType; + } + + public String toJSON() { + String jsonString = + "{\"callbackUrl\": \"" + callbackUrl + "\",\"clientName\": \"" + clientName + "\", \"tokenScope\": " + + "\"" + tokenScope + "\", \"owner\": \"" + owner + "\"," + "\"grantType\": \"" + grantType + + "\", \"saasApp\" :false }\n"; + return jsonString; + } +} \ No newline at end of file diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/resources/org/wso2/carbon/event/input/adapter/extensions/http/i18n/Resources.properties b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/resources/org/wso2/carbon/event/input/adapter/extensions/http/i18n/Resources.properties new file mode 100644 index 0000000000..de84fc0124 --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/resources/org/wso2/carbon/event/input/adapter/extensions/http/i18n/Resources.properties @@ -0,0 +1,38 @@ +# +# Copyright (c) 2005-2014, 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. +# + +transports=Transport(s) +http.usage.tips_prefix=Following url formats are used to receive events
For super tenants:
  http://localhost: +http.usage.tips_mid1=/endpoints/<event_receiver_name>
  https://localhost: +http.usage.tips_mid2=/endpoints/<event_receiver_name>

For other tenants:
  http://localhost: +http.usage.tips_mid3=/endpoints/t/<tenant_domain>/<event_receiver_name>
  https://localhost: +http.usage.tips_postfix=/endpoints/t/<tenant_domain>/<event_receiver_name> +tokenValidationEndpointUrl=tokenEndpointUrl +tokenValidationEndpointUrl.hint=OAUTH Token Validation Endpoint +username=username +username.hint=username of the user to connect to the admin services +password=password +password.hint=password of the user to connect to the admin services. +maximumTotalHttpConnection=maximumTotalHttpConnection +maximumTotalHttpConnection.hint=Maximum Total connection to be made with the endpoint +maximumHttpConnectionPerHost=maximumHttpConnectionPerHost +maximumHttpConnectionPerHost.hint=Maximum Http connection per host. +contentValidation=contentValidation +contentValidation.hint=Class Name of the content Validation or 'default' to set default class, required to implement (if required) +contentValidationParams=contentValidationParams +contentValidationParams.hint=ContentValidationParams, comma seperated. (if required) \ No newline at end of file diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/resources/org/wso2/carbon/event/input/adapter/extensions/mqtt/i18n/Resources.properties b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/resources/org/wso2/carbon/event/input/adapter/extensions/mqtt/i18n/Resources.properties new file mode 100644 index 0000000000..70d4019e42 --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.input.adapter.extensions/src/main/resources/org/wso2/carbon/event/input/adapter/extensions/mqtt/i18n/Resources.properties @@ -0,0 +1,38 @@ +# +# Copyright (c) 2015, 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. +# + +topic=Topic +topic.hint=Topic subscribed +clientId=Client Id +clientId.hint=client identifier is used by the server to identify a client when it reconnects, It used for durable subscriptions or reliable delivery of messages is required. +url=Broker Url +username=Username +username.hint=Username of the broker (if required) +scopes=Scopes +scopes.hint=Scopes required to connect to broker (if required) +dcrUrl=dcrUrl +dcrUrl.hint=dynamic client registration endpoint URL to create application (if required) eg: https://localhost:9443/dynamic-client-web/register +contentValidation=contentValidation +contentValidation.hint=Class Name of the content Validation or 'default' to set default class, required to implement (if required) +contentValidationParams=contentValidationParams +contentValidationParams.hint=ContentValidationParams, comma seperated. (if required) +url.hint=MQTT broker url tcp://localhost:1883 +cleanSession=Clean Session +cleanSession.hint=Persist topic subscriptions and ack positions across client sessions +keepAlive=Keep Alive (In seconds) +events.duplicated.in.cluster=Is events duplicated in cluster \ No newline at end of file diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/pom.xml b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/pom.xml new file mode 100644 index 0000000000..466120b71e --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/pom.xml @@ -0,0 +1,82 @@ + + + + + + + das-extensions + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.event.output.adapter.extensions.ui.endpoint + war + WSO2 Carbon UI Webapp - Webapp for UI Output Event Adapter + http://wso2.org + + + + junit + junit + test + + + org.apache.tomcat + tomcat-websocket-api + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.event.output.adapter.extensions.ui + provided + + + org.apache.httpcomponents.wso2 + httpcore + + + javax.ws.rs + javax.ws.rs-api + + + org.apache.cxf + cxf-rt-frontend-jaxrs + + + org.apache.httpcomponents.wso2 + httpcore + provided + + + org.wso2.orbit.org.apache.httpcomponents + httpclient + provided + + + org.wso2.carbon.identity + org.wso2.carbon.identity.oauth.stub + provided + + + + + secured-outputui + + diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/java/SubscriptionEndpoint.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/java/SubscriptionEndpoint.java new file mode 100644 index 0000000000..d6e0e49092 --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/java/SubscriptionEndpoint.java @@ -0,0 +1,74 @@ +/* + * + * Copyright (c) 2015, 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. + * + */ + +import oauth.OAuthTokenValdiator; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.servlet.ServiceHolder; + +import javax.websocket.CloseReason; +import javax.websocket.Session; + +/** + * Interface for subscription and un-subscription for web socket + */ + +public class SubscriptionEndpoint { + + private static final Log log = LogFactory.getLog(SubscriptionEndpoint.class); + + public SubscriptionEndpoint() { + + } + + /** + * Web socket onClose - Remove the registered sessions + * + * @param session - Users registered session. + * @param reason - Status code for web-socket close. + * @param streamName - StreamName extracted from the ws url. + * @param version - Version extracted from the ws url. + */ + public void onClose(Session session, CloseReason reason, String streamName, String version) { + if (log.isDebugEnabled()) { + log.debug("Closing a WebSocket due to " + reason.getReasonPhrase() + ", for session ID:" + session.getId + () + + ", for request URI - " + session.getRequestURI()); + } + ServiceHolder.getInstance().getUiOutputCallbackControllerService().unsubscribeWebsocket(streamName, version, + session); + } + + /** + * Web socket onError - Remove the registered sessions + * + * @param session - Users registered session. + * @param throwable - Status code for web-socket close. + * @param streamName - StreamName extracted from the ws url. + * @param version - Version extracted from the ws url. + */ + public void onError(Session session, Throwable throwable, String streamName, String version) { + log.error( + "Error occurred in session ID: " + session.getId() + ", for request URI - " + session.getRequestURI() + + ", " + throwable.getMessage(), throwable); + ServiceHolder.getInstance().getUiOutputCallbackControllerService().unsubscribeWebsocket(streamName, version, + session); + } +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/java/SuperTenantSubscriptionEndpoint.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/java/SuperTenantSubscriptionEndpoint.java new file mode 100644 index 0000000000..674b32447f --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/java/SuperTenantSubscriptionEndpoint.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2015, 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. + */ + +import oauth.OAuthTokenValdiator; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.servlet.ServiceHolder; +import org.wso2.carbon.utils.multitenancy.MultitenantConstants; +import util.AuthenticationInfo; + +import javax.websocket.CloseReason; +import javax.websocket.OnClose; +import javax.websocket.OnError; +import javax.websocket.OnMessage; +import javax.websocket.OnOpen; +import javax.websocket.Session; +import javax.websocket.server.PathParam; +import javax.websocket.server.ServerEndpoint; + +/** + * Connect to web socket with Super tenant + */ + +@ServerEndpoint(value = "/{streamname}/{version}") +public class SuperTenantSubscriptionEndpoint extends SubscriptionEndpoint { + + private static final Log log = LogFactory.getLog(SuperTenantSubscriptionEndpoint.class); + + /** + * Web socket onOpen - When client sends a message + * + * @param session - Users registered session. + * @param streamName - StreamName extracted from the ws url. + * @param version - Version extracted from the ws url. + */ + @OnOpen + public void onOpen(Session session, @PathParam("streamname") String streamName, + @PathParam("version") String version) { + if (log.isDebugEnabled()) { + log.debug("WebSocket opened, for Session id: " + session.getId() + ", for the Stream:" + streamName); + } + AuthenticationInfo authenticationInfo = OAuthTokenValdiator.getInstance().validateToken(session); + //TODO Authorization + if (authenticationInfo != null && authenticationInfo.isAuthenticated()) { + try { + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantId(MultitenantConstants.SUPER_TENANT_ID); + + ServiceHolder.getInstance().getUiOutputCallbackControllerService().subscribeWebsocket(streamName, + version, + session); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + } + + /** + * Web socket onMessage - When client sens a message + * + * @param session - Users registered session. + * @param message - Status code for web-socket close. + * @param streamName - StreamName extracted from the ws url. + */ + @OnMessage + public void onMessage(Session session, String message, @PathParam("streamname") String streamName) { + if (log.isDebugEnabled()) { + log.debug("Received and dropped message from client. Message: " + message + ", " + + "for Session id: " + session.getId() + ", for the Stream:" + streamName); + } + } + + /** + * Web socket onClose - Remove the registered sessions + * + * @param session - Users registered session. + * @param reason - Status code for web-socket close. + * @param streamName - StreamName extracted from the ws url. + * @param version - Version extracted from the ws url. + */ + @OnClose + public void onClose(Session session, CloseReason reason, @PathParam("streamname") String streamName, + @PathParam("version") String version) { + try { + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantId(MultitenantConstants.SUPER_TENANT_ID); + super.onClose(session, reason, streamName, version); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + /** + * Web socket onError - Remove the registered sessions + * + * @param session - Users registered session. + * @param throwable - Status code for web-socket close. + * @param streamName - StreamName extracted from the ws url. + * @param version - Version extracted from the ws url. + */ + @OnError + public void onError(Session session, Throwable throwable, @PathParam("streamname") String streamName, + @PathParam("version") String version) { + try { + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantId(MultitenantConstants.SUPER_TENANT_ID); + super.onError(session, throwable, streamName, version); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/java/TenantSubscriptionEndpoint.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/java/TenantSubscriptionEndpoint.java new file mode 100644 index 0000000000..640fb0de17 --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/java/TenantSubscriptionEndpoint.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2015, 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. + */ + +import oauth.OAuthTokenValdiator; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.servlet.ServiceHolder; +import util.AuthenticationInfo; + +import javax.websocket.CloseReason; +import javax.websocket.OnClose; +import javax.websocket.OnError; +import javax.websocket.OnMessage; +import javax.websocket.OnOpen; +import javax.websocket.Session; +import javax.websocket.server.PathParam; +import javax.websocket.server.ServerEndpoint; + +/** + * Connect to web socket with a tenant + */ + +@ServerEndpoint(value = "/t/{tdomain}/{streamname}/{version}") +public class TenantSubscriptionEndpoint extends SubscriptionEndpoint { + + private static final Log log = LogFactory.getLog(TenantSubscriptionEndpoint.class); + + /** + * Web socket onOpen - When client sends a message + * + * @param session - Users registered session. + * @param streamName - StreamName extracted from the ws url. + * @param version - Version extracted from the ws url. + * @param tdomain - Tenant domain extracted from ws url. + */ + @OnOpen + public void onOpen (Session session, @PathParam("streamname") String streamName , + @PathParam("version") String version, @PathParam("tdomain") String tdomain) { + if (log.isDebugEnabled()) { + log.debug("WebSocket opened, for Session id: "+session.getId()+", for the Stream:"+streamName); + } + AuthenticationInfo authenticationInfo = OAuthTokenValdiator.getInstance().validateToken(session); + //TODO Authorization + if (authenticationInfo != null && authenticationInfo.isAuthenticated()) { + try { + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tdomain, true); + ServiceHolder.getInstance().getUiOutputCallbackControllerService().subscribeWebsocket(streamName, + version, session); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + } + + /** + * Web socket onMessage - When client sens a message + * + * @param session - Users registered session. + * @param message - Status code for web-socket close. + * @param streamName - StreamName extracted from the ws url. + */ + @OnMessage + public void onMessage (Session session, String message, @PathParam("streamname") String streamName, @PathParam("tdomain") String tdomain) { + if (log.isDebugEnabled()) { + log.debug("Received and dropped message from client. Message: " + message+", for Session id: "+session.getId()+", for tenant domain"+tdomain+", for the Adaptor:"+streamName); + } + } + + /** + * Web socket onClose - Remove the registered sessions + * + * @param session - Users registered session. + * @param reason - Status code for web-socket close. + * @param streamName - StreamName extracted from the ws url. + * @param version - Version extracted from the ws url. + */ + @OnClose + public void onClose (Session session, CloseReason reason, @PathParam("streamname") String streamName, + @PathParam("version") String version, @PathParam("tdomain") String tdomain) { + + try { + PrivilegedCarbonContext.getThreadLocalCarbonContext().startTenantFlow(); + PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tdomain,true); + super.onClose(session, reason, streamName, version); + } finally { + PrivilegedCarbonContext.getThreadLocalCarbonContext().endTenantFlow(); + } + } + + /** + * Web socket onError - Remove the registered sessions + * + * @param session - Users registered session. + * @param throwable - Status code for web-socket close. + * @param streamName - StreamName extracted from the ws url. + * @param version - Version extracted from the ws url. + */ + @OnError + public void onError (Session session, Throwable throwable, @PathParam("streamname") String streamName, + @PathParam("version") String version, @PathParam("tdomain") String tdomain) { + + try { + PrivilegedCarbonContext.getThreadLocalCarbonContext().startTenantFlow(); + PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tdomain, true); + super.onError(session, throwable, streamName, version); + } finally { + PrivilegedCarbonContext.getThreadLocalCarbonContext().endTenantFlow(); + } + } +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/java/oauth/OAuthTokenValdiator.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/java/oauth/OAuthTokenValdiator.java new file mode 100644 index 0000000000..1abe5f1792 --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/java/oauth/OAuthTokenValdiator.java @@ -0,0 +1,174 @@ +package oauth; + +import org.apache.axis2.context.ServiceContext; +import org.apache.axis2.transport.http.HTTPConstants; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.pool.impl.GenericObjectPool; +import org.wso2.carbon.identity.oauth2.stub.OAuth2TokenValidationServiceStub; +import org.wso2.carbon.identity.oauth2.stub.dto.OAuth2TokenValidationRequestDTO; +import org.wso2.carbon.identity.oauth2.stub.dto.OAuth2TokenValidationRequestDTO_OAuth2AccessToken; +import org.wso2.carbon.identity.oauth2.stub.dto.OAuth2TokenValidationResponseDTO; +import org.wso2.carbon.user.api.UserStoreException; +import org.wso2.carbon.utils.CarbonUtils; +import org.wso2.carbon.utils.multitenancy.MultitenantUtils; +import util.AuthenticationInfo; + +import javax.websocket.Session; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.rmi.RemoteException; +import java.util.Properties; + +public class OAuthTokenValdiator { + + private static String cookie; + private GenericObjectPool stubs; + private static Log log = LogFactory.getLog(OAuthTokenValdiator.class); + private static final String WEBSOCKET_CONFIG_LOCATION = + CarbonUtils.getEtcCarbonConfigDirPath() + File.separator + "websocket-validation.properties"; + private static final String QUERY_STRING_SEPERATOR = "&"; + private static final String QUERY_KEY_VALUE_SEPERATOR = "="; + private static final String TOKEN_TYPE = "bearer"; + private static final String TOKEN_IDENTIFIER = "token"; + private static OAuthTokenValdiator oAuthTokenValdiator = new OAuthTokenValdiator(); + + public static OAuthTokenValdiator getInstance() { + return oAuthTokenValdiator; + } + + private OAuthTokenValdiator() { + Properties properties = null; + try { + properties = getWebSocketConfig(); + this.stubs = new GenericObjectPool(new OAuthTokenValidaterStubFactory(properties)); + } catch (IOException e) { + log.error("Failed to parse the web socket config file " + WEBSOCKET_CONFIG_LOCATION); + } + } + + /** + * This method gets a string accessToken and validates it + * + * @param session which need to be validated. + * @return AuthenticationInfo with the validated results. + */ + public AuthenticationInfo validateToken(Session session) { + String token = getTokenFromSession(session); + if (token == null) { + AuthenticationInfo authenticationInfo = new AuthenticationInfo(); + authenticationInfo.setAuthenticated(false); + return authenticationInfo; + } + OAuth2TokenValidationServiceStub tokenValidationServiceStub = null; + try { + Object stub = this.stubs.borrowObject(); + if (stub != null) { + tokenValidationServiceStub = (OAuth2TokenValidationServiceStub) stub; + if (cookie != null) { + tokenValidationServiceStub._getServiceClient().getOptions().setProperty( + HTTPConstants.COOKIE_STRING, cookie); + } + return getAuthenticationInfo(token, tokenValidationServiceStub); + } else { + log.warn("Stub initialization failed."); + } + } catch (RemoteException e) { + log.error("Error on connecting with the validation endpoint.", e); + } catch (Exception e) { + log.error("Error occurred in borrowing an validation stub from the pool.", e); + + } finally { + try { + if (tokenValidationServiceStub != null) { + this.stubs.returnObject(tokenValidationServiceStub); + } + } catch (Exception e) { + log.warn("Error occurred while returning the object back to the oauth token validation service " + + "stub pool.", e); + } + } + AuthenticationInfo authenticationInfo = new AuthenticationInfo(); + authenticationInfo.setAuthenticated(false); + return authenticationInfo; + } + + /** + * This creates an AuthenticationInfo object that is used for authorization. This method will validate the token + * and + * sets the required parameters to the object. + * + * @param token that needs to be validated. + * @param tokenValidationServiceStub stub that is used to call the external service. + * @return AuthenticationInfo This contains the information related to authenticated client. + * @throws RemoteException that triggers when failing to call the external service.. + */ + private AuthenticationInfo getAuthenticationInfo(String token, + OAuth2TokenValidationServiceStub tokenValidationServiceStub) + throws RemoteException, UserStoreException { + AuthenticationInfo authenticationInfo = new AuthenticationInfo(); + OAuth2TokenValidationRequestDTO validationRequest = new OAuth2TokenValidationRequestDTO(); + OAuth2TokenValidationRequestDTO_OAuth2AccessToken accessToken = + new OAuth2TokenValidationRequestDTO_OAuth2AccessToken(); + accessToken.setTokenType(TOKEN_TYPE); + accessToken.setIdentifier(token); + validationRequest.setAccessToken(accessToken); + boolean authenticated; + OAuth2TokenValidationResponseDTO tokenValidationResponse; + tokenValidationResponse = tokenValidationServiceStub.validate(validationRequest); + if (tokenValidationResponse == null) { + authenticationInfo.setAuthenticated(false); + return authenticationInfo; + } + authenticated = tokenValidationResponse.getValid(); + if (authenticated) { + String authorizedUser = tokenValidationResponse.getAuthorizedUser(); + String username = MultitenantUtils.getTenantAwareUsername(authorizedUser); + String tenantDomain = MultitenantUtils.getTenantDomain(authorizedUser); + authenticationInfo.setUsername(username); + authenticationInfo.setTenantDomain(tenantDomain); + } else { + if (log.isDebugEnabled()) { + log.debug("Token validation failed for token: " + token); + } + } + ServiceContext serviceContext = tokenValidationServiceStub._getServiceClient() + .getLastOperationContext().getServiceContext(); + cookie = (String) serviceContext.getProperty(HTTPConstants.COOKIE_STRING); + authenticationInfo.setAuthenticated(authenticated); + return authenticationInfo; + } + + /** + * Retrieve JWT configs from registry. + */ + private Properties getWebSocketConfig() throws IOException { + Properties properties = new Properties(); + InputStream inputStream = getClass().getClassLoader().getResourceAsStream(WEBSOCKET_CONFIG_LOCATION); + if (inputStream != null) { + properties.load(inputStream); + } + return properties; + } + + private String getTokenFromSession(Session session) { + String queryString = session.getQueryString(); + if (queryString != null) { + String[] allQueryParamPairs = queryString.split(QUERY_STRING_SEPERATOR); + + for (String keyValuePair : allQueryParamPairs) { + String[] queryParamPair = keyValuePair.split(QUERY_KEY_VALUE_SEPERATOR); + + if (queryParamPair.length != 2) { + log.warn("Invalid query string [" + queryString + "] passed in."); + break; + } + if (queryParamPair[0].equals(TOKEN_IDENTIFIER)) { + return queryParamPair[1]; + } + } + } + return null; + } +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/java/oauth/OAuthTokenValidaterStubFactory.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/java/oauth/OAuthTokenValidaterStubFactory.java new file mode 100644 index 0000000000..a43f874729 --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/java/oauth/OAuthTokenValidaterStubFactory.java @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2016, 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. + */ +package oauth; + +import oauth.exception.OAuthTokenValidationException; +import org.apache.axis2.AxisFault; +import org.apache.axis2.Constants; +import org.apache.axis2.client.Options; +import org.apache.axis2.client.ServiceClient; +import org.apache.axis2.transport.http.HTTPConstants; +import org.apache.axis2.transport.http.HttpTransportProperties; +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpConnectionManager; +import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager; +import org.apache.commons.httpclient.contrib.ssl.EasySSLProtocolSocketFactory; +import org.apache.commons.httpclient.params.HttpConnectionManagerParams; +import org.apache.commons.httpclient.protocol.Protocol; +import org.apache.commons.httpclient.protocol.ProtocolSocketFactory; +import org.apache.commons.pool.BasePoolableObjectFactory; +import org.apache.log4j.Logger; +import org.wso2.carbon.identity.oauth2.stub.OAuth2TokenValidationServiceStub; +import util.UIConstants; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.security.GeneralSecurityException; +import java.util.Properties; + +/** + * This follows object pool pattern to manage the stub for oauth validation service. + */ +public class OAuthTokenValidaterStubFactory extends BasePoolableObjectFactory { + private static final Logger log = Logger.getLogger(OAuthTokenValidaterStubFactory.class); + private HttpClient httpClient; + Properties tokenValidationProperties; + + + public OAuthTokenValidaterStubFactory(Properties tokenValidationProperties) { + this.tokenValidationProperties = tokenValidationProperties; + this.httpClient = createHttpClient(); + } + + /** + * This creates a OAuth2TokenValidationServiceStub object to the pool. + * + * @return an OAuthValidationStub object + * @throws Exception thrown when creating the object. + */ + @Override + public Object makeObject() throws Exception { + return this.generateStub(); + } + + /** + * This is used to clean up the OAuth validation stub and releases to the object pool. + * + * @param o object that needs to be released. + * @throws Exception throws when failed to release to the pool + */ + @Override + public void passivateObject(Object o) throws Exception { + if (o instanceof OAuth2TokenValidationServiceStub) { + OAuth2TokenValidationServiceStub stub = (OAuth2TokenValidationServiceStub) o; + stub._getServiceClient().cleanupTransport(); + } + } + + /** + * This is used to create a stub which will be triggered through object pool factory, which will create an + * instance of it. + * + * @return OAuth2TokenValidationServiceStub stub that is used to call an external service. + * @throws OAuthTokenValidationException will be thrown when initialization failed. + */ + private OAuth2TokenValidationServiceStub generateStub() throws OAuthTokenValidationException { + OAuth2TokenValidationServiceStub stub; + try { + URL hostURL = new URL(tokenValidationProperties.getProperty((UIConstants.TOKEN_VALIDATION_ENDPOINT_URL))); + if (hostURL != null) { + stub = new OAuth2TokenValidationServiceStub(hostURL.toString()); + if (stub != null) { + ServiceClient client = stub._getServiceClient(); + client.getServiceContext().getConfigurationContext().setProperty( + HTTPConstants.CACHED_HTTP_CLIENT, httpClient); + + HttpTransportProperties.Authenticator auth = + new HttpTransportProperties.Authenticator(); + auth.setPreemptiveAuthentication(true); + String username = tokenValidationProperties.getProperty(UIConstants.USERNAME); + String password = tokenValidationProperties.getProperty(UIConstants.PASSWORD); + auth.setPassword(username); + auth.setUsername(password); + Options options = client.getOptions(); + options.setProperty(HTTPConstants.AUTHENTICATE, auth); + options.setProperty(HTTPConstants.REUSE_HTTP_CLIENT, Constants.VALUE_TRUE); + client.setOptions(options); + if (hostURL.getProtocol().equals("https")) { + // set up ssl factory since axis2 https transport is used. + EasySSLProtocolSocketFactory sslProtocolSocketFactory = + createProtocolSocketFactory(); + Protocol authhttps = new Protocol(hostURL.getProtocol(), + (ProtocolSocketFactory) sslProtocolSocketFactory, + hostURL.getPort()); + Protocol.registerProtocol(hostURL.getProtocol(), authhttps); + options.setProperty(HTTPConstants.CUSTOM_PROTOCOL_HANDLER, authhttps); + } + } else { + String errorMsg = "OAuth Validation instanization failed."; + throw new OAuthTokenValidationException(errorMsg); + } + } else { + String errorMsg = "host url is invalid"; + throw new OAuthTokenValidationException(errorMsg); + } + } catch (AxisFault axisFault) { + throw new OAuthTokenValidationException( + "Error occurred while creating the OAuth2TokenValidationServiceStub.", axisFault); + } catch (MalformedURLException e) { + throw new OAuthTokenValidationException( + "Error occurred while parsing token endpoint URL", e); + } + + return stub; + } + + /** + * This is required to create a trusted connection with the external entity. + * Have to manually configure it since we use CommonHTTPTransport(axis2 transport) in axis2. + * + * @return an EasySSLProtocolSocketFactory for SSL communication. + */ + private EasySSLProtocolSocketFactory createProtocolSocketFactory() throws OAuthTokenValidationException { + try { + EasySSLProtocolSocketFactory easySSLPSFactory = new EasySSLProtocolSocketFactory(); + return easySSLPSFactory; + } catch (IOException e) { + String errorMsg = "Failed to initiate EasySSLProtocolSocketFactory."; + throw new OAuthTokenValidationException(errorMsg, e); + } catch (GeneralSecurityException e) { + String errorMsg = "Failed to set the key material in easy ssl factory."; + throw new OAuthTokenValidationException(errorMsg, e); + } + } + + /** + * This created httpclient pool that can be used to connect to external entity. This connection can be configured + * via broker.xml by setting up the required http connection parameters. + * + * @return an instance of HttpClient that is configured with MultiThreadedHttpConnectionManager + */ + private HttpClient createHttpClient() { + HttpConnectionManagerParams params = new HttpConnectionManagerParams(); + params.setDefaultMaxConnectionsPerHost(Integer.parseInt(tokenValidationProperties.getProperty( + UIConstants.MAXIMUM_HTTP_CONNECTION_PER_HOST))); + params.setMaxTotalConnections(Integer.parseInt(tokenValidationProperties.getProperty( + UIConstants.MAXIMUM_TOTAL_HTTP_CONNECTION))); + HttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager(); + connectionManager.setParams(params); + return new HttpClient(connectionManager); + } +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/java/oauth/exception/OAuthTokenValidationException.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/java/oauth/exception/OAuthTokenValidationException.java new file mode 100644 index 0000000000..3f54c5244c --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/java/oauth/exception/OAuthTokenValidationException.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2016, 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. + */ +package oauth.exception; + +/** + * This Exception will be thrown, when there any interference with token validation flow. + */ +public class OAuthTokenValidationException extends Exception { + private String errMessage; + + public OAuthTokenValidationException(String msg, Exception nestedEx) { + super(msg, nestedEx); + setErrorMessage(msg); + } + + public OAuthTokenValidationException(String message, Throwable cause) { + super(message, cause); + setErrorMessage(message); + } + + public OAuthTokenValidationException(String msg) { + super(msg); + setErrorMessage(msg); + } + + public OAuthTokenValidationException() { + super(); + } + + public OAuthTokenValidationException(Throwable cause) { + super(cause); + } + + public String getErrorMessage() { + return errMessage; + } + + public void setErrorMessage(String errMessage) { + this.errMessage = errMessage; + } +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/java/org/wso2/carbon/servlet/ServiceHolder.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/java/org/wso2/carbon/servlet/ServiceHolder.java new file mode 100644 index 0000000000..08d07a44c6 --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/java/org/wso2/carbon/servlet/ServiceHolder.java @@ -0,0 +1,28 @@ +package org.wso2.carbon.servlet; + + +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.event.output.adapter.extensions.ui.UIOutputCallbackControllerService; + +public class ServiceHolder { + + private static ServiceHolder instance; + private UIOutputCallbackControllerService uiOutputCallbackControllerService; + + private ServiceHolder(){ + uiOutputCallbackControllerService = (UIOutputCallbackControllerService) PrivilegedCarbonContext + .getThreadLocalCarbonContext() + .getOSGiService(UIOutputCallbackControllerService.class,null); + } + + public synchronized static ServiceHolder getInstance(){ + if (instance==null){ + instance= new ServiceHolder(); + } + return instance; + } + + public UIOutputCallbackControllerService getUiOutputCallbackControllerService() { + return uiOutputCallbackControllerService; + } +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/java/org/wso2/carbon/servlet/SuperTenantEventRetrievalEndpoint.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/java/org/wso2/carbon/servlet/SuperTenantEventRetrievalEndpoint.java new file mode 100644 index 0000000000..41a0d8b33a --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/java/org/wso2/carbon/servlet/SuperTenantEventRetrievalEndpoint.java @@ -0,0 +1,85 @@ +package org.wso2.carbon.servlet;/* + * + * Copyright (c) 2014-2015, 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. + * + */ + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.utils.multitenancy.MultitenantConstants; +import util.UIConstants; + +import javax.ws.rs.GET; +import javax.ws.rs.QueryParam; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +/** + * Getting events for HTTP request for super tenant + */ + +@Path("/") +public class SuperTenantEventRetrievalEndpoint{ + + public SuperTenantEventRetrievalEndpoint() { + } + + /** + * Retrieve events when polling + * + * @param streamName - StreamName extracted from the http url. + * @param version - Version extracted from the http url. + * @param lastUpdatedTime - Last event's dispatched name. + * @return respnse + */ + @GET + @Path("/{streamname}/{version}") + public Response retrieveEvents(@PathParam("streamname") String streamName, @PathParam("version") String version, + @QueryParam("lastUpdatedTime") String lastUpdatedTime) { + String streamId; + JsonObject eventDetails; + String jsonString; + + try { + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantId(MultitenantConstants.SUPER_TENANT_ID); + streamId = streamName + UIConstants.ADAPTER_UI_COLON + version; + + eventDetails = ServiceHolder.getInstance().getUiOutputCallbackControllerService().retrieveEvents(streamName, version, + lastUpdatedTime); + + } finally { + PrivilegedCarbonContext.getThreadLocalCarbonContext().endTenantFlow(); + } + + if(eventDetails == null){ + JsonObject errorData = new JsonObject(); + errorData.addProperty("error","StreamId: " + streamId + " is not registered to receive events."); + jsonString = new Gson().toJson(errorData); + return Response.status(Response.Status.NOT_FOUND).entity(jsonString).header + ("Access-Control-Allow-Origin","*").build(); + } else{ + jsonString = new Gson().toJson(eventDetails); + return Response.ok(jsonString, MediaType.APPLICATION_JSON).header("Access-Control-Allow-Origin", + "*").build(); + } + } + +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/java/org/wso2/carbon/servlet/TenantEventRetrievalEndpoint.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/java/org/wso2/carbon/servlet/TenantEventRetrievalEndpoint.java new file mode 100644 index 0000000000..ec14e57221 --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/java/org/wso2/carbon/servlet/TenantEventRetrievalEndpoint.java @@ -0,0 +1,89 @@ +package org.wso2.carbon.servlet; +/* + * + * Copyright (c) 2014-2015, 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. + * + */ + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import util.UIConstants; + +import javax.ws.rs.GET; +import javax.ws.rs.QueryParam; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +/** + * Getting events for HTTP request from a tenant + */ + +@Path("/t/{tdomain}/") +public class TenantEventRetrievalEndpoint { + + private static final Log log = LogFactory.getLog(SuperTenantEventRetrievalEndpoint.class); + + public TenantEventRetrievalEndpoint() { + + } + + /** + * Retrieve events when polling + * + * @param streamName - StreamName extracted from the http url. + * @param version - Version extracted from the http url. + * @param lastUpdatedTime - Last event's dispatched name. + * @param tdomain - Tenant domain extracted from http url + * @return response + */ + @GET + @Path("/{streamname}/{version}") + public Response retrieveEvents(@PathParam("streamname") String streamName, @PathParam("version") String version, + @QueryParam("lastUpdatedTime") String lastUpdatedTime, + @PathParam("tdomain") String tdomain) { + + String streamId; + JsonObject eventDetails; + try { + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tdomain, true); + streamId = streamName + UIConstants.ADAPTER_UI_COLON + version; + eventDetails = ServiceHolder.getInstance().getUiOutputCallbackControllerService().retrieveEvents + (streamName, version, lastUpdatedTime); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + + String jsonString; + if (eventDetails == null) { + JsonObject errorData = new JsonObject(); + errorData.addProperty("error", "StreamId: " + streamId + " is not registered to receive events."); + jsonString = new Gson().toJson(errorData); + return Response.status(Response.Status.NOT_FOUND).entity(jsonString).header + ("Access-Control-Allow-Origin", "*").build(); + } else { + jsonString = new Gson().toJson(eventDetails); + return Response.ok(jsonString, MediaType.APPLICATION_JSON).header("Access-Control-Allow-Origin", + "*").build(); + } + } +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/java/util/AuthenticationInfo.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/java/util/AuthenticationInfo.java new file mode 100644 index 0000000000..2bac34e68f --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/java/util/AuthenticationInfo.java @@ -0,0 +1,43 @@ +package util; + +public class AuthenticationInfo { + + /** + * this variable is used to check whether the client is authenticated. + */ + private boolean authenticated; + private String username; + private String tenantDomain; + /** + * returns whether the client is authenticated + */ + public boolean isAuthenticated() { + return authenticated; + } + + public void setAuthenticated(boolean authenticated) { + this.authenticated = authenticated; + } + + /** + * returns the authenticated client username + */ + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + /** + * return the authenticated client tenant domain + */ + public String getTenantDomain() { + return tenantDomain; + } + + public void setTenantDomain(String tenantDomain) { + this.tenantDomain = tenantDomain; + } +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/java/util/UIConstants.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/java/util/UIConstants.java new file mode 100644 index 0000000000..52f61f0201 --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/java/util/UIConstants.java @@ -0,0 +1,38 @@ +/* + * + * * + * * Copyright (c) 2015, 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. + * * + * + */ + +package util; + +/** + * This class contains the constants related to ui client. + */ +public class UIConstants { + + private UIConstants() { + } + public static final String ADAPTER_UI_COLON = ":"; + public static final String MAXIMUM_TOTAL_HTTP_CONNECTION = "maximumTotalHttpConnection"; + public static final String MAXIMUM_HTTP_CONNECTION_PER_HOST = "maximumHttpConnectionPerHost"; + public static final String TOKEN_VALIDATION_ENDPOINT_URL = "tokenValidationEndpointUrl"; + public static final String USERNAME = "username"; + public static final String PASSWORD = "password"; +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/webapp/WEB-INF/web.xml b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000000..4c01cc52c2 --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui.endpoint/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,41 @@ + + + + + Output WebSocket + + JAXServlet + + org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet + + + jaxrs.serviceClasses + org.wso2.carbon.servlet.TenantEventRetrievalEndpoint org.wso2.carbon.servlet.SuperTenantEventRetrievalEndpoint + + 1 + + + + + JAXServlet + /* + + diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui/pom.xml b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui/pom.xml new file mode 100644 index 0000000000..0dee07435a --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui/pom.xml @@ -0,0 +1,137 @@ + + + + + + das-extensions + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.event.output.adapter.extensions.ui + bundle + WSO2 Carbon - Event Output UI Adapter Module + org.wso2.carbon.event.output.adapter.ui provides the back-end functionality of + ui event adapter + + http://wso2.org + + + + org.wso2.carbon.analytics-common + org.wso2.carbon.event.output.adapter.core + + + org.wso2.carbon + org.wso2.carbon.logging + + + org.wso2.carbon + org.wso2.carbon.core + + + javax.websocket + javax.websocket-api + + + org.wso2.carbon.analytics-common + org.wso2.carbon.databridge.commons + + + com.google.code.gson + gson + + + org.wso2.carbon.analytics-common + org.wso2.carbon.event.stream.core + + + + + + + org.apache.felix + maven-scr-plugin + + + generate-scr-descriptor + + scr + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + org.apache.felix + maven-bundle-plugin + true + + + ${project.artifactId} + ${project.artifactId} + + org.wso2.carbon.event.output.adapter.extensions.ui.internal, + org.wso2.carbon.event.output.adapter.extensions.ui.internal.* + + + !org.wso2.carbon.event.output.adapter.extensions.ui.internal, + !org.wso2.carbon.event.output.adapter.extensions.ui.internal.*, + org.wso2.carbon.event.output.adapter.extensions.ui.* + + + org.wso2.carbon.event.output.adapter.core.*, + javax.xml.namespace; version=0.0.0, + org.apache.axis2, + org.apache.axis2.client, + org.apache.axis2.context, + org.apache.axis2.transport.http, + org.apache.commons.httpclient, + org.apache.commons.httpclient.contrib.ssl, + org.apache.commons.httpclient.params, + org.apache.commons.httpclient.protocol, + org.apache.commons.pool, + org.apache.commons.pool.impl, + org.apache.log4j, + com.google.gson, + javax.websocket, + org.apache.commons.logging, + org.osgi.framework, + org.osgi.service.component, + org.wso2.carbon.context, + org.wso2.carbon.databridge.commons, + org.wso2.carbon.event.stream.core, + org.wso2.carbon.event.stream.core.exception, + org.wso2.carbon.utils + + + + + + + + + + + diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui/src/main/java/org/wso2/carbon/event/output/adapter/extensions/ui/UIEventAdapter.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui/src/main/java/org/wso2/carbon/event/output/adapter/extensions/ui/UIEventAdapter.java new file mode 100644 index 0000000000..f34ee03df5 --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui/src/main/java/org/wso2/carbon/event/output/adapter/extensions/ui/UIEventAdapter.java @@ -0,0 +1,459 @@ +/* + * + * Copyright (c) 2015, 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. + * + */ +package org.wso2.carbon.event.output.adapter.extensions.ui; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.context.CarbonContext; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.databridge.commons.Attribute; +import org.wso2.carbon.databridge.commons.Event; +import org.wso2.carbon.databridge.commons.StreamDefinition; +import org.wso2.carbon.event.output.adapter.core.EventAdapterUtil; +import org.wso2.carbon.event.output.adapter.core.OutputEventAdapter; +import org.wso2.carbon.event.output.adapter.core.OutputEventAdapterConfiguration; +import org.wso2.carbon.event.output.adapter.core.exception.OutputEventAdapterException; +import org.wso2.carbon.event.output.adapter.core.exception.OutputEventAdapterRuntimeException; +import org.wso2.carbon.event.output.adapter.core.exception.TestConnectionNotSupportedException; +import org.wso2.carbon.event.output.adapter.extensions.ui.internal.ds.OutputAdaptorEventStreamServiceValueHolder; +import org.wso2.carbon.event.output.adapter.extensions.ui.internal.util.UIEventAdapterConstants; +import org.wso2.carbon.event.output.adapter.extensions.ui.internal.UIOutputCallbackControllerServiceImpl; +import org.wso2.carbon.event.output.adapter.extensions.ui.internal.ds.UIEventAdaptorServiceInternalValueHolder; +import org.wso2.carbon.event.output.adapter.extensions.ui.internal.util.CEPWebSocketSession; +import org.wso2.carbon.event.stream.core.EventStreamService; +import org.wso2.carbon.event.stream.core.exception.EventStreamConfigurationException; + +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.LinkedBlockingDeque; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * Contains the life cycle of executions regarding the UI Adapter + */ + +public class UIEventAdapter implements OutputEventAdapter { + + private static final Log log = LogFactory.getLog(UIEventAdapter.class); + private OutputEventAdapterConfiguration eventAdapterConfiguration; + private Map globalProperties; + private int queueSize; + private LinkedBlockingDeque streamSpecificEvents; + private static ThreadPoolExecutor executorService; + private int tenantId; + private boolean doLogDroppedMessage; + + private String streamId; + private StreamDefinition streamDefinition; + private List streamMetaAttributes; + private List streamCorrelationAttributes; + private List streamPayloadAttributes; + + public UIEventAdapter(OutputEventAdapterConfiguration eventAdapterConfiguration, Map globalProperties) { + this.eventAdapterConfiguration = eventAdapterConfiguration; + this.globalProperties = globalProperties; + this.doLogDroppedMessage = true; + } + + @Override + public void init() throws OutputEventAdapterException { + + tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(); + + //ExecutorService will be assigned if it is null + if (executorService == null) { + int minThread; + int maxThread; + long defaultKeepAliveTime; + int jobQueSize; + + //If global properties are available those will be assigned else constant values will be assigned + if (globalProperties.get(UIEventAdapterConstants.ADAPTER_MIN_THREAD_POOL_SIZE_NAME) != null) { + minThread = Integer.parseInt(globalProperties.get( + UIEventAdapterConstants.ADAPTER_MIN_THREAD_POOL_SIZE_NAME)); + } else { + minThread = UIEventAdapterConstants.ADAPTER_MIN_THREAD_POOL_SIZE; + } + + if (globalProperties.get(UIEventAdapterConstants.ADAPTER_MAX_THREAD_POOL_SIZE_NAME) != null) { + maxThread = Integer.parseInt(globalProperties.get( + UIEventAdapterConstants.ADAPTER_MAX_THREAD_POOL_SIZE_NAME)); + } else { + maxThread = UIEventAdapterConstants.ADAPTER_MAX_THREAD_POOL_SIZE; + } + + if (globalProperties.get(UIEventAdapterConstants.ADAPTER_KEEP_ALIVE_TIME_NAME) != null) { + defaultKeepAliveTime = Integer.parseInt(globalProperties.get( + UIEventAdapterConstants.ADAPTER_KEEP_ALIVE_TIME_NAME)); + } else { + defaultKeepAliveTime = UIEventAdapterConstants.DEFAULT_KEEP_ALIVE_TIME_IN_MILLIS; + } + + if (globalProperties.get(UIEventAdapterConstants.ADAPTER_EXECUTOR_JOB_QUEUE_SIZE_NAME) != null) { + jobQueSize = Integer.parseInt(globalProperties.get( + UIEventAdapterConstants.ADAPTER_EXECUTOR_JOB_QUEUE_SIZE_NAME)); + } else { + jobQueSize = UIEventAdapterConstants.ADAPTER_EXECUTOR_JOB_QUEUE_SIZE; + } + + executorService = new ThreadPoolExecutor(minThread, maxThread, defaultKeepAliveTime, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue(jobQueSize)); + } + + streamId = eventAdapterConfiguration.getOutputStreamIdOfWso2eventMessageFormat(); + if (streamId == null || streamId.isEmpty()) { + throw new OutputEventAdapterRuntimeException("UI event adapter needs a output stream id"); + } + + // fetch the "streamDefinition" corresponding to the "streamId" and then fetch the different attribute types + // of the streamDefinition corresponding to the event's streamId. They are required when validating values in + // the events against the streamDef attributes. + streamDefinition = getStreamDefinition(streamId); + streamMetaAttributes = streamDefinition.getMetaData(); + streamCorrelationAttributes = streamDefinition.getCorrelationData(); + streamPayloadAttributes = streamDefinition.getPayloadData(); + + ConcurrentHashMap> tenantSpecifcEventOutputAdapterMap = + UIEventAdaptorServiceInternalValueHolder.getTenantSpecificOutputEventStreamAdapterMap(); + + ConcurrentHashMap streamSpecifAdapterMap = tenantSpecifcEventOutputAdapterMap.get(tenantId); + + if (streamSpecifAdapterMap == null) { + streamSpecifAdapterMap = new ConcurrentHashMap(); + if (null != tenantSpecifcEventOutputAdapterMap.putIfAbsent(tenantId, streamSpecifAdapterMap)) { + streamSpecifAdapterMap = tenantSpecifcEventOutputAdapterMap.get(tenantId); + } + } + + String adapterName = streamSpecifAdapterMap.get(streamId); + + if (adapterName != null) { + throw new OutputEventAdapterException(("An Output ui event adapter \"" + adapterName + "\" is already" + + " exist for stream id \"" + streamId + "\"")); + } else { + streamSpecifAdapterMap.put(streamId, eventAdapterConfiguration.getName()); + + ConcurrentHashMap>> tenantSpecificStreamMap = + UIEventAdaptorServiceInternalValueHolder.getTenantSpecificStreamEventMap(); + ConcurrentHashMap> streamSpecificEventsMap = + tenantSpecificStreamMap.get(tenantId); + + if (streamSpecificEventsMap == null) { + streamSpecificEventsMap = new ConcurrentHashMap>(); + if (null != tenantSpecificStreamMap.putIfAbsent(tenantId, streamSpecificEventsMap)) { + streamSpecificEventsMap = tenantSpecificStreamMap.get(tenantId); + } + } + streamSpecificEvents = streamSpecificEventsMap.get(streamId); + + if (streamSpecificEvents == null) { + streamSpecificEvents = new LinkedBlockingDeque(); + if (null != streamSpecificEventsMap.putIfAbsent(streamId, streamSpecificEvents)) { + streamSpecificEvents = streamSpecificEventsMap.get(streamId); + } + } + } + + if (globalProperties.get(UIEventAdapterConstants.ADAPTER_EVENT_QUEUE_SIZE_NAME) != null) { + try { + queueSize = Integer.parseInt( + globalProperties.get(UIEventAdapterConstants.ADAPTER_EVENT_QUEUE_SIZE_NAME)); + } catch (NumberFormatException e) { + log.error("String does not have the appropriate format for conversion." + e.getMessage()); + queueSize = UIEventAdapterConstants.EVENTS_QUEUE_SIZE; + } + } else { + queueSize = UIEventAdapterConstants.EVENTS_QUEUE_SIZE; + } + } + + @Override + public void testConnect() throws TestConnectionNotSupportedException { + throw new TestConnectionNotSupportedException("Test connection is not available"); + } + + @Override + public void connect() { + //Not needed + } + + @Override + public void publish(Object message, Map dynamicProperties) { + + Event event = (Event) message; + StringBuilder eventBuilder = new StringBuilder("["); + + if (streamSpecificEvents.size() == queueSize) { + streamSpecificEvents.removeFirst(); + } + + eventBuilder.append(event.getTimeStamp()); + + if (event.getMetaData() != null) { + eventBuilder.append(","); + Object[] metaData = event.getMetaData(); + for (int i = 0; i < metaData.length; i++) { + eventBuilder.append("\""); + eventBuilder.append(metaData[i]); + eventBuilder.append("\""); + if (i != (metaData.length - 1)) { + eventBuilder.append(","); + } + } + } + + if (event.getCorrelationData() != null) { + Object[] correlationData = event.getCorrelationData(); + + eventBuilder.append(","); + + for (int i = 0; i < correlationData.length; i++) { + eventBuilder.append("\""); + eventBuilder.append(correlationData[i]); + eventBuilder.append("\""); + if (i != (correlationData.length - 1)) { + eventBuilder.append(","); + } + } + } + + if (event.getPayloadData() != null) { + Object[] payloadData = event.getPayloadData(); + eventBuilder.append(","); + for (int i = 0; i < payloadData.length; i++) { + eventBuilder.append("\""); + eventBuilder.append(payloadData[i]); + eventBuilder.append("\""); + if (i != (payloadData.length - 1)) { + eventBuilder.append(","); + } + } + } + + eventBuilder.append("]"); + String eventString = eventBuilder.toString(); + Object[] eventValues = new Object[UIEventAdapterConstants.INDEX_TWO]; + eventValues[UIEventAdapterConstants.INDEX_ZERO] = eventString; + eventValues[UIEventAdapterConstants.INDEX_ONE] = System.currentTimeMillis(); + streamSpecificEvents.add(eventValues); + + // fetch all valid sessions checked against any queryParameters provided when subscribing. + CopyOnWriteArrayList validSessions = getValidSessions(event); + + try { + executorService.execute(new WebSocketSender(validSessions, eventString)); + } catch (RejectedExecutionException e) { + EventAdapterUtil.logAndDrop(eventAdapterConfiguration.getName(), message, "Job queue is full", e, log, + tenantId); + } + + } + + @Override + public void disconnect() { + //Not needed + } + + @Override + public void destroy() { + + int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId(); + + ConcurrentHashMap tenantSpecificAdapterMap = UIEventAdaptorServiceInternalValueHolder + .getTenantSpecificOutputEventStreamAdapterMap().get(tenantId); + if (tenantSpecificAdapterMap != null && streamId != null) { + tenantSpecificAdapterMap.remove(streamId); //Removing outputadapter and streamId + } + + ConcurrentHashMap> tenantSpecificStreamEventMap = + UIEventAdaptorServiceInternalValueHolder.getTenantSpecificStreamEventMap().get(tenantId); + if (tenantSpecificStreamEventMap != null && streamId != null) { + //Removing the streamId and events registered for the output adapter + tenantSpecificStreamEventMap.remove(streamId); + } + } + + @Override + public boolean isPolled() { + return true; + } + + /** + * Fetch the StreamDefinition corresponding to the given StreamId from the EventStreamService. + * + * @param streamId the streamId of this UIEventAdaptor. + * @return the "StreamDefinition" object corresponding to the streamId of this EventAdaptor. + * @throws OutputEventAdapterException if the "EventStreamService" OSGI service is unavailable/unregistered or if + * the matching Steam-Definition for the given StreamId cannot be retrieved. + */ + private StreamDefinition getStreamDefinition(String streamId) throws OutputEventAdapterException { + EventStreamService eventStreamService = OutputAdaptorEventStreamServiceValueHolder.getEventStreamService(); + if (eventStreamService != null) { + try { + return eventStreamService.getStreamDefinition(streamId); + } catch (EventStreamConfigurationException e) { + String adaptorType = eventAdapterConfiguration.getType(); + String adaptorName = eventAdapterConfiguration.getName(); + String errorMsg = "Error while retrieving Stream-Definition for Stream with id [" + streamId + "] " + + "for Adaptor [" + adaptorName + "] of type [" + adaptorType + "]."; + log.error(errorMsg); + throw new OutputEventAdapterException(errorMsg, e); + } + } + throw new OutputEventAdapterException( + "Could not retrieve the EventStreamService whilst trying to fetch the Stream-Definition of Stream " + + "with Id [" + streamId + "]."); + } + + /** + * Fetches all valid web-socket sessions from the entire pool of subscribed sessions. The validity is checked + * against any queryString provided when subscribing to the web-socket endpoint. + * + * @param event the current event received and that which needs to be published to subscribed sessions. + * @return a list of all validated web-socket sessions against the queryString values. + */ + private CopyOnWriteArrayList getValidSessions(Event event) { + CopyOnWriteArrayList validSessions = new CopyOnWriteArrayList<>(); + UIOutputCallbackControllerServiceImpl uiOutputCallbackControllerServiceImpl = + UIEventAdaptorServiceInternalValueHolder.getUIOutputCallbackRegisterServiceImpl(); + // get all subscribed web-socket sessions. + CopyOnWriteArrayList cepWebSocketSessions = + uiOutputCallbackControllerServiceImpl.getSessions(tenantId, streamId); + + for (CEPWebSocketSession cepWebSocketSession : cepWebSocketSessions) { + boolean isValidSession = validateEventAgainstSessionFilters(event, cepWebSocketSession); + if (isValidSession) { + validSessions.add(cepWebSocketSession); + } + } + return validSessions; + } + + + /** + * Processes the given session's validity to receive the current "event" against any queryParams that was used at + * the time when the web-socket-session is subscribed. This method can be extended to validate the event against + * any additional attribute of the given session too. + * + * @param event the current event received and that which needs to be published to subscribed + * sessions. + * @param cepWebSocketSession the session which needs validated for its authenticity to receive this event. + * @return "true" if the session is valid to receive the event else "false". + */ + private boolean validateEventAgainstSessionFilters(Event event, CEPWebSocketSession cepWebSocketSession) { + + // fetch the queryString Key:Value pair map of the given session. + Map queryParamValuePairs = cepWebSocketSession.getQueryParamValuePairs(); + if (queryParamValuePairs != null) { + // fetch the different attribute values received as part of the current event. + Object[] eventMetaData = event.getMetaData(); + Object[] eventCorrelationData = event.getCorrelationData(); + Object[] eventPayloadData = event.getPayloadData(); + + if (streamMetaAttributes != null) { + for (int i = 0; i < streamMetaAttributes.size(); i++) { + String attributeName = streamMetaAttributes.get(i).getName(); + String queryValue = queryParamValuePairs.get(attributeName); + + if (queryValue != null && + (eventMetaData == null || !eventMetaData[i].toString().equals(queryValue))) { + return false; + } + } + } + + if (streamCorrelationAttributes != null) { + for (int i = 0; i < streamCorrelationAttributes.size(); i++) { + String attributeName = streamCorrelationAttributes.get(i).getName(); + String queryValue = queryParamValuePairs.get(attributeName); + + if (queryValue != null && + (eventCorrelationData == null || !eventCorrelationData[i].toString().equals(queryValue))) { + return false; + } + } + } + + if (streamPayloadAttributes != null) { + for (int i = 0; i < streamPayloadAttributes.size(); i++) { + String attributeName = streamPayloadAttributes.get(i).getName(); + String queryValue = queryParamValuePairs.get(attributeName); + + if (queryValue != null && (eventPayloadData == null || !eventPayloadData[i].toString().equals( + queryValue))) { + return false; + } + } + } + } + return true; + } + + private class WebSocketSender implements Runnable { + + private String message; + private CopyOnWriteArrayList cepWebSocketSessions; + + public WebSocketSender(CopyOnWriteArrayList cepWebSocketSessions, String message) { + this.cepWebSocketSessions = cepWebSocketSessions; + this.message = message; + } + + /** + * When an object implementing interface Runnable is used + * to create a thread, starting the thread causes the object's + * run method to be called in that separately executing + * thread. + *

+ * The general contract of the method run is that it may + * take any action whatsoever. + * + * @see Thread#run() + */ + @Override + public void run() { + if (cepWebSocketSessions != null) { + doLogDroppedMessage = true; + for (CEPWebSocketSession cepWebSocketSession : cepWebSocketSessions) { + synchronized (cepWebSocketSession) { + try { + cepWebSocketSession.getSession().getBasicRemote().sendText(message); + } catch (IOException e) { + EventAdapterUtil.logAndDrop(eventAdapterConfiguration.getName(), message, + "Cannot send to endpoint", e, log, tenantId); + } + } + } + } else if (doLogDroppedMessage) { + EventAdapterUtil.logAndDrop(eventAdapterConfiguration.getName(), message, "No clients registered", log, + tenantId); + doLogDroppedMessage = false; + } + } + } +} + diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui/src/main/java/org/wso2/carbon/event/output/adapter/extensions/ui/UIEventAdapterFactory.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui/src/main/java/org/wso2/carbon/event/output/adapter/extensions/ui/UIEventAdapterFactory.java new file mode 100644 index 0000000000..c28f982f36 --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui/src/main/java/org/wso2/carbon/event/output/adapter/extensions/ui/UIEventAdapterFactory.java @@ -0,0 +1,89 @@ +/* + * + * Copyright (c) 2015, 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. + * + */ +package org.wso2.carbon.event.output.adapter.extensions.ui; + +import org.wso2.carbon.event.output.adapter.core.MessageType; +import org.wso2.carbon.event.output.adapter.core.OutputEventAdapter; +import org.wso2.carbon.event.output.adapter.core.OutputEventAdapterConfiguration; +import org.wso2.carbon.event.output.adapter.core.OutputEventAdapterFactory; +import org.wso2.carbon.event.output.adapter.core.Property; +import org.wso2.carbon.event.output.adapter.extensions.ui.internal.util.UIEventAdapterConstants; +import org.wso2.carbon.utils.CarbonUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.ResourceBundle; + +/** + * The UI event adapter factory class to create a UI output adapter + */ +public class UIEventAdapterFactory extends OutputEventAdapterFactory { + + private ResourceBundle resourceBundle = ResourceBundle.getBundle("org.wso2.carbon.event.output.adapter.extensions.ui.i18n" + + ".Resources", Locale.getDefault()); + private int httpPort; + private int httpsPort; + private int portOffset; + + public UIEventAdapterFactory() { + portOffset = getPortOffset(); + httpPort = UIEventAdapterConstants.DEFAULT_HTTP_PORT + portOffset; + httpsPort = UIEventAdapterConstants.DEFAULT_HTTPS_PORT + portOffset; + } + + @Override + public String getType() { + return UIEventAdapterConstants.ADAPTER_TYPE_UI; + } + + @Override + public List getSupportedMessageFormats() { + List supportedMessageFormats = new ArrayList(); + supportedMessageFormats.add(MessageType.WSO2EVENT); + return supportedMessageFormats; + } + + @Override + public List getStaticPropertyList() { + return null; + } + + @Override + public List getDynamicPropertyList() { + return null; + } + + @Override + public String getUsageTips() { + return resourceBundle.getString(UIEventAdapterConstants.ADAPTER_USAGE_TIPS_PREFIX) + " " + resourceBundle.getString(UIEventAdapterConstants.ADAPTER_USAGE_TIPS_POSTFIX); + } + + @Override + public OutputEventAdapter createEventAdapter(OutputEventAdapterConfiguration eventAdapterConfiguration, + Map globalProperties) { + return new UIEventAdapter(eventAdapterConfiguration, globalProperties); + } + + private int getPortOffset() { + return CarbonUtils.getPortFromServerConfig(UIEventAdapterConstants.CARBON_CONFIG_PORT_OFFSET_NODE) + 1; + } +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui/src/main/java/org/wso2/carbon/event/output/adapter/extensions/ui/UIOutputCallbackControllerService.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui/src/main/java/org/wso2/carbon/event/output/adapter/extensions/ui/UIOutputCallbackControllerService.java new file mode 100644 index 0000000000..9b9375271b --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui/src/main/java/org/wso2/carbon/event/output/adapter/extensions/ui/UIOutputCallbackControllerService.java @@ -0,0 +1,61 @@ +/* + * + * Copyright (c) 2015, 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. + * + */ + +package org.wso2.carbon.event.output.adapter.extensions.ui; + +import com.google.gson.JsonObject; + +import javax.websocket.Session; + +/** + * This interface is exposed as an OSGI service, which will be invoked by the local websocket endpoint to inform new subscriptions; and do un-subscriptions.. + */ +public interface UIOutputCallbackControllerService { + + /** + * Used to subscribe the session id and stream id for later web socket connectivity + * + * @param streamName - Stream name which user register to. + * @param version - Stream version which user uses. + * @param session - Session which user registered. + * @return + */ + public void subscribeWebsocket(String streamName, String version, Session session); + + /** + * Used to return events per streamId + * + * @param streamName - Stream name which user register to. + * @param version - Stream version which user uses. + * @param session - Session which user subscribed to. + * @return the events list. + */ + public void unsubscribeWebsocket(String streamName, String version, Session session); + + /** + * Used to return events per http GET request. + * + * @param streamName - Stream name which user register to. + * @param version - Stream version which user uses. + * @param lastUpdatedTime - Last dispatched events time. + * @return the events list. + */ + public JsonObject retrieveEvents(String streamName, String version, String lastUpdatedTime); +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui/src/main/java/org/wso2/carbon/event/output/adapter/extensions/ui/internal/UIOutputCallbackControllerServiceImpl.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui/src/main/java/org/wso2/carbon/event/output/adapter/extensions/ui/internal/UIOutputCallbackControllerServiceImpl.java new file mode 100644 index 0000000000..9da8578bc6 --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui/src/main/java/org/wso2/carbon/event/output/adapter/extensions/ui/internal/UIOutputCallbackControllerServiceImpl.java @@ -0,0 +1,210 @@ +/* + * + * Copyright (c) 2015, 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. + * + */ +package org.wso2.carbon.event.output.adapter.extensions.ui.internal; + +import com.google.gson.JsonObject; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.event.output.adapter.extensions.ui.UIOutputCallbackControllerService; +import org.wso2.carbon.event.output.adapter.extensions.ui.internal.util.CEPWebSocketSession; +import org.wso2.carbon.event.output.adapter.extensions.ui.internal.util.UIEventAdapterConstants; +import org.wso2.carbon.event.output.adapter.extensions.ui.internal.ds.UIEventAdaptorServiceInternalValueHolder; + +import javax.websocket.Session; +import java.util.Iterator; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.LinkedBlockingDeque; + +/** + * Service implementation class which exposes to front end + */ +public class UIOutputCallbackControllerServiceImpl implements UIOutputCallbackControllerService { + + private ConcurrentHashMap>> + outputEventAdaptorSessionMap; + + public UIOutputCallbackControllerServiceImpl() { + outputEventAdaptorSessionMap = + new ConcurrentHashMap>>(); + } + + + /** + * Used to subscribe the session id and stream id for later web socket connectivity + * + * @param streamName - Stream name which user register to. + * @param version - Stream version which user uses. + * @param session - Session which user registered. + * @return + */ + public void subscribeWebsocket(String streamName, String version, Session session) { + + int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(); + + if (version == null || " ".equals(version)) { + version = UIEventAdapterConstants.ADAPTER_UI_DEFAULT_OUTPUT_STREAM_VERSION; + } + String streamId = streamName + UIEventAdapterConstants.ADAPTER_UI_COLON + version; + ConcurrentHashMap> tenantSpecificAdaptorMap = + outputEventAdaptorSessionMap.get(tenantId); + if (tenantSpecificAdaptorMap == null) { + tenantSpecificAdaptorMap = new ConcurrentHashMap>(); + if (null != outputEventAdaptorSessionMap.putIfAbsent(tenantId, tenantSpecificAdaptorMap)) { + tenantSpecificAdaptorMap = outputEventAdaptorSessionMap.get(tenantId); + } + } + CopyOnWriteArrayList adapterSpecificSessions = tenantSpecificAdaptorMap.get(streamId); + if (adapterSpecificSessions == null) { + adapterSpecificSessions = new CopyOnWriteArrayList(); + if (null != tenantSpecificAdaptorMap.putIfAbsent(streamId, adapterSpecificSessions)) { + adapterSpecificSessions = tenantSpecificAdaptorMap.get(streamId); + } + } + + CEPWebSocketSession cepWebSocketSession = new CEPWebSocketSession(session); + adapterSpecificSessions.add(cepWebSocketSession); + } + + /** + * Used to return registered sessions per streamId + * + * @param tenantId - Tenant id of the user. + * @param streamId - Stream name and version which user register to. + * @return the sessions list. + */ + public CopyOnWriteArrayList getSessions(int tenantId, String streamId) { + ConcurrentHashMap> tenantSpecificAdaptorMap = outputEventAdaptorSessionMap.get(tenantId); + if (tenantSpecificAdaptorMap != null) { + return tenantSpecificAdaptorMap.get(streamId); + } + return null; + } + + /** + * Used to return events per streamId + * + * @param tenanId - Tenant id of the user. + * @param streamName - Stream name which user register to. + * @param version - Stream version which user uses. + * @return the events list. + */ + public LinkedBlockingDeque getEvents(int tenanId, String streamName, String version) { + + ConcurrentHashMap> tenantSpecificStreamMap = + UIEventAdaptorServiceInternalValueHolder.getTenantSpecificStreamEventMap().get(tenanId); + + if (tenantSpecificStreamMap != null) { + String streamId = streamName + UIEventAdapterConstants.ADAPTER_UI_COLON + version; + return tenantSpecificStreamMap.get(streamId); + } + return null; + } + + /** + * Used to return events per streamId + * + * @param streamName - Stream name which user register to. + * @param version - Stream version which user uses. + * @param session - Session which user subscribed to. + * @return the events list. + */ + public void unsubscribeWebsocket(String streamName, String version, Session session) { + + int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(); + + if (version == null || " ".equals(version)) { + version = UIEventAdapterConstants.ADAPTER_UI_DEFAULT_OUTPUT_STREAM_VERSION; + } + String id = streamName + UIEventAdapterConstants.ADAPTER_UI_COLON + version; + ConcurrentHashMap> tenantSpecificAdaptorMap = outputEventAdaptorSessionMap.get(tenantId); + if (tenantSpecificAdaptorMap != null) { + CopyOnWriteArrayList adapterSpecificSessions = tenantSpecificAdaptorMap.get(id); + if (adapterSpecificSessions != null) { + CEPWebSocketSession sessionToRemove = null; + for (Iterator iterator = adapterSpecificSessions.iterator(); iterator.hasNext(); ) { + CEPWebSocketSession cepWebSocketSession = iterator.next(); + if (session.getId().equals(cepWebSocketSession.getSession().getId())) { + sessionToRemove = cepWebSocketSession; + break; + } + } + if (sessionToRemove != null) { + adapterSpecificSessions.remove(sessionToRemove); + } + } + } + } + + /** + * Used to return events per http GET request. + * + * @param streamName - Stream name which user register to. + * @param version - Stream version which user uses. + * @param lastUpdatedTime - Last dispatched events time. + * @return the events list. + */ + @Override + public JsonObject retrieveEvents(String streamName, String version, String lastUpdatedTime) { + + int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(); + LinkedBlockingDeque allEvents = getEvents(tenantId, streamName, version); + //List eventsListToBeSent; + Object lastEventTime = null; + JsonObject eventsData; + + if (allEvents != null) { + eventsData = new JsonObject(); + + Boolean firstFilteredValue = true; + long sentTimeStamp = Long.parseLong(lastUpdatedTime); + //eventsListToBeSent = new ArrayList(); + + StringBuilder allEventsAsString = new StringBuilder("["); + // set Iterator as descending + Iterator iterator = allEvents.descendingIterator(); + + while (iterator.hasNext()) { + + Object[] eventValues = (Object[]) iterator.next(); + long eventTimeStamp = (Long) eventValues[UIEventAdapterConstants.INDEX_ONE]; + if (sentTimeStamp < eventTimeStamp) { + + if (!firstFilteredValue) { + allEventsAsString.append(","); + } + firstFilteredValue = false; + String eventString = (String) eventValues[UIEventAdapterConstants.INDEX_ZERO]; + allEventsAsString.append(eventString); + } + } + allEventsAsString.append("]"); + + if (allEvents.size() != 0) { + Object[] lastObj = (Object[]) allEvents.getLast(); + lastEventTime = lastObj[UIEventAdapterConstants.INDEX_ONE]; + eventsData.addProperty("lastEventTime", String.valueOf(lastEventTime)); + } + eventsData.addProperty("events", allEventsAsString.toString()); + + return eventsData; + } + return null; + } +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui/src/main/java/org/wso2/carbon/event/output/adapter/extensions/ui/internal/ds/OutputAdaptorEventStreamServiceValueHolder.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui/src/main/java/org/wso2/carbon/event/output/adapter/extensions/ui/internal/ds/OutputAdaptorEventStreamServiceValueHolder.java new file mode 100644 index 0000000000..99515467a6 --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui/src/main/java/org/wso2/carbon/event/output/adapter/extensions/ui/internal/ds/OutputAdaptorEventStreamServiceValueHolder.java @@ -0,0 +1,23 @@ +package org.wso2.carbon.event.output.adapter.extensions.ui.internal.ds; + +import org.wso2.carbon.event.stream.core.EventStreamService; + +/** + * This class holds a reference to the current EventStream OSGI service component "eventStreamService.component" in the + * OSGI runtime. + */ +public class OutputAdaptorEventStreamServiceValueHolder { + private static EventStreamService eventStreamService; + + public static void registerEventStreamService(EventStreamService eventBuilderService) { + OutputAdaptorEventStreamServiceValueHolder.eventStreamService = eventBuilderService; + } + + public static EventStreamService getEventStreamService() { + return OutputAdaptorEventStreamServiceValueHolder.eventStreamService; + } + + public static void unregisterEventStreamService(EventStreamService eventStreamService) { + OutputAdaptorEventStreamServiceValueHolder.eventStreamService = null; + } +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui/src/main/java/org/wso2/carbon/event/output/adapter/extensions/ui/internal/ds/UIEventAdaptorServiceInternalValueHolder.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui/src/main/java/org/wso2/carbon/event/output/adapter/extensions/ui/internal/ds/UIEventAdaptorServiceInternalValueHolder.java new file mode 100644 index 0000000000..145b320d63 --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui/src/main/java/org/wso2/carbon/event/output/adapter/extensions/ui/internal/ds/UIEventAdaptorServiceInternalValueHolder.java @@ -0,0 +1,56 @@ +/* + * + * Copyright (c) 2015, 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. + * + */ +package org.wso2.carbon.event.output.adapter.extensions.ui.internal.ds; + +import org.wso2.carbon.event.output.adapter.extensions.ui.internal.UIOutputCallbackControllerServiceImpl; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.LinkedBlockingDeque; + +/** + * Creates a holder of type UIOutputCallbackRegisterServiceImpl. + */ +public final class UIEventAdaptorServiceInternalValueHolder { + + private static UIOutputCallbackControllerServiceImpl UIOutputCallbackRegisterServiceImpl; + private static ConcurrentHashMap> tenantSpecificOutputEventStreamAdapterMap = new + ConcurrentHashMap>(); + private static ConcurrentHashMap>> tenantSpecificStreamEventMap + = new ConcurrentHashMap>>(); + + public static void registerUIOutputCallbackRegisterServiceInternal( + UIOutputCallbackControllerServiceImpl UIOutputCallbackRegisterServiceImpl) { + UIEventAdaptorServiceInternalValueHolder.UIOutputCallbackRegisterServiceImpl = + UIOutputCallbackRegisterServiceImpl; + } + + public static UIOutputCallbackControllerServiceImpl getUIOutputCallbackRegisterServiceImpl() { + return UIEventAdaptorServiceInternalValueHolder.UIOutputCallbackRegisterServiceImpl; + } + + public static ConcurrentHashMap> getTenantSpecificOutputEventStreamAdapterMap() { + return tenantSpecificOutputEventStreamAdapterMap; + } + + public static ConcurrentHashMap>> + getTenantSpecificStreamEventMap() { + return tenantSpecificStreamEventMap; + } +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui/src/main/java/org/wso2/carbon/event/output/adapter/extensions/ui/internal/ds/UILocalEventAdapterDS.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui/src/main/java/org/wso2/carbon/event/output/adapter/extensions/ui/internal/ds/UILocalEventAdapterDS.java new file mode 100644 index 0000000000..be43fc9556 --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui/src/main/java/org/wso2/carbon/event/output/adapter/extensions/ui/internal/ds/UILocalEventAdapterDS.java @@ -0,0 +1,80 @@ +/* + * + * Copyright (c) 2015, 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. + * + */ +package org.wso2.carbon.event.output.adapter.extensions.ui.internal.ds; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.osgi.service.component.ComponentContext; +import org.wso2.carbon.event.output.adapter.core.OutputEventAdapterFactory; +import org.wso2.carbon.event.output.adapter.extensions.ui.UIEventAdapterFactory; +import org.wso2.carbon.event.output.adapter.extensions.ui.UIOutputCallbackControllerService; +import org.wso2.carbon.event.output.adapter.extensions.ui.internal.UIOutputCallbackControllerServiceImpl; +import org.wso2.carbon.event.stream.core.EventStreamService; + +/** + * @scr.component component.name="output.extensions.Ui.AdapterService.component" immediate="true" + * @scr.reference name="eventStreamService.service" + * interface="org.wso2.carbon.event.stream.core.EventStreamService" cardinality="1..1" + * policy="dynamic" bind="setEventStreamService" unbind="unsetEventStreamService" + */ +public class UILocalEventAdapterDS { + + private static final Log log = LogFactory.getLog(UILocalEventAdapterDS.class); + + /** + * initialize the ui adapter service here service here. + * + * @param context + */ + protected void activate(ComponentContext context) { + + try { + OutputEventAdapterFactory uiEventAdapterFactory = new UIEventAdapterFactory(); + context.getBundleContext().registerService(OutputEventAdapterFactory.class.getName(), uiEventAdapterFactory, null); + + UIOutputCallbackControllerServiceImpl UIOutputCallbackRegisterServiceImpl = new UIOutputCallbackControllerServiceImpl(); + context.getBundleContext().registerService(UIOutputCallbackControllerService.class.getName(), + UIOutputCallbackRegisterServiceImpl, null); + + UIEventAdaptorServiceInternalValueHolder.registerUIOutputCallbackRegisterServiceInternal( + UIOutputCallbackRegisterServiceImpl); + + if (log.isDebugEnabled()) { + log.debug("Successfully deployed the output ui adapter service"); + } + } catch (RuntimeException e) { + log.error("Can not create the output ui adapter service ", e); + } + } + + protected void setEventStreamService(EventStreamService eventStreamService) { + if (log.isDebugEnabled()) { + log.debug("Setting the EventStreamService reference for the UILocalEventAdaptor Service"); + } + OutputAdaptorEventStreamServiceValueHolder.registerEventStreamService(eventStreamService); + } + + protected void unsetEventStreamService(EventStreamService eventStreamService) { + if (log.isDebugEnabled()) { + log.debug("Un-Setting the EventStreamService reference for the UILocalEventAdaptor Service"); + } + OutputAdaptorEventStreamServiceValueHolder.unregisterEventStreamService(eventStreamService); + } +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui/src/main/java/org/wso2/carbon/event/output/adapter/extensions/ui/internal/util/CEPWebSocketSession.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui/src/main/java/org/wso2/carbon/event/output/adapter/extensions/ui/internal/util/CEPWebSocketSession.java new file mode 100644 index 0000000000..751631b383 --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui/src/main/java/org/wso2/carbon/event/output/adapter/extensions/ui/internal/util/CEPWebSocketSession.java @@ -0,0 +1,62 @@ +package org.wso2.carbon.event.output.adapter.extensions.ui.internal.util; + + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.websocket.Session; +import java.util.HashMap; +import java.util.Map; + +/** + * This is wrapper class over the javax.websocket.Session implementation. This class contains additional attributes + * of the Session object derived from processing some of the (default) existing attributes. + * Ex: Query-String's [Key:Value] Map derived from the queryString attribute of the original class. + */ +public class CEPWebSocketSession { + private static final Log log = LogFactory.getLog(CEPWebSocketSession.class); + + private static final String QUERY_STRING_SEPERATOR = "&"; + private static final String QUERY_KEY_VALUE_SEPERATOR = "="; + private Map queryParamValuePairs = null; + private Session session; + + public CEPWebSocketSession(Session session) { + this.session = session; + setQueryParamValuePairs(); + } + + public Map getQueryParamValuePairs() { + return queryParamValuePairs; + } + + public Session getSession() { + return session; + } + + /** + * Processes the queryString from the current instance's Session attribute and constructs a map of Query + * Key:Value pair. + */ + private void setQueryParamValuePairs() { + if (session.getQueryString() != null) { + String queryString = session.getQueryString(); + String[] allQueryParamPairs = queryString.split(QUERY_STRING_SEPERATOR); + + for (String keyValuePair : allQueryParamPairs) { + String[] thisQueryParamPair = keyValuePair.split(QUERY_KEY_VALUE_SEPERATOR); + + if (thisQueryParamPair.length != 2) { + log.warn("Invalid query string [" + queryString + "] passed in."); + break; + } + + if (queryParamValuePairs == null) { + queryParamValuePairs = new HashMap<>(); + } + + queryParamValuePairs.put(thisQueryParamPair[0], thisQueryParamPair[1]); + } + } + } +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui/src/main/java/org/wso2/carbon/event/output/adapter/extensions/ui/internal/util/UIEventAdapterConstants.java b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui/src/main/java/org/wso2/carbon/event/output/adapter/extensions/ui/internal/util/UIEventAdapterConstants.java new file mode 100644 index 0000000000..9c1ea3ad5e --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui/src/main/java/org/wso2/carbon/event/output/adapter/extensions/ui/internal/util/UIEventAdapterConstants.java @@ -0,0 +1,54 @@ +/* + * + * Copyright (c) 2014-2015, 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. + * + */ +package org.wso2.carbon.event.output.adapter.extensions.ui.internal.util; + +/** + * This class contains the constants related to ui Output Event Adaptor. + */ +public class UIEventAdapterConstants { + + private UIEventAdapterConstants() { + } + + public static final String ADAPTER_TYPE_UI = "iot-ui"; + public static final String ADAPTER_USAGE_TIPS_PREFIX = "ui.usage.tips_prefix"; + public static final String ADAPTER_USAGE_TIPS_POSTFIX = "ui.usage.tips_postfix"; + public static final String ADAPTER_UI_DEFAULT_OUTPUT_STREAM_VERSION = "1.0.0"; + public static final String ADAPTER_UI_COLON = ":"; + public static final int INDEX_ZERO = 0; + public static final int INDEX_ONE = 1; + public static final int INDEX_TWO = 2; + + public static final int ADAPTER_MIN_THREAD_POOL_SIZE = 8; + public static final int ADAPTER_MAX_THREAD_POOL_SIZE = 100; + public static final int ADAPTER_EXECUTOR_JOB_QUEUE_SIZE = 2000; + public static final long DEFAULT_KEEP_ALIVE_TIME_IN_MILLIS = 20000; + public static final String ADAPTER_MIN_THREAD_POOL_SIZE_NAME = "minThread"; + public static final String ADAPTER_MAX_THREAD_POOL_SIZE_NAME = "maxThread"; + public static final String ADAPTER_KEEP_ALIVE_TIME_NAME = "keepAliveTimeInMillis"; + public static final String ADAPTER_EXECUTOR_JOB_QUEUE_SIZE_NAME = "jobQueueSize"; + + public static final String ADAPTER_EVENT_QUEUE_SIZE_NAME = "eventQueueSize"; + public static final int EVENTS_QUEUE_SIZE = 30; + + public static final String CARBON_CONFIG_PORT_OFFSET_NODE = "Ports.Offset"; + public static final int DEFAULT_HTTP_PORT = 9763; + public static final int DEFAULT_HTTPS_PORT = 9443; +} diff --git a/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui/src/main/resources/org/wso2/carbon/event/output/adapter/extensions/ui/i18n/Resources.properties b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui/src/main/resources/org/wso2/carbon/event/output/adapter/extensions/ui/i18n/Resources.properties new file mode 100644 index 0000000000..4a3dcba8e3 --- /dev/null +++ b/components/iot-plugins/das-extensions/org.wso2.carbon.event.output.adapter.extensions.ui/src/main/resources/org/wso2/carbon/event/output/adapter/extensions/ui/i18n/Resources.properties @@ -0,0 +1,22 @@ +# +# Copyright (c) 2015, 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. +# + +output.event.stream.name=Output Stream Name +output.event.stream.version=Output Stream Version +ui.usage.tips_prefix=There must be an UI output adaptor for each stream to be visualized +ui.usage.tips_postfix= via Analytics Dashboard. diff --git a/components/iot-plugins/das-extensions/pom.xml b/components/iot-plugins/das-extensions/pom.xml new file mode 100644 index 0000000000..7c1f0be175 --- /dev/null +++ b/components/iot-plugins/das-extensions/pom.xml @@ -0,0 +1,40 @@ + + + + + + + org.wso2.carbon.devicemgt-plugins + iot-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + das-extensions + pom + This contains das extension + http://wso2.org + + + org.wso2.carbon.event.input.adapter.extensions + org.wso2.carbon.event.output.adapter.extensions.ui + org.wso2.carbon.event.output.adapter.extensions.ui.endpoint + + diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/service/impl/DigitalDisplayManagerServiceImpl.java b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/service/impl/DigitalDisplayManagerServiceImpl.java index 382a22c6f0..d0e5f332cf 100644 --- a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/service/impl/DigitalDisplayManagerServiceImpl.java +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/service/impl/DigitalDisplayManagerServiceImpl.java @@ -35,7 +35,6 @@ import org.wso2.carbon.device.mgt.iot.exception.DeviceControllerException; import org.wso2.carbon.device.mgt.iot.util.ZipArchive; import org.wso2.carbon.device.mgt.iot.util.ZipUtil; import org.wso2.carbon.identity.jwt.client.extension.JWTClient; -import org.wso2.carbon.identity.jwt.client.extension.JWTClientManager; import org.wso2.carbon.identity.jwt.client.extension.dto.AccessTokenInfo; import org.wso2.carbon.identity.jwt.client.extension.exception.JWTClientException; import org.wso2.carbon.user.api.UserStoreException; @@ -169,16 +168,13 @@ public class DigitalDisplayManagerServiceImpl implements DigitalDisplayManagerSe apiApplicationKey = apiManagementProviderService.generateAndRetrieveApplicationKeys( DigitalDisplayConstants.DEVICE_TYPE, tags, KEY_TYPE, applicationUsername, true); } - JWTClient jwtClient = JWTClientManager.getInstance().getJWTClient(); + JWTClient jwtClient = APIUtil.getJWTClientManagerService().getJWTClient(); String scopes = "device_type_" + DigitalDisplayConstants.DEVICE_TYPE + " device_" + deviceId; AccessTokenInfo accessTokenInfo = jwtClient.getAccessToken(apiApplicationKey.getConsumerKey(), apiApplicationKey.getConsumerSecret(), owner, scopes); - //create token - String accessToken = accessTokenInfo.getAccess_token(); - String refreshToken = accessTokenInfo.getRefresh_token(); - //adding registering data + String accessToken = accessTokenInfo.getAccessToken(); + String refreshToken = accessTokenInfo.getRefreshToken(); boolean status; - //Register the device with CDMF status = register(deviceId, deviceName); if (!status) { String msg = "Error occurred while registering the device with " + "id: " + deviceId + " owner:" + owner; diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/service/impl/util/APIUtil.java b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/service/impl/util/APIUtil.java index 51b41cd72e..1c8855a328 100644 --- a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/service/impl/util/APIUtil.java +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/service/impl/util/APIUtil.java @@ -5,6 +5,7 @@ import org.apache.commons.logging.LogFactory; import org.wso2.carbon.apimgt.application.extension.APIManagementProviderService; import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; +import org.wso2.carbon.identity.jwt.client.extension.service.JWTClientManagerService; /** * This class provides utility functions used by REST-API. @@ -52,4 +53,17 @@ public class APIUtil { } return apiManagementProviderService; } + + public static JWTClientManagerService getJWTClientManagerService() { + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + JWTClientManagerService jwtClientManagerService = + (JWTClientManagerService) ctx.getOSGiService(JWTClientManagerService.class, null); + if (jwtClientManagerService == null) { + String msg = "JWT Client manager service has not initialized."; + log.error(msg); + throw new IllegalStateException(msg); + } + return jwtClientManagerService; + } + } diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/service/impl/DroneManagerServiceImpl.java b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/service/impl/DroneManagerServiceImpl.java index d9fbfb44bf..60cb5520a7 100644 --- a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/service/impl/DroneManagerServiceImpl.java +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/service/impl/DroneManagerServiceImpl.java @@ -36,7 +36,6 @@ import org.wso2.carbon.device.mgt.iot.exception.DeviceControllerException; import org.wso2.carbon.device.mgt.iot.util.ZipArchive; import org.wso2.carbon.device.mgt.iot.util.ZipUtil; import org.wso2.carbon.identity.jwt.client.extension.JWTClient; -import org.wso2.carbon.identity.jwt.client.extension.JWTClientManager; import org.wso2.carbon.identity.jwt.client.extension.dto.AccessTokenInfo; import org.wso2.carbon.identity.jwt.client.extension.exception.JWTClientException; import org.wso2.carbon.user.api.UserStoreException; @@ -209,14 +208,14 @@ public class DroneManagerServiceImpl implements DroneManagerService { apiApplicationKey = apiManagementProviderService.generateAndRetrieveApplicationKeys( DroneConstants.DEVICE_TYPE, tags, KEY_TYPE, applicationUsername, true); } - JWTClient jwtClient = JWTClientManager.getInstance().getJWTClient(); + JWTClient jwtClient = APIUtil.getJWTClientManagerService().getJWTClient(); String owner = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername(); String scopes = "device_type_" + DroneConstants.DEVICE_TYPE + " device_" + deviceId; AccessTokenInfo accessTokenInfo = jwtClient.getAccessToken(apiApplicationKey.getConsumerKey(), apiApplicationKey.getConsumerSecret(), owner, scopes); //create token - String accessToken = accessTokenInfo.getAccess_token(); - String refreshToken = accessTokenInfo.getRefresh_token(); + String accessToken = accessTokenInfo.getAccessToken(); + String refreshToken = accessTokenInfo.getRefreshToken(); //adding registering data XmppAccount newXmppAccount = new XmppAccount(); newXmppAccount.setAccountName(APIUtil.getAuthenticatedUser() + "_" + deviceId); diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/service/impl/util/APIUtil.java b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/service/impl/util/APIUtil.java index 4af82a9ba9..6d8bb627d6 100644 --- a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/service/impl/util/APIUtil.java +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/service/impl/util/APIUtil.java @@ -5,6 +5,7 @@ import org.apache.commons.logging.LogFactory; import org.wso2.carbon.apimgt.application.extension.APIManagementProviderService; import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; +import org.wso2.carbon.identity.jwt.client.extension.service.JWTClientManagerService; /** * This class provides utility functions used by REST-API. @@ -52,4 +53,16 @@ public class APIUtil { } return apiManagementProviderService; } + + public static JWTClientManagerService getJWTClientManagerService() { + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + JWTClientManagerService jwtClientManagerService = + (JWTClientManagerService) ctx.getOSGiService(JWTClientManagerService.class, null); + if (jwtClientManagerService == null) { + String msg = "JWT Client manager service has not initialized."; + log.error(msg); + throw new IllegalStateException(msg); + } + return jwtClientManagerService; + } } diff --git a/components/iot-plugins/pom.xml b/components/iot-plugins/pom.xml index 5738bf180e..039f5bdddb 100644 --- a/components/iot-plugins/pom.xml +++ b/components/iot-plugins/pom.xml @@ -40,6 +40,7 @@ raspberrypi-plugin virtual-fire-alarm-plugin iot-base-plugin + das-extensions diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.api/pom.xml b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.api/pom.xml index 3a00959390..3c79211237 100644 --- a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.api/pom.xml +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.api/pom.xml @@ -141,6 +141,11 @@ org.wso2.carbon.apimgt.application.extension provided + + org.wso2.carbon.analytics + org.wso2.carbon.analytics.api + provided + diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.api/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/service/impl/RaspberryPiControllerServiceImpl.java b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.api/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/service/impl/RaspberryPiControllerServiceImpl.java index 81b906a59d..ca7ce2487b 100644 --- a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.api/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/service/impl/RaspberryPiControllerServiceImpl.java +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.api/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/service/impl/RaspberryPiControllerServiceImpl.java @@ -20,20 +20,19 @@ package org.wso2.carbon.device.mgt.iot.raspberrypi.service.impl; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.wso2.carbon.context.PrivilegedCarbonContext; -import org.wso2.carbon.device.mgt.analytics.data.publisher.AnalyticsDataRecord; -import org.wso2.carbon.device.mgt.analytics.data.publisher.exception.DeviceManagementAnalyticsException; -import org.wso2.carbon.device.mgt.analytics.data.publisher.service.DeviceAnalyticsService; +import org.wso2.carbon.analytics.dataservice.commons.SORT; +import org.wso2.carbon.analytics.dataservice.commons.SortByField; +import org.wso2.carbon.analytics.datasource.commons.exception.AnalyticsException; import org.wso2.carbon.device.mgt.common.DeviceManagementException; import org.wso2.carbon.device.mgt.iot.controlqueue.mqtt.MqttConfig; import org.wso2.carbon.device.mgt.iot.exception.DeviceControllerException; import org.wso2.carbon.device.mgt.iot.raspberrypi.service.impl.dto.DeviceData; -import org.wso2.carbon.device.mgt.iot.raspberrypi.service.impl.dto.SensorData; +import org.wso2.carbon.device.mgt.iot.raspberrypi.service.impl.dto.SensorRecord; import org.wso2.carbon.device.mgt.iot.raspberrypi.service.impl.transport.RaspberryPiMQTTConnector; +import org.wso2.carbon.device.mgt.iot.raspberrypi.service.impl.util.APIUtil; import org.wso2.carbon.device.mgt.iot.raspberrypi.service.impl.util.RaspberrypiServiceUtils; import org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.constants.RaspberrypiConstants; import org.wso2.carbon.device.mgt.iot.sensormgt.SensorDataManager; -import org.wso2.carbon.device.mgt.iot.sensormgt.SensorRecord; import org.wso2.carbon.device.mgt.iot.service.IoTServerStartupListener; import javax.servlet.http.HttpServletRequest; @@ -41,8 +40,6 @@ import javax.ws.rs.PathParam; import javax.ws.rs.core.Response; import java.util.ArrayList; import java.util.Calendar; -import java.util.Collections; -import java.util.Comparator; import java.util.List; import java.util.concurrent.ConcurrentHashMap; @@ -123,7 +120,7 @@ public class RaspberryPiControllerServiceImpl implements RaspberryPiControllerSe } public Response requestTemperature(@PathParam("deviceId") String deviceId) { - SensorRecord sensorRecord = null; + org.wso2.carbon.device.mgt.iot.sensormgt.SensorRecord sensorRecord = null; if (log.isDebugEnabled()) { log.debug("Sending request to read raspberrypi-temperature of device [" + deviceId + "] via "); } @@ -179,42 +176,19 @@ public class RaspberryPiControllerServiceImpl implements RaspberryPiControllerSe public Response getArduinoTemperatureStats(String deviceId, String user, long from, long to) { String fromDate = String.valueOf(from); String toDate = String.valueOf(to); - List sensorDatas = new ArrayList<>(); - PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); - DeviceAnalyticsService deviceAnalyticsService = (DeviceAnalyticsService) ctx - .getOSGiService(DeviceAnalyticsService.class, null); String query = "owner:" + user + " AND deviceId:" + deviceId + " AND deviceType:" + RaspberrypiConstants.DEVICE_TYPE + " AND time : [" + fromDate + " TO " + toDate + "]"; String sensorTableName = RaspberrypiConstants.TEMPERATURE_EVENT_TABLE; try { - List records = deviceAnalyticsService.getAllEventsForDevice(sensorTableName, query); - Collections.sort(records, new Comparator() { - @Override - public int compare(AnalyticsDataRecord o1, AnalyticsDataRecord o2) { - long t1 = (Long) o1.getValue("time"); - long t2 = (Long) o2.getValue("time"); - if (t1 < t2) { - return -1; - } else if (t1 > t2) { - return 1; - } else { - return 0; - } - } - }); - for (AnalyticsDataRecord record : records) { - SensorData sensorData = new SensorData(); - sensorData.setTime((long) record.getValue("time")); - sensorData.setValue("" + (float) record.getValue(RaspberrypiConstants.SENSOR_TEMPERATURE)); - sensorDatas.add(sensorData); - } - SensorData[] sensorDetails = sensorDatas.toArray(new SensorData[sensorDatas.size()]); - return Response.ok().entity(sensorDetails).build(); - } catch (DeviceManagementAnalyticsException e) { + List sortByFields = new ArrayList<>(); + SortByField sortByField = new SortByField("time", SORT.ASC, false); + sortByFields.add(sortByField); + List sensorRecords = APIUtil.getAllEventsForDevice(sensorTableName, query, sortByFields); + return Response.status(Response.Status.OK.getStatusCode()).entity(sensorRecords).build(); + } catch (AnalyticsException e) { String errorMsg = "Error on retrieving stats on table " + sensorTableName + " with query " + query; log.error(errorMsg); - SensorData[] sensorDetails = sensorDatas.toArray(new SensorData[sensorDatas.size()]); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).entity(sensorDetails).build(); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).entity(errorMsg).build(); } } diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.api/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/service/impl/RaspberryPiManagerServiceImpl.java b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.api/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/service/impl/RaspberryPiManagerServiceImpl.java index 5151a6fa99..edb966d822 100644 --- a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.api/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/service/impl/RaspberryPiManagerServiceImpl.java +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.api/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/service/impl/RaspberryPiManagerServiceImpl.java @@ -38,7 +38,6 @@ import org.wso2.carbon.device.mgt.iot.raspberrypi.service.impl.util.APIUtil; import org.wso2.carbon.device.mgt.iot.util.ZipArchive; import org.wso2.carbon.device.mgt.iot.util.ZipUtil; import org.wso2.carbon.identity.jwt.client.extension.JWTClient; -import org.wso2.carbon.identity.jwt.client.extension.JWTClientManager; import org.wso2.carbon.identity.jwt.client.extension.dto.AccessTokenInfo; import org.wso2.carbon.identity.jwt.client.extension.exception.JWTClientException; import org.wso2.carbon.user.api.UserStoreException; @@ -213,13 +212,13 @@ public class RaspberryPiManagerServiceImpl implements RaspberryPiManagerService apiApplicationKey = apiManagementProviderService.generateAndRetrieveApplicationKeys( RaspberrypiConstants.DEVICE_TYPE, tags, KEY_TYPE, applicationUsername, true); } - JWTClient jwtClient = JWTClientManager.getInstance().getJWTClient(); + JWTClient jwtClient = APIUtil.getJWTClientManagerService().getJWTClient(); String scopes = "device_type_" + RaspberrypiConstants.DEVICE_TYPE + " device_" + deviceId; AccessTokenInfo accessTokenInfo = jwtClient.getAccessToken(apiApplicationKey.getConsumerKey(), apiApplicationKey.getConsumerSecret(), owner, scopes); //create token - String accessToken = accessTokenInfo.getAccess_token(); - String refreshToken = accessTokenInfo.getRefresh_token(); + String accessToken = accessTokenInfo.getAccessToken(); + String refreshToken = accessTokenInfo.getRefreshToken(); //adding registering data XmppAccount newXmppAccount = new XmppAccount(); newXmppAccount.setAccountName(owner + "_" + deviceId); diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.api/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/service/impl/dto/SensorRecord.java b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.api/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/service/impl/dto/SensorRecord.java new file mode 100644 index 0000000000..18b01f29d2 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.api/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/service/impl/dto/SensorRecord.java @@ -0,0 +1,68 @@ +package org.wso2.carbon.device.mgt.iot.raspberrypi.service.impl.dto; + +import org.codehaus.jackson.annotate.JsonIgnoreProperties; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementWrapper; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@XmlRootElement +/** + * This stores sensor event data for android sense. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class SensorRecord { + + @XmlElementWrapper(required = true, name = "values") + private Map values; + + /** The id. */ + @XmlElement(required = false, name = "id") + private String id; + + /** + * Gets the values. + * @return the values + */ + public Map getValues() { + return values; + } + + /** + * Sets the values. + * @param values the values + */ + public void setValues(Map values) { + this.values = values; + } + + /** + * Sets the id. + * @param id the new id + */ + public void setId(String id) { + this.id = id; + } + + /** + * Gets the id. + * @return the id + */ + public String getId() { + return id; + } + + @Override + public String toString(){ + List valueList = new ArrayList(); + for (Map.Entry entry : values.entrySet()) { + valueList.add(entry.getKey() + ":" + entry.getValue()); + } + return valueList.toString(); + + } + +} diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.api/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/service/impl/util/APIUtil.java b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.api/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/service/impl/util/APIUtil.java index b0e91eb495..9cdb687bb3 100644 --- a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.api/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/service/impl/util/APIUtil.java +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.api/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/service/impl/util/APIUtil.java @@ -2,9 +2,25 @@ package org.wso2.carbon.device.mgt.iot.raspberrypi.service.impl.util; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.analytics.api.AnalyticsDataAPI; +import org.wso2.carbon.analytics.dataservice.commons.AnalyticsDataResponse; +import org.wso2.carbon.analytics.dataservice.commons.AnalyticsDrillDownRequest; +import org.wso2.carbon.analytics.dataservice.commons.SearchResultEntry; +import org.wso2.carbon.analytics.dataservice.commons.SortByField; +import org.wso2.carbon.analytics.dataservice.core.AnalyticsDataServiceUtils; +import org.wso2.carbon.analytics.datasource.commons.Record; +import org.wso2.carbon.analytics.datasource.commons.exception.AnalyticsException; import org.wso2.carbon.apimgt.application.extension.APIManagementProviderService; +import org.wso2.carbon.context.CarbonContext; import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; +import org.wso2.carbon.device.mgt.iot.raspberrypi.service.impl.dto.SensorRecord; +import org.wso2.carbon.identity.jwt.client.extension.service.JWTClientManagerService; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** * This class provides utility functions used by REST-API. @@ -23,12 +39,6 @@ public class APIUtil { return username; } - public static String getTenantDomainOftheUser() { - PrivilegedCarbonContext threadLocalCarbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext(); - String tenantDomain = threadLocalCarbonContext.getTenantDomain(); - return tenantDomain; - } - public static DeviceManagementProviderService getDeviceManagementService() { PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); DeviceManagementProviderService deviceManagementProviderService = @@ -41,10 +51,90 @@ public class APIUtil { return deviceManagementProviderService; } + public 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; + } + + public static List getAllEventsForDevice(String tableName, String query, List sortByFields) throws AnalyticsException { + int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId(); + AnalyticsDataAPI analyticsDataAPI = getAnalyticsDataAPI(); + int eventCount = analyticsDataAPI.searchCount(tenantId, tableName, query); + if (eventCount == 0) { + return null; + } + AnalyticsDrillDownRequest drillDownRequest = new AnalyticsDrillDownRequest(); + drillDownRequest.setQuery(query); + drillDownRequest.setTableName(tableName); + drillDownRequest.setRecordCount(eventCount); + if (sortByFields != null) { + drillDownRequest.setSortByFields(sortByFields); + } + List resultEntries = analyticsDataAPI.drillDownSearch(tenantId, drillDownRequest); + List recordIds = getRecordIds(resultEntries); + AnalyticsDataResponse response = analyticsDataAPI.get(tenantId, tableName, 1, null, recordIds); + Map sensorDatas = createSensorData(AnalyticsDataServiceUtils.listRecords( + analyticsDataAPI, response)); + List sortedSensorData = getSortedSensorData(sensorDatas, resultEntries); + return sortedSensorData; + } + + private static List getRecordIds(List searchResults) { + List ids = new ArrayList<>(); + for (SearchResultEntry searchResult : searchResults) { + ids.add(searchResult.getId()); + } + return ids; + } + + public static List getSortedSensorData(Map sensorDatas, + List searchResults) { + List sortedRecords = new ArrayList<>(); + for (SearchResultEntry searchResultEntry : searchResults) { + sortedRecords.add(sensorDatas.get(searchResultEntry.getId())); + } + return sortedRecords; + } + + /** + * Creates the SensorDatas from records. + * + * @param records the records + * @return the Map of SensorRecord + */ + public static Map createSensorData(List records) { + Map sensorDatas = new HashMap<>(); + for (Record record : records) { + SensorRecord sensorData = createSensorData(record); + sensorDatas.put(sensorData.getId(), sensorData); + } + return sensorDatas; + } + + /** + * Create a SensorRecord object out of a Record object + * + * @param record the record object + * @return SensorRecord object + */ + public static SensorRecord createSensorData(Record record) { + SensorRecord recordBean = new SensorRecord(); + recordBean.setId(record.getId()); + recordBean.setValues(record.getValues()); + return recordBean; + } + public static APIManagementProviderService getAPIManagementProviderService() { PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); APIManagementProviderService apiManagementProviderService = - (APIManagementProviderService) ctx.getOSGiService(DeviceManagementProviderService.class, null); + (APIManagementProviderService) ctx.getOSGiService(APIManagementProviderService.class, null); if (apiManagementProviderService == null) { String msg = "API management provider service has not initialized."; log.error(msg); @@ -52,4 +142,21 @@ public class APIUtil { } return apiManagementProviderService; } + + public static JWTClientManagerService getJWTClientManagerService() { + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + JWTClientManagerService jwtClientManagerService = + (JWTClientManagerService) ctx.getOSGiService(JWTClientManagerService.class, null); + if (jwtClientManagerService == null) { + String msg = "JWT Client manager service has not initialized."; + log.error(msg); + throw new IllegalStateException(msg); + } + return jwtClientManagerService; + } + + public static String getTenantDomainOftheUser() { + PrivilegedCarbonContext threadLocalCarbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + return threadLocalCarbonContext.getTenantDomain(); + } } diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.api/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/service/impl/util/RaspberrypiServiceUtils.java b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.api/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/service/impl/util/RaspberrypiServiceUtils.java index cb4d52c487..1992a0e013 100644 --- a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.api/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/service/impl/util/RaspberrypiServiceUtils.java +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.api/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/service/impl/util/RaspberrypiServiceUtils.java @@ -27,7 +27,7 @@ import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; import org.apache.http.impl.nio.client.HttpAsyncClients; import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.device.mgt.analytics.data.publisher.exception.DataPublisherConfigurationException; -import org.wso2.carbon.device.mgt.analytics.data.publisher.service.DeviceAnalyticsService; +import org.wso2.carbon.device.mgt.analytics.data.publisher.service.EventsPublisherService; import org.wso2.carbon.device.mgt.common.DeviceManagementException; import org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.constants.RaspberrypiConstants; @@ -211,8 +211,8 @@ public class RaspberrypiServiceUtils { public static boolean publishToDAS(String deviceId, float temperature) { PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); - DeviceAnalyticsService deviceAnalyticsService = (DeviceAnalyticsService) ctx.getOSGiService( - DeviceAnalyticsService.class, null); + EventsPublisherService deviceAnalyticsService = (EventsPublisherService) ctx.getOSGiService( + EventsPublisherService.class, null); String owner = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername(); Object metdaData[] = {owner, RaspberrypiConstants.DEVICE_TYPE, deviceId, System.currentTimeMillis()}; Object payloadData[] = {temperature}; diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/pom.xml b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/pom.xml index e50829cf85..291381f857 100644 --- a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/pom.xml +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/pom.xml @@ -245,6 +245,11 @@ org.wso2.carbon.apimgt.application.extension provided + + org.wso2.carbon.analytics + org.wso2.carbon.analytics.api + provided + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/VirtualFireAlarmControllerServiceImpl.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/VirtualFireAlarmControllerServiceImpl.java index 60fb360d34..b59887fe34 100644 --- a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/VirtualFireAlarmControllerServiceImpl.java +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/VirtualFireAlarmControllerServiceImpl.java @@ -20,26 +20,25 @@ package org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.analytics.dataservice.commons.SORT; +import org.wso2.carbon.analytics.dataservice.commons.SortByField; +import org.wso2.carbon.analytics.datasource.commons.exception.AnalyticsException; import org.wso2.carbon.certificate.mgt.core.dto.SCEPResponse; import org.wso2.carbon.certificate.mgt.core.exception.KeystoreException; import org.wso2.carbon.certificate.mgt.core.service.CertificateManagementService; -import org.wso2.carbon.context.PrivilegedCarbonContext; -import org.wso2.carbon.device.mgt.analytics.data.publisher.AnalyticsDataRecord; -import org.wso2.carbon.device.mgt.analytics.data.publisher.exception.DeviceManagementAnalyticsException; -import org.wso2.carbon.device.mgt.analytics.data.publisher.service.DeviceAnalyticsService; import org.wso2.carbon.device.mgt.common.DeviceManagementException; import org.wso2.carbon.device.mgt.iot.controlqueue.mqtt.MqttConfig; import org.wso2.carbon.device.mgt.iot.controlqueue.xmpp.XmppConfig; import org.wso2.carbon.device.mgt.iot.exception.DeviceControllerException; import org.wso2.carbon.device.mgt.iot.sensormgt.SensorDataManager; -import org.wso2.carbon.device.mgt.iot.sensormgt.SensorRecord; import org.wso2.carbon.device.mgt.iot.service.IoTServerStartupListener; import org.wso2.carbon.device.mgt.iot.transport.TransportHandlerException; import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.dto.DeviceData; -import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.dto.SensorData; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.dto.SensorRecord; import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.exception.VirtualFireAlarmException; import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.transport.VirtualFireAlarmMQTTConnector; import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.transport.VirtualFireAlarmXMPPConnector; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.util.APIUtil; import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.util.SecurityManager; import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.util.VirtualFireAlarmServiceUtils; import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.util.scep.ContentType; @@ -52,8 +51,6 @@ import javax.ws.rs.core.Response; import java.io.InputStream; import java.util.ArrayList; import java.util.Calendar; -import java.util.Collections; -import java.util.Comparator; import java.util.List; import java.util.concurrent.ConcurrentHashMap; @@ -253,7 +250,7 @@ public class VirtualFireAlarmControllerServiceImpl implements VirtualFireAlarmCo } public Response requestTemperature(String deviceId, String protocol) { - SensorRecord sensorRecord = null; + org.wso2.carbon.device.mgt.iot.sensormgt.SensorRecord sensorRecord = null; String protocolString = protocol.toUpperCase(); if (log.isDebugEnabled()) { log.debug("Sending request to read virtual-firealarm-temperature of device " + @@ -405,45 +402,23 @@ public class VirtualFireAlarmControllerServiceImpl implements VirtualFireAlarmCo } public Response getVirtualFirealarmStats(String deviceId, String sensor, String user, long from, long to) { + String fromDate = String.valueOf(from); + String toDate = String.valueOf(to); + String query = "owner:" + user + " AND deviceId:" + deviceId + " AND deviceType:" + + VirtualFireAlarmConstants.DEVICE_TYPE + " AND time : [" + fromDate + " TO " + toDate + "]"; + String sensorTableName = getSensorEventTableName(sensor); try { - String fromDate = String.valueOf(from); - String toDate = String.valueOf(to); - List sensorDatas = new ArrayList<>(); - PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); - DeviceAnalyticsService deviceAnalyticsService = (DeviceAnalyticsService) ctx - .getOSGiService(DeviceAnalyticsService.class, null); - String query = "owner:" + user + " AND deviceId:" + deviceId + " AND deviceType:" + - VirtualFireAlarmConstants.DEVICE_TYPE + " AND time : [" + fromDate + " TO " + toDate + "]"; - String sensorTableName = getSensorEventTableName(sensor); if (sensorTableName != null) { - List records = deviceAnalyticsService.getAllEventsForDevice(sensorTableName, query); - Collections.sort(records, new Comparator() { - @Override - public int compare(AnalyticsDataRecord o1, AnalyticsDataRecord o2) { - long t1 = (Long) o1.getValue("time"); - long t2 = (Long) o2.getValue("time"); - if (t1 < t2) { - return -1; - } else if (t1 > t2) { - return 1; - } else { - return 0; - } - } - }); - for (AnalyticsDataRecord record : records) { - SensorData sensorData = new SensorData(); - sensorData.setTime((long) record.getValue("time")); - sensorData.setValue("" + (float) record.getValue(sensor)); - sensorDatas.add(sensorData); - } - SensorData[] sensorDetails = sensorDatas.toArray(new SensorData[sensorDatas.size()]); - return Response.ok().entity(sensorDetails).build(); + List sortByFields = new ArrayList<>(); + SortByField sortByField = new SortByField("time", SORT.ASC, false); + sortByFields.add(sortByField); + List sensorRecords = APIUtil.getAllEventsForDevice(sensorTableName, query, sortByFields); + return Response.status(Response.Status.OK.getStatusCode()).entity(sensorRecords).build(); } - } catch (DeviceManagementAnalyticsException e) { - String errorMsg = "Error on retrieving stats on table for sensor name" + sensor; + } catch (AnalyticsException e) { + String errorMsg = "Error on retrieving stats on table " + sensorTableName + " with query " + query; log.error(errorMsg); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).entity(errorMsg).build(); } return Response.status(Response.Status.BAD_REQUEST).build(); } diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/VirtualFireAlarmManagerServiceImpl.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/VirtualFireAlarmManagerServiceImpl.java index f230dac1a9..9e226acc0c 100644 --- a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/VirtualFireAlarmManagerServiceImpl.java +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/VirtualFireAlarmManagerServiceImpl.java @@ -36,7 +36,6 @@ import org.wso2.carbon.device.mgt.iot.util.ZipUtil; import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.util.APIUtil; import org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.constants.VirtualFireAlarmConstants; import org.wso2.carbon.identity.jwt.client.extension.JWTClient; -import org.wso2.carbon.identity.jwt.client.extension.JWTClientManager; import org.wso2.carbon.identity.jwt.client.extension.dto.AccessTokenInfo; import org.wso2.carbon.identity.jwt.client.extension.exception.JWTClientException; import org.wso2.carbon.user.api.UserStoreException; @@ -210,12 +209,12 @@ public class VirtualFireAlarmManagerServiceImpl implements VirtualFireAlarmManag apiApplicationKey = apiManagementProviderService.generateAndRetrieveApplicationKeys( VirtualFireAlarmConstants.DEVICE_TYPE, tags, KEY_TYPE, applicationUsername, true); } - JWTClient jwtClient = JWTClientManager.getInstance().getJWTClient(); + JWTClient jwtClient = APIUtil.getJWTClientManagerService().getJWTClient(); String scopes = "device_type_" + VirtualFireAlarmConstants.DEVICE_TYPE + " device_" + deviceId; AccessTokenInfo accessTokenInfo = jwtClient.getAccessToken(apiApplicationKey.getConsumerKey(), apiApplicationKey.getConsumerSecret(), owner, scopes); - String accessToken = accessTokenInfo.getAccess_token(); - String refreshToken = accessTokenInfo.getRefresh_token(); + String accessToken = accessTokenInfo.getAccessToken(); + String refreshToken = accessTokenInfo.getRefreshToken(); //adding registering data XmppAccount newXmppAccount = new XmppAccount(); newXmppAccount.setAccountName(owner + "_" + deviceId); diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/dto/SensorData.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/dto/SensorData.java deleted file mode 100644 index e5e99609fe..0000000000 --- a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/dto/SensorData.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.dto; - -import org.codehaus.jackson.annotate.JsonIgnoreProperties; - -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; - -@XmlRootElement -/** - * This stores sensor event data for the device type. - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class SensorData { - - @XmlElement public Long time; - @XmlElement public String key; - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - public String getKey() { - return key; - } - - public void setKey(String key) { - this.key = key; - } - - public Long getTime() { - return time; - } - - public void setTime(Long time) { - this.time = time; - } - - @XmlElement public String value; - -} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/dto/SensorRecord.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/dto/SensorRecord.java new file mode 100644 index 0000000000..e1f46d2d79 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/dto/SensorRecord.java @@ -0,0 +1,68 @@ +package org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.dto; + +import org.codehaus.jackson.annotate.JsonIgnoreProperties; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementWrapper; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@XmlRootElement +/** + * This stores sensor event data for android sense. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class SensorRecord { + + @XmlElementWrapper(required = true, name = "values") + private Map values; + + /** The id. */ + @XmlElement(required = false, name = "id") + private String id; + + /** + * Gets the values. + * @return the values + */ + public Map getValues() { + return values; + } + + /** + * Sets the values. + * @param values the values + */ + public void setValues(Map values) { + this.values = values; + } + + /** + * Sets the id. + * @param id the new id + */ + public void setId(String id) { + this.id = id; + } + + /** + * Gets the id. + * @return the id + */ + public String getId() { + return id; + } + + @Override + public String toString(){ + List valueList = new ArrayList(); + for (Map.Entry entry : values.entrySet()) { + valueList.add(entry.getKey() + ":" + entry.getValue()); + } + return valueList.toString(); + + } + +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/util/APIUtil.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/util/APIUtil.java index 8f92c500af..ed6f9892c8 100644 --- a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/util/APIUtil.java +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/util/APIUtil.java @@ -2,9 +2,25 @@ package org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.util; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.analytics.api.AnalyticsDataAPI; +import org.wso2.carbon.analytics.dataservice.commons.AnalyticsDataResponse; +import org.wso2.carbon.analytics.dataservice.commons.AnalyticsDrillDownRequest; +import org.wso2.carbon.analytics.dataservice.commons.SearchResultEntry; +import org.wso2.carbon.analytics.dataservice.commons.SortByField; +import org.wso2.carbon.analytics.dataservice.core.AnalyticsDataServiceUtils; +import org.wso2.carbon.analytics.datasource.commons.Record; +import org.wso2.carbon.analytics.datasource.commons.exception.AnalyticsException; import org.wso2.carbon.apimgt.application.extension.APIManagementProviderService; +import org.wso2.carbon.context.CarbonContext; import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.dto.SensorRecord; +import org.wso2.carbon.identity.jwt.client.extension.service.JWTClientManagerService; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** * This class provides utility functions used by REST-API. @@ -23,12 +39,6 @@ public class APIUtil { return username; } - public static String getTenantDomainOftheUser() { - PrivilegedCarbonContext threadLocalCarbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext(); - String tenantDomain = threadLocalCarbonContext.getTenantDomain(); - return tenantDomain; - } - public static DeviceManagementProviderService getDeviceManagementService() { PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); DeviceManagementProviderService deviceManagementProviderService = @@ -41,6 +51,86 @@ public class APIUtil { return deviceManagementProviderService; } + public 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; + } + + public static List getAllEventsForDevice(String tableName, String query, List sortByFields) throws AnalyticsException { + int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId(); + AnalyticsDataAPI analyticsDataAPI = getAnalyticsDataAPI(); + int eventCount = analyticsDataAPI.searchCount(tenantId, tableName, query); + if (eventCount == 0) { + return null; + } + AnalyticsDrillDownRequest drillDownRequest = new AnalyticsDrillDownRequest(); + drillDownRequest.setQuery(query); + drillDownRequest.setTableName(tableName); + drillDownRequest.setRecordCount(eventCount); + if (sortByFields != null) { + drillDownRequest.setSortByFields(sortByFields); + } + List resultEntries = analyticsDataAPI.drillDownSearch(tenantId, drillDownRequest); + List recordIds = getRecordIds(resultEntries); + AnalyticsDataResponse response = analyticsDataAPI.get(tenantId, tableName, 1, null, recordIds); + Map sensorDatas = createSensorData(AnalyticsDataServiceUtils.listRecords( + analyticsDataAPI, response)); + List sortedSensorData = getSortedSensorData(sensorDatas, resultEntries); + return sortedSensorData; + } + + private static List getRecordIds(List searchResults) { + List ids = new ArrayList<>(); + for (SearchResultEntry searchResult : searchResults) { + ids.add(searchResult.getId()); + } + return ids; + } + + public static List getSortedSensorData(Map sensorDatas, + List searchResults) { + List sortedRecords = new ArrayList<>(); + for (SearchResultEntry searchResultEntry : searchResults) { + sortedRecords.add(sensorDatas.get(searchResultEntry.getId())); + } + return sortedRecords; + } + + /** + * Creates the SensorDatas from records. + * + * @param records the records + * @return the Map of SensorRecord + */ + public static Map createSensorData(List records) { + Map sensorDatas = new HashMap<>(); + for (Record record : records) { + SensorRecord sensorData = createSensorData(record); + sensorDatas.put(sensorData.getId(), sensorData); + } + return sensorDatas; + } + + /** + * Create a SensorRecord object out of a Record object + * + * @param record the record object + * @return SensorRecord object + */ + public static SensorRecord createSensorData(Record record) { + SensorRecord recordBean = new SensorRecord(); + recordBean.setId(record.getId()); + recordBean.setValues(record.getValues()); + return recordBean; + } + public static APIManagementProviderService getAPIManagementProviderService() { PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); APIManagementProviderService apiManagementProviderService = @@ -52,4 +142,21 @@ public class APIUtil { } return apiManagementProviderService; } + + public static JWTClientManagerService getJWTClientManagerService() { + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + JWTClientManagerService jwtClientManagerService = + (JWTClientManagerService) ctx.getOSGiService(JWTClientManagerService.class, null); + if (jwtClientManagerService == null) { + String msg = "JWT Client manager service has not initialized."; + log.error(msg); + throw new IllegalStateException(msg); + } + return jwtClientManagerService; + } + + public static String getTenantDomainOftheUser() { + PrivilegedCarbonContext threadLocalCarbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + return threadLocalCarbonContext.getTenantDomain(); + } } diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/util/VirtualFireAlarmServiceUtils.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/util/VirtualFireAlarmServiceUtils.java index 4b8f1d2adb..21f27acf99 100644 --- a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/util/VirtualFireAlarmServiceUtils.java +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/util/VirtualFireAlarmServiceUtils.java @@ -30,7 +30,7 @@ import org.wso2.carbon.certificate.mgt.core.exception.KeystoreException; import org.wso2.carbon.certificate.mgt.core.service.CertificateManagementService; import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.device.mgt.analytics.data.publisher.exception.DataPublisherConfigurationException; -import org.wso2.carbon.device.mgt.analytics.data.publisher.service.DeviceAnalyticsService; +import org.wso2.carbon.device.mgt.analytics.data.publisher.service.EventsPublisherService; import org.wso2.carbon.device.mgt.common.DeviceManagementException; import org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.constants.VirtualFireAlarmConstants; import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.exception.VirtualFireAlarmException; @@ -242,8 +242,8 @@ public class VirtualFireAlarmServiceUtils { public static boolean publishToDAS(String deviceId, float temperature) { PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); - DeviceAnalyticsService deviceAnalyticsService = (DeviceAnalyticsService) ctx.getOSGiService( - DeviceAnalyticsService.class, null); + EventsPublisherService deviceAnalyticsService = (EventsPublisherService) ctx.getOSGiService( + EventsPublisherService.class, null); if (deviceAnalyticsService != null) { String owner = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername(); Object metdaData[] = {owner, VirtualFireAlarmConstants.DEVICE_TYPE, deviceId, System.currentTimeMillis()}; diff --git a/features/iot-plugins-feature/das-extensions-feature/org.wso2.carbon.event.adapter.extensions.server.feature/pom.xml b/features/iot-plugins-feature/das-extensions-feature/org.wso2.carbon.event.adapter.extensions.server.feature/pom.xml new file mode 100644 index 0000000000..088e9babca --- /dev/null +++ b/features/iot-plugins-feature/das-extensions-feature/org.wso2.carbon.event.adapter.extensions.server.feature/pom.xml @@ -0,0 +1,120 @@ + + + + + + + + org.wso2.carbon.devicemgt-plugins + das-extensions-feature + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.event.adapter.extensions.server.feature + pom + WSO2 Carbon - Event Input Adapter Server Feature + http://wso2.org + This feature contains the bundles required for Input Event Adapter functionality + + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.event.input.adapter.extensions + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.event.output.adapter.extensions.ui + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy + package + + copy + + + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.event.output.adapter.extensions.ui.endpoint + ${carbon.devicemgt.plugins.version} + war + true + ${project.build.directory}/maven-shared-archive-resources/webapps/ + secured-outputui.war + + + + + + + + org.wso2.maven + carbon-p2-plugin + ${carbon.p2.plugin.version} + + + 4-p2-feature-generation + package + + p2-feature-gen + + + org.wso2.carbon.event.adapter.extensions.server + ../../etc/feature.properties + + + org.wso2.carbon.p2.category.type:server + org.eclipse.equinox.p2.type.group:true + + + + + org.wso2.carbon.devicemgt-plugins:org.wso2.carbon.event.input.adapter.extensions:${carbon.devicemgt.plugins.version} + + + org.wso2.carbon.devicemgt-plugins:org.wso2.carbon.event.output.adapter.extensions.ui:${carbon.devicemgt.plugins.version} + + + com.jayway.jsonpath.wso2:json-path:${json.path.version} + + + net.minidev.wso2:json-smart:${json.smart.version} + + + + org.wso2.carbon.core.server:${carbon.kernel.version} + + + + + + + + + + diff --git a/features/iot-plugins-feature/das-extensions-feature/org.wso2.carbon.event.adapter.extensions.server.feature/src/main/resources/build.properties b/features/iot-plugins-feature/das-extensions-feature/org.wso2.carbon.event.adapter.extensions.server.feature/src/main/resources/build.properties new file mode 100644 index 0000000000..6448563e33 --- /dev/null +++ b/features/iot-plugins-feature/das-extensions-feature/org.wso2.carbon.event.adapter.extensions.server.feature/src/main/resources/build.properties @@ -0,0 +1,20 @@ +# +# Copyright (c) 2005-2014, 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. +# + +custom = true +root.agent=conf diff --git a/features/iot-plugins-feature/das-extensions-feature/org.wso2.carbon.event.adapter.extensions.server.feature/src/main/resources/p2.inf b/features/iot-plugins-feature/das-extensions-feature/org.wso2.carbon.event.adapter.extensions.server.feature/src/main/resources/p2.inf new file mode 100644 index 0000000000..948ab4471a --- /dev/null +++ b/features/iot-plugins-feature/das-extensions-feature/org.wso2.carbon.event.adapter.extensions.server.feature/src/main/resources/p2.inf @@ -0,0 +1,4 @@ +instructions.configure = \ +org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../deployment/server/webapps/);\ +org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.event.adapter.extensions.server_${feature.version}/webapps/,target:${installFolder}/../../deployment/server/webapps/,overwrite:true);\ +org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.event.adapter.extensions.server_${feature.version}/websocket-validation.properties,target:${installFolder}/../../conf/etc/websocket-validation.properties,overwrite:true);\ diff --git a/features/iot-plugins-feature/das-extensions-feature/org.wso2.carbon.event.adapter.extensions.server.feature/src/main/resources/websocket-validation.properties b/features/iot-plugins-feature/das-extensions-feature/org.wso2.carbon.event.adapter.extensions.server.feature/src/main/resources/websocket-validation.properties new file mode 100644 index 0000000000..ac35d4733d --- /dev/null +++ b/features/iot-plugins-feature/das-extensions-feature/org.wso2.carbon.event.adapter.extensions.server.feature/src/main/resources/websocket-validation.properties @@ -0,0 +1,5 @@ +tokenValidationEndpoint=https://localhost:9443/services/OAuth2TokenValidationService +username=admin +password=admin +maxConnectionsPerHost=2 +maxTotalConnections=100 \ No newline at end of file diff --git a/features/iot-plugins-feature/das-extensions-feature/pom.xml b/features/iot-plugins-feature/das-extensions-feature/pom.xml new file mode 100644 index 0000000000..8d55a17c74 --- /dev/null +++ b/features/iot-plugins-feature/das-extensions-feature/pom.xml @@ -0,0 +1,40 @@ + + + + + + + org.wso2.carbon.devicemgt-plugins + iot-plugins-feature + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + das-extensions-feature + 2.1.0-SNAPSHOT + pom + WSO2 Carbon - Device Management, DAS Extensions Feature + http://wso2.org + + + org.wso2.carbon.event.adapter.extensions.server.feature + + + diff --git a/features/iot-plugins-feature/pom.xml b/features/iot-plugins-feature/pom.xml index 10a0ac19a3..5f7681d071 100644 --- a/features/iot-plugins-feature/pom.xml +++ b/features/iot-plugins-feature/pom.xml @@ -41,6 +41,7 @@ raspberrypi-plugin-feature virtual-fire-alarm-plugin-feature iot-base-plugin-feature + das-extensions-feature diff --git a/pom.xml b/pom.xml index c0df257a15..d72b551cc9 100644 --- a/pom.xml +++ b/pom.xml @@ -256,7 +256,6 @@ org.wso2.carbon.devicemgt org.wso2.carbon.device.mgt.analytics.data.publisher ${carbon.device.mgt.version} - provided org.wso2.carbon.devicemgt @@ -294,6 +293,16 @@ org.wso2.carbon.databridge.core ${carbon.analytics.common.version} + + org.wso2.carbon.analytics-common + org.wso2.carbon.event.output.adapter.core + ${carbon.analytics.common.version} + + + org.wso2.carbon.analytics-common + org.wso2.carbon.event.stream.core + ${carbon.analytics.common.version} + org.wso2.carbon.analytics-common org.wso2.carbon.databridge.agent @@ -310,6 +319,11 @@ org.wso2.carbon.databridge.commons ${carbon.analytics.common.version} + + org.wso2.carbon.analytics + org.wso2.carbon.analytics.api + ${carbon.analytics.version} + @@ -441,12 +455,28 @@ + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.event.input.adapter.extensions + ${carbon.devicemgt.plugins.version} + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.event.output.adapter.extensions.ui + ${carbon.devicemgt.plugins.version} + + org.wso2.carbon.analytics org.wso2.carbon.analytics.datasource.commons ${carbon.analytics.version} + + org.wso2.carbon.analytics-common + org.wso2.carbon.event.input.adapter.core + ${carbon.analytics.common.version} + @@ -1005,6 +1035,45 @@ ${junit.version} + + + org.apache.httpcomponents.wso2 + httpcore + ${httpcore.version} + + + org.wso2.orbit.org.apache.httpcomponents + httpclient + ${httpclient.version} + + + com.googlecode.json-simple.wso2 + json-simple + ${json-simple.version} + + + com.jayway.jsonpath.wso2 + json-path + ${json.path.version} + + + + + javax.websocket + javax.websocket-api + ${javax.websocket.version} + + + org.apache.tomcat + tomcat-websocket-api + ${tomcat.websocket.version} + provided + + + javax.ws.rs + javax.ws.rs-api + ${javax.version} + @@ -1042,7 +1111,7 @@ 7.0.34.wso2v2 - 2.7.16 + 2.6.1 2.5.11 1.9.0 1.1.1 @@ -1061,6 +1130,7 @@ 5.0.7 + [5.0.7, 6.0.0) 4.5.0 @@ -1092,7 +1162,7 @@ 5.0.11 [5.0.11,6.0.0) - 1.0.5 + 1.0.6-ALPHA [1.0.5,2.0.0] @@ -1126,7 +1196,18 @@ 1.8 7.0.59.wso2v1 - + + 4.3.1.wso2v2 + [4.3.1, 5.0.0) + 4.3.3.wso2v1 + + 1.1.wso2v1 + 1.2.0.wso2v1 + 2.1.0.wso2v1 + + 7.0.54 + 1.0 + 2.0 github-scm