DeviceManagementServiceImpl.java
/*
* 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.mdm.services.android.services.impl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.device.mgt.common.Device;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import org.wso2.carbon.device.mgt.common.DeviceManagementConstants;
import org.wso2.carbon.device.mgt.common.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.InvalidDeviceException;
import org.wso2.carbon.device.mgt.common.app.mgt.Application;
import org.wso2.carbon.device.mgt.common.app.mgt.ApplicationManagementException;
import org.wso2.carbon.device.mgt.common.device.details.DeviceLocation;
import org.wso2.carbon.device.mgt.common.notification.mgt.NotificationManagementException;
import org.wso2.carbon.device.mgt.common.operation.mgt.Operation;
import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManagementException;
import org.wso2.carbon.device.mgt.common.policy.mgt.monitor.PolicyComplianceException;
import org.wso2.carbon.device.mgt.core.device.details.mgt.DeviceDetailsMgtException;
import org.wso2.carbon.device.mgt.core.device.details.mgt.DeviceInformationManager;
import org.wso2.carbon.device.mgt.core.operation.mgt.CommandOperation;
import org.wso2.carbon.mdm.services.android.bean.ErrorResponse;
import org.wso2.carbon.mdm.services.android.bean.wrapper.AndroidApplication;
import org.wso2.carbon.mdm.services.android.bean.wrapper.AndroidDevice;
import org.wso2.carbon.mdm.services.android.exception.UnexpectedServerErrorException;
import org.wso2.carbon.mdm.services.android.services.DeviceManagementService;
import org.wso2.carbon.mdm.services.android.util.AndroidAPIUtils;
import org.wso2.carbon.mdm.services.android.util.AndroidConstants;
import org.wso2.carbon.mdm.services.android.util.AndroidDeviceUtils;
import org.wso2.carbon.mdm.services.android.util.Message;
import org.wso2.carbon.policy.mgt.common.PolicyManagementException;
import org.wso2.carbon.policy.mgt.core.PolicyManagerService;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.ArrayList;
import java.util.List;
@Path("/devices")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class DeviceManagementServiceImpl implements DeviceManagementService {
private static final String OPERATION_ERROR_STATUS = "ERROR";
private static final Log log = LogFactory.getLog(DeviceManagementServiceImpl.class);
@PUT
@Path("/{id}/applications")
@Override
public Response updateApplicationList(@PathParam("id")
@NotNull
@Size(min = 2, max = 45)
@Pattern(regexp = "^[A-Za-z0-9]*$")
String id, List<AndroidApplication> androidApplications) {
Application application;
List<Application> applications = new ArrayList<>();
for (AndroidApplication androidApplication : androidApplications) {
application = new Application();
application.setPlatform(androidApplication.getPlatform());
application.setCategory(androidApplication.getCategory());
application.setName(androidApplication.getName());
application.setLocationUrl(androidApplication.getLocationUrl());
application.setImageUrl(androidApplication.getImageUrl());
application.setVersion(androidApplication.getVersion());
application.setType(androidApplication.getType());
application.setAppProperties(androidApplication.getAppProperties());
application.setApplicationIdentifier(androidApplication.getApplicationIdentifier());
application.setMemoryUsage(androidApplication.getMemoryUsage());
applications.add(application);
}
Message responseMessage = new Message();
DeviceIdentifier deviceIdentifier = new DeviceIdentifier();
deviceIdentifier.setId(id);
deviceIdentifier.setType(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID);
try {
AndroidAPIUtils.getApplicationManagerService().
updateApplicationListInstalledInDevice(deviceIdentifier, applications);
responseMessage.setResponseMessage("Device information has modified successfully.");
return Response.status(Response.Status.ACCEPTED).entity(responseMessage).build();
} catch (ApplicationManagementException e) {
String msg = "Error occurred while modifying the application list.";
log.error(msg, e);
throw new UnexpectedServerErrorException(
new ErrorResponse.ErrorResponseBuilder().setCode(500l).setMessage(msg).build());
}
}
@PUT
@Path("/{id}/pending-operations")
@Override
public Response getPendingOperations(@PathParam("id") String id,
@HeaderParam("If-Modified-Since") String ifModifiedSince,
List<? extends Operation> resultOperations) {
if (id == null || id.isEmpty()) {
String msg = "Device identifier is null or empty, hence returning device not found";
log.error(msg);
return Response.status(Response.Status.BAD_REQUEST).entity(msg).build();
}
DeviceIdentifier deviceIdentifier = AndroidDeviceUtils.convertToDeviceIdentifierObject(id);
try {
if (!AndroidDeviceUtils.isValidDeviceIdentifier(deviceIdentifier)) {
String msg = "Device not found for identifier '" + id + "'";
log.error(msg);
return Response.status(Response.Status.NOT_FOUND).entity(msg).build();
}
if (log.isDebugEnabled()) {
log.debug("Invoking Android pending operations:" + id);
}
if (resultOperations != null && !resultOperations.isEmpty()) {
updateOperations(id, resultOperations);
}
} catch (OperationManagementException e) {
String msg = "Issue in retrieving operation management service instance";
log.error(msg, e);
throw new UnexpectedServerErrorException(
new ErrorResponse.ErrorResponseBuilder().setCode(500l).setMessage(msg).build());
} catch (PolicyComplianceException e) {
String msg = "Issue in updating Monitoring operation";
log.error(msg, e);
throw new UnexpectedServerErrorException(
new ErrorResponse.ErrorResponseBuilder().setCode(500l).setMessage(msg).build());
} catch (DeviceManagementException e) {
String msg = "Issue in retrieving device management service instance";
log.error(msg, e);
throw new UnexpectedServerErrorException(
new ErrorResponse.ErrorResponseBuilder().setCode(500l).setMessage(msg).build());
} catch (ApplicationManagementException e) {
String msg = "Issue in retrieving application management service instance";
log.error(msg, e);
throw new UnexpectedServerErrorException(
new ErrorResponse.ErrorResponseBuilder().setCode(500l).setMessage(msg).build());
} catch (NotificationManagementException e) {
String msg = "Issue in retrieving Notification management service instance";
log.error(msg, e);
throw new UnexpectedServerErrorException(
new ErrorResponse.ErrorResponseBuilder().setCode(500l).setMessage(msg).build());
}
List<? extends Operation> pendingOperations;
try {
pendingOperations = AndroidDeviceUtils.getPendingOperations(deviceIdentifier);
} catch (OperationManagementException e) {
String msg = "Issue in retrieving operation management service instance";
log.error(msg, e);
throw new UnexpectedServerErrorException(
new ErrorResponse.ErrorResponseBuilder().setCode(500l).setMessage(msg).build());
}
return Response.status(Response.Status.CREATED).entity(pendingOperations).build();
}
private void updateOperations(String deviceId, List<? extends Operation> operations)
throws OperationManagementException, PolicyComplianceException,
ApplicationManagementException, NotificationManagementException, DeviceManagementException {
for (org.wso2.carbon.device.mgt.common.operation.mgt.Operation operation : operations) {
AndroidDeviceUtils.updateOperation(deviceId, operation);
if (OPERATION_ERROR_STATUS.equals(operation.getStatus().toString())) {
org.wso2.carbon.device.mgt.common.notification.mgt.Notification notification = new
org.wso2.carbon.device.mgt.common.notification.mgt.Notification();
DeviceIdentifier id = new DeviceIdentifier();
id.setId(deviceId);
id.setType(AndroidConstants.DEVICE_TYPE_ANDROID);
String deviceName = AndroidAPIUtils.getDeviceManagementService().getDevice(id, false).getName();
notification.setOperationId(operation.getId());
notification.setStatus(org.wso2.carbon.device.mgt.common.notification.mgt.Notification.
Status.NEW.toString());
notification.setDescription(operation.getCode() + " operation failed to execute on device " +
deviceName + " (ID: " + deviceId + ")");
AndroidAPIUtils.getNotificationManagementService().addNotification(id, notification);
}
if (log.isDebugEnabled()) {
log.debug("Updating operation '" + operation.toString() + "'");
}
}
}
@POST
@Override
public Response enrollDevice(@Valid AndroidDevice androidDevice) {
if (androidDevice == null) {
String errorMessage = "The payload of the android device enrollment is incorrect.";
log.error(errorMessage);
throw new org.wso2.carbon.mdm.services.android.exception.BadRequestException(
new ErrorResponse.ErrorResponseBuilder().setCode(400l).setMessage(errorMessage).build());
}
try {
Device device = new Device();
device.setType(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID);
device.setEnrolmentInfo(androidDevice.getEnrolmentInfo());
device.getEnrolmentInfo().setOwner(AndroidAPIUtils.getAuthenticatedUser());
device.setDeviceInfo(androidDevice.getDeviceInfo());
device.setDeviceIdentifier(androidDevice.getDeviceIdentifier());
device.setDescription(androidDevice.getDescription());
device.setName(androidDevice.getName());
device.setFeatures(androidDevice.getFeatures());
device.setProperties(androidDevice.getProperties());
boolean status = AndroidAPIUtils.getDeviceManagementService().enrollDevice(device);
if (status) {
DeviceIdentifier deviceIdentifier = new DeviceIdentifier(androidDevice.getDeviceIdentifier(),
device.getType());
//Immediately update location information from initial payload
DeviceLocation deviceLocation = extractLocation(deviceIdentifier, androidDevice.getProperties());
if (deviceLocation != null) {
try {
DeviceInformationManager informationManager = AndroidAPIUtils
.getDeviceInformationManagerService();
informationManager.addDeviceLocation(deviceLocation);
} catch (DeviceDetailsMgtException e) {
String msg = "Error occurred while updating the device location upon android " +
"', which carries the id '" + androidDevice.getDeviceIdentifier() + "'";
log.error(msg, e);
throw new UnexpectedServerErrorException(
new ErrorResponse.ErrorResponseBuilder().setCode(500l).setMessage(msg).build());
}
}
//Adding Tasks to get device information
List<DeviceIdentifier> deviceIdentifiers = new ArrayList<>();
deviceIdentifiers.add(deviceIdentifier);
List<String> taskOperaions = new ArrayList<>();
taskOperaions.add(AndroidConstants.OperationCodes.APPLICATION_LIST);
taskOperaions.add(AndroidConstants.OperationCodes.DEVICE_INFO);
taskOperaions.add(AndroidConstants.OperationCodes.DEVICE_LOCATION);
for (String str : taskOperaions) {
CommandOperation operation = new CommandOperation();
operation.setEnabled(true);
operation.setType(Operation.Type.COMMAND);
operation.setCode(str);
AndroidAPIUtils.getDeviceManagementService().
addOperation(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID,
operation, deviceIdentifiers);
}
PolicyManagerService policyManagerService = AndroidAPIUtils.getPolicyManagerService();
policyManagerService.getEffectivePolicy(new DeviceIdentifier(androidDevice.getDeviceIdentifier(), device.getType()));
Message responseMessage = new Message();
responseMessage.setResponseCode(Response.Status.OK.toString());
responseMessage.setResponseMessage("Android device, which carries the id '" +
androidDevice.getDeviceIdentifier() + "' has successfully been enrolled");
return Response.status(Response.Status.OK).entity(responseMessage).build();
} else {
Message responseMessage = new Message();
responseMessage.setResponseCode(Response.Status.INTERNAL_SERVER_ERROR.toString());
responseMessage.setResponseMessage("Failed to enroll '" +
device.getType() + "' device, which carries the id '" +
androidDevice.getDeviceIdentifier() + "'");
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(responseMessage).build();
}
} catch (DeviceManagementException e) {
String msg = "Error occurred while enrolling the android, which carries the id '" +
androidDevice.getDeviceIdentifier() + "'";
log.error(msg, e);
throw new UnexpectedServerErrorException(
new ErrorResponse.ErrorResponseBuilder().setCode(500l).setMessage(msg).build());
} catch (PolicyManagementException e) {
String msg = "Error occurred while enforcing default enrollment policy upon android " +
"', which carries the id '" +
androidDevice.getDeviceIdentifier() + "'";
log.error(msg, e);
throw new UnexpectedServerErrorException(
new ErrorResponse.ErrorResponseBuilder().setCode(500l).setMessage(msg).build());
} catch (OperationManagementException e) {
String msg = "Error occurred while enforcing default enrollment policy upon android " +
"', which carries the id '" +
androidDevice.getDeviceIdentifier() + "'";
log.error(msg, e);
throw new UnexpectedServerErrorException(
new ErrorResponse.ErrorResponseBuilder().setCode(500l).setMessage(msg).build());
} catch (InvalidDeviceException e) {
String msg = "Error occurred while enforcing default enrollment policy upon android " +
"', which carries the id '" +
androidDevice.getDeviceIdentifier() + "'";
log.error(msg, e);
throw new UnexpectedServerErrorException(
new ErrorResponse.ErrorResponseBuilder().setCode(500l).setMessage(msg).build());
}
}
@GET
@Path("/{id}/status")
@Override
public Response isEnrolled(@PathParam("id") String id, @HeaderParam("If-Modified-Since") String ifModifiedSince) {
DeviceIdentifier deviceIdentifier = AndroidDeviceUtils.convertToDeviceIdentifierObject(id);
try {
Device device = AndroidAPIUtils.getDeviceManagementService().getDevice(deviceIdentifier);
if (device != null) {
String status = String.valueOf(device.getEnrolmentInfo().getStatus());
Message responseMessage = new Message();
responseMessage.setResponseCode(Response.Status.OK.toString());
responseMessage
.setResponseMessage("Status of android device that carries the id '" + id + "' is " + status);
return Response.status(Response.Status.OK).entity(responseMessage).build();
} else {
Message responseMessage = new Message();
responseMessage.setResponseCode(Response.Status.NOT_FOUND.toString());
responseMessage.setResponseMessage("No Android device is found upon the id '" + id + "'");
return Response.status(Response.Status.NOT_FOUND).entity(responseMessage).build();
}
} catch (DeviceManagementException e) {
String msg = "Error occurred while checking enrollment status of the device.";
log.error(msg, e);
throw new UnexpectedServerErrorException(
new ErrorResponse.ErrorResponseBuilder().setCode(500l).setMessage(msg).build());
}
}
@PUT
@Path("/{id}")
@Override
public Response modifyEnrollment(@PathParam("id") String id, @Valid AndroidDevice androidDevice) {
Device device;
DeviceIdentifier deviceIdentifier = new DeviceIdentifier();
deviceIdentifier.setId(id);
deviceIdentifier.setType(AndroidConstants.DEVICE_TYPE_ANDROID);
try {
device = AndroidAPIUtils.getDeviceManagementService().getDevice(deviceIdentifier);
} catch (DeviceManagementException e) {
String msg = "Error occurred while getting enrollment details of the Android device that carries the id '" +
id + "'";
log.error(msg, e);
throw new UnexpectedServerErrorException(
new ErrorResponse.ErrorResponseBuilder().setCode(500l).setMessage(msg).build());
}
if (androidDevice == null) {
String errorMessage = "The payload of the android device enrollment is incorrect.";
log.error(errorMessage);
throw new org.wso2.carbon.mdm.services.android.exception.BadRequestException(
new ErrorResponse.ErrorResponseBuilder().setCode(400l).setMessage(errorMessage).build());
}
if (device == null) {
String errorMessage = "The device to be modified doesn't exist.";
log.error(errorMessage);
throw new org.wso2.carbon.mdm.services.android.exception.NotFoundException(
new ErrorResponse.ErrorResponseBuilder().setCode(404l).setMessage(errorMessage).build());
}
if(androidDevice.getEnrolmentInfo() != null){
device.setEnrolmentInfo(device.getEnrolmentInfo());
}
device.getEnrolmentInfo().setOwner(AndroidAPIUtils.getAuthenticatedUser());
if(androidDevice.getDeviceInfo() != null) {
device.setDeviceInfo(androidDevice.getDeviceInfo());
}
device.setDeviceIdentifier(androidDevice.getDeviceIdentifier());
if(androidDevice.getDescription() != null) {
device.setDescription(androidDevice.getDescription());
}
if(androidDevice.getName() != null) {
device.setName(androidDevice.getName());
}
if(androidDevice.getFeatures() != null) {
device.setFeatures(androidDevice.getFeatures());
}
if(androidDevice.getProperties() != null) {
device.setProperties(androidDevice.getProperties());
}
boolean result;
try {
device.setType(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID);
result = AndroidAPIUtils.getDeviceManagementService().modifyEnrollment(device);
if (result) {
Message responseMessage = new Message();
responseMessage.setResponseCode(Response.Status.ACCEPTED.toString());
responseMessage.setResponseMessage("Enrollment of Android device that " +
"carries the id '" + id + "' has successfully updated");
return Response.status(Response.Status.ACCEPTED).entity(responseMessage).build();
} else {
Message responseMessage = new Message();
responseMessage.setResponseCode(Response.Status.NOT_MODIFIED.toString());
responseMessage.setResponseMessage("Enrollment of Android device that " +
"carries the id '" + id + "' has not been updated");
return Response.status(Response.Status.NOT_MODIFIED).entity(responseMessage).build();
}
} catch (DeviceManagementException e) {
String msg = "Error occurred while modifying enrollment of the Android device that carries the id '" +
id + "'";
log.error(msg, e);
throw new UnexpectedServerErrorException(
new ErrorResponse.ErrorResponseBuilder().setCode(500l).setMessage(msg).build());
}
}
@DELETE
@Path("/{id}")
@Override
public Response disEnrollDevice(@PathParam("id") String id) {
boolean result;
DeviceIdentifier deviceIdentifier = AndroidDeviceUtils.convertToDeviceIdentifierObject(id);
try {
result = AndroidAPIUtils.getDeviceManagementService().disenrollDevice(deviceIdentifier);
if (result) {
Message responseMessage = new Message();
responseMessage.setResponseCode(Response.Status.OK.toString());
responseMessage.setResponseMessage("Android device that carries id '" + id +
"' has successfully dis-enrolled");
return Response.status(Response.Status.OK).entity(responseMessage).build();
} else {
Message responseMessage = new Message();
responseMessage.setResponseCode(Response.Status.NOT_FOUND.toString());
responseMessage.setResponseMessage("Android device that carries id '" + id +
"' has not been dis-enrolled");
return Response.status(Response.Status.NOT_FOUND).entity(responseMessage).build();
}
} catch (DeviceManagementException e) {
String msg = "Error occurred while dis-enrolling the Android device that carries the id '" + id + "'";
log.error(msg, e);
throw new UnexpectedServerErrorException(
new ErrorResponse.ErrorResponseBuilder().setCode(500l).setMessage(msg).build());
}
}
/**
* Extracts the device location
*
* @param deviceIdentifier
* @param properties
* @return returns null when location not found
*/
private DeviceLocation extractLocation(DeviceIdentifier deviceIdentifier, List<Device.Property> properties)
throws DeviceManagementException {
DeviceLocation location = null;
String latitude = "", longitude = "";
if (properties == null) return null;
for (Device.Property property : properties) {
String propertyName = property.getName();
if (propertyName == null) continue;
if (propertyName.equals("LATITUDE")) {
latitude = property.getValue();
if (!longitude.isEmpty()) break;
} else if (propertyName.equals("LONGITUDE")) {
longitude = property.getValue();
if (!latitude.isEmpty()) break;
}
}
if (!latitude.isEmpty() && !longitude.isEmpty()) {
location = new DeviceLocation();
location.setLatitude(Double.valueOf(latitude));
location.setLongitude(Double.valueOf(longitude));
location.setDeviceIdentifier(deviceIdentifier);
Device savedDevice = AndroidAPIUtils.getDeviceManagementService().getDevice(deviceIdentifier, false);
location.setDeviceId(savedDevice.getId());
}
return location;
}
}