Improve app subscription functionality

Further integrate app management component with device mgt
4.x.x
Dharmakeerthi Lasantha 6 years ago
parent 0c939c54b4
commit 3e0360a6fa

@ -17,7 +17,6 @@
package org.wso2.carbon.device.application.mgt.common; package org.wso2.carbon.device.application.mgt.common;
import org.wso2.carbon.device.application.mgt.common.dto.DeviceSubscriptionDTO;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier; import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import java.util.HashMap; import java.util.HashMap;
@ -26,8 +25,6 @@ import java.util.Map;
public class SubscribingDeviceIdHolder { public class SubscribingDeviceIdHolder {
private Map<DeviceIdentifier, Integer> subscribedDevices = new HashMap<>(); private Map<DeviceIdentifier, Integer> subscribedDevices = new HashMap<>();
private Map<DeviceIdentifier, Integer> subscribableDevices = new HashMap<>(); private Map<DeviceIdentifier, Integer> subscribableDevices = new HashMap<>();
// private Map<Integer, DeviceSubscriptionDTO> deviceSubscriptions = new HashMap<>();
public Map<DeviceIdentifier, Integer> getSubscribedDevices() { public Map<DeviceIdentifier, Integer> getSubscribedDevices() {
return subscribedDevices; return subscribedDevices;
} }
@ -43,12 +40,4 @@ public class SubscribingDeviceIdHolder {
public void setSubscribableDevices(Map<DeviceIdentifier, Integer> subscribableDevices) { public void setSubscribableDevices(Map<DeviceIdentifier, Integer> subscribableDevices) {
this.subscribableDevices = subscribableDevices; this.subscribableDevices = subscribableDevices;
} }
// public Map<Integer, DeviceSubscriptionDTO> getDeviceSubscriptions() {
// return deviceSubscriptions;
// }
//
// public void setDeviceSubscriptions(Map<Integer, DeviceSubscriptionDTO> deviceSubscriptions) {
// this.deviceSubscriptions = deviceSubscriptions;
// }
} }

@ -27,7 +27,7 @@ public class DeviceSubscriptionDTO {
private boolean isUnsubscribed; private boolean isUnsubscribed;
private String unsubscribedBy; private String unsubscribedBy;
private Timestamp unsubscribedTimestamp; private Timestamp unsubscribedTimestamp;
private String subscribedFrom; private String actionTriggeredFrom;
private String status; private String status;
private int deviceId; private int deviceId;
@ -59,9 +59,9 @@ public class DeviceSubscriptionDTO {
this.unsubscribedTimestamp = unsubscribedTimestamp; this.unsubscribedTimestamp = unsubscribedTimestamp;
} }
public String getSubscribedFrom() { return subscribedFrom; } public String getActionTriggeredFrom() { return actionTriggeredFrom; }
public void setSubscribedFrom(String subscribedFrom) { this.subscribedFrom = subscribedFrom; } public void setActionTriggeredFrom(String actionTriggeredFrom) { this.actionTriggeredFrom = actionTriggeredFrom; }
public String getStatus() { return status; } public String getStatus() { return status; }

@ -23,9 +23,7 @@ import org.wso2.carbon.device.application.mgt.common.dto.ApplicationReleaseDTO;
import org.wso2.carbon.device.application.mgt.common.dto.DeviceSubscriptionDTO; import org.wso2.carbon.device.application.mgt.common.dto.DeviceSubscriptionDTO;
import org.wso2.carbon.device.application.mgt.core.exception.ApplicationManagementDAOException; import org.wso2.carbon.device.application.mgt.core.exception.ApplicationManagementDAOException;
import org.wso2.carbon.device.mgt.common.Device; import org.wso2.carbon.device.mgt.common.Device;
import org.wso2.carbon.device.mgt.common.group.mgt.DeviceGroup;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -35,24 +33,12 @@ import java.util.Map;
*/ */
public interface SubscriptionDAO { public interface SubscriptionDAO {
/** List<Integer> addDeviceSubscription(String subscribedBy, List<Integer> deviceIds, String subscribedFrom,
* Adds a mapping between devices and the application which the application is installed on.
*
* @param tenantId id of the tenant
* @param subscribedBy username of the user who subscribe the application
* @param deviceList List of {@link Device} which the application is installed on
* @param appId id of the {@link ApplicationDTO} which installs
* @param releaseId id of the {@link ApplicationReleaseDTO}
* @throws ApplicationManagementDAOException If unable to add a mapping between device and application
*/
void subscribeDeviceToApplicationTmp(int tenantId, String subscribedBy, List<Device> deviceList, int appId,
int releaseId, String installStatus) throws ApplicationManagementDAOException;
List<Integer> subscribeDeviceToApplication(String subscribedBy, List<Integer> deviceIds, String subscribedFrom,
String installStatus, int releaseId, int tenantId ) throws ApplicationManagementDAOException; String installStatus, int releaseId, int tenantId ) throws ApplicationManagementDAOException;
List<Integer> updateDeviceSubscription(String subscribedBy, List<Integer> deviceIds, List<Integer> updateDeviceSubscription(String updateBy, List<Integer> deviceIds, boolean isUnsubscribed,
String subscribedFrom, String installStatus, int releaseId, int tenantId) throws ApplicationManagementDAOException; String actionTriggeredFrom, String installStatus, int releaseId, int tenantId)
throws ApplicationManagementDAOException;
void addOperationMapping (int operationId, List<Integer> deviceSubscriptionId, int tenantId) throws ApplicationManagementDAOException; void addOperationMapping (int operationId, List<Integer> deviceSubscriptionId, int tenantId) throws ApplicationManagementDAOException;
@ -62,40 +48,18 @@ public interface SubscriptionDAO {
* *
* @param tenantId id of the tenant * @param tenantId id of the tenant
* @param subscribedBy username of the user who subscribe the application * @param subscribedBy username of the user who subscribe the application
* @param userList list of user names of the users whose devices are subscribed to the application * @param users list of user names of the users whose devices are subscribed to the application
* @param releaseId id of the {@link ApplicationReleaseDTO} * @param releaseId id of the {@link ApplicationReleaseDTO}
* @throws ApplicationManagementDAOException If unable to add a mapping between device and application * @throws ApplicationManagementDAOException If unable to add a mapping between device and application
*/ */
void subscribeUserToApplication(int tenantId, String subscribedBy, List<String> userList, int releaseId) void addUserSubscriptions(int tenantId, String subscribedBy, List<String> users, int releaseId)
throws ApplicationManagementDAOException; throws ApplicationManagementDAOException;
/** void addRoleSubscriptions(int tenantId, String subscribedBy, List<String> roles, int releaseId)
* Adds a mapping between user and the application which the application is installed on. This mapping will be
* added when an enterprise installation triggered to the role.
*
* @param tenantId id of the tenant
* @param subscribedBy username of the user who subscribe the application
* @param roleList list of roles which belongs devices are subscribed to the application
* @param appId id of the {@link ApplicationDTO} which installs
* @param releaseId id of the {@link ApplicationReleaseDTO}
* @throws ApplicationManagementDAOException If unable to add a mapping between device and application
*/
void subscribeRoleToApplication(int tenantId, String subscribedBy, List<String> roleList, int appId, int releaseId)
throws ApplicationManagementDAOException; throws ApplicationManagementDAOException;
/** void addGroupSubscriptions(int tenantId, String subscribedBy, List<String> groups, int releaseId)
* Adds a mapping between user and the application which the application is installed on. This mapping will be throws ApplicationManagementDAOException;
* added when an enterprise installation triggered to the role.
*
* @param tenantId id of the tenant
* @param subscribedBy username of the user who subscribe the application
* @param groupList list of {@link DeviceGroup} which belongs the devices that are subscribed to the application
* @param appId id of the {@link ApplicationDTO} which installs
* @param releaseId id of the {@link ApplicationReleaseDTO}
* @throws ApplicationManagementDAOException If unable to add a mapping between device and application
*/
void subscribeGroupToApplication(int tenantId, String subscribedBy, List<DeviceGroup> groupList, int appId,
int releaseId) throws ApplicationManagementDAOException;
List<DeviceSubscriptionDTO> getDeviceSubscriptions(int appReleaseId, int tenantId) throws List<DeviceSubscriptionDTO> getDeviceSubscriptions(int appReleaseId, int tenantId) throws
ApplicationManagementDAOException; ApplicationManagementDAOException;
@ -106,8 +70,14 @@ public interface SubscriptionDAO {
List<String> getSubscribedUsernames(List<String> users, int tenantId) throws List<String> getSubscribedUsernames(List<String> users, int tenantId) throws
ApplicationManagementDAOException; ApplicationManagementDAOException;
void updateUserSubscription(int tenantId, String updateBy, boolean isUnsubscribed, List<String> userList, List<String> getSubscribedRolenames(List<String> roles, int tenantId) throws
int releaseId) throws ApplicationManagementDAOException; ApplicationManagementDAOException;
List<String> getSubscribedGroupnames(List<String> groups, int tenantId) throws
ApplicationManagementDAOException;
void updateSubscriptions(int tenantId, String updateBy, List<String> paramList,
int releaseId, String subType, String action) throws ApplicationManagementDAOException;
List<Integer> getSubscribedDeviceIds(List<Integer> deviceIds, int tenantId) throws ApplicationManagementDAOException; List<Integer> getSubscribedDeviceIds(List<Integer> deviceIds, int tenantId) throws ApplicationManagementDAOException;

@ -813,7 +813,7 @@ public class GenericApplicationDAOImpl extends AbstractDAOImpl implements Applic
try { try {
Connection conn = this.getDBConnection(); Connection conn = this.getDBConnection();
List<Integer> distinctCategoryIds = new ArrayList<>(); List<Integer> distinctCategoryIds = new ArrayList<>();
String sql = "SELECT DISTINCT AP_APP_CATEGORY.ID AS ID FROM AP_APP_CATEGORY"; String sql = "SELECT DISTINCT AP_APP_CATEGORY_ID AS ID FROM AP_APP_CATEGORY_MAPPING;";
try (PreparedStatement ps = conn.prepareStatement(sql)) { try (PreparedStatement ps = conn.prepareStatement(sql)) {
try (ResultSet rs = ps.executeQuery()) { try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) { while (rs.next()) {

@ -19,14 +19,14 @@ package org.wso2.carbon.device.application.mgt.core.dao.impl.subscription;
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.device.application.mgt.common.SubAction;
import org.wso2.carbon.device.application.mgt.common.SubsciptionType;
import org.wso2.carbon.device.application.mgt.common.dto.DeviceSubscriptionDTO; import org.wso2.carbon.device.application.mgt.common.dto.DeviceSubscriptionDTO;
import org.wso2.carbon.device.application.mgt.common.exception.DBConnectionException; import org.wso2.carbon.device.application.mgt.common.exception.DBConnectionException;
import org.wso2.carbon.device.application.mgt.core.dao.SubscriptionDAO; import org.wso2.carbon.device.application.mgt.core.dao.SubscriptionDAO;
import org.wso2.carbon.device.application.mgt.core.util.DAOUtil; import org.wso2.carbon.device.application.mgt.core.util.DAOUtil;
import org.wso2.carbon.device.application.mgt.core.dao.impl.AbstractDAOImpl; import org.wso2.carbon.device.application.mgt.core.dao.impl.AbstractDAOImpl;
import org.wso2.carbon.device.application.mgt.core.exception.ApplicationManagementDAOException; import org.wso2.carbon.device.application.mgt.core.exception.ApplicationManagementDAOException;
import org.wso2.carbon.device.mgt.common.Device;
import org.wso2.carbon.device.mgt.common.group.mgt.DeviceGroup;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
@ -44,41 +44,7 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc
private static Log log = LogFactory.getLog(GenericSubscriptionDAOImpl.class); private static Log log = LogFactory.getLog(GenericSubscriptionDAOImpl.class);
@Override @Override
public void subscribeDeviceToApplicationTmp(int tenantId, String subscribedBy, List<Device> deviceList, int appId, public List<Integer> addDeviceSubscription(String subscribedBy, List<Integer> deviceIds,
int releaseId, String installStatus) throws ApplicationManagementDAOException {
Connection conn;
PreparedStatement stmt = null;
try {
conn = this.getDBConnection();
long time = System.currentTimeMillis() / 1000;
String sql = "INSERT INTO AP_DEVICE_SUBSCRIPTION(TENANT_ID, SUBSCRIBED_BY, SUBSCRIBED_TIMESTAMP, "
+ "DM_DEVICE_ID, AP_APP_RELEASE_ID, AP_APP_ID, INSTALL_STATUS) VALUES (?, ?, ?, ?, ?, ?, ?)";
stmt = conn.prepareStatement(sql);
for (Device device : deviceList) {
stmt.setInt(1, tenantId);
stmt.setString(2, subscribedBy);
stmt.setLong(3, time);
stmt.setInt(4, device.getId());
stmt.setInt(5, releaseId);
stmt.setInt(6, appId);
stmt.setString(7, installStatus);
stmt.addBatch();
if (log.isDebugEnabled()) {
log.debug("Adding a mapping to device ID[" + device.getId() + "] to the application [" + appId
+ "], release[" + releaseId + "]");
}
}
stmt.executeBatch();
} catch (SQLException | DBConnectionException e) {
throw new ApplicationManagementDAOException("Error occurred while adding device application mapping to DB",
e);
} finally {
DAOUtil.cleanupResources(stmt, null);
}
}
@Override
public List<Integer> subscribeDeviceToApplication(String subscribedBy, List<Integer> deviceIds,
String subscribedFrom, String installStatus, int releaseId, int tenantId) String subscribedFrom, String installStatus, int releaseId, int tenantId)
throws ApplicationManagementDAOException { throws ApplicationManagementDAOException {
Connection conn; Connection conn;
@ -87,7 +53,7 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc
+ "AP_DEVICE_SUBSCRIPTION(" + "AP_DEVICE_SUBSCRIPTION("
+ "SUBSCRIBED_BY, " + "SUBSCRIBED_BY, "
+ "SUBSCRIBED_TIMESTAMP, " + "SUBSCRIBED_TIMESTAMP, "
+ "SUBSCRIBED_FROM, " + "ACTION_TRIGGERED_FROM, "
+ "STATUS, " + "STATUS, "
+ "DM_DEVICE_ID, " + "DM_DEVICE_ID, "
+ "AP_APP_RELEASE_ID," + "AP_APP_RELEASE_ID,"
@ -122,30 +88,34 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc
} }
@Override @Override
public List<Integer> updateDeviceSubscription(String subscribedBy, List<Integer> deviceIds, public List<Integer> updateDeviceSubscription(String updateBy, List<Integer> deviceIds,
String subscribedFrom, String installStatus, int releaseId, int tenantId) throws ApplicationManagementDAOException { boolean isUnsubscribed, String actionTriggeredFrom, String installStatus, int releaseId, int tenantId)
throws ApplicationManagementDAOException {
Connection conn; Connection conn;
try { try {
conn = this.getDBConnection(); conn = this.getDBConnection();
String sql = "UPDATE AP_USER_SUBSCRIPTION " String sql = "UPDATE AP_USER_SUBSCRIPTION " + "SET ";
+ "SET "
+ "SUBSCRIBED_BY = ?, " if (isUnsubscribed) {
+ "SUBSCRIBED_TIMESTAMP = ?, " sql += "UNSUBSCRIBED = true, UNSUBSCRIBED_BY = ?, UNSUBSCRIBED_TIMESTAMP = ? ";
+ "SUBSCRIBED_FROM = ?, " } else {
+ "STATUS = ? " sql += "SUBSCRIBED_BY = ?, SUBSCRIBED_TIMESTAMP = ? ";
+ "WHERE " }
+ "DM_DEVICE_ID = ? AND " sql += "ACTION_TRIGGERED_FROM = ?, " +
+ "AP_APP_RELEASE_ID = ? AND " "STATUS = ? " +
+ "TENANT_ID = ?"; "WHERE " +
"DM_DEVICE_ID = ? AND " +
"AP_APP_RELEASE_ID = ? AND " +
"TENANT_ID = ?";
try (PreparedStatement stmt = conn.prepareStatement(sql)) { try (PreparedStatement stmt = conn.prepareStatement(sql)) {
Calendar calendar = Calendar.getInstance(); Calendar calendar = Calendar.getInstance();
Timestamp timestamp = new Timestamp(calendar.getTime().getTime()); Timestamp timestamp = new Timestamp(calendar.getTime().getTime());
for (Integer deviceId : deviceIds) { for (Integer deviceId : deviceIds) {
stmt.setString(1, subscribedBy); stmt.setString(1, updateBy);
stmt.setTimestamp(2, timestamp); stmt.setTimestamp(2, timestamp);
stmt.setString(3, subscribedFrom); stmt.setString(3, actionTriggeredFrom);
stmt.setString(4, installStatus); stmt.setString(4, installStatus);
stmt.setInt(5, deviceId); stmt.setInt(5, deviceId);
stmt.setInt(6, releaseId); stmt.setInt(6, releaseId);
@ -162,8 +132,6 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc
log.error(msg); log.error(msg);
throw new ApplicationManagementDAOException(msg, e); throw new ApplicationManagementDAOException(msg, e);
} }
return deviceIds; return deviceIds;
} }
@ -198,7 +166,7 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc
} }
@Override @Override
public void subscribeUserToApplication(int tenantId, String subscribedBy, List<String> userList, int releaseId) public void addUserSubscriptions(int tenantId, String subscribedBy, List<String> users, int releaseId)
throws ApplicationManagementDAOException { throws ApplicationManagementDAOException {
Connection conn; Connection conn;
try { try {
@ -212,7 +180,7 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc
+ "VALUES (?, ?, ?, ?, ?)"; + "VALUES (?, ?, ?, ?, ?)";
conn = this.getDBConnection(); conn = this.getDBConnection();
try (PreparedStatement stmt = conn.prepareStatement(sql)) { try (PreparedStatement stmt = conn.prepareStatement(sql)) {
for (String user : userList) { for (String user : users) {
Calendar calendar = Calendar.getInstance(); Calendar calendar = Calendar.getInstance();
Timestamp timestamp = new Timestamp(calendar.getTime().getTime()); Timestamp timestamp = new Timestamp(calendar.getTime().getTime());
stmt.setInt(1, tenantId); stmt.setInt(1, tenantId);
@ -234,68 +202,74 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc
} }
@Override @Override
public void subscribeRoleToApplication(int tenantId, String subscribedBy, List<String> roleList, int appId, public void addRoleSubscriptions(int tenantId, String subscribedBy, List<String> roles, int releaseId)
int releaseId) throws ApplicationManagementDAOException { throws ApplicationManagementDAOException {
Connection conn; Connection conn;
PreparedStatement stmt = null;
try { try {
String sql = "INSERT INTO "
+ "AP_ROLE_SUBSCRIPTION("
+ "TENANT_ID, "
+ "SUBSCRIBED_BY, "
+ "SUBSCRIBED_TIMESTAMP, "
+ "ROLE_NAME, "
+ "AP_APP_RELEASE_ID) "
+ "VALUES (?, ?, ?, ?, ?)";
conn = this.getDBConnection(); conn = this.getDBConnection();
long time = System.currentTimeMillis() / 1000; try (PreparedStatement stmt = conn.prepareStatement(sql)) {
String sql = "INSERT INTO AP_ROLE_SUBSCRIPTION(TENANT_ID, SUBSCRIBED_BY, SUBSCRIBED_TIMESTAMP, " for (String role : roles) {
+ "ROLE_NAME, AP_APP_RELEASE_ID, AP_APP_ID) VALUES (?, ?, ?, ?, ?, ?)"; Calendar calendar = Calendar.getInstance();
stmt = conn.prepareStatement(sql); Timestamp timestamp = new Timestamp(calendar.getTime().getTime());
for (String role : roleList) { stmt.setInt(1, tenantId);
stmt.setInt(1, tenantId); stmt.setString(2, subscribedBy);
stmt.setString(2, subscribedBy); stmt.setTimestamp(3, timestamp);
stmt.setLong(3, time); stmt.setString(4, role);
stmt.setString(4, role); stmt.setInt(5, releaseId);
stmt.setInt(5, releaseId); stmt.addBatch();
stmt.setInt(6, appId); if (log.isDebugEnabled()) {
stmt.addBatch(); log.debug("Adding a mapping to role[" + role + "] to the application release[" + releaseId + "]");
if (log.isDebugEnabled()) { }
log.debug("Adding a mapping to role[" + role + "] to the application [" + appId + "], release["
+ releaseId + "]");
} }
stmt.executeBatch();
} }
stmt.executeBatch();
} catch (SQLException | DBConnectionException e) { } catch (SQLException | DBConnectionException e) {
throw new ApplicationManagementDAOException("Error occurred while adding device application mapping to DB", throw new ApplicationManagementDAOException("Error occurred while adding role subscription to APPM DB",
e); e);
} finally {
DAOUtil.cleanupResources(stmt, null);
} }
} }
@Override @Override
public void subscribeGroupToApplication(int tenantId, String subscribedBy, List<DeviceGroup> groupList, int appId, public void addGroupSubscriptions(int tenantId, String subscribedBy, List<String> groups, int releaseId)
int releaseId) throws ApplicationManagementDAOException { throws ApplicationManagementDAOException {
Connection conn; Connection conn;
PreparedStatement stmt = null;
try { try {
String sql = "INSERT INTO "
+ "AP_GROUP_SUBSCRIPTION("
+ "TENANT_ID, "
+ "SUBSCRIBED_BY, "
+ "SUBSCRIBED_TIMESTAMP, "
+ "GROUP_NAME, "
+ "AP_APP_RELEASE_ID) "
+ "VALUES (?, ?, ?, ?, ?)";
conn = this.getDBConnection(); conn = this.getDBConnection();
long time = System.currentTimeMillis() / 1000; try (PreparedStatement stmt = conn.prepareStatement(sql)) {
String sql = "INSERT INTO AP_GROUP_SUBSCRIPTION(TENANT_ID, SUBSCRIBED_BY, SUBSCRIBED_TIMESTAMP, " for (String group : groups) {
+ "DM_GROUP_ID, AP_APP_RELEASE_ID, AP_APP_ID) VALUES (?, ?, ?, ?, ?, ?)"; Calendar calendar = Calendar.getInstance();
stmt = conn.prepareStatement(sql); Timestamp timestamp = new Timestamp(calendar.getTime().getTime());
for (DeviceGroup group : groupList) { stmt.setInt(1, tenantId);
stmt.setInt(1, tenantId); stmt.setString(2, subscribedBy);
stmt.setString(2, subscribedBy); stmt.setTimestamp(3, timestamp);
stmt.setLong(3, time); stmt.setString(4, group);
stmt.setInt(4, group.getGroupId()); stmt.setInt(5, releaseId);
stmt.setInt(5, releaseId); stmt.addBatch();
stmt.setInt(6, appId); if (log.isDebugEnabled()) {
stmt.addBatch(); log.debug("Adding a mapping to group[" + group + "] to the application release[" + releaseId + "]");
if (log.isDebugEnabled()) { }
log.debug("Adding a mapping to group ID[" + group.getGroupId() + "] to the application [" + appId
+ "], release[" + releaseId + "]");
} }
stmt.executeBatch();
} }
stmt.executeBatch();
} catch (SQLException | DBConnectionException e) { } catch (SQLException | DBConnectionException e) {
throw new ApplicationManagementDAOException("Error occurred while adding device application mapping to DB", throw new ApplicationManagementDAOException("Error occurred while adding group subscription to APPM DB",
e); e);
} finally {
DAOUtil.cleanupResources(stmt, null);
} }
} }
@ -316,7 +290,7 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc
+ "DS.UNSUBSCRIBED AS IS_UNSUBSCRIBED, " + "DS.UNSUBSCRIBED AS IS_UNSUBSCRIBED, "
+ "DS.UNSUBSCRIBED_BY AS UNSUBSCRIBED_BY, " + "DS.UNSUBSCRIBED_BY AS UNSUBSCRIBED_BY, "
+ "DS.UNSUBSCRIBED_TIMESTAMP AS UNSUBSCRIBED_AT, " + "DS.UNSUBSCRIBED_TIMESTAMP AS UNSUBSCRIBED_AT, "
+ "DS.SUBSCRIBED_FROM AS SUBSCRIBED_FROM, " + "DS.ACTION_TRIGGERED_FROM AS ACTION_TRIGGERED_FROM, "
+ "DS.DM_DEVICE_ID AS DEVICE_ID " + "DS.DM_DEVICE_ID AS DEVICE_ID "
+ "FROM AP_DEVICE_SUBSCRIPTION DS " + "FROM AP_DEVICE_SUBSCRIPTION DS "
+ "WHERE DS.AP_APP_RELEASE_ID = ? AND DS.TENANT_ID=?"; + "WHERE DS.AP_APP_RELEASE_ID = ? AND DS.TENANT_ID=?";
@ -363,7 +337,7 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc
+ "DS.UNSUBSCRIBED AS IS_UNSUBSCRIBED, " + "DS.UNSUBSCRIBED AS IS_UNSUBSCRIBED, "
+ "DS.UNSUBSCRIBED_BY AS UNSUBSCRIBED_BY, " + "DS.UNSUBSCRIBED_BY AS UNSUBSCRIBED_BY, "
+ "DS.UNSUBSCRIBED_TIMESTAMP AS UNSUBSCRIBED_AT, " + "DS.UNSUBSCRIBED_TIMESTAMP AS UNSUBSCRIBED_AT, "
+ "DS.SUBSCRIBED_FROM AS SUBSCRIBED_FROM, " + "DS.ACTION_TRIGGERED_FROM AS ACTION_TRIGGERED_FROM, "
+ "DS.DM_DEVICE_ID AS DEVICE_ID, " + "DS.DM_DEVICE_ID AS DEVICE_ID, "
+ "DS.STATUS AS STATUS " + "DS.STATUS AS STATUS "
+ "FROM AP_DEVICE_SUBSCRIPTION DS " + "FROM AP_DEVICE_SUBSCRIPTION DS "
@ -431,6 +405,83 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc
} }
} }
@Override
public List<String> getSubscribedRolenames(List<String> roles, int tenantId)
throws ApplicationManagementDAOException {
if (log.isDebugEnabled()) {
log.debug(
"Request received in DAO Layer to get already subscribed role names for given list of role names.");
}
try {
Connection conn = this.getDBConnection();
int index = 1;
List<String> subscribedUsers = new ArrayList<>();
StringJoiner joiner = new StringJoiner(",",
"SELECT RS.ROLE_NAME AS ROLE "
+ "FROM AP_ROLE_SUBSCRIPTION RS "
+ "WHERE RS.ROLE_NAME IN (", ") AND TENANT_ID = ?");
roles.stream().map(ignored -> "?").forEach(joiner::add);
String query = joiner.toString();
try (PreparedStatement ps = conn.prepareStatement(query)) {
for (String roleName : roles) {
ps.setObject(index++, roleName);
}
ps.setInt(index, tenantId);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
subscribedUsers.add(rs.getString("ROLE"));
}
}
}
return subscribedUsers;
} catch (DBConnectionException e) {
throw new ApplicationManagementDAOException(
"Error occurred while obtaining the DB connection when getting subscribed roles for given "
+ "role names.", e);
} catch (SQLException e) {
throw new ApplicationManagementDAOException("SWL Error occurred while getting subscribes roles for given"
+ " role names.", e);
}
}
@Override
public List<String> getSubscribedGroupnames(List<String> groups, int tenantId)
throws ApplicationManagementDAOException {
if (log.isDebugEnabled()) {
log.debug("Request received in DAO Layer to get already subscribed groups for given list of group names.");
}
try {
Connection conn = this.getDBConnection();
int index = 1;
List<String> subscribedUsers = new ArrayList<>();
StringJoiner joiner = new StringJoiner(",",
"SELECT GS.GROUP_NAME AS GROUP "
+ "FROM AP_GROUP_SUBSCRIPTION GS "
+ "WHERE GS.GROUP_NAME IN (", ") AND TENANT_ID = ?");
groups.stream().map(ignored -> "?").forEach(joiner::add);
String query = joiner.toString();
try (PreparedStatement ps = conn.prepareStatement(query)) {
for (String groupName : groups) {
ps.setObject(index++, groupName);
}
ps.setInt(index, tenantId);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
subscribedUsers.add(rs.getString("GROUP"));
}
}
}
return subscribedUsers;
} catch (DBConnectionException e) {
throw new ApplicationManagementDAOException(
"Error occurred while obtaining the DB connection when getting subscribed groups for given "
+ "group names.", e);
} catch (SQLException e) {
throw new ApplicationManagementDAOException("SWL Error occurred while getting subscribed groups for given"
+ " group names.", e);
}
}
@Override public List<Integer> getSubscribedDeviceIds(List<Integer> deviceIds, int tenantId) @Override public List<Integer> getSubscribedDeviceIds(List<Integer> deviceIds, int tenantId)
throws ApplicationManagementDAOException { throws ApplicationManagementDAOException {
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
@ -468,25 +519,42 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc
} } } }
@Override @Override
public void updateUserSubscription(int tenantId, String updateBy, boolean isUnsubscribed, public void updateSubscriptions(int tenantId, String updateBy, List<String> paramList, int releaseId,
List<String> userList, int releaseId) throws ApplicationManagementDAOException { String subType, String action) throws ApplicationManagementDAOException {
Connection conn; Connection conn;
try { try {
conn = this.getDBConnection(); conn = this.getDBConnection();
String sql = "UPDATE AP_USER_SUBSCRIPTION SET "; String sql = "UPDATE ";
if (SubsciptionType.USER.toString().equalsIgnoreCase(subType)) {
sql += "AP_USER_SUBSCRIPTION ";
} else if (SubsciptionType.ROLE.toString().equalsIgnoreCase(subType)) {
sql += "AP_ROLE_SUBSCRIPTION ";
} else if (SubsciptionType.GROUP.toString().equalsIgnoreCase(subType)) {
sql += "AP_GROUP_SUBSCRIPTION ";
}
if (isUnsubscribed){ if (SubAction.UNINSTALL.toString().equalsIgnoreCase(action)) {
sql += "UNSUBSCRIBED = true, UNSUBSCRIBED_BY = ?, UNSUBSCRIBED_TIMESTAMP "; sql += "SET UNSUBSCRIBED = true, UNSUBSCRIBED_BY = ?, UNSUBSCRIBED_TIMESTAMP = ? ";
} else { } else {
sql += "SUBSCRIBED_BY = ?, SUBSCRIBED_TIMESTAMP =? "; sql += "SET SUBSCRIBED_BY = ?, SUBSCRIBED_TIMESTAMP = ? ";
}
sql += "WHERE ";
if (SubsciptionType.USER.toString().equalsIgnoreCase(subType)) {
sql += "USER_NAME = ? ";
} else if (SubsciptionType.ROLE.toString().equalsIgnoreCase(subType)) {
sql += "ROLE_NAME = ? ";
} else if (SubsciptionType.GROUP.toString().equalsIgnoreCase(subType)) {
sql += "GROUP_NAME = ? ";
} }
sql += "WHERE USER_NAME = ? AND AP_APP_RELEASE_ID = ? AND AND TENANT_ID = ?"; sql += "AND AP_APP_RELEASE_ID = ? AND AND TENANT_ID = ?";
try (PreparedStatement stmt = conn.prepareStatement(sql)) { try (PreparedStatement stmt = conn.prepareStatement(sql)) {
Calendar calendar = Calendar.getInstance(); Calendar calendar = Calendar.getInstance();
Timestamp timestamp = new Timestamp(calendar.getTime().getTime()); Timestamp timestamp = new Timestamp(calendar.getTime().getTime());
for (String username : userList) { for (String username : paramList) {
stmt.setString(1, updateBy); stmt.setString(1, updateBy);
stmt.setTimestamp(2, timestamp); stmt.setTimestamp(2, timestamp);
stmt.setString(3, username); stmt.setString(3, username);

@ -1,125 +0,0 @@
/*
* Copyright (c) 2018, 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.impl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.application.mgt.common.AppOperation;
import org.wso2.carbon.device.application.mgt.common.exception.DeviceConnectorException;
import org.wso2.carbon.device.application.mgt.common.services.DeviceConnector;
import org.wso2.carbon.device.application.mgt.core.dao.ApplicationDAO;
import org.wso2.carbon.device.application.mgt.core.dao.SubscriptionDAO;
import org.wso2.carbon.device.application.mgt.core.dao.common.ApplicationManagementDAOFactory;
import org.wso2.carbon.device.application.mgt.core.exception.ApplicationManagementDAOException;
import org.wso2.carbon.device.mgt.common.Device;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;;
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
import java.util.ArrayList;
import java.util.List;
public class MAMDeviceConnectorImpl implements DeviceConnector{
private static final Log log = LogFactory.getLog(MAMDeviceConnectorImpl.class);
private ApplicationDAO applicationDAO;
private SubscriptionDAO subscriptionDAO;
public MAMDeviceConnectorImpl() {
this.applicationDAO = ApplicationManagementDAOFactory.getApplicationDAO();
this.subscriptionDAO = ApplicationManagementDAOFactory.getSubscriptionDAO();
}
@Override
public Boolean sendOperationToDevice(AppOperation appOperation, DeviceIdentifier deviceIdentifier) throws DeviceConnectorException {
if (String.valueOf(appOperation.getType()).equals("INSTALL")) {
} else if (String.valueOf(appOperation.getType()).equals("UNINSTALL")) {
} else if (String.valueOf(appOperation.getType()).equals("UPDATE")) {
}
return null;
}
@Override
public Boolean sendOperationToGroup(AppOperation appOperation, String groupID) throws DeviceConnectorException {
return null;
}
@Override
public Boolean sendOperationToUser(AppOperation appOperation, List<String> userList) throws DeviceConnectorException {
if (String.valueOf(appOperation.getType()).equals("INSTALL")) {
//First subscribe the user to the app.
try {
subscriptionDAO.subscribeUserToApplication(appOperation.getTenantId(), appOperation.getSubscribedBy(),
userList, appOperation.getAppReleaseId());
for (String username: userList) {
List<Device> devices = getDeviceManagementService().getDevicesOfUser(username);
List<DeviceIdentifier> deviceIdentifiers = convertDeviceToDeviceIdentifier(devices);
// getDeviceManagementService().addOperation(appOperation.getApplication().getDeviceTypeName(),
// operationEKA, devices);
subscriptionDAO.subscribeDeviceToApplicationTmp(appOperation.getTenantId(), appOperation.getSubscribedBy(),
devices, appOperation.getApplication().getId(), appOperation.getAppReleaseId(),
String.valueOf(AppOperation.InstallState.PENDING));
}
} catch (ApplicationManagementDAOException e) {
String msg = "Error subscribing the user to the application Id" + appOperation.getApplication().getId();
log.error(msg, e);
throw new DeviceConnectorException(msg, e);
} catch (DeviceManagementException e) {
String msg = "Error getting the list of user devices.";
log.error(msg, e);
throw new DeviceConnectorException(msg, e);
}
} else if (String.valueOf(appOperation.getType()).equals("UNINSTALL")) {
} else if (String.valueOf(appOperation.getType()).equals("UPDATE")) {
}
return null;
}
@Override
public Boolean sendOperationToRole(AppOperation appOperation, String role) throws DeviceConnectorException {
return null;
}
private List<DeviceIdentifier> convertDeviceToDeviceIdentifier(List<Device> devices) {
List<DeviceIdentifier> deviceIdentifiers = new ArrayList<>();
for (Device device:devices) {
deviceIdentifiers.add(new DeviceIdentifier(device.getDeviceIdentifier(), device.getType()));
}
return deviceIdentifiers;
}
public DeviceManagementProviderService getDeviceManagementService() {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
DeviceManagementProviderService deviceManagementProviderService =
(DeviceManagementProviderService) ctx.getOSGiService(DeviceManagementProviderService.class, null);
if (deviceManagementProviderService == null) {
String msg = "DeviceImpl Management provider service has not initialized.";
log.error(msg);
throw new IllegalStateException(msg);
}
return deviceManagementProviderService;
}
}

@ -33,6 +33,7 @@ import org.wso2.carbon.device.application.mgt.common.exception.ApplicationManage
import org.wso2.carbon.device.application.mgt.common.exception.DBConnectionException; import org.wso2.carbon.device.application.mgt.common.exception.DBConnectionException;
import org.wso2.carbon.device.application.mgt.common.exception.LifecycleManagementException; import org.wso2.carbon.device.application.mgt.common.exception.LifecycleManagementException;
import org.wso2.carbon.device.application.mgt.common.exception.TransactionManagementException; import org.wso2.carbon.device.application.mgt.common.exception.TransactionManagementException;
import org.wso2.carbon.device.application.mgt.common.response.Application;
import org.wso2.carbon.device.application.mgt.common.services.SubscriptionManager; import org.wso2.carbon.device.application.mgt.common.services.SubscriptionManager;
import org.wso2.carbon.device.application.mgt.core.dao.ApplicationDAO; import org.wso2.carbon.device.application.mgt.core.dao.ApplicationDAO;
import org.wso2.carbon.device.application.mgt.core.dao.SubscriptionDAO; import org.wso2.carbon.device.application.mgt.core.dao.SubscriptionDAO;
@ -94,22 +95,7 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
+ " users."); + " users.");
} }
try { try {
if (params.isEmpty()) { validateRequest(params, subType, action);
String msg = "In order to install application release which has UUID " + applicationUUID + ", you should"
+ " provide list of subscribers. But found an empty list of users.";
log.error(msg);
throw new BadRequestException(msg);
}
boolean isValidSubType = Arrays.stream(SubsciptionType.values())
.anyMatch(sub -> sub.name().equalsIgnoreCase(subType));
if (!isValidSubType) {
String msg = "Found invalid subscription type to install application release witch has UUID: "
+ applicationUUID + ". Subscription type is " + subType;
log.error(msg);
throw new BadRequestException(msg);
}
DeviceManagementProviderService deviceManagementProviderService = HelperUtil DeviceManagementProviderService deviceManagementProviderService = HelperUtil
.getDeviceManagementProviderService(); .getDeviceManagementProviderService();
GroupManagementProviderService groupManagementProviderService = HelperUtil GroupManagementProviderService groupManagementProviderService = HelperUtil
@ -120,6 +106,7 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
List<DeviceIdentifier> errorDeviceIdentifiers = new ArrayList<>(); List<DeviceIdentifier> errorDeviceIdentifiers = new ArrayList<>();
ApplicationInstallResponse applicationInstallResponse; ApplicationInstallResponse applicationInstallResponse;
//todo validate users, groups and roles
ApplicationDTO applicationDTO = getApplicationDTO(applicationUUID); ApplicationDTO applicationDTO = getApplicationDTO(applicationUUID);
if (SubsciptionType.DEVICE.toString().equals(subType)) { if (SubsciptionType.DEVICE.toString().equals(subType)) {
for (T param : params) { for (T param : params) {
@ -143,19 +130,19 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
} }
devices.add(deviceManagementProviderService.getDevice(deviceIdentifier, false)); devices.add(deviceManagementProviderService.getDevice(deviceIdentifier, false));
} }
} else if (SubsciptionType.USER.toString().equals(subType)) { } else if (SubsciptionType.USER.toString().equalsIgnoreCase(subType)) {
for (T param : params) { for (T param : params) {
String username = (String) param; String username = (String) param;
subscribers.add(username); subscribers.add(username);
devices.addAll(deviceManagementProviderService.getDevicesOfUser(username)); devices.addAll(deviceManagementProviderService.getDevicesOfUser(username));
} }
} else if (SubsciptionType.ROLE.toString().equals(subType)) { } else if (SubsciptionType.ROLE.toString().equalsIgnoreCase(subType)) {
for (T param : params) { for (T param : params) {
String roleName = (String) param; String roleName = (String) param;
subscribers.add(roleName); subscribers.add(roleName);
devices.addAll(deviceManagementProviderService.getAllDevicesOfRole(roleName)); devices.addAll(deviceManagementProviderService.getAllDevicesOfRole(roleName));
} }
} else if (SubsciptionType.GROUP.toString().equals(subType)) { } else if (SubsciptionType.GROUP.toString().equalsIgnoreCase(subType)) {
for (T param : params) { for (T param : params) {
String groupName = (String) param; String groupName = (String) param;
subscribers.add(groupName); subscribers.add(groupName);
@ -166,6 +153,7 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
if (!ApplicationType.WEB_CLIP.toString().equals(applicationDTO.getType())) { if (!ApplicationType.WEB_CLIP.toString().equals(applicationDTO.getType())) {
DeviceType deviceType = APIUtil.getDeviceTypeData(applicationDTO.getDeviceTypeId()); DeviceType deviceType = APIUtil.getDeviceTypeData(applicationDTO.getDeviceTypeId());
String deviceTypeName = deviceType.getName(); String deviceTypeName = deviceType.getName();
//filter devices by device type
for (Device device : devices) { for (Device device : devices) {
if (deviceTypeName.equals(device.getType())) { if (deviceTypeName.equals(device.getType())) {
filteredDevices.add(device); filteredDevices.add(device);
@ -173,13 +161,9 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
} }
applicationInstallResponse = performActionOnDevices(deviceTypeName, filteredDevices, applicationDTO, applicationInstallResponse = performActionOnDevices(deviceTypeName, filteredDevices, applicationDTO,
subType, subscribers, action); subType, subscribers, action);
//todo add db insert to here
} else { } else {
//todo improve this
applicationInstallResponse = performActionOnDevices(null, devices, applicationDTO, subType, applicationInstallResponse = performActionOnDevices(null, devices, applicationDTO, subType,
subscribers, action); subscribers, action);
//todo add db insert to here
} }
applicationInstallResponse.setErrorDevices(errorDeviceIdentifiers); applicationInstallResponse.setErrorDevices(errorDeviceIdentifiers);
return applicationInstallResponse; return applicationInstallResponse;
@ -194,6 +178,29 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
} }
} }
private <T> void validateRequest(List<T> params, String subType, String action) throws BadRequestException {
if (params.isEmpty()) {
String msg = "In order to install application release, you should provide list of subscribers. "
+ "But found an empty list of users.";
log.error(msg);
throw new BadRequestException(msg);
}
boolean isValidSubType = Arrays.stream(SubsciptionType.values())
.anyMatch(sub -> sub.name().equalsIgnoreCase(subType));
if (!isValidSubType) {
String msg = "Found invalid subscription type " + subType+ " to install application release" ;
log.error(msg);
throw new BadRequestException(msg);
}
boolean isValidAction = Arrays.stream(SubAction.values())
.anyMatch(sub -> sub.name().equalsIgnoreCase(action));
if (!isValidAction) {
String msg = "Found invalid action " + action +" to perform on application release";
log.error(msg);
throw new BadRequestException(msg);
}
}
private ApplicationInstallResponse performActionOnDevices(String deviceType, List<Device> devices, private ApplicationInstallResponse performActionOnDevices(String deviceType, List<Device> devices,
ApplicationDTO applicationDTO, String subType, List<String> subscribers, String action) ApplicationDTO applicationDTO, String subType, List<String> subscribers, String action)
throws ApplicationManagementException { throws ApplicationManagementException {
@ -236,30 +243,21 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
deviceIdentifierMap.put(identifier.getType(), identifiers); deviceIdentifierMap.put(identifier.getType(), identifiers);
} }
} }
for (Map.Entry<String, List<DeviceIdentifier>> entry : deviceIdentifierMap.entrySet()) { for (Map.Entry<String, List<DeviceIdentifier>> entry : deviceIdentifierMap.entrySet()) {
Activity activity = addAppInstallOperationToDevices(applicationDTO, Activity activity = addAppOperationOnDevices(applicationDTO, new ArrayList<>(entry.getValue()),
new ArrayList<>(entry.getValue()), entry.getKey()); entry.getKey(), action);
activityList.add(activity); activityList.add(activity);
} }
} else {
ApplicationInstallResponse applicationInstallResponse = new ApplicationInstallResponse(); Activity activity = addAppOperationOnDevices(applicationDTO, deviceIdentifiers, deviceType, action);
applicationInstallResponse.setActivities(activityList); activityList.add(activity);
applicationInstallResponse.setIgnoredDeviceIdentifiers(ignoredDeviceIdentifiers);
return applicationInstallResponse;
} }
//todo consider action
Activity activity = addAppInstallOperationToDevices(applicationDTO, deviceIdentifiers, deviceType);
activityList.add(activity);
ApplicationInstallResponse applicationInstallResponse = new ApplicationInstallResponse(); ApplicationInstallResponse applicationInstallResponse = new ApplicationInstallResponse();
applicationInstallResponse.setActivities(activityList); applicationInstallResponse.setActivities(activityList);
applicationInstallResponse.setIgnoredDeviceIdentifiers(ignoredDeviceIdentifiers); applicationInstallResponse.setIgnoredDeviceIdentifiers(ignoredDeviceIdentifiers);
//todo updateSubscriptions(applicationDTO.getApplicationReleaseDTOs().get(0).getId(), activityList,
addSubscriptions(applicationDTO.getApplicationReleaseDTOs().get(0).getId(), activity, subscribingDeviceIdHolder, subscribingDeviceIdHolder, subscribers, subType, action);
subscribers, subType, action);
return applicationInstallResponse; return applicationInstallResponse;
} }
@ -285,7 +283,6 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
SubscribingDeviceIdHolder subscribingDeviceIdHolder = new SubscribingDeviceIdHolder(); SubscribingDeviceIdHolder subscribingDeviceIdHolder = new SubscribingDeviceIdHolder();
subscribingDeviceIdHolder.setSubscribableDevices(subscribableDevices); subscribingDeviceIdHolder.setSubscribableDevices(subscribableDevices);
subscribingDeviceIdHolder.setSubscribedDevices(subscribedDevices); subscribingDeviceIdHolder.setSubscribedDevices(subscribedDevices);
// subscribingDeviceIdHolder.setDeviceSubscriptions(deviceSubscriptions);
return subscribingDeviceIdHolder; return subscribingDeviceIdHolder;
} }
@ -324,55 +321,65 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
} }
} }
//todo pass SubscribingDeviceIdHolder and action private void updateSubscriptions(int applicationReleaseId, List<Activity> activities,
private void addSubscriptions(int applicationReleaseId, Activity activity, SubscribingDeviceIdHolder subscribingDeviceIdHolder, List<String> params, String subType,
SubscribingDeviceIdHolder subscribingDeviceIdHolder, List<String> subscribers, String subType, String action) String action) throws ApplicationManagementException {
throws ApplicationManagementException {
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true); int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true);
String subscriber = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername(); String username = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername();
try { try {
ConnectionManagerUtil.beginDBTransaction(); ConnectionManagerUtil.beginDBTransaction();
List<Integer> deviceResubscribingIds = new ArrayList<>(); List<Integer> deviceIds = new ArrayList<>();
List<Integer> deviceSubscriptingIds;
List<String> subscribedEntities = new ArrayList<>();
if (SubsciptionType.USER.toString().equals(subType)) { if (SubsciptionType.USER.toString().equals(subType)) {
//todo check action subscribedEntities = subscriptionDAO.getSubscribedUsernames(params, tenantId);
List<String> subscribedUsers = subscriptionDAO.getSubscribedUsernames(subscribers, tenantId); if (SubAction.INSTALL.toString().equalsIgnoreCase(action)) {
if (!subscribedUsers.isEmpty()) { params.removeAll(subscribedEntities);
subscriptionDAO subscriptionDAO.addUserSubscriptions(tenantId, username, params, applicationReleaseId);
.updateUserSubscription(tenantId, subscriber, false, subscribedUsers, applicationReleaseId);
subscribers.removeAll(subscribedUsers);
} }
subscriptionDAO.subscribeUserToApplication(tenantId, subscriber, subscribers, applicationReleaseId); } else if (SubsciptionType.ROLE.toString().equals(subType)) {
} subscribedEntities = subscriptionDAO.getSubscribedRolenames(params, tenantId);
if (SubAction.INSTALL.toString().equalsIgnoreCase(action)) {
//todo add for other subscription types params.removeAll(subscribedEntities);
subscriptionDAO.addRoleSubscriptions(tenantId, username, params, applicationReleaseId);
List<Integer> deviceIds = new ArrayList<>(); }
List<ActivityStatus> activityStatuses = activity.getActivityStatus(); } else if (SubsciptionType.GROUP.toString().equals(subType)) {
for (ActivityStatus status : activityStatuses) { subscribedEntities = subscriptionDAO.getSubscribedGroupnames(params, tenantId);
if (status.getStatus().equals(ActivityStatus.Status.PENDING)) { if (SubAction.INSTALL.toString().equalsIgnoreCase(action)) {
//todo params.removeAll(subscribedEntities);
// deviceIds.add(compatibleDevices.get(status.getDeviceIdentifier())); subscriptionDAO.addGroupSubscriptions(tenantId, username, params, applicationReleaseId);
} }
} }
subscriptionDAO.updateSubscriptions(tenantId, username, subscribedEntities, applicationReleaseId, subType,
int operationId = Integer.parseInt(activity.getActivityId().split("ACTIVITY_")[1]); action);
//todo if INSTALL get Ids of subscribable devices and update those ids and insert other ids
for (Activity activity : activities) {
int operationId = Integer.parseInt(activity.getActivityId().split("ACTIVITY_")[1]);
//todo List<Integer> operationAddedDeviceIds = getOperationAddedDeviceIds(activity,
subscribingDeviceIdHolder.getSubscribableDevices());
// if (!subDeviceIds.isEmpty()) { List<Integer> alreadySubscribedDevices = subscriptionDAO
// deviceResubscribingIds = subscriptionDAO.updateDeviceSubscription(subscriber, subDeviceIds, subType, .getSubscribedDeviceIds(operationAddedDeviceIds, tenantId);
// Operation.Status.PENDING.toString(), applicationReleaseId, tenantId); if (SubAction.INSTALL.toString().equalsIgnoreCase(action)) {
// deviceIds.removeAll(subDeviceIds); if (!alreadySubscribedDevices.isEmpty()) {
// } List<Integer> deviceResubscribingIds = subscriptionDAO
deviceSubscriptingIds = subscriptionDAO .updateDeviceSubscription(username, alreadySubscribedDevices, false, subType,
.subscribeDeviceToApplication(subscriber, deviceIds, subType, Operation.Status.PENDING.toString(), Operation.Status.PENDING.toString(), applicationReleaseId, tenantId);
applicationReleaseId, tenantId); operationAddedDeviceIds.removeAll(alreadySubscribedDevices);
deviceSubscriptingIds.addAll(deviceResubscribingIds); deviceIds.addAll(deviceResubscribingIds);
subscriptionDAO.addOperationMapping(operationId, deviceSubscriptingIds, tenantId); }
List<Integer> subscribingDevices = subscriptionDAO
.addDeviceSubscription(username, operationAddedDeviceIds, subType,
Operation.Status.PENDING.toString(), applicationReleaseId, tenantId);
deviceIds.addAll(subscribingDevices);
} else if (SubAction.UNINSTALL.toString().equalsIgnoreCase(action) && !alreadySubscribedDevices.isEmpty()) {
List<Integer> deviceResubscribingIds = subscriptionDAO
.updateDeviceSubscription(username, alreadySubscribedDevices, false, subType,
Operation.Status.PENDING.toString(), applicationReleaseId, tenantId);
deviceIds.addAll(deviceResubscribingIds);
}
subscriptionDAO.addOperationMapping(operationId, deviceIds, tenantId);
}
ConnectionManagerUtil.commitDBTransaction(); ConnectionManagerUtil.commitDBTransaction();
} catch (ApplicationManagementDAOException e) { } catch (ApplicationManagementDAOException e) {
ConnectionManagerUtil.rollbackDBTransaction(); ConnectionManagerUtil.rollbackDBTransaction();
@ -395,6 +402,17 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
} }
} }
private List<Integer> getOperationAddedDeviceIds(Activity activity, Map<DeviceIdentifier, Integer> deviceMap) {
List<Integer> deviceIds = new ArrayList<>();
List<ActivityStatus> activityStatuses = activity.getActivityStatus();
for (ActivityStatus status : activityStatuses) {
if (status.getStatus().equals(ActivityStatus.Status.PENDING)) {
deviceIds.add(deviceMap.get(status.getDeviceIdentifier()));
}
}
return deviceIds;
}
private Map<Integer, DeviceSubscriptionDTO> getDeviceSubscriptions(List<Integer> filteredDeviceIds) private Map<Integer, DeviceSubscriptionDTO> getDeviceSubscriptions(List<Integer> filteredDeviceIds)
throws ApplicationManagementException { throws ApplicationManagementException {
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true); int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true);
@ -416,13 +434,14 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
} }
private Activity addAppInstallOperationToDevices(ApplicationDTO application, private Activity addAppOperationOnDevices(ApplicationDTO applicationDTO,
List<DeviceIdentifier> deviceIdentifierList, String deviceType) throws ApplicationManagementException { List<DeviceIdentifier> deviceIdentifierList, String deviceType, String action)
throws ApplicationManagementException {
DeviceManagementProviderService deviceManagementProviderService = HelperUtil DeviceManagementProviderService deviceManagementProviderService = HelperUtil
.getDeviceManagementProviderService(); .getDeviceManagementProviderService();
try { try {
Operation operation = generateOperationPayloadByDeviceType(deviceType, application, null); Application application = APIUtil.appDtoToAppResponse(applicationDTO);
//todo refactor add operation code to get successful operations Operation operation = generateOperationPayloadByDeviceType(deviceType, application, action);
return deviceManagementProviderService.addOperation(deviceType, operation, deviceIdentifierList); return deviceManagementProviderService.addOperation(deviceType, operation, deviceIdentifierList);
} catch (OperationManagementException e) { } catch (OperationManagementException e) {
throw new ApplicationManagementException( throw new ApplicationManagementException(
@ -433,7 +452,7 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
} }
} }
private Operation generateOperationPayloadByDeviceType(String deviceType, ApplicationDTO application, String action) private Operation generateOperationPayloadByDeviceType(String deviceType, Application application, String action)
throws ApplicationManagementException { throws ApplicationManagementException {
try { try {
@ -464,12 +483,10 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
log.error(msg); log.error(msg);
throw new ApplicationManagementException(msg); throw new ApplicationManagementException(msg);
} }
} catch (UnknownApplicationTypeException e) { } catch (UnknownApplicationTypeException e) {
String msg = "Unknown Application type is found."; String msg = "Unknown Application type is found.";
log.error(msg); log.error(msg);
throw new ApplicationManagementException(msg); throw new ApplicationManagementException(msg);
} }
} }
} }

@ -18,18 +18,26 @@
package org.wso2.carbon.device.application.mgt.core.util; package org.wso2.carbon.device.application.mgt.core.util;
import org.apache.commons.lang.StringUtils;
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.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.application.mgt.common.dto.ApplicationDTO;
import org.wso2.carbon.device.application.mgt.common.dto.ApplicationReleaseDTO;
import org.wso2.carbon.device.application.mgt.common.response.Application;
import org.wso2.carbon.device.application.mgt.common.response.ApplicationRelease;
import org.wso2.carbon.device.application.mgt.common.services.*; import org.wso2.carbon.device.application.mgt.common.services.*;
import org.wso2.carbon.device.application.mgt.common.ErrorResponse; import org.wso2.carbon.device.application.mgt.common.ErrorResponse;
import org.wso2.carbon.device.application.mgt.core.config.ConfigurationManager;
import org.wso2.carbon.device.application.mgt.core.exception.BadRequestException; import org.wso2.carbon.device.application.mgt.core.exception.BadRequestException;
import org.wso2.carbon.device.application.mgt.core.exception.UnexpectedServerErrorException; import org.wso2.carbon.device.application.mgt.core.exception.UnexpectedServerErrorException;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException; import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
import org.wso2.carbon.device.mgt.core.dto.DeviceType; import org.wso2.carbon.device.mgt.core.dto.DeviceType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
/** /**
* Holds util methods required for ApplicationDTO-Mgt API component. * Holds util methods required for ApplicationDTO-Mgt API component.
@ -204,4 +212,63 @@ public class APIUtil {
} }
} }
public static Application appDtoToAppResponse(ApplicationDTO applicationDTO)
throws BadRequestException, UnexpectedServerErrorException {
Application application = new Application();
DeviceType deviceType = getDeviceTypeData(applicationDTO.getDeviceTypeId());
application.setId(applicationDTO.getId());
application.setName(applicationDTO.getName());
application.setDescription(applicationDTO.getDescription());
application.setAppCategories(applicationDTO.getAppCategories());
application.setType(applicationDTO.getType());
application.setSubType(applicationDTO.getSubType());
application.setPaymentCurrency(applicationDTO.getPaymentCurrency());
application.setTags(applicationDTO.getTags());
application.setUnrestrictedRoles(applicationDTO.getUnrestrictedRoles());
application.setDeviceType(deviceType.getName());
application.setRating(applicationDTO.getAppRating());
List<ApplicationRelease> applicationReleases = applicationDTO.getApplicationReleaseDTOs()
.stream().map(APIUtil::releaseDtoToRelease).collect(Collectors.toList());
application.setApplicationReleases(applicationReleases);
return application;
}
public static ApplicationRelease releaseDtoToRelease(ApplicationReleaseDTO applicationReleaseDTO){
String artifactDownloadEndpoint = ConfigurationManager.getInstance().getConfiguration()
.getArtifactDownloadEndpoint();
String basePath = artifactDownloadEndpoint + Constants.FORWARD_SLASH + applicationReleaseDTO.getUuid()
+ Constants.FORWARD_SLASH;
List<String> screenshotPaths = new ArrayList<>();
ApplicationRelease applicationRelease = new ApplicationRelease();
applicationRelease.setDescription(applicationReleaseDTO.getDescription());
applicationRelease.setVersion(applicationReleaseDTO.getVersion());
applicationRelease.setUuid(applicationReleaseDTO.getUuid());
applicationRelease.setReleaseType(applicationReleaseDTO.getReleaseType());
applicationRelease.setPrice(applicationReleaseDTO.getPrice());
applicationRelease.setIsSharedWithAllTenants(applicationReleaseDTO.getIsSharedWithAllTenants());
applicationRelease.setMetaData(applicationReleaseDTO.getMetaData());
applicationRelease.setUrl(applicationReleaseDTO.getUrl());
applicationRelease.setCurrentStatus(applicationReleaseDTO.getCurrentState());
applicationRelease.setIsSharedWithAllTenants(applicationReleaseDTO.getIsSharedWithAllTenants());
applicationRelease.setSupportedOsVersions(applicationReleaseDTO.getSupportedOsVersions());
applicationRelease.setRating(applicationReleaseDTO.getRating());
applicationRelease
.setInstallerPath(basePath + applicationReleaseDTO.getInstallerName());
applicationRelease.setIconPath(basePath + applicationReleaseDTO.getIconName());
applicationRelease.setBannerPath(basePath + applicationReleaseDTO.getBannerName());
if (!StringUtils.isEmpty(applicationReleaseDTO.getScreenshotName1())) {
screenshotPaths.add(basePath + applicationReleaseDTO.getScreenshotName1());
}
if (!StringUtils.isEmpty(applicationReleaseDTO.getScreenshotName2())) {
screenshotPaths.add(basePath + applicationReleaseDTO.getScreenshotName2());
}
if (!StringUtils.isEmpty(applicationReleaseDTO.getScreenshotName3())) {
screenshotPaths.add(basePath + applicationReleaseDTO.getScreenshotName3());
}
applicationRelease.setScreenshots(screenshotPaths);
return applicationRelease;
}
} }

@ -121,7 +121,7 @@ public class DAOUtil {
deviceSubscriptionDTO.setUnsubscribed(rs.getBoolean("IS_UNSUBSCRIBED")); deviceSubscriptionDTO.setUnsubscribed(rs.getBoolean("IS_UNSUBSCRIBED"));
deviceSubscriptionDTO.setUnsubscribedBy(rs.getString("UNSUBSCRIBED_BY")); deviceSubscriptionDTO.setUnsubscribedBy(rs.getString("UNSUBSCRIBED_BY"));
deviceSubscriptionDTO.setUnsubscribedTimestamp(rs.getTimestamp("UNSUBSCRIBED_AT")); deviceSubscriptionDTO.setUnsubscribedTimestamp(rs.getTimestamp("UNSUBSCRIBED_AT"));
deviceSubscriptionDTO.setSubscribedFrom(rs.getString("SUBSCRIBED_FROM")); deviceSubscriptionDTO.setActionTriggeredFrom(rs.getString("ACTION_TRIGGERED_FROM"));
deviceSubscriptionDTO.setDeviceId(rs.getInt("DEVICE_ID")); deviceSubscriptionDTO.setDeviceId(rs.getInt("DEVICE_ID"));
deviceSubscriptionDTO.setStatus(rs.getString("STATUS")); deviceSubscriptionDTO.setStatus(rs.getString("STATUS"));
return deviceSubscriptionDTO; return deviceSubscriptionDTO;

@ -43,7 +43,7 @@ import java.util.List;
* Implementation of Application Management related APIs. * Implementation of Application Management related APIs.
*/ */
@Produces({"application/json"}) @Produces({"application/json"})
@Path("/applications") @Path("/admin/applications")
public class ApplicationManagementPublisherAdminAPIImpl implements ApplicationManagementPublisherAdminAPI { public class ApplicationManagementPublisherAdminAPIImpl implements ApplicationManagementPublisherAdminAPI {
private static Log log = LogFactory.getLog(ApplicationManagementPublisherAdminAPIImpl.class); private static Log log = LogFactory.getLog(ApplicationManagementPublisherAdminAPIImpl.class);

@ -151,6 +151,10 @@
<Scope>perm:app:publisher:view</Scope> <Scope>perm:app:publisher:view</Scope>
<Scope>perm:app:publisher:update</Scope> <Scope>perm:app:publisher:update</Scope>
<Scope>perm:app:store:view</Scope> <Scope>perm:app:store:view</Scope>
<Scope>perm:app:subscription:install</Scope>
<Scope>perm:app:subscription:uninstall</Scope>
<Scope>perm:admin:app:review:update</Scope>
<Scope>perm:admin:app:publisher:update</Scope>
</Scopes> </Scopes>
<SSOConfiguration> <SSOConfiguration>
<Issuer>app-mgt</Issuer> <Issuer>app-mgt</Issuer>

@ -54,7 +54,7 @@ CREATE INDEX fk_AP_APP_RELEASE_AP_APP1_idx ON AP_APP_RELEASE (AP_APP_ID ASC);
CREATE TABLE IF NOT EXISTS AP_APP_REVIEW( CREATE TABLE IF NOT EXISTS AP_APP_REVIEW(
ID INTEGER NOT NULL AUTO_INCREMENT, ID INTEGER NOT NULL AUTO_INCREMENT,
TENANT_ID INTEGER NOT NULL, TENANT_ID INTEGER NOT NULL,
COMMENT VARCHAR(250) NOT NULL, COMMENT TEXT NOT NULL,
ROOT_PARENT_ID INTEGER NOT NULL, ROOT_PARENT_ID INTEGER NOT NULL,
IMMEDIATE_PARENT_ID INTEGER NOT NULL, IMMEDIATE_PARENT_ID INTEGER NOT NULL,
CREATED_AT TIMESTAMP NOT NULL, CREATED_AT TIMESTAMP NOT NULL,
@ -110,7 +110,7 @@ CREATE TABLE IF NOT EXISTS AP_DEVICE_SUBSCRIPTION(
UNSUBSCRIBED BOOLEAN NULL DEFAULT NULL, UNSUBSCRIBED BOOLEAN NULL DEFAULT NULL,
UNSUBSCRIBED_BY VARCHAR(100) NULL DEFAULT NULL, UNSUBSCRIBED_BY VARCHAR(100) NULL DEFAULT NULL,
UNSUBSCRIBED_TIMESTAMP TIMESTAMP NULL DEFAULT NULL, UNSUBSCRIBED_TIMESTAMP TIMESTAMP NULL DEFAULT NULL,
SUBSCRIBED_FROM VARCHAR(45) NOT NULL, ACTION_TRIGGERED_FROM VARCHAR(45) NOT NULL,
STATUS VARCHAR(45) NOT NULL, STATUS VARCHAR(45) NOT NULL,
DM_DEVICE_ID INTEGER NOT NULL, DM_DEVICE_ID INTEGER NOT NULL,
AP_APP_RELEASE_ID INTEGER NOT NULL, AP_APP_RELEASE_ID INTEGER NOT NULL,
@ -133,7 +133,7 @@ CREATE TABLE IF NOT EXISTS AP_GROUP_SUBSCRIPTION(
UNSUBSCRIBED BOOLEAN NULL DEFAULT NULL, UNSUBSCRIBED BOOLEAN NULL DEFAULT NULL,
UNSUBSCRIBED_BY VARCHAR(100) NULL DEFAULT NULL, UNSUBSCRIBED_BY VARCHAR(100) NULL DEFAULT NULL,
UNSUBSCRIBED_TIMESTAMP TIMESTAMP NULL DEFAULT NULL, UNSUBSCRIBED_TIMESTAMP TIMESTAMP NULL DEFAULT NULL,
DM_GROUP_ID INTEGER NOT NULL, GROUP_NAME VARCHAR(100) NOT NULL,
AP_APP_RELEASE_ID INTEGER NOT NULL, AP_APP_RELEASE_ID INTEGER NOT NULL,
AP_APP_ID INTEGER NOT NULL, AP_APP_ID INTEGER NOT NULL,
PRIMARY KEY (ID), PRIMARY KEY (ID),

@ -62,15 +62,16 @@ CREATE TABLE IF NOT EXISTS `APP_MANAGER`.`AP_APP_RELEASE`
-- ----------------------------------------------------- -- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `APP_MANAGER`.`AP_APP_REVIEW` CREATE TABLE IF NOT EXISTS `APP_MANAGER`.`AP_APP_REVIEW`
( (
`ID` INT(11) NOT NULL, `ID` INT(11) NOT NULL,
`TENANT_ID` INT(11) NOT NULL, `TENANT_ID` INT(11) NOT NULL,
`COMMENT` VARCHAR(250) NOT NULL, `COMMENT` TEXT NOT NULL,
`REPLY_COMMENT` VARCHAR(250) NULL, `ROOT_PARENT_ID` INT(11) NOT NULL,
`CREATED_AT` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, `IMMEDIATE_PARENT_ID` INT(11) NOT NULL,
`MODIFIED_AT` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `CREATED_AT` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`RATING` INT(11) NOT NULL, `MODIFIED_AT` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`USERNAME` VARCHAR(45) NOT NULL, `RATING` INT(11) NOT NULL,
`AP_APP_RELEASE_ID` INT(11) NOT NULL, `USERNAME` VARCHAR(45) NOT NULL,
`AP_APP_RELEASE_ID` INT(11) NOT NULL,
PRIMARY KEY (`ID`), PRIMARY KEY (`ID`),
INDEX `fk_AP_APP_REVIEW_AP_APP_RELEASE1_idx` (`AP_APP_RELEASE_ID` ASC), INDEX `fk_AP_APP_REVIEW_AP_APP_RELEASE1_idx` (`AP_APP_RELEASE_ID` ASC),
CONSTRAINT `fk_AP_APP_REVIEW_AP_APP_RELEASE1` CONSTRAINT `fk_AP_APP_REVIEW_AP_APP_RELEASE1`
@ -134,7 +135,7 @@ CREATE TABLE IF NOT EXISTS `APP_MANAGER`.`AP_DEVICE_SUBSCRIPTION`
`UNSUBSCRIBED` TINYINT(1) NULL DEFAULT NULL, `UNSUBSCRIBED` TINYINT(1) NULL DEFAULT NULL,
`UNSUBSCRIBED_BY` VARCHAR(100) NULL DEFAULT NULL, `UNSUBSCRIBED_BY` VARCHAR(100) NULL DEFAULT NULL,
`UNSUBSCRIBED_TIMESTAMP` TIMESTAMP NULL DEFAULT NULL, `UNSUBSCRIBED_TIMESTAMP` TIMESTAMP NULL DEFAULT NULL,
`SUBSCRIBED_FROM` VARCHAR(45) NULL, `ACTION_TRIGGERED_FROM` VARCHAR(45) NULL,
`DM_DEVICE_ID` INT(11) NOT NULL, `DM_DEVICE_ID` INT(11) NOT NULL,
`AP_APP_RELEASE_ID` INT(11) NOT NULL, `AP_APP_RELEASE_ID` INT(11) NOT NULL,
PRIMARY KEY (`ID`), PRIMARY KEY (`ID`),
@ -161,7 +162,7 @@ CREATE TABLE IF NOT EXISTS `APP_MANAGER`.`AP_GROUP_SUBSCRIPTION`
`UNSUBSCRIBED` TINYINT(1) NULL DEFAULT NULL, `UNSUBSCRIBED` TINYINT(1) NULL DEFAULT NULL,
`UNSUBSCRIBED_BY` VARCHAR(100) NULL DEFAULT NULL, `UNSUBSCRIBED_BY` VARCHAR(100) NULL DEFAULT NULL,
`UNSUBSCRIBED_TIMESTAMP` TIMESTAMP NULL DEFAULT NULL, `UNSUBSCRIBED_TIMESTAMP` TIMESTAMP NULL DEFAULT NULL,
`DM_GROUP_ID` INT(11) NOT NULL, `GROUP_NAME` VARCHAR(100) NOT NULL,
`AP_APP_RELEASE_ID` INT(11) NOT NULL, `AP_APP_RELEASE_ID` INT(11) NOT NULL,
INDEX `fk_AP_GROUP_SUBSCRIPTION_AP_APP_RELEASE1_idx` (`AP_APP_RELEASE_ID` ASC), INDEX `fk_AP_GROUP_SUBSCRIPTION_AP_APP_RELEASE1_idx` (`AP_APP_RELEASE_ID` ASC),
PRIMARY KEY (`ID`), PRIMARY KEY (`ID`),

Loading…
Cancel
Save