Integrated DAS for stat

application-manager-new
ayyoob 9 years ago
parent 20b5469e2a
commit b7daf92ada

@ -29,7 +29,6 @@
<Issuer>social</Issuer> <Issuer>social</Issuer>
<AssertionConsumerServiceURLs><AssertionConsumerServiceURL>https://localhost:9443/store/acs</AssertionConsumerServiceURL></AssertionConsumerServiceURLs> <AssertionConsumerServiceURLs><AssertionConsumerServiceURL>https://localhost:9443/store/acs</AssertionConsumerServiceURL></AssertionConsumerServiceURLs>
<DefaultAssertionConsumerServiceURL>https://localhost:9443/social/acs</DefaultAssertionConsumerServiceURL> <DefaultAssertionConsumerServiceURL>https://localhost:9443/social/acs</DefaultAssertionConsumerServiceURL>
<AssertionConsumerService>https://localhost:9443/social/acs</AssertionConsumerService>
<SignResponse>true</SignResponse> <SignResponse>true</SignResponse>
<CustomLoginPage>/social/login</CustomLoginPage> <CustomLoginPage>/social/login</CustomLoginPage>
</ServiceProvider> </ServiceProvider>
@ -37,7 +36,6 @@
<Issuer>publisher</Issuer> <Issuer>publisher</Issuer>
<AssertionConsumerServiceURLs><AssertionConsumerServiceURL>https://localhost:9443/store/acs</AssertionConsumerServiceURL></AssertionConsumerServiceURLs> <AssertionConsumerServiceURLs><AssertionConsumerServiceURL>https://localhost:9443/store/acs</AssertionConsumerServiceURL></AssertionConsumerServiceURLs>
<DefaultAssertionConsumerServiceURL>https://localhost:9443/publisher/acs</DefaultAssertionConsumerServiceURL> <DefaultAssertionConsumerServiceURL>https://localhost:9443/publisher/acs</DefaultAssertionConsumerServiceURL>
<AssertionConsumerService>https://localhost:9443/publisher/acs</AssertionConsumerService>
<SignResponse>true</SignResponse> <SignResponse>true</SignResponse>
<CustomLoginPage>/publisher/controllers/login.jag</CustomLoginPage> <CustomLoginPage>/publisher/controllers/login.jag</CustomLoginPage>
</ServiceProvider> </ServiceProvider>

@ -1165,14 +1165,14 @@
<id>org.wso2.carbon.social.feature.group</id> <id>org.wso2.carbon.social.feature.group</id>
<version>${carbon.social.version}</version> <version>${carbon.social.version}</version>
</feature> </feature>
<feature> <!--<feature>-->
<id>org.wso2.carbon.store.extensions.assets.gadget.feature.group</id> <!--<id>org.wso2.carbon.store.extensions.assets.gadget.feature.group</id>-->
<version>${carbon.store.version}</version> <!--<version>${carbon.store.version}</version>-->
</feature> <!--</feature>-->
<feature> <!--<feature>-->
<id>org.wso2.carbon.store.extensions.assets.site.feature.group</id> <!--<id>org.wso2.carbon.store.extensions.assets.site.feature.group</id>-->
<version>${carbon.store.version}</version> <!--<version>${carbon.store.version}</version>-->
</feature> <!--</feature>-->
<!--+++++++++++++++++++++++++++++++++++++++++++++++--> <!--+++++++++++++++++++++++++++++++++++++++++++++++-->
<!-- End of Store Features --> <!-- End of Store Features -->

@ -21,29 +21,35 @@
<dependency> <dependency>
<groupId>org.wso2.carbon.devicemgt</groupId> <groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.device.mgt.common</artifactId> <artifactId>org.wso2.carbon.device.mgt.common</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.wso2.carbon.devicemgt</groupId> <groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.device.mgt.core</artifactId> <artifactId>org.wso2.carbon.device.mgt.core</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<!--CXF --> <!--CXF -->
<dependency> <dependency>
<groupId>org.apache.cxf</groupId> <groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId> <artifactId>cxf-rt-frontend-jaxws</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.cxf</groupId> <groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId> <artifactId>cxf-rt-frontend-jaxrs</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.cxf</groupId> <groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId> <artifactId>cxf-rt-transports-http</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<!--MQTT --> <!--MQTT -->
<dependency> <dependency>
<groupId>org.eclipse.paho</groupId> <groupId>org.eclipse.paho</groupId>
<artifactId>mqtt-client</artifactId> <artifactId>mqtt-client</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<!--IOT --> <!--IOT -->
@ -55,10 +61,12 @@
<dependency> <dependency>
<groupId>org.wso2.carbon.device.mgt.iot</groupId> <groupId>org.wso2.carbon.device.mgt.iot</groupId>
<artifactId>org.wso2.carbon.device.mgt.iot.common</artifactId> <artifactId>org.wso2.carbon.device.mgt.iot.common</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.wso2.carbon.device.mgt.iot.server.sample</groupId> <groupId>org.wso2.carbon.device.mgt.iot.server.sample</groupId>
<artifactId>org.wso2.carbon.device.mgt.iot.sample.android.sense.plugin.impl</artifactId> <artifactId>org.wso2.carbon.device.mgt.iot.sample.android.sense.plugin.impl</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<!--JAX-RS --> <!--JAX-RS -->
<dependency> <dependency>
@ -72,10 +80,12 @@
<dependency> <dependency>
<groupId>javax</groupId> <groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId> <artifactId>javaee-web-api</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>javax.ws.rs</groupId> <groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId> <artifactId>jsr311-api</artifactId>
<scope>provided</scope>
</dependency> </dependency>
</dependencies> </dependencies>

@ -27,30 +27,36 @@
<dependency> <dependency>
<groupId>org.wso2.carbon.devicemgt</groupId> <groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.device.mgt.common</artifactId> <artifactId>org.wso2.carbon.device.mgt.common</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.wso2.carbon.devicemgt</groupId> <groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.device.mgt.core</artifactId> <artifactId>org.wso2.carbon.device.mgt.core</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<!--CXF --> <!--CXF -->
<dependency> <dependency>
<groupId>org.apache.cxf</groupId> <groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId> <artifactId>cxf-rt-frontend-jaxws</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.cxf</groupId> <groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId> <artifactId>cxf-rt-frontend-jaxrs</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.cxf</groupId> <groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId> <artifactId>cxf-rt-transports-http</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<!--MQTT --> <!--MQTT -->
<dependency> <dependency>
<groupId>org.eclipse.paho</groupId> <groupId>org.eclipse.paho</groupId>
<artifactId>mqtt-client</artifactId> <artifactId>mqtt-client</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<!--IOT --> <!--IOT -->
@ -62,10 +68,12 @@
<dependency> <dependency>
<groupId>org.wso2.carbon.device.mgt.iot</groupId> <groupId>org.wso2.carbon.device.mgt.iot</groupId>
<artifactId>org.wso2.carbon.device.mgt.iot.common</artifactId> <artifactId>org.wso2.carbon.device.mgt.iot.common</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.wso2.carbon.device.mgt.iot.server.sample</groupId> <groupId>org.wso2.carbon.device.mgt.iot.server.sample</groupId>
<artifactId>org.wso2.carbon.device.mgt.iot.sample.arduino.plugin.impl</artifactId> <artifactId>org.wso2.carbon.device.mgt.iot.sample.arduino.plugin.impl</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<!--JAX-RS --> <!--JAX-RS -->
<dependency> <dependency>
@ -79,16 +87,19 @@
<dependency> <dependency>
<groupId>javax</groupId> <groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId> <artifactId>javaee-web-api</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>javax.ws.rs</groupId> <groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId> <artifactId>jsr311-api</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.wso2.carbon.devicemgt</groupId> <groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.device.mgt.analytics</artifactId> <artifactId>org.wso2.carbon.device.mgt.analytics</artifactId>
<scope>provided</scope>
</dependency> </dependency>
</dependencies> </dependencies>

@ -27,9 +27,7 @@ import org.wso2.carbon.device.mgt.iot.sample.arduino.service.impl.util.DeviceJSO
import org.wso2.carbon.device.mgt.iot.sample.arduino.service.impl.util.MqttArduinoSubscriber; import org.wso2.carbon.device.mgt.iot.sample.arduino.service.impl.util.MqttArduinoSubscriber;
import org.wso2.carbon.device.mgt.iot.sample.arduino.plugin.constants.ArduinoConstants; import org.wso2.carbon.device.mgt.iot.sample.arduino.plugin.constants.ArduinoConstants;
import org.wso2.carbon.device.mgt.iot.common.DeviceController; import org.wso2.carbon.device.mgt.iot.common.DeviceController;
import org.wso2.carbon.device.mgt.iot.common.datastore.impl.DataStreamDefinitions;
import org.wso2.carbon.device.mgt.iot.common.exception.DeviceControllerException; import org.wso2.carbon.device.mgt.iot.common.exception.DeviceControllerException;
import org.wso2.carbon.device.mgt.iot.common.exception.UnauthorizedException;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.*; import javax.ws.rs.*;
@ -44,7 +42,8 @@ public class ArduinoControllerService {
private static Map<String, LinkedList<String>> replyMsgQueue = new HashMap<>(); private static Map<String, LinkedList<String>> replyMsgQueue = new HashMap<>();
private static Map<String, LinkedList<String>> internalControlsQueue = new HashMap<>(); private static Map<String, LinkedList<String>> internalControlsQueue = new HashMap<>();
private static MqttArduinoSubscriber mqttArduinoSubscriber; private static MqttArduinoSubscriber mqttArduinoSubscriber;
private static final String TEMPERATURE_STREAM_DEFINITION = "org.wso2.iot.devices.temperature";
private final String SUPER_TENANT = "carbon.super";
public void setMqttArduinoSubscriber(MqttArduinoSubscriber mqttArduinoSubscriber) { public void setMqttArduinoSubscriber(MqttArduinoSubscriber mqttArduinoSubscriber) {
ArduinoControllerService.mqttArduinoSubscriber = mqttArduinoSubscriber; ArduinoControllerService.mqttArduinoSubscriber = mqttArduinoSubscriber;
@ -137,57 +136,32 @@ public class ArduinoControllerService {
} }
/* Service to push all the sensor data collected by the Arduino /*Service to push all the sensor data collected by the Arduino
Called by the Arduino device */ Called by the Arduino device */
@Path("/pushdata") @Path("/pushdata")
@POST @POST
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public void pushData(final DeviceJSON dataMsg, @Context HttpServletResponse response) { public void pushData(final DeviceJSON dataMsg, @Context HttpServletResponse response) {
String temperature = dataMsg.value; //TEMP float temperature = dataMsg.value;
log.info("Recieved Sensor Data Values: " + temperature);
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("Recieved Temperature Data Value: " + temperature + " degrees C"); log.debug("Recieved Temperature Data Value: " + temperature + " degrees C");
} }
try {
DeviceController deviceController = new DeviceController();
boolean result = deviceController.pushBamData(dataMsg.owner,
ArduinoConstants.DEVICE_TYPE,
dataMsg.deviceId,
System.currentTimeMillis(), "DeviceData",
temperature,
DataStreamDefinitions.StreamTypeLabel
.TEMPERATURE);
if (!result) {
response.setStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR);
}
} catch (UnauthorizedException e) {
response.setStatus(HttpStatus.SC_UNAUTHORIZED);
}
}
@Path("/test/{value}")
@POST
public void pushtData(@PathParam("value") double value, @Context HttpServletResponse
response) {
PrivilegedCarbonContext.startTenantFlow(); PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
ctx.setTenantDomain("carbon.super", true); ctx.setTenantDomain(SUPER_TENANT, true);
DeviceAnalyticsService deviceAnalyticsService = (DeviceAnalyticsService) ctx DeviceAnalyticsService deviceAnalyticsService = (DeviceAnalyticsService) ctx
.getOSGiService( .getOSGiService(DeviceAnalyticsService.class, null);
DeviceAnalyticsService.class, null); Object metdaData[] = {dataMsg.owner, ArduinoConstants.DEVICE_TYPE, dataMsg.deviceId,
Object metdaData[] = {"ayyoob", "firealarm", "123", System.currentTimeMillis()}; System.currentTimeMillis()};
Object payloadData[] = {value}; Object payloadData[] = {temperature};
try { try {
deviceAnalyticsService.publishEvent("org.wso2.iot.devices.temperature", "1.0.0", deviceAnalyticsService.publishEvent(TEMPERATURE_STREAM_DEFINITION, "1.0.0",
metdaData, new Object[0], payloadData); metdaData, new Object[0], payloadData);
} catch (DataPublisherConfigurationException e) { } catch (DataPublisherConfigurationException e) {
log.error("Error on connecting to data publisher");
response.setStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR); response.setStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR);
} finally { } finally {

@ -14,5 +14,5 @@ public class DeviceJSON {
@XmlElement(required = true) public String reply; @XmlElement(required = true) public String reply;
@XmlElement public Long time; @XmlElement public Long time;
@XmlElement public String key; @XmlElement public String key;
@XmlElement public String value; @XmlElement public float value;
} }

@ -21,29 +21,35 @@
<dependency> <dependency>
<groupId>org.wso2.carbon.devicemgt</groupId> <groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.device.mgt.common</artifactId> <artifactId>org.wso2.carbon.device.mgt.common</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.wso2.carbon.devicemgt</groupId> <groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.device.mgt.core</artifactId> <artifactId>org.wso2.carbon.device.mgt.core</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<!--CXF --> <!--CXF -->
<dependency> <dependency>
<groupId>org.apache.cxf</groupId> <groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId> <artifactId>cxf-rt-frontend-jaxws</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.cxf</groupId> <groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId> <artifactId>cxf-rt-frontend-jaxrs</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.cxf</groupId> <groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId> <artifactId>cxf-rt-transports-http</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<!--MQTT --> <!--MQTT -->
<dependency> <dependency>
<groupId>org.eclipse.paho</groupId> <groupId>org.eclipse.paho</groupId>
<artifactId>mqtt-client</artifactId> <artifactId>mqtt-client</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<!--IOT --> <!--IOT -->
@ -55,10 +61,12 @@
<dependency> <dependency>
<groupId>org.wso2.carbon.device.mgt.iot</groupId> <groupId>org.wso2.carbon.device.mgt.iot</groupId>
<artifactId>org.wso2.carbon.device.mgt.iot.common</artifactId> <artifactId>org.wso2.carbon.device.mgt.iot.common</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.wso2.carbon.device.mgt.iot.server.sample</groupId> <groupId>org.wso2.carbon.device.mgt.iot.server.sample</groupId>
<artifactId>org.wso2.carbon.device.mgt.iot.sample.digitaldisplay.plugin.impl</artifactId> <artifactId>org.wso2.carbon.device.mgt.iot.sample.digitaldisplay.plugin.impl</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<!--JAX-RS --> <!--JAX-RS -->
<dependency> <dependency>
@ -72,10 +80,12 @@
<dependency> <dependency>
<groupId>javax</groupId> <groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId> <artifactId>javaee-web-api</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>javax.ws.rs</groupId> <groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId> <artifactId>jsr311-api</artifactId>
<scope>provided</scope>
</dependency> </dependency>
</dependencies> </dependencies>

@ -21,29 +21,35 @@
<dependency> <dependency>
<groupId>org.wso2.carbon.devicemgt</groupId> <groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.device.mgt.common</artifactId> <artifactId>org.wso2.carbon.device.mgt.common</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.wso2.carbon.devicemgt</groupId> <groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.device.mgt.core</artifactId> <artifactId>org.wso2.carbon.device.mgt.core</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<!--CXF --> <!--CXF -->
<dependency> <dependency>
<groupId>org.apache.cxf</groupId> <groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId> <artifactId>cxf-rt-frontend-jaxws</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.cxf</groupId> <groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId> <artifactId>cxf-rt-frontend-jaxrs</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.cxf</groupId> <groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId> <artifactId>cxf-rt-transports-http</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<!--MQTT --> <!--MQTT -->
<dependency> <dependency>
<groupId>org.eclipse.paho</groupId> <groupId>org.eclipse.paho</groupId>
<artifactId>mqtt-client</artifactId> <artifactId>mqtt-client</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<!--IOT --> <!--IOT -->
@ -55,10 +61,12 @@
<dependency> <dependency>
<groupId>org.wso2.carbon.device.mgt.iot</groupId> <groupId>org.wso2.carbon.device.mgt.iot</groupId>
<artifactId>org.wso2.carbon.device.mgt.iot.common</artifactId> <artifactId>org.wso2.carbon.device.mgt.iot.common</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.wso2.carbon.device.mgt.iot.server.sample</groupId> <groupId>org.wso2.carbon.device.mgt.iot.server.sample</groupId>
<artifactId>org.wso2.carbon.device.mgt.iot.sample.firealarm.plugin.impl</artifactId> <artifactId>org.wso2.carbon.device.mgt.iot.sample.firealarm.plugin.impl</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<!--JAX-RS --> <!--JAX-RS -->
<dependency> <dependency>
@ -72,20 +80,30 @@
<dependency> <dependency>
<groupId>javax</groupId> <groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId> <artifactId>javaee-web-api</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>javax.ws.rs</groupId> <groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId> <artifactId>jsr311-api</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>commons-httpclient.wso2</groupId> <groupId>commons-httpclient.wso2</groupId>
<artifactId>commons-httpclient</artifactId> <artifactId>commons-httpclient</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.wso2.carbon</groupId> <groupId>org.wso2.carbon</groupId>
<artifactId>org.wso2.carbon.utils</artifactId> <artifactId>org.wso2.carbon.utils</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.device.mgt.analytics</artifactId>
<scope>provided</scope>
</dependency>
</dependencies> </dependencies>

@ -23,6 +23,9 @@ import org.apache.http.client.methods.HttpGet;
import org.apache.http.concurrent.FutureCallback; import org.apache.http.concurrent.FutureCallback;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients; import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.analytics.exception.DataPublisherConfigurationException;
import org.wso2.carbon.device.mgt.analytics.service.DeviceAnalyticsService;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier; import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import org.wso2.carbon.device.mgt.common.DeviceManagementException; import org.wso2.carbon.device.mgt.common.DeviceManagementException;
import org.wso2.carbon.device.mgt.iot.common.DeviceController; import org.wso2.carbon.device.mgt.iot.common.DeviceController;
@ -65,7 +68,7 @@ public class FireAlarmControllerService {
private final String SUPER_TENANT = "carbon.super"; private final String SUPER_TENANT = "carbon.super";
@Context //injected response proxy supporting multiple thread @Context //injected response proxy supporting multiple thread
private HttpServletResponse response; private HttpServletResponse response;
private static final String TEMPERATURE_STREAM_DEFINITION = "org.wso2.iot.devices.temperature";
private static final String URL_PREFIX = "http://"; private static final String URL_PREFIX = "http://";
private static final String BULB_CONTEXT = "/BULB/"; private static final String BULB_CONTEXT = "/BULB/";
@ -380,143 +383,121 @@ public class FireAlarmControllerService {
boolean result; boolean result;
String deviceId = dataMsg.deviceId; String deviceId = dataMsg.deviceId;
String deviceIp = dataMsg.reply; String deviceIp = dataMsg.reply;
String temperature = dataMsg.value; float temperature = dataMsg.value;
String registeredIp = deviceToIpMap.get(deviceId); String registeredIp = deviceToIpMap.get(deviceId);
if (registeredIp == null) { if (registeredIp == null) {
log.warn( log.warn("Unregistered IP: Temperature Data Received from an un-registered IP " +
"Unregistered IP: Temperature Data Received from an un-registered IP " + deviceIp + " for device ID - " + deviceId);
deviceIp +
" for device ID - " + deviceId);
response.setStatus(Response.Status.PRECONDITION_FAILED.getStatusCode()); response.setStatus(Response.Status.PRECONDITION_FAILED.getStatusCode());
return; return;
} else if (!registeredIp.equals(deviceIp)) { } else if (!registeredIp.equals(deviceIp)) {
log.warn("Conflicting IP: Received IP is " + deviceIp + ". Device with ID " + log.warn("Conflicting IP: Received IP is " + deviceIp + ". Device with ID " +
deviceId + deviceId + " is already registered under some other IP. Re-registration " + "required");
" is already registered under some other IP. Re-registration " +
"required");
response.setStatus(Response.Status.CONFLICT.getStatusCode()); response.setStatus(Response.Status.CONFLICT.getStatusCode());
return; return;
} }
PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
ctx.setTenantDomain(SUPER_TENANT, true);
DeviceAnalyticsService deviceAnalyticsService = (DeviceAnalyticsService) ctx
.getOSGiService(DeviceAnalyticsService.class, null);
Object metdaData[] = {dataMsg.owner, FireAlarmConstants.DEVICE_TYPE, dataMsg.deviceId,
System.currentTimeMillis()};
Object payloadData[] = {temperature};
try { try {
DeviceController deviceController = new DeviceController(); deviceAnalyticsService.publishEvent(TEMPERATURE_STREAM_DEFINITION, "1.0.0",
result = deviceController.pushBamData(dataMsg.owner, FireAlarmConstants metdaData, new Object[0], payloadData);
.DEVICE_TYPE, } catch (DataPublisherConfigurationException e) {
dataMsg.deviceId,
System.currentTimeMillis(), "DeviceData",
temperature,
DataStreamDefinitions.StreamTypeLabel
.TEMPERATURE);
if (!result) {
response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
}
} catch (UnauthorizedException e) {
response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
log.error("Data Push Attempt Failed for BAM Publisher: " + e.getMessage());
}
try { } finally {
DeviceController deviceController = new DeviceController(); PrivilegedCarbonContext.endTenantFlow();
result = deviceController.pushCepData(dataMsg.owner, FireAlarmConstants
.DEVICE_TYPE,
dataMsg.deviceId,
System.currentTimeMillis(), "DeviceData",
temperature,
DataStreamDefinitions.StreamTypeLabel
.TEMPERATURE);
if (!result) {
response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
}
} catch (UnauthorizedException e) {
response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
log.error("Data Push Attempt Failed for CEP Publisher: " + e.getMessage());
} }
} }
/* Service to push all the sensor data collected by the FireAlarm /* Service to push all the sensor data collected by the FireAlarm
Called by the FireAlarm device */ Called by the FireAlarm device */
@Path("/pushalarmdata") // @Path("/pushalarmdata")
@POST // @POST
@Consumes(MediaType.APPLICATION_JSON) // @Consumes(MediaType.APPLICATION_JSON)
public void pushAlarmData(final DeviceJSON dataMsg, @Context HttpServletResponse response) { // public void pushAlarmData(final DeviceJSON dataMsg, @Context HttpServletResponse response) {
boolean result; // boolean result;
String sensorValues = dataMsg.value; // String sensorValues = dataMsg.value;
log.info("Recieved Sensor Data Values: " + sensorValues); // log.info("Recieved Sensor Data Values: " + sensorValues);
//
String sensors[] = sensorValues.split(":"); // String sensors[] = sensorValues.split(":");
try { // try {
if (sensors.length == 3) { // if (sensors.length == 3) {
String temperature = sensors[0]; // String temperature = sensors[0];
String bulb = sensors[1]; // String bulb = sensors[1];
String sonar = sensors[2]; // String sonar = sensors[2];
sensorValues = "Temperature:" + temperature + "C\tBulb Status:" + bulb + // sensorValues = "Temperature:" + temperature + "C\tBulb Status:" + bulb +
"\t\tSonar Status:" + sonar; // "\t\tSonar Status:" + sonar;
log.info(sensorValues); // log.info(sensorValues);
DeviceController deviceController = new DeviceController(); // DeviceController deviceController = new DeviceController();
result = deviceController.pushBamData(dataMsg.owner, FireAlarmConstants // result = deviceController.pushBamData(dataMsg.owner, FireAlarmConstants
.DEVICE_TYPE, // .DEVICE_TYPE,
dataMsg.deviceId, // dataMsg.deviceId,
System.currentTimeMillis(), "DeviceData", // System.currentTimeMillis(), "DeviceData",
temperature, "TEMPERATURE"); // temperature, "TEMPERATURE");
//
if (!result) { // if (!result) {
response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); // response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
log.error("Error whilst pushing temperature: " + sensorValues); // log.error("Error whilst pushing temperature: " + sensorValues);
return; // return;
} // }
//
result = deviceController.pushBamData(dataMsg.owner, FireAlarmConstants // result = deviceController.pushBamData(dataMsg.owner, FireAlarmConstants
.DEVICE_TYPE, // .DEVICE_TYPE,
dataMsg.deviceId, // dataMsg.deviceId,
System.currentTimeMillis(), "DeviceData", // System.currentTimeMillis(), "DeviceData",
bulb, // bulb,
"BULB"); // "BULB");
//
if (!result) { // if (!result) {
response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); // response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
log.error("Error whilst pushing Bulb data: " + sensorValues); // log.error("Error whilst pushing Bulb data: " + sensorValues);
return; // return;
} // }
//
result = deviceController.pushBamData(dataMsg.owner, FireAlarmConstants // result = deviceController.pushBamData(dataMsg.owner, FireAlarmConstants
.DEVICE_TYPE, // .DEVICE_TYPE,
dataMsg.deviceId, // dataMsg.deviceId,
System.currentTimeMillis(), "DeviceData", // System.currentTimeMillis(), "DeviceData",
sonar, // sonar,
"SONAR"); // "SONAR");
//
if (!result) { // if (!result) {
response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); // response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
log.error("Error whilst pushing Sonar data: " + sensorValues); // log.error("Error whilst pushing Sonar data: " + sensorValues);
} // }
//
} else { // } else {
DeviceController deviceController = new DeviceController(); // DeviceController deviceController = new DeviceController();
result = deviceController.pushBamData(dataMsg.owner, FireAlarmConstants // result = deviceController.pushBamData(dataMsg.owner, FireAlarmConstants
.DEVICE_TYPE, // .DEVICE_TYPE,
dataMsg.deviceId, // dataMsg.deviceId,
System.currentTimeMillis(), "DeviceData", // System.currentTimeMillis(), "DeviceData",
dataMsg.value, dataMsg.reply); // dataMsg.value, dataMsg.reply);
if (!result) { // if (!result) {
response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); // response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
log.error("Error whilst pushing sensor data: " + sensorValues); // log.error("Error whilst pushing sensor data: " + sensorValues);
} // }
} // }
//
} catch (UnauthorizedException e) { // } catch (UnauthorizedException e) {
response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); // response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
log.error("Data Push Attempt Failed at Publisher: " + e.getMessage()); // log.error("Data Push Attempt Failed at Publisher: " + e.getMessage());
} // }
} // }
private String sendCommandViaXMPP(String deviceOwner, String deviceId, String resource, private String sendCommandViaXMPP(String deviceOwner, String deviceId, String resource,

@ -14,5 +14,5 @@ public class DeviceJSON {
@XmlElement(required = true) public String reply; @XmlElement(required = true) public String reply;
@XmlElement public Long time; @XmlElement public Long time;
@XmlElement public String key; @XmlElement public String key;
@XmlElement public String value; @XmlElement public float value;
} }

@ -210,6 +210,16 @@
<!--<scope>provided</scope>--> <!--<scope>provided</scope>-->
</dependency> </dependency>
<!--Analytics dependencies-->
<dependency>
<groupId>org.wso2.carbon.analytics</groupId>
<artifactId>org.wso2.carbon.analytics.datasource.commons</artifactId>
<version>${carbon.analytics.version}</version>
<scope>provided</scope>
</dependency>
<!--Osgi dependencies--> <!--Osgi dependencies-->
<dependency> <dependency>
<groupId>org.eclipse.osgi</groupId> <groupId>org.eclipse.osgi</groupId>
@ -305,8 +315,6 @@
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.wso2.carbon</groupId> <groupId>org.wso2.carbon</groupId>
<artifactId>org.wso2.carbon.utils</artifactId> <artifactId>org.wso2.carbon.utils</artifactId>
@ -369,6 +377,7 @@
<artifactId>org.wso2.carbon.registry.api</artifactId> <artifactId>org.wso2.carbon.registry.api</artifactId>
</exclusion> </exclusion>
</exclusions> </exclusions>
<scope>provided</scope>
</dependency> </dependency>
@ -435,6 +444,7 @@
<!-- Source code --> <!-- Source code -->
<wso2.maven.compiler.source>1.7</wso2.maven.compiler.source> <wso2.maven.compiler.source>1.7</wso2.maven.compiler.source>
<wso2.maven.compiler.target>1.7</wso2.maven.compiler.target> <wso2.maven.compiler.target>1.7</wso2.maven.compiler.target>
<carbon.analytics.version>1.0.3</carbon.analytics.version>
</properties> </properties>

@ -21,29 +21,35 @@
<dependency> <dependency>
<groupId>org.wso2.carbon.devicemgt</groupId> <groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.device.mgt.common</artifactId> <artifactId>org.wso2.carbon.device.mgt.common</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.wso2.carbon.devicemgt</groupId> <groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.device.mgt.core</artifactId> <artifactId>org.wso2.carbon.device.mgt.core</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<!--CXF --> <!--CXF -->
<dependency> <dependency>
<groupId>org.apache.cxf</groupId> <groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId> <artifactId>cxf-rt-frontend-jaxws</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.cxf</groupId> <groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId> <artifactId>cxf-rt-frontend-jaxrs</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.cxf</groupId> <groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId> <artifactId>cxf-rt-transports-http</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<!--MQTT --> <!--MQTT -->
<dependency> <dependency>
<groupId>org.eclipse.paho</groupId> <groupId>org.eclipse.paho</groupId>
<artifactId>mqtt-client</artifactId> <artifactId>mqtt-client</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<!--IOT --> <!--IOT -->
@ -55,10 +61,12 @@
<dependency> <dependency>
<groupId>org.wso2.carbon.device.mgt.iot</groupId> <groupId>org.wso2.carbon.device.mgt.iot</groupId>
<artifactId>org.wso2.carbon.device.mgt.iot.common</artifactId> <artifactId>org.wso2.carbon.device.mgt.iot.common</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.wso2.carbon.device.mgt.iot.server.sample</groupId> <groupId>org.wso2.carbon.device.mgt.iot.server.sample</groupId>
<artifactId>org.wso2.carbon.device.mgt.iot.sample.raspberrypi.plugin.impl</artifactId> <artifactId>org.wso2.carbon.device.mgt.iot.sample.raspberrypi.plugin.impl</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<!--JAX-RS --> <!--JAX-RS -->
<dependency> <dependency>
@ -72,10 +80,17 @@
<dependency> <dependency>
<groupId>javax</groupId> <groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId> <artifactId>javaee-web-api</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>javax.ws.rs</groupId> <groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId> <artifactId>jsr311-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.device.mgt.analytics</artifactId>
<scope>provided</scope>
</dependency> </dependency>

@ -17,6 +17,9 @@
package org.wso2.carbon.device.mgt.iot.sample.raspberrypi.service.impl; package org.wso2.carbon.device.mgt.iot.sample.raspberrypi.service.impl;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.analytics.exception.DataPublisherConfigurationException;
import org.wso2.carbon.device.mgt.analytics.service.DeviceAnalyticsService;
import org.wso2.carbon.device.mgt.iot.common.datastore.impl.DataStreamDefinitions; import org.wso2.carbon.device.mgt.iot.common.datastore.impl.DataStreamDefinitions;
import org.wso2.carbon.device.mgt.iot.sample.raspberrypi.service.impl.util.DeviceJSON; import org.wso2.carbon.device.mgt.iot.sample.raspberrypi.service.impl.util.DeviceJSON;
import org.wso2.carbon.device.mgt.iot.sample.raspberrypi.plugin.constants.RaspberrypiConstants; import org.wso2.carbon.device.mgt.iot.sample.raspberrypi.plugin.constants.RaspberrypiConstants;
@ -35,6 +38,9 @@ import javax.ws.rs.core.Response;
public class RaspberrypiControllerService { public class RaspberrypiControllerService {
private static Log log = LogFactory.getLog(RaspberrypiControllerService.class); private static Log log = LogFactory.getLog(RaspberrypiControllerService.class);
private static final String TEMPERATURE_STREAM_DEFINITION = "org.wso2.iot.devices.temperature";
//TODO; replace this tenant domain
private final String SUPER_TENANT = "carbon.super";
@Context //injected response proxy supporting multiple thread @Context //injected response proxy supporting multiple thread
private HttpServletResponse response; private HttpServletResponse response;
@ -46,29 +52,29 @@ public class RaspberrypiControllerService {
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public void pushData(final DeviceJSON dataMsg, @Context HttpServletResponse response) { public void pushData(final DeviceJSON dataMsg, @Context HttpServletResponse response) {
String temperature = dataMsg.value; //TEMP float temperature = dataMsg.value; //TEMP
log.info("Recieved Sensor Data Values: " + temperature); log.info("Recieved Sensor Data Values: " + temperature);
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("Recieved Temperature Data Value: " + temperature + " degrees C"); log.debug("Recieved Temperature Data Value: " + temperature + " degrees C");
} }
try {
DeviceController deviceController = new DeviceController();
boolean result = deviceController.pushBamData(dataMsg.owner,
RaspberrypiConstants.DEVICE_TYPE,
dataMsg.deviceId,
System.currentTimeMillis(), "DeviceData",
temperature,
DataStreamDefinitions.StreamTypeLabel.TEMPERATURE);
if (!result) { PrivilegedCarbonContext.startTenantFlow();
response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
} ctx.setTenantDomain(SUPER_TENANT, true);
DeviceAnalyticsService deviceAnalyticsService = (DeviceAnalyticsService) ctx
} catch (UnauthorizedException e) { .getOSGiService(DeviceAnalyticsService.class, null);
response.setStatus(Response.Status.UNAUTHORIZED.getStatusCode()); Object metdaData[] = {dataMsg.owner, RaspberrypiConstants.DEVICE_TYPE, dataMsg.deviceId,
System.currentTimeMillis()};
Object payloadData[] = {temperature};
try {
deviceAnalyticsService.publishEvent(TEMPERATURE_STREAM_DEFINITION, "1.0.0",
metdaData, new Object[0], payloadData);
} catch (DataPublisherConfigurationException e) {
response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
} finally {
PrivilegedCarbonContext.endTenantFlow();
} }
} }
} }

@ -14,5 +14,5 @@ public class DeviceJSON {
@XmlElement(required = true) public String reply; @XmlElement(required = true) public String reply;
@XmlElement public Long time; @XmlElement public Long time;
@XmlElement public String key; @XmlElement public String key;
@XmlElement public String value; @XmlElement public float value;
} }

@ -21,29 +21,35 @@
<dependency> <dependency>
<groupId>org.wso2.carbon.devicemgt</groupId> <groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.device.mgt.common</artifactId> <artifactId>org.wso2.carbon.device.mgt.common</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.wso2.carbon.devicemgt</groupId> <groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.device.mgt.core</artifactId> <artifactId>org.wso2.carbon.device.mgt.core</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<!--CXF --> <!--CXF -->
<dependency> <dependency>
<groupId>org.apache.cxf</groupId> <groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId> <artifactId>cxf-rt-frontend-jaxws</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.cxf</groupId> <groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId> <artifactId>cxf-rt-frontend-jaxrs</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.cxf</groupId> <groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId> <artifactId>cxf-rt-transports-http</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<!--MQTT --> <!--MQTT -->
<dependency> <dependency>
<groupId>org.eclipse.paho</groupId> <groupId>org.eclipse.paho</groupId>
<artifactId>mqtt-client</artifactId> <artifactId>mqtt-client</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<!--IOT --> <!--IOT -->
@ -55,10 +61,12 @@
<dependency> <dependency>
<groupId>org.wso2.carbon.device.mgt.iot</groupId> <groupId>org.wso2.carbon.device.mgt.iot</groupId>
<artifactId>org.wso2.carbon.device.mgt.iot.common</artifactId> <artifactId>org.wso2.carbon.device.mgt.iot.common</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.wso2.carbon.device.mgt.iot.server.sample</groupId> <groupId>org.wso2.carbon.device.mgt.iot.server.sample</groupId>
<artifactId>org.wso2.carbon.device.mgt.iot.sample.sensebot.plugin.impl</artifactId> <artifactId>org.wso2.carbon.device.mgt.iot.sample.sensebot.plugin.impl</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<!--JAX-RS --> <!--JAX-RS -->
<dependency> <dependency>
@ -72,15 +80,18 @@
<dependency> <dependency>
<groupId>javax</groupId> <groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId> <artifactId>javaee-web-api</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>javax.ws.rs</groupId> <groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId> <artifactId>jsr311-api</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>commons-httpclient.wso2</groupId> <groupId>commons-httpclient.wso2</groupId>
<artifactId>commons-httpclient</artifactId> <artifactId>commons-httpclient</artifactId>
<scope>provided</scope>
</dependency> </dependency>
</dependencies> </dependencies>

Loading…
Cancel
Save