Java tutorial
/* * 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 ${groupId}.${rootArtifactId}.api; import ${groupId}.${rootArtifactId}.api.dto.DeviceJSON; import ${groupId}.${rootArtifactId}.api.dto.SensorRecord; import ${groupId}.${rootArtifactId}.api.util.APIUtil; import ${groupId}.${rootArtifactId}.api.util.ZipUtil; import ${groupId}.${rootArtifactId}.plugin.constants.DeviceTypeConstants; import ${groupId}.${rootArtifactId}.api.DeviceTypeService; import org.apache.commons.io.FileUtils; 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.apimgt.annotations.api.API; import org.wso2.carbon.apimgt.application.extension.APIManagementProviderService; import org.wso2.carbon.apimgt.application.extension.dto.ApiApplicationKey; import org.wso2.carbon.apimgt.application.extension.exception.APIManagerException; import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.device.mgt.common.Device; import org.wso2.carbon.device.mgt.common.DeviceIdentifier; import org.wso2.carbon.device.mgt.common.DeviceManagementException; import org.wso2.carbon.device.mgt.common.EnrolmentInfo; import org.wso2.carbon.device.mgt.common.authorization.DeviceAccessAuthorizationException; import org.wso2.carbon.device.mgt.extensions.feature.mgt.annotations.DeviceType; import org.wso2.carbon.device.mgt.extensions.feature.mgt.annotations.Feature; import org.wso2.carbon.device.mgt.iot.util.ZipArchive; import org.wso2.carbon.identity.jwt.client.extension.JWTClient; 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; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.Path; import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Produces; import javax.ws.rs.PathParam; import javax.ws.rs.QueryParam; import javax.ws.rs.PUT; import javax.ws.rs.DELETE; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.UUID; import java.util.Map; import java.util.List; import java.util.HashMap; import java.util.ArrayList; import java.util.Date; import java.util.concurrent.ConcurrentHashMap; /** * This is the controller API which is used to control agent side functionality */ @SuppressWarnings("NonJaxWsWebServices") @API(name = "${deviceType}", version = "1.0.0", context = "/${deviceType}", tags = "${deviceType}") @DeviceType(value = "${deviceType}") public class DeviceTypeServiceImpl implements DeviceTypeService { private static final String KEY_TYPE = "PRODUCTION"; private static Log log = LogFactory.getLog(DeviceTypeService.class); private static ApiApplicationKey apiApplicationKey; private ConcurrentHashMap<String, DeviceJSON> deviceToIpMap = new ConcurrentHashMap<>(); private static String shortUUID() { UUID uuid = UUID.randomUUID(); long l = ByteBuffer.wrap(uuid.toString().getBytes(StandardCharsets.UTF_8)).getLong(); return Long.toString(l, Character.MAX_RADIX); } /** * @param agentInfo device owner,id and sensor value * @return */ @Path("device/register") @POST @Consumes(MediaType.APPLICATION_JSON) public Response registerDevice(final DeviceJSON agentInfo) { String deviceId = agentInfo.deviceId; if ((agentInfo.deviceId != null) && (agentInfo.owner != null)) { deviceToIpMap.put(deviceId, agentInfo); return Response.status(Response.Status.OK).build(); } return Response.status(Response.Status.NOT_ACCEPTABLE).build(); } /** * @param deviceId unique identifier for given device type * @param state change status of sensor: on/off * @param response */ @Path("device/{deviceId}/change-status") @POST @Feature(code = "change-status", name = "Change status of sensor: on/off", description = "Change status of sensor: on/off") public Response changeStatus(@PathParam("deviceId") String deviceId, @QueryParam("state") String state, @Context HttpServletResponse response) { try { if (!APIUtil.getDeviceAccessAuthorizationService() .isUserAuthorized(new DeviceIdentifier(deviceId, DeviceTypeConstants.DEVICE_TYPE))) { return Response.status(Response.Status.UNAUTHORIZED.getStatusCode()).build(); } String sensorState = state.toUpperCase(); if (!sensorState.equals(DeviceTypeConstants.STATE_ON) && !sensorState.equals(DeviceTypeConstants.STATE_OFF)) { log.error("The requested state change should be either - 'ON' or 'OFF'"); return Response.status(Response.Status.BAD_REQUEST.getStatusCode()).build(); } Map<String, String> dynamicProperties = new HashMap<>(); String publishTopic = APIUtil.getAuthenticatedUserTenantDomain() + "/" + DeviceTypeConstants.DEVICE_TYPE + "/" + deviceId + "/command"; dynamicProperties.put(DeviceTypeConstants.ADAPTER_TOPIC_PROPERTY, publishTopic); APIUtil.getOutputEventAdapterService().publish(DeviceTypeConstants.MQTT_ADAPTER_NAME, dynamicProperties, state); return Response.ok().build(); } catch (DeviceAccessAuthorizationException e) { log.error(e.getErrorMessage(), e); return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); } } /** * Retrieve Sensor data for the */ @Path("device/stats/{deviceId}") @GET @Consumes("application/json") @Produces("application/json") public Response getSensorStats(@PathParam("deviceId") String deviceId, @QueryParam("from") long from, @QueryParam("to") long to) { String fromDate = String.valueOf(from); String toDate = String.valueOf(to); String query = "deviceId:" + deviceId + " AND deviceType:" + DeviceTypeConstants.DEVICE_TYPE + " AND time : [" + fromDate + " TO " + toDate + "]"; String sensorTableName = DeviceTypeConstants.SENSOR_EVENT_TABLE; try { if (!APIUtil.getDeviceAccessAuthorizationService() .isUserAuthorized(new DeviceIdentifier(deviceId, DeviceTypeConstants.DEVICE_TYPE))) { return Response.status(Response.Status.UNAUTHORIZED.getStatusCode()).build(); } if (sensorTableName != null) { List<SortByField> sortByFields = new ArrayList<>(); SortByField sortByField = new SortByField("time", SORT.ASC, false); sortByFields.add(sortByField); List<SensorRecord> 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); return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).entity(errorMsg).build(); } catch (DeviceAccessAuthorizationException e) { log.error(e.getErrorMessage(), e); return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); } return Response.status(Response.Status.BAD_REQUEST).build(); } @Path("/device/{device_id}") @DELETE public Response removeDevice(@PathParam("device_id") String deviceId) { try { DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); deviceIdentifier.setId(deviceId); deviceIdentifier.setType(DeviceTypeConstants.DEVICE_TYPE); if (!APIUtil.getDeviceAccessAuthorizationService().isUserAuthorized(deviceIdentifier)) { return Response.status(Response.Status.UNAUTHORIZED.getStatusCode()).build(); } boolean removed = APIUtil.getDeviceManagementService().disenrollDevice(deviceIdentifier); if (removed) { return Response.ok().build(); } else { return Response.status(Response.Status.NOT_ACCEPTABLE.getStatusCode()).build(); } } catch (DeviceManagementException e) { log.error(e.getErrorMessage(), e); return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build(); } catch (DeviceAccessAuthorizationException e) { log.error(e.getErrorMessage(), e); return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build(); } } @Path("/device/{device_id}") @PUT public Response updateDevice(@PathParam("device_id") String deviceId, @QueryParam("name") String name) { try { DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); deviceIdentifier.setId(deviceId); deviceIdentifier.setType(DeviceTypeConstants.DEVICE_TYPE); if (!APIUtil.getDeviceAccessAuthorizationService().isUserAuthorized(deviceIdentifier)) { return Response.status(Response.Status.UNAUTHORIZED.getStatusCode()).build(); } Device device = APIUtil.getDeviceManagementService().getDevice(deviceIdentifier); device.setDeviceIdentifier(deviceId); device.getEnrolmentInfo().setDateOfLastUpdate(new Date().getTime()); device.setName(name); device.setType(DeviceTypeConstants.DEVICE_TYPE); boolean updated = APIUtil.getDeviceManagementService().modifyEnrollment(device); if (updated) { return Response.ok().build(); } else { return Response.status(Response.Status.NOT_ACCEPTABLE.getStatusCode()).build(); } } catch (DeviceManagementException e) { log.error(e.getErrorMessage(), e); return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build(); } catch (DeviceAccessAuthorizationException e) { log.error(e.getErrorMessage(), e); return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build(); } } @Path("/device/{device_id}") @GET @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public Response getDevice(@PathParam("device_id") String deviceId) { try { DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); deviceIdentifier.setId(deviceId); deviceIdentifier.setType(DeviceTypeConstants.DEVICE_TYPE); if (!APIUtil.getDeviceAccessAuthorizationService().isUserAuthorized(deviceIdentifier)) { return Response.status(Response.Status.UNAUTHORIZED.getStatusCode()).build(); } Device device = APIUtil.getDeviceManagementService().getDevice(deviceIdentifier); return Response.ok().entity(device).build(); } catch (DeviceManagementException e) { log.error(e.getErrorMessage(), e); return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build(); } catch (DeviceAccessAuthorizationException e) { log.error(e.getErrorMessage(), e); return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build(); } } @Path("/devices") @GET @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public Response getAllDevices() { try { List<Device> userDevices = APIUtil.getDeviceManagementService() .getDevicesOfUser(APIUtil.getAuthenticatedUser()); ArrayList<Device> userDevicesforFirealarm = new ArrayList<>(); for (Device device : userDevices) { if (device.getType().equals(DeviceTypeConstants.DEVICE_TYPE) && device.getEnrolmentInfo().getStatus().equals(EnrolmentInfo.Status.ACTIVE)) { userDevicesforFirealarm.add(device); } } Device[] devices = userDevicesforFirealarm.toArray(new Device[] {}); return Response.ok().entity(devices).build(); } catch (DeviceManagementException e) { log.error(e.getErrorMessage(), e); return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build(); } } @Path("/device/download") @GET @Produces("application/zip") public Response downloadSketch(@QueryParam("deviceName") String deviceName, @QueryParam("sketchType") String sketchType) { try { ZipArchive zipFile = createDownloadFile(APIUtil.getAuthenticatedUser(), deviceName, sketchType); Response.ResponseBuilder response = Response.ok(FileUtils.readFileToByteArray(zipFile.getZipFile())); response.status(Response.Status.OK); response.type("application/zip"); response.header("Content-Disposition", "attachment; filename=\"" + zipFile.getFileName() + "\""); Response resp = response.build(); zipFile.getZipFile().delete(); return resp; } catch (IllegalArgumentException ex) { return Response.status(400).entity(ex.getMessage()).build();//bad request } catch (DeviceManagementException ex) { log.error(ex.getMessage(), ex); return Response.status(500).entity(ex.getMessage()).build(); } catch (JWTClientException ex) { log.error(ex.getMessage(), ex); return Response.status(500).entity(ex.getMessage()).build(); } catch (APIManagerException ex) { log.error(ex.getMessage(), ex); return Response.status(500).entity(ex.getMessage()).build(); } catch (IOException ex) { log.error(ex.getMessage(), ex); return Response.status(500).entity(ex.getMessage()).build(); } catch (UserStoreException ex) { log.error(ex.getMessage(), ex); return Response.status(500).entity(ex.getMessage()).build(); } } private boolean register(String deviceId, String name) { try { DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); deviceIdentifier.setId(deviceId); deviceIdentifier.setType(DeviceTypeConstants.DEVICE_TYPE); if (APIUtil.getDeviceManagementService().isEnrolled(deviceIdentifier)) { return false; } Device device = new Device(); device.setDeviceIdentifier(deviceId); EnrolmentInfo enrolmentInfo = new EnrolmentInfo(); enrolmentInfo.setDateOfEnrolment(new Date().getTime()); enrolmentInfo.setDateOfLastUpdate(new Date().getTime()); enrolmentInfo.setStatus(EnrolmentInfo.Status.ACTIVE); enrolmentInfo.setOwnership(EnrolmentInfo.OwnerShip.BYOD); device.setName(name); device.setType(DeviceTypeConstants.DEVICE_TYPE); enrolmentInfo.setOwner(APIUtil.getAuthenticatedUser()); device.setEnrolmentInfo(enrolmentInfo); boolean added = APIUtil.getDeviceManagementService().enrollDevice(device); if (added) { APIUtil.registerApiAccessRoles(APIUtil.getAuthenticatedUser()); } return added; } catch (DeviceManagementException e) { log.error(e.getMessage(), e); return false; } } private ZipArchive createDownloadFile(String owner, String deviceName, String sketchType) throws DeviceManagementException, JWTClientException, APIManagerException, UserStoreException { //create new device id String deviceId = shortUUID(); if (apiApplicationKey == null) { String applicationUsername = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUserRealm() .getRealmConfiguration().getAdminUserName(); applicationUsername = applicationUsername + "@" + APIUtil.getAuthenticatedUserTenantDomain(); APIManagementProviderService apiManagementProviderService = APIUtil.getAPIManagementProviderService(); String[] tags = { DeviceTypeConstants.DEVICE_TYPE }; apiApplicationKey = apiManagementProviderService.generateAndRetrieveApplicationKeys( DeviceTypeConstants.DEVICE_TYPE, tags, KEY_TYPE, applicationUsername, true); } JWTClient jwtClient = APIUtil.getJWTClientManagerService().getJWTClient(); String scopes = "device_type_" + DeviceTypeConstants.DEVICE_TYPE + " device_" + deviceId; AccessTokenInfo accessTokenInfo = jwtClient.getAccessToken(apiApplicationKey.getConsumerKey(), apiApplicationKey.getConsumerSecret(), owner + "@" + APIUtil.getAuthenticatedUserTenantDomain(), scopes); //create token String accessToken = accessTokenInfo.getAccessToken(); String refreshToken = accessTokenInfo.getRefreshToken(); boolean status = register(deviceId, deviceName); if (!status) { String msg = "Error occurred while registering the device with " + "id: " + deviceId + " owner:" + owner; throw new DeviceManagementException(msg); } ZipUtil ziputil = new ZipUtil(); ZipArchive zipFile = ziputil.createZipFile(owner, APIUtil.getTenantDomainOftheUser(), sketchType, deviceId, deviceName, accessToken, refreshToken); return zipFile; } }