diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.api/src/main/java/org/wso2/carbon/device/application/mgt/api/services/SubscriptionManagementAPI.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.api/src/main/java/org/wso2/carbon/device/application/mgt/api/services/SubscriptionManagementAPI.java index d68cfb92353..570acb449cc 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.api/src/main/java/org/wso2/carbon/device/application/mgt/api/services/SubscriptionManagementAPI.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.api/src/main/java/org/wso2/carbon/device/application/mgt/api/services/SubscriptionManagementAPI.java @@ -24,10 +24,7 @@ import org.wso2.carbon.device.application.mgt.common.Application; import org.wso2.carbon.device.application.mgt.common.InstallationDetails; import javax.validation.Valid; -import javax.ws.rs.Consumes; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; +import javax.ws.rs.*; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; @@ -111,7 +108,88 @@ public interface SubscriptionManagementAPI { Response installApplication( @ApiParam( name = "installationDetails", - value = "The application ID and list the devices/users/roles", + value = "The application ID and list of devices/users/roles", required = true) @Valid InstallationDetails installationDetails); + + @POST + @Path("/uninstall-application") + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + @ApiOperation( + consumes = MediaType.APPLICATION_JSON, + produces = MediaType.APPLICATION_JSON, + httpMethod = "POST", + value = "Uninstall an application", + notes = "This will uninstall an application to a given list of devices/users/roles", + tags = "Subscription Management", + extensions = { + @Extension(properties = { + @ExtensionProperty(name = SCOPE, value = "perm:subscription:uninstall") + }) + } + ) + @ApiResponses( + value = { + @ApiResponse( + code = 200, + message = "OK. \n Successfully uninstalled the application.", + response = Application.class), + @ApiResponse( + code = 304, + message = "Not Modified. \n " + + "Empty body because the application is already uninstalled."), + @ApiResponse( + code = 500, + message = "Internal Server Error. \n Error occurred while installing the application.", + response = ErrorResponse.class) + }) + Response uninstallApplication( + @ApiParam( + name = "installationDetails", + value = "The application ID and list of devices/users/roles", + required = true) + @Valid InstallationDetails installationDetails); + + @GET + @Path("/application/{applicationUUID}/device/{deviceId}") + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + @ApiOperation( + consumes = MediaType.APPLICATION_JSON, + produces = MediaType.APPLICATION_JSON, + httpMethod = "GET", + value = "Get an application", + notes = "This will return an application to a given valid token", + tags = "Subscription Management", + extensions = { + @Extension(properties = { + @ExtensionProperty(name = SCOPE, value = "perm:subscription:getApplication") + }) + } + ) + @ApiResponses( + value = { + @ApiResponse( + code = 200, + message = "OK. \n Successfully installed the application.", + response = Application.class), + @ApiResponse( + code = 304, + message = "Not Modified. \n " + + "Empty body because the application is already installed."), + @ApiResponse( + code = 500, + message = "Internal Server Error. \n Error occurred while fetching the application.", + response = ErrorResponse.class) + }) + Response getApplication( + @ApiParam( + name = "applicationUUID", + value = "Application ID") + @QueryParam("applicationUUID") String applicationUUID, + @ApiParam( + name = "deviceId", + value = "The device ID") + @QueryParam("deviceId") String deviceId); } diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.api/src/main/java/org/wso2/carbon/device/application/mgt/api/services/impl/SubscriptionManagementAPIImpl.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.api/src/main/java/org/wso2/carbon/device/application/mgt/api/services/impl/SubscriptionManagementAPIImpl.java index 5c521487de2..881da552bc4 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.api/src/main/java/org/wso2/carbon/device/application/mgt/api/services/impl/SubscriptionManagementAPIImpl.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.api/src/main/java/org/wso2/carbon/device/application/mgt/api/services/impl/SubscriptionManagementAPIImpl.java @@ -64,9 +64,22 @@ public class SubscriptionManagementAPIImpl implements SubscriptionManagementAPI{ } return Response.status(Response.Status.OK).entity(response).build(); } catch (ApplicationManagementException e) { - String msg = "Error occurred while creating the application"; + String msg = "Error occurred while installing the application"; log.error(msg, e); return Response.status(Response.Status.BAD_REQUEST).build(); } } + + @Override + public Response uninstallApplication(@ApiParam(name = "installationDetails", value = "The application ID and list" + + " of devices/users/roles", required = true) @Valid InstallationDetails installationDetails) { + return null; + } + + @Override + public Response getApplication(@ApiParam(name = "applicationUUID", value = "Application ID") String + applicationUUID, @ApiParam(name = "deviceId", value = "The device ID") + String deviceId) { + return null; + } } diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.api/src/main/webapp/META-INF/permissions.xml b/components/application-mgt/org.wso2.carbon.device.application.mgt.api/src/main/webapp/META-INF/permissions.xml index 27df5059a3d..df2d1cf5b58 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.api/src/main/webapp/META-INF/permissions.xml +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.api/src/main/webapp/META-INF/permissions.xml @@ -95,4 +95,16 @@ /application-mgt/subscription POST + + Uninstall Application + /device-mgt/subscription/uninstall + /application-mgt/subscription + POST + + + Get Application + /device-mgt/subscription/getApplication + /application-mgt/subscription + GET + diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/DeviceIdentifier.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/DeviceIdentifier.java index 3da016bf04a..8f7e656319e 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/DeviceIdentifier.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/DeviceIdentifier.java @@ -29,7 +29,7 @@ public class DeviceIdentifier { name = "id", value = "Identity of the device.", required = true, - example = "123456") + example = "d24f870f390352a4") private String id; @ApiModelProperty( diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/dao/SubscriptionDAO.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/dao/SubscriptionDAO.java index 010e50203be..59f3b532f10 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/dao/SubscriptionDAO.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/dao/SubscriptionDAO.java @@ -22,5 +22,8 @@ package org.wso2.carbon.device.application.mgt.core.dao; * This interface provides the list of operations that are supported with subscription database. * */ +import org.wso2.carbon.device.application.mgt.common.exception.ApplicationManagementException; + public interface SubscriptionDAO { + int addDeviceApplicationMapping(String deviceIdentifier, String applicationUUID, boolean installed) throws ApplicationManagementException; } diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/dao/common/DAOFactory.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/dao/common/DAOFactory.java index 51a4b393473..4016192d141 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/dao/common/DAOFactory.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/dao/common/DAOFactory.java @@ -26,6 +26,7 @@ import org.wso2.carbon.device.application.mgt.core.dao.ApplicationDAO; import org.wso2.carbon.device.application.mgt.core.dao.ApplicationReleaseDAO; import org.wso2.carbon.device.application.mgt.core.dao.LifecycleStateDAO; import org.wso2.carbon.device.application.mgt.core.dao.PlatformDAO; +import org.wso2.carbon.device.application.mgt.core.dao.SubscriptionDAO; import org.wso2.carbon.device.application.mgt.core.dao.VisibilityDAO; import org.wso2.carbon.device.application.mgt.core.dao.impl.application.GenericApplicationDAOImpl; import org.wso2.carbon.device.application.mgt.core.dao.impl.application.release.GenericApplicationReleaseDAOImpl; @@ -34,6 +35,7 @@ import org.wso2.carbon.device.application.mgt.core.dao.impl.lifecyclestate.Gener import org.wso2.carbon.device.application.mgt.core.dao.impl.platform.GenericPlatformDAOImpl; import org.wso2.carbon.device.application.mgt.core.dao.impl.platform.OracleMsSQLPlatformDAOImpl; import org.wso2.carbon.device.application.mgt.core.dao.impl.visibility.GenericVisibilityDAOImpl; +import org.wso2.carbon.device.application.mgt.core.dao.impl.subscription.GenericSubscriptionDAOImpl; import org.wso2.carbon.device.application.mgt.core.exception.ApplicationManagementDAOException; import org.wso2.carbon.device.application.mgt.core.util.ApplicationMgtDatabaseCreator; import org.wso2.carbon.device.application.mgt.core.util.ConnectionManagerUtil; @@ -144,6 +146,24 @@ public class DAOFactory { throw new IllegalStateException("Database engine has not initialized properly."); } + /** + * To get the instance of SubscriptionDAOImplementation of the particular database engine. + * @return GenericSubscriptionDAOImpl + */ + public static SubscriptionDAO getSubscriptionDAO() { + if (databaseEngine != null) { + switch (databaseEngine) { + case Constants.DataBaseTypes.DB_TYPE_H2: + case Constants.DataBaseTypes.DB_TYPE_MYSQL: + case Constants.DataBaseTypes.DB_TYPE_POSTGRESQL: + return new GenericSubscriptionDAOImpl(); + default: + throw new UnsupportedDatabaseEngineException("Unsupported database engine : " + databaseEngine); + } + } + throw new IllegalStateException("Database engine has not initialized properly."); + } + /** * This method initializes the databases by creating the database. * diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/dao/impl/subscription/GenericSubscriptionDAOImpl.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/dao/impl/subscription/GenericSubscriptionDAOImpl.java new file mode 100644 index 00000000000..b00b0499af1 --- /dev/null +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/dao/impl/subscription/GenericSubscriptionDAOImpl.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2017, 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.device.application.mgt.core.dao.impl.subscription; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.application.mgt.common.exception.ApplicationManagementException; +import org.wso2.carbon.device.application.mgt.core.dao.SubscriptionDAO; +import org.wso2.carbon.device.application.mgt.core.dao.common.Util; +import org.wso2.carbon.device.application.mgt.core.dao.impl.AbstractDAOImpl; + +import java.sql.*; + +public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements SubscriptionDAO { + private static Log log = LogFactory.getLog(GenericSubscriptionDAOImpl.class); + + @Override + public int addDeviceApplicationMapping(String deviceIdentifier, String applicationUUID, boolean installed) throws ApplicationManagementException { + Connection conn; + PreparedStatement stmt = null; + ResultSet rs = null; + int mappingId = -1; + try { + conn = this.getDBConnection(); + String sql = "INSERT INTO APPM_DEVICE_APPLICATION_MAPPING (DEVICE_IDENTIFIER, APPLICATION_UUID, " + + "INSTALLED) VALUES (?, ?, ?)"; + stmt = conn.prepareStatement(sql, new String[] {"id"}); + stmt.setString(1, deviceIdentifier); + stmt.setString(2, applicationUUID); + stmt.setBoolean(3, installed); + stmt.executeUpdate(); + + rs = stmt.getGeneratedKeys(); + if (rs.next()) { + mappingId = rs.getInt(1); + } + return mappingId; + } catch (SQLException e) { + throw new ApplicationManagementException("Error occurred while adding device application mapping to DB", e); + } finally { + Util.cleanupResources(stmt, rs); + } + } +} diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/impl/SubscriptionManagerImpl.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/impl/SubscriptionManagerImpl.java index 0c89f631149..07eedb19806 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/impl/SubscriptionManagerImpl.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/impl/SubscriptionManagerImpl.java @@ -22,7 +22,12 @@ import org.apache.commons.logging.LogFactory; import org.wso2.carbon.device.application.mgt.common.DeviceIdentifier; import org.wso2.carbon.device.application.mgt.common.exception.ApplicationManagementException; import org.wso2.carbon.device.application.mgt.common.services.SubscriptionManager; +import org.wso2.carbon.device.application.mgt.core.dao.common.DAOFactory; +import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOException; +import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOFactory; +import java.sql.SQLException; +import java.util.ArrayList; import java.util.List; /** @@ -37,13 +42,29 @@ public class SubscriptionManagerImpl implements SubscriptionManager { List deviceList) throws ApplicationManagementException { log.info("Install application: " + applicationUUID + " to: " + deviceList.size() + " devices."); + List failedDeviceList = new ArrayList<>(deviceList); for (DeviceIdentifier device : deviceList) { - String deviceId = device.getId(); - //Todo: implementation, validations - //Todo: generating one time download link for the application and put install operation to device. - //Todo: Store the mappings in DB. + org.wso2.carbon.device.mgt.common.DeviceIdentifier deviceIdentifier = new org.wso2.carbon.device.mgt + .common.DeviceIdentifier(device.getId(), device.getType()); + try { + DeviceManagementDAOFactory.openConnection(); + if (DeviceManagementDAOFactory.getDeviceDAO().getDevice(deviceIdentifier).isEmpty()) { + log.error("Device with ID: " + device.getId() + " not found to install the application."); + } else { + if (log.isDebugEnabled()) { + log.debug("Installing application to : " + device.getId()); + } + //Todo: generating one time download link for the application and put install operation to device. + DAOFactory.getSubscriptionDAO().addDeviceApplicationMapping(device.getId(), applicationUUID, false); + failedDeviceList.remove(device); + } + } catch (DeviceManagementDAOException | SQLException e) { + throw new ApplicationManagementException("Error locating device.", e); + } finally { + DeviceManagementDAOFactory.closeConnection(); + } } - return deviceList; + return failedDeviceList; } @Override @@ -52,6 +73,7 @@ public class SubscriptionManagerImpl implements SubscriptionManager { log.info("Install application: " + applicationUUID + " to: " + userList.size() + " users."); for (String user : userList) { //Todo: implementation + //Todo: get the device list and call installApplicationForDevices } return userList; } @@ -62,6 +84,7 @@ public class SubscriptionManagerImpl implements SubscriptionManager { log.info("Install application: " + applicationUUID + " to: " + roleList.size() + " users."); for (String role : roleList) { //Todo: implementation + //Todo: get the device list and call installApplicationForDevices } return roleList; } diff --git a/features/application-mgt/org.wso2.carbon.device.application.mgt.server.feature/src/main/resources/dbscripts/cdm/application-mgt/mysql.sql b/features/application-mgt/org.wso2.carbon.device.application.mgt.server.feature/src/main/resources/dbscripts/cdm/application-mgt/mysql.sql index c8ecd3c81a5..1d840f1e2a7 100644 --- a/features/application-mgt/org.wso2.carbon.device.application.mgt.server.feature/src/main/resources/dbscripts/cdm/application-mgt/mysql.sql +++ b/features/application-mgt/org.wso2.carbon.device.application.mgt.server.feature/src/main/resources/dbscripts/cdm/application-mgt/mysql.sql @@ -390,6 +390,19 @@ CREATE TABLE IF NOT EXISTS `APPM_SUBSCRIPTION_PROPERTIES` ( ON UPDATE NO ACTION) ENGINE = InnoDB; +-- ----------------------------------------------------- +-- Table `APPM_DEVICE_APPLICATION_MAPPING` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `APPM_DEVICE_APPLICATION_MAPPING` ( + `ID` INT AUTO_INCREMENT NOT NULL, + `DEVICE_IDENTIFIER` VARCHAR(255) NOT NULL, + `APPLICATION_UUID` VARCHAR(100) NOT NULL, + `INSTALLED` BOOLEAN NOT NULL, + `SENT_AT` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (ID), + CONSTRAINT fk_appm_application FOREIGN KEY (`APPLICATION_UUID`) REFERENCES + APPM_APPLICATION (`UUID`) ON DELETE NO ACTION ON UPDATE NO ACTION +) ENGINE = InnoDB; SET SQL_MODE=@OLD_SQL_MODE; SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;