Merge branch 'application-mgt-new' into 'application-mgt-new'

Add new application type

See merge request entgra/carbon-device-mgt!247
feature/appm-store/pbac
Charitha Goonetilleke 5 years ago
commit 0e22d24e61

@ -23,6 +23,6 @@ package org.wso2.carbon.device.application.mgt.common;
* Application Types. * Application Types.
*/ */
public enum ApplicationType { public enum ApplicationType {
ENTERPRISE, PUBLIC, WEB_APP, WEB_CLIP ENTERPRISE, PUBLIC, WEB_APP, WEB_CLIP, CUSTOM
} }

@ -31,6 +31,8 @@ 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.response.ApplicationRelease;
import org.wso2.carbon.device.application.mgt.common.response.Category; import org.wso2.carbon.device.application.mgt.common.response.Category;
import org.wso2.carbon.device.application.mgt.common.response.Tag; import org.wso2.carbon.device.application.mgt.common.response.Tag;
import org.wso2.carbon.device.application.mgt.common.wrapper.CustomAppReleaseWrapper;
import org.wso2.carbon.device.application.mgt.common.wrapper.CustomAppWrapper;
import org.wso2.carbon.device.application.mgt.common.wrapper.EntAppReleaseWrapper; import org.wso2.carbon.device.application.mgt.common.wrapper.EntAppReleaseWrapper;
import org.wso2.carbon.device.application.mgt.common.wrapper.ApplicationUpdateWrapper; import org.wso2.carbon.device.application.mgt.common.wrapper.ApplicationUpdateWrapper;
import org.wso2.carbon.device.application.mgt.common.wrapper.ApplicationWrapper; import org.wso2.carbon.device.application.mgt.common.wrapper.ApplicationWrapper;
@ -63,6 +65,9 @@ public interface ApplicationManager {
Application createPublicApp(PublicAppWrapper publicAppWrapper, ApplicationArtifact applicationArtifact) Application createPublicApp(PublicAppWrapper publicAppWrapper, ApplicationArtifact applicationArtifact)
throws ApplicationManagementException; throws ApplicationManagementException;
Application createCustomApp(CustomAppWrapper customAppWrapper, ApplicationArtifact applicationArtifact)
throws ApplicationManagementException;
/** /**
* Updates an already existing application. * Updates an already existing application.
* *
@ -203,6 +208,9 @@ public interface ApplicationManager {
ApplicationRelease updateWebAppRelease(String releaseUuid, WebAppReleaseWrapper webAppReleaseWrapper, ApplicationRelease updateWebAppRelease(String releaseUuid, WebAppReleaseWrapper webAppReleaseWrapper,
ApplicationArtifact applicationArtifact) throws ApplicationManagementException; ApplicationArtifact applicationArtifact) throws ApplicationManagementException;
ApplicationRelease updateCustomAppRelease(String releaseUuid, CustomAppReleaseWrapper customAppReleaseWrapper,
ApplicationArtifact applicationArtifact) throws ApplicationManagementException;
/*** /***
* To validate the application creating request * To validate the application creating request
* *
@ -211,9 +219,9 @@ public interface ApplicationManager {
/*** /***
* *
* @throws RequestValidatingException throws if payload does not satisfy requrements. * @throws ApplicationManagementException throws if payload does not satisfy requirements.
*/ */
<T> void validateReleaseCreatingRequest(T param) throws ApplicationManagementException; <T> void validateReleaseCreatingRequest(T param, String deviceType) throws ApplicationManagementException;
/*** /***
* *

@ -47,15 +47,15 @@ public interface ApplicationStorageManager {
/** /**
* To upload release artifacts for an ApplicationDTO. * To upload release artifacts for an Application.
* *
* @param applicationRelease ApplicationDTO Release Object. * @param applicationRelease ApplicationDTO Release Object.
* @param deviceType Compatible device tipe of the application. * @param deviceType Compatible device type of the application.
* @param binaryFile Binary File for the release. * @param binaryFile Binary File for the release.
* @throws ResourceManagementException Resource Management Exception. * @throws ResourceManagementException if IO Exception occured while saving the release artifacts in the server.
*/ */
ApplicationReleaseDTO uploadReleaseArtifact(ApplicationReleaseDTO applicationRelease, String deviceType, void uploadReleaseArtifact(ApplicationReleaseDTO applicationRelease, String deviceType, InputStream binaryFile)
InputStream binaryFile) throws ResourceManagementException; throws ResourceManagementException;
/** /**
* To upload release artifacts for an ApplicationDTO. * To upload release artifacts for an ApplicationDTO.

@ -0,0 +1,125 @@
/* Copyright (c) 2019, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. 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.common.wrapper;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import javax.validation.constraints.NotNull;
@ApiModel(value = "CustomAppReleaseWrapper", description = "This class holds the details when releasing an Custom app release to application store")
public class CustomAppReleaseWrapper {
@ApiModelProperty(name = "description",
value = "Description of the application release")
@NotNull
private String description;
@ApiModelProperty(name = "releaseType",
value = "Release type of the application release",
required = true,
example = "alpha, beta etc")
@NotNull
private String releaseType;
@ApiModelProperty(name = "price",
value = "Price of the application release",
required = true)
@NotNull
private Double price;
@ApiModelProperty(name = "isSharedWithAllTenants",
value = "If application release is shared with all tenants it is eqal to 1 otherwise 0",
required = true)
@NotNull
private boolean isSharedWithAllTenants;
@ApiModelProperty(name = "metaData",
value = "Meta data of the application release",
required = true)
private String metaData;
@ApiModelProperty(name = "version",
value = "Version of the public app release.",
required = true)
@NotNull
private String version;
@ApiModelProperty(name = "packageName",
value = "Package name of the public app release.",
required = true)
@NotNull
private String packageName;
public String getReleaseType() {
return releaseType;
}
public void setReleaseType(String releaseType) {
this.releaseType = releaseType;
}
public void setIsSharedWithAllTenants(boolean isSharedWithAllTenants) {
this.isSharedWithAllTenants = isSharedWithAllTenants;
}
public void setMetaData(String metaData) {
this.metaData = metaData;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public boolean getIsSharedWithAllTenants() {
return isSharedWithAllTenants;
}
public String getMetaData() {
return metaData;
}
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public boolean isSharedWithAllTenants() { return isSharedWithAllTenants; }
public void setSharedWithAllTenants(boolean sharedWithAllTenants) {
isSharedWithAllTenants = sharedWithAllTenants;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getPackageName() {
return packageName;
}
public void setPackageName(String packageName) {
this.packageName = packageName;
}
}

@ -0,0 +1,123 @@
/* Copyright (c) 2019, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. 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.common.wrapper;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import javax.validation.constraints.NotNull;
import java.util.List;
@ApiModel(value = "CustomAppWrapper", description = "CustomAppWrapper represents an Application used to install in IoT devices")
public class CustomAppWrapper {
@ApiModelProperty(name = "name",
value = "Name of the application",
required = true)
@NotNull
private String name;
@ApiModelProperty(name = "description",
value = "Description of the application",
required = true)
@NotNull
private String description;
@ApiModelProperty(name = "categories",
value = "CategoryDTO of the application",
required = true,
example = "Educational, Gaming, Travel, Entertainment etc")
@NotNull
private List<String> categories;
@ApiModelProperty(name = "subMethod",
value = "Subscription type of the application",
required = true,
example = "PAID, FREE")
@NotNull
private String subMethod;
@ApiModelProperty(name = "paymentCurrency",
value = "Payment currency of the application",
required = true,
example = "$")
private String paymentCurrency;
@ApiModelProperty(name = "tags",
value = "List of application tags")
@NotNull
private List<String> tags;
@ApiModelProperty(name = "unrestrictedRoles",
value = "List of roles that users should have to access the application")
@NotNull
private List<String> unrestrictedRoles;
@ApiModelProperty(name = "deviceType",
value = "Related device type of the application",
required = true,
example = "IoS, Android, Arduino, RaspberryPi etc")
@NotNull
private String deviceType;
@ApiModelProperty(name = "customAppReleaseWrappers",
value = "List of custom app releases",
required = true)
@NotNull
private List<CustomAppReleaseWrapper> customAppReleaseWrappers;
public String getName() {
return name;
}
public void setName(String name) { this.name = name; }
public List<String> getCategories() { return categories; }
public void setCategories(List<String> categories) {
this.categories = categories;
}
public List<String> getTags() { return tags; }
public void setTags(List<String> tags) { this.tags = tags; }
public String getSubMethod() { return subMethod; }
public void setSubMethod(String subMethod) { this.subMethod = subMethod; }
public String getPaymentCurrency() { return paymentCurrency; }
public void setPaymentCurrency(String paymentCurrency) { this.paymentCurrency = paymentCurrency; }
public List<CustomAppReleaseWrapper> getCustomAppReleaseWrappers() { return customAppReleaseWrappers; }
public void setCustomAppReleaseWrappers(List<CustomAppReleaseWrapper> customAppReleaseWrappers) {
this.customAppReleaseWrappers = customAppReleaseWrappers; }
public List<String> getUnrestrictedRoles() { return unrestrictedRoles; }
public void setUnrestrictedRoles(List<String> unrestrictedRoles) { this.unrestrictedRoles = unrestrictedRoles; }
public String getDeviceType() { return deviceType; }
public void setDeviceType(String deviceType) { this.deviceType = deviceType; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
}

@ -56,6 +56,8 @@ import org.wso2.carbon.device.application.mgt.common.response.Category;
import org.wso2.carbon.device.application.mgt.common.response.Tag; import org.wso2.carbon.device.application.mgt.common.response.Tag;
import org.wso2.carbon.device.application.mgt.common.services.ApplicationManager; import org.wso2.carbon.device.application.mgt.common.services.ApplicationManager;
import org.wso2.carbon.device.application.mgt.common.services.ApplicationStorageManager; import org.wso2.carbon.device.application.mgt.common.services.ApplicationStorageManager;
import org.wso2.carbon.device.application.mgt.common.wrapper.CustomAppReleaseWrapper;
import org.wso2.carbon.device.application.mgt.common.wrapper.CustomAppWrapper;
import org.wso2.carbon.device.application.mgt.common.wrapper.EntAppReleaseWrapper; import org.wso2.carbon.device.application.mgt.common.wrapper.EntAppReleaseWrapper;
import org.wso2.carbon.device.application.mgt.common.wrapper.ApplicationUpdateWrapper; import org.wso2.carbon.device.application.mgt.common.wrapper.ApplicationUpdateWrapper;
import org.wso2.carbon.device.application.mgt.common.wrapper.ApplicationWrapper; import org.wso2.carbon.device.application.mgt.common.wrapper.ApplicationWrapper;
@ -133,49 +135,31 @@ public class ApplicationManagerImpl implements ApplicationManager {
@Override @Override
public Application createEntApp(ApplicationWrapper applicationWrapper, public Application createEntApp(ApplicationWrapper applicationWrapper,
ApplicationArtifact applicationArtifact) throws ApplicationManagementException { ApplicationArtifact applicationArtifact) throws ApplicationManagementException {
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true);
String userName = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername();
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("Application create request is received for the tenant : " + tenantId + " and the user: " log.debug("Ent. Application create request is received. Application name: " + applicationWrapper.getName()
+ userName); + " Device type: " + applicationWrapper.getDeviceType());
} }
ApplicationDTO applicationDTO = APIUtil.convertToAppDTO(applicationWrapper); ApplicationDTO applicationDTO = APIUtil.convertToAppDTO(applicationWrapper);
ApplicationReleaseDTO applicationReleaseDTO = applicationDTO.getApplicationReleaseDTOs().get(0);
if (!isValidOsVersions(applicationReleaseDTO.getSupportedOsVersions(), applicationWrapper.getDeviceType())) {
String msg = "You are trying to create application which has an application release contains invalid or "
+ "unsupported OS versions in the supportedOsVersions section. Hence, please re-evaluate the "
+ "request payload.";
log.error(msg);
throw new BadRequestException(msg);
}
//uploading application artifacts //uploading application artifacts
applicationReleaseDTO = uploadEntAppReleaseArtifacts(applicationReleaseDTO, applicationArtifact, ApplicationReleaseDTO applicationReleaseDTO = uploadEntAppReleaseArtifacts(
applicationDTO.getApplicationReleaseDTOs().get(0), applicationArtifact,
applicationWrapper.getDeviceType(), false); applicationWrapper.getDeviceType(), false);
applicationDTO.getApplicationReleaseDTOs().clear(); applicationDTO.getApplicationReleaseDTOs().clear();
applicationDTO.getApplicationReleaseDTOs().add(applicationReleaseDTO); applicationDTO.getApplicationReleaseDTOs().add(applicationReleaseDTO);
return addAppDataIntoDB(applicationDTO, tenantId); return addAppDataIntoDB(applicationDTO);
} }
@Override @Override
public Application createWebClip(WebAppWrapper webAppWrapper, ApplicationArtifact applicationArtifact) public Application createWebClip(WebAppWrapper webAppWrapper, ApplicationArtifact applicationArtifact)
throws ApplicationManagementException { throws ApplicationManagementException {
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true);
String userName = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername();
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("Web clip create request is received for the tenant : " + tenantId + " From" + " the user : " log.debug("Web clip create request is received. App name: " + webAppWrapper.getName() + " Device type: "
+ userName); + Constants.ANY);
} }
ApplicationDTO applicationDTO = APIUtil.convertToAppDTO(webAppWrapper); ApplicationDTO applicationDTO = APIUtil.convertToAppDTO(webAppWrapper);
ApplicationReleaseDTO applicationReleaseDTO = applicationDTO.getApplicationReleaseDTOs().get(0); ApplicationReleaseDTO applicationReleaseDTO = applicationDTO.getApplicationReleaseDTOs().get(0);
String uuid = UUID.randomUUID().toString(); applicationReleaseDTO.setUuid(UUID.randomUUID().toString());
String md5 = DigestUtils.md5Hex(applicationReleaseDTO.getInstallerName()); applicationReleaseDTO.setAppHashValue(DigestUtils.md5Hex(applicationReleaseDTO.getInstallerName()));
applicationReleaseDTO.setUuid(uuid);
applicationReleaseDTO.setAppHashValue(md5);
//uploading application artifacts //uploading application artifacts
try { try {
applicationDTO.getApplicationReleaseDTOs().clear(); applicationDTO.getApplicationReleaseDTOs().clear();
@ -185,46 +169,31 @@ public class ApplicationManagerImpl implements ApplicationManager {
log.error(msg); log.error(msg);
throw new ApplicationManagementException(msg, e); throw new ApplicationManagementException(msg, e);
} }
//insert application data into database //insert application data into database
return addAppDataIntoDB(applicationDTO, tenantId); return addAppDataIntoDB(applicationDTO);
} }
@Override @Override
public Application createPublicApp(PublicAppWrapper publicAppWrapper, ApplicationArtifact applicationArtifact) public Application createPublicApp(PublicAppWrapper publicAppWrapper, ApplicationArtifact applicationArtifact)
throws ApplicationManagementException { throws ApplicationManagementException {
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true);
String userName = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername();
String publicAppStorePath = "";
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("Public app creating request is received for the tenant : " + tenantId + " From" + " the user : " log.debug("Public app creating request is received. App name: " + publicAppWrapper.getName()
+ userName); + " Device Type: " + publicAppWrapper.getDeviceType());
}
if (!isValidOsVersions(publicAppWrapper.getPublicAppReleaseWrappers().get(0).getSupportedOsVersions(),
publicAppWrapper.getDeviceType())) {
String msg = "You are trying to add application release which has invalid or unsupported OS versions in "
+ "the supportedOsVersions section. Hence, please re-evaluate the request payload.";
log.error(msg);
throw new BadRequestException(msg);
} }
String publicAppStorePath = "";
if (DeviceTypes.ANDROID.toString().equals(publicAppWrapper.getDeviceType())) { if (DeviceTypes.ANDROID.toString().equals(publicAppWrapper.getDeviceType())) {
publicAppStorePath = Constants.GOOGLE_PLAY_STORE_URL; publicAppStorePath = Constants.GOOGLE_PLAY_STORE_URL;
} else if (DeviceTypes.IOS.toString().equals(publicAppWrapper.getDeviceType())) { } else if (DeviceTypes.IOS.toString().equals(publicAppWrapper.getDeviceType())) {
publicAppStorePath = Constants.APPLE_STORE_URL; publicAppStorePath = Constants.APPLE_STORE_URL;
} }
ApplicationDTO applicationDTO = APIUtil.convertToAppDTO(publicAppWrapper); ApplicationDTO applicationDTO = APIUtil.convertToAppDTO(publicAppWrapper);
ApplicationReleaseDTO applicationReleaseDTO = applicationDTO.getApplicationReleaseDTOs().get(0); ApplicationReleaseDTO applicationReleaseDTO = applicationDTO.getApplicationReleaseDTOs().get(0);
String uuid = UUID.randomUUID().toString();
String appInstallerUrl = publicAppStorePath + applicationReleaseDTO.getPackageName(); String appInstallerUrl = publicAppStorePath + applicationReleaseDTO.getPackageName();
//todo check app package name exist or not, do it in validation method //todo check app package name exist or not, do it in validation method
applicationReleaseDTO.setInstallerName(appInstallerUrl); applicationReleaseDTO.setInstallerName(appInstallerUrl);
String md5 = DigestUtils.md5Hex(appInstallerUrl); applicationReleaseDTO.setUuid(UUID.randomUUID().toString());
applicationReleaseDTO.setUuid(uuid); applicationReleaseDTO.setAppHashValue(DigestUtils.md5Hex(appInstallerUrl));
applicationReleaseDTO.setAppHashValue(md5);
//uploading application artifacts //uploading application artifacts
try { try {
applicationDTO.getApplicationReleaseDTOs().clear(); applicationDTO.getApplicationReleaseDTOs().clear();
@ -235,9 +204,70 @@ public class ApplicationManagerImpl implements ApplicationManager {
log.error(msg, e); log.error(msg, e);
throw new ApplicationManagementException(msg, e); throw new ApplicationManagementException(msg, e);
} }
//insert application data into database //insert application data into database
return addAppDataIntoDB(applicationDTO, tenantId); return addAppDataIntoDB(applicationDTO);
}
@Override
public Application createCustomApp(CustomAppWrapper customAppWrapper, ApplicationArtifact applicationArtifact)
throws ApplicationManagementException {
try {
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true);
ApplicationStorageManager applicationStorageManager = DAOUtil.getApplicationStorageManager();
byte[] content = IOUtils.toByteArray(applicationArtifact.getInstallerStream());
String md5OfApp = StorageManagementUtil.getMD5(new ByteArrayInputStream(content));
if (md5OfApp == null) {
String msg =
"Error occurred while getting md5sum value of custom app. Application name: " + customAppWrapper
.getName() + " Device type: " + customAppWrapper.getDeviceType();
log.error(msg);
throw new ApplicationManagementException(msg);
}
try {
ConnectionManagerUtil.openDBConnection();
if (this.applicationReleaseDAO.verifyReleaseExistenceByHash(md5OfApp, tenantId)) {
String msg = "Application release exists for the uploaded binary file. Application name: "
+ customAppWrapper.getName() + " Device type: " + customAppWrapper.getDeviceType();
log.error(msg);
throw new BadRequestException(msg);
}
} catch (ApplicationManagementDAOException e) {
String msg = "Error occurred while adding application data into the database. Application name: "
+ customAppWrapper.getName() + " Device type: " + customAppWrapper.getDeviceType();
log.error(msg, e);
throw new ApplicationManagementException(msg, e);
} finally {
ConnectionManagerUtil.closeDBConnection();
}
ApplicationDTO applicationDTO = APIUtil.convertToAppDTO(customAppWrapper);
ApplicationReleaseDTO applicationReleaseDTO = applicationDTO.getApplicationReleaseDTOs().get(0);
applicationReleaseDTO.setUuid(UUID.randomUUID().toString());
applicationReleaseDTO.setAppHashValue(md5OfApp);
applicationReleaseDTO.setInstallerName(applicationArtifact.getInstallerName());
try (ByteArrayInputStream binaryDuplicate = new ByteArrayInputStream(content)) {
applicationStorageManager.uploadReleaseArtifact(applicationReleaseDTO, customAppWrapper.getDeviceType(),
binaryDuplicate);
} catch (IOException e) {
String msg = "Error occurred when uploading release artifact into the server.";
log.error(msg);
throw new ApplicationManagementException(msg);
}
applicationReleaseDTO = addImageArtifacts(applicationReleaseDTO, applicationArtifact);
applicationDTO.getApplicationReleaseDTOs().clear();
applicationDTO.getApplicationReleaseDTOs().add(applicationReleaseDTO);
return addAppDataIntoDB(applicationDTO);
} catch (ResourceManagementException e) {
String msg = "Error occurred while uploading application artifact into the server. Application name: "
+ customAppWrapper.getName() + " Device type: " + customAppWrapper.getDeviceType();
log.error(msg, e);
throw new ApplicationManagementException(msg, e);
} catch (IOException e) {
String msg = "Error occurred while getting bytes from application release artifact. Application name: "
+ customAppWrapper.getName() + " Device type: " + customAppWrapper.getDeviceType();
log.error(msg, e);
throw new ApplicationManagementException(msg, e);
}
} }
private void deleteApplicationArtifacts(List<String> directoryPaths) throws ApplicationManagementException { private void deleteApplicationArtifacts(List<String> directoryPaths) throws ApplicationManagementException {
@ -264,9 +294,7 @@ public class ApplicationManagerImpl implements ApplicationManager {
// The application executable artifacts such as apks are uploaded. // The application executable artifacts such as apks are uploaded.
try { try {
byte[] content = IOUtils.toByteArray(applicationArtifact.getInstallerStream()); byte[] content = IOUtils.toByteArray(applicationArtifact.getInstallerStream());
applicationReleaseDTO.setInstallerName(applicationArtifact.getInstallerName()); applicationReleaseDTO.setInstallerName(applicationArtifact.getInstallerName());
try (ByteArrayInputStream binary = new ByteArrayInputStream(content)) { try (ByteArrayInputStream binary = new ByteArrayInputStream(content)) {
ApplicationInstaller applicationInstaller = applicationStorageManager ApplicationInstaller applicationInstaller = applicationStorageManager
.getAppInstallerData(binary, deviceType); .getAppInstallerData(binary, deviceType);
@ -286,7 +314,6 @@ public class ApplicationManagerImpl implements ApplicationManager {
} }
applicationReleaseDTO.setVersion(applicationInstaller.getVersion()); applicationReleaseDTO.setVersion(applicationInstaller.getVersion());
applicationReleaseDTO.setPackageName(packagename); applicationReleaseDTO.setPackageName(packagename);
String md5OfApp = StorageManagementUtil.getMD5(new ByteArrayInputStream(content)); String md5OfApp = StorageManagementUtil.getMD5(new ByteArrayInputStream(content));
if (md5OfApp == null) { if (md5OfApp == null) {
String msg = "Error occurred while md5sum value retrieving process: application UUID " String msg = "Error occurred while md5sum value retrieving process: application UUID "
@ -303,7 +330,7 @@ public class ApplicationManagerImpl implements ApplicationManager {
applicationReleaseDTO.setAppHashValue(md5OfApp); applicationReleaseDTO.setAppHashValue(md5OfApp);
try (ByteArrayInputStream binaryDuplicate = new ByteArrayInputStream(content)) { try (ByteArrayInputStream binaryDuplicate = new ByteArrayInputStream(content)) {
applicationReleaseDTO = applicationStorageManager applicationStorageManager
.uploadReleaseArtifact(applicationReleaseDTO, deviceType, binaryDuplicate); .uploadReleaseArtifact(applicationReleaseDTO, deviceType, binaryDuplicate);
} }
} catch (DBConnectionException e) { } catch (DBConnectionException e) {
@ -384,7 +411,7 @@ public class ApplicationManagerImpl implements ApplicationManager {
String deletingAppHashValue = applicationReleaseDTO.getAppHashValue(); String deletingAppHashValue = applicationReleaseDTO.getAppHashValue();
applicationReleaseDTO.setAppHashValue(md5OfApp); applicationReleaseDTO.setAppHashValue(md5OfApp);
try (ByteArrayInputStream binaryDuplicate = new ByteArrayInputStream(content)) { try (ByteArrayInputStream binaryDuplicate = new ByteArrayInputStream(content)) {
applicationReleaseDTO = applicationStorageManager applicationStorageManager
.uploadReleaseArtifact(applicationReleaseDTO, deviceType, binaryDuplicate); .uploadReleaseArtifact(applicationReleaseDTO, deviceType, binaryDuplicate);
applicationStorageManager.copyImageArtifactsAndDeleteInstaller(deletingAppHashValue, applicationStorageManager.copyImageArtifactsAndDeleteInstaller(deletingAppHashValue,
applicationReleaseDTO); applicationReleaseDTO);
@ -624,12 +651,11 @@ public class ApplicationManagerImpl implements ApplicationManager {
* required to do the validation of request and check the existence of application releaseDTO. * required to do the validation of request and check the existence of application releaseDTO.
* *
* @param applicationDTO Application DTO object. * @param applicationDTO Application DTO object.
* @param tenantId Tenant Id
* @return {@link Application} * @return {@link Application}
* @throws ApplicationManagementException which throws if error occurs while during application management. * @throws ApplicationManagementException which throws if error occurs while during application management.
*/ */
private Application addAppDataIntoDB(ApplicationDTO applicationDTO, int tenantId) private Application addAppDataIntoDB(ApplicationDTO applicationDTO) throws ApplicationManagementException {
throws ApplicationManagementException { int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true);
ApplicationStorageManager applicationStorageManager = DAOUtil.getApplicationStorageManager(); ApplicationStorageManager applicationStorageManager = DAOUtil.getApplicationStorageManager();
List<String> unrestrictedRoles = applicationDTO.getUnrestrictedRoles(); List<String> unrestrictedRoles = applicationDTO.getUnrestrictedRoles();
ApplicationReleaseDTO applicationReleaseDTO = applicationDTO.getApplicationReleaseDTOs().get(0); ApplicationReleaseDTO applicationReleaseDTO = applicationDTO.getApplicationReleaseDTOs().get(0);
@ -2492,6 +2518,130 @@ public class ApplicationManagerImpl implements ApplicationManager {
} }
} }
@Override
public ApplicationRelease updateCustomAppRelease(String releaseUuid,
CustomAppReleaseWrapper customAppReleaseWrapper, ApplicationArtifact applicationArtifact)
throws ApplicationManagementException {
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true);
ApplicationStorageManager applicationStorageManager = DAOUtil.getApplicationStorageManager();
try {
ConnectionManagerUtil.beginDBTransaction();
ApplicationDTO applicationDTO = this.applicationDAO.getAppWithRelatedRelease(releaseUuid, tenantId);
AtomicReference<ApplicationReleaseDTO> applicationReleaseDTO = new AtomicReference<>(
applicationDTO.getApplicationReleaseDTOs().get(0));
validateAppReleaseUpdating(applicationDTO, ApplicationType.ENTERPRISE.toString());
applicationReleaseDTO.get().setPrice(customAppReleaseWrapper.getPrice());
applicationReleaseDTO.get()
.setIsSharedWithAllTenants(applicationReleaseDTO.get().getIsSharedWithAllTenants());
if (!StringUtils.isEmpty(customAppReleaseWrapper.getPackageName())) {
applicationReleaseDTO.get().setVersion(customAppReleaseWrapper.getVersion());
}
if (!StringUtils.isEmpty(customAppReleaseWrapper.getVersion())) {
applicationReleaseDTO.get().setVersion(customAppReleaseWrapper.getVersion());
}
if (!StringUtils.isEmpty(customAppReleaseWrapper.getDescription())) {
applicationReleaseDTO.get().setDescription(customAppReleaseWrapper.getDescription());
}
if (!StringUtils.isEmpty(customAppReleaseWrapper.getReleaseType())) {
applicationReleaseDTO.get().setReleaseType(customAppReleaseWrapper.getReleaseType());
}
if (!StringUtils.isEmpty(customAppReleaseWrapper.getMetaData())) {
applicationReleaseDTO.get().setMetaData(customAppReleaseWrapper.getMetaData());
}
if (!StringUtils.isEmpty(applicationArtifact.getInstallerName())
&& applicationArtifact.getInstallerStream() != null) {
DeviceType deviceTypeObj = APIUtil.getDeviceTypeData(applicationDTO.getDeviceTypeId());
// The application executable artifacts such as deb are uploaded.
try {
byte[] content = IOUtils.toByteArray(applicationArtifact.getInstallerStream());
try (ByteArrayInputStream binaryClone = new ByteArrayInputStream(content)) {
String md5OfApp = StorageManagementUtil.getMD5(binaryClone);
if (md5OfApp == null) {
String msg = "Error occurred while retrieving md5sum value from the binary file for "
+ "application release UUID " + applicationReleaseDTO.get().getUuid();
log.error(msg);
throw new ApplicationStorageManagementException(msg);
}
if (!applicationReleaseDTO.get().getAppHashValue().equals(md5OfApp)) {
applicationReleaseDTO.get().setInstallerName(applicationArtifact.getInstallerName());
try {
ConnectionManagerUtil.getDBConnection();
if (this.applicationReleaseDAO.verifyReleaseExistenceByHash(md5OfApp, tenantId)) {
String msg =
"Same binary file is in the server. Hence you can't add same file into the "
+ "server. Device Type: " + deviceTypeObj.getName()
+ " and package name: " + applicationDTO.getApplicationReleaseDTOs()
.get(0).getPackageName();
log.error(msg);
throw new BadRequestException(msg);
}
String deletingAppHashValue = applicationReleaseDTO.get().getAppHashValue();
applicationReleaseDTO.get().setAppHashValue(md5OfApp);
try (ByteArrayInputStream binaryDuplicate = new ByteArrayInputStream(content)) {
applicationStorageManager
.uploadReleaseArtifact(applicationReleaseDTO.get(), deviceTypeObj.getName(),
binaryDuplicate);
applicationStorageManager.copyImageArtifactsAndDeleteInstaller(deletingAppHashValue,
applicationReleaseDTO.get());
}
} catch (DBConnectionException e) {
String msg = "Error occurred when getting database connection for verifying application"
+ " release existing for new app hash value.";
log.error(msg, e);
throw new ApplicationManagementException(msg, e);
} catch (ApplicationManagementDAOException e) {
String msg =
"Error occurred when executing the query for verifying application release "
+ "existence for the new app hash value.";
log.error(msg, e);
throw new ApplicationManagementException(msg, e);
} finally {
ConnectionManagerUtil.closeDBConnection();
}
}
}
} catch (IOException e) {
String msg = "Error occurred when getting byte array of binary file. Installer name: "
+ applicationArtifact.getInstallerName();
log.error(msg, e);
throw new ApplicationStorageManagementException(msg, e);
}
}
applicationReleaseDTO.set(updateImageArtifacts(applicationReleaseDTO.get(), applicationArtifact));
boolean updateStatus = applicationReleaseDAO.updateRelease(applicationReleaseDTO.get(), tenantId) != null;
if (!updateStatus) {
ConnectionManagerUtil.rollbackDBTransaction();
return null;
}
ConnectionManagerUtil.commitDBTransaction();
return APIUtil.releaseDtoToRelease(applicationReleaseDTO.get());
} catch (DBConnectionException e) {
String msg = "Error occurred while getting the database connection to update enterprise app release which "
+ "has release UUID: " + releaseUuid;
log.error(msg, e);
throw new ApplicationManagementException(msg, e);
} catch (TransactionManagementException e) {
String msg = "Database access error is occurred when updating enterprise app release which has release "
+ "UUID: " + releaseUuid;
log.error(msg, e);
throw new ApplicationManagementException(msg, e);
} catch (ApplicationManagementDAOException e) {
ConnectionManagerUtil.rollbackDBTransaction();
String msg = "Error occured when updating Ent Application release of UUID: " + releaseUuid;
log.error(msg, e);
throw new ApplicationManagementException(msg, e);
} catch (ResourceManagementException e) {
String msg = "Error occured when updating application release artifact in the file system. Ent App release "
+ "UUID:" + releaseUuid;
log.error(msg, e);
throw new ApplicationManagementException(msg, e);
} finally {
ConnectionManagerUtil.closeDBConnection();
}
}
private void validateAppReleaseUpdating(ApplicationDTO applicationDTO, String appType) private void validateAppReleaseUpdating(ApplicationDTO applicationDTO, String appType)
throws ApplicationManagementException { throws ApplicationManagementException {
if (applicationDTO == null) { if (applicationDTO == null) {
@ -2660,6 +2810,43 @@ public class ApplicationManagerImpl implements ApplicationManager {
throw new BadRequestException(msg); throw new BadRequestException(msg);
} }
unrestrictedRoles = publicAppWrapper.getUnrestrictedRoles(); unrestrictedRoles = publicAppWrapper.getUnrestrictedRoles();
} else if (param instanceof CustomAppWrapper) {
CustomAppWrapper customAppWrapper = (CustomAppWrapper) param;
appName = customAppWrapper.getName();
if (StringUtils.isEmpty(appName)) {
String msg = "Application name cannot be empty.";
log.error(msg);
throw new BadRequestException(msg);
}
appCategories = customAppWrapper.getCategories();
if (appCategories == null) {
String msg = "Application category can't be null.";
log.error(msg);
throw new BadRequestException(msg);
}
if (appCategories.isEmpty()) {
String msg = "Application category can't be empty.";
log.error(msg);
throw new BadRequestException(msg);
}
if (StringUtils.isEmpty(customAppWrapper.getDeviceType())) {
String msg = "Device type can't be empty for the application.";
log.error(msg);
throw new BadRequestException(msg);
}
DeviceType deviceType = APIUtil.getDeviceTypeData(customAppWrapper.getDeviceType());
deviceTypeId = deviceType.getId();
List<CustomAppReleaseWrapper> customAppReleaseWrappers;
customAppReleaseWrappers = customAppWrapper.getCustomAppReleaseWrappers();
if (customAppReleaseWrappers == null || customAppReleaseWrappers.size() != 1) {
String msg = "Invalid custom app creating request. Application creating request must have single "
+ "application release. Application name:" + customAppWrapper.getName() + ".";
log.error(msg);
throw new BadRequestException(msg);
}
unrestrictedRoles = customAppWrapper.getUnrestrictedRoles();
} else { } else {
String msg = "Invalid payload found with the request. Hence verify the request payload object."; String msg = "Invalid payload found with the request. Hence verify the request payload object.";
log.error(msg); log.error(msg);
@ -2738,7 +2925,7 @@ public class ApplicationManagerImpl implements ApplicationManager {
} }
@Override @Override
public <T> void validateReleaseCreatingRequest(T param) throws ApplicationManagementException { public <T> void validateReleaseCreatingRequest(T param, String deviceType) throws ApplicationManagementException {
if (param == null) { if (param == null) {
String msg = "In order to validate release creating request param shouldn't be null."; String msg = "In order to validate release creating request param shouldn't be null.";
log.error(msg); log.error(msg);
@ -2746,12 +2933,20 @@ public class ApplicationManagerImpl implements ApplicationManager {
} }
if (param instanceof EntAppReleaseWrapper) { if (param instanceof EntAppReleaseWrapper) {
EntAppReleaseWrapper entAppReleaseWrapper = (EntAppReleaseWrapper) param; AtomicReference<EntAppReleaseWrapper> entAppReleaseWrapper = new AtomicReference<>(
if (StringUtils.isEmpty(entAppReleaseWrapper.getSupportedOsVersions())) { (EntAppReleaseWrapper) param);
if (StringUtils.isEmpty(entAppReleaseWrapper.get().getSupportedOsVersions())) {
String msg = "Supported OS Version shouldn't be null or empty."; String msg = "Supported OS Version shouldn't be null or empty.";
log.error(msg); log.error(msg);
throw new BadRequestException(msg); throw new BadRequestException(msg);
} }
if (!isValidOsVersions(entAppReleaseWrapper.get().getSupportedOsVersions(), deviceType)) {
String msg = "You are trying to create application which has an application release contains invalid or "
+ "unsupported OS versions in the supportedOsVersions section. Hence, please re-evaluate the "
+ "request payload.";
log.error(msg);
throw new BadRequestException(msg);
}
} else if (param instanceof WebAppReleaseWrapper) { } else if (param instanceof WebAppReleaseWrapper) {
WebAppReleaseWrapper webAppReleaseWrapper = (WebAppReleaseWrapper) param; WebAppReleaseWrapper webAppReleaseWrapper = (WebAppReleaseWrapper) param;
UrlValidator urlValidator = new UrlValidator(); UrlValidator urlValidator = new UrlValidator();
@ -2788,7 +2983,25 @@ public class ApplicationManagerImpl implements ApplicationManager {
log.error(msg); log.error(msg);
throw new BadRequestException(msg); throw new BadRequestException(msg);
} }
if (!isValidOsVersions(publicAppReleaseWrapper.getSupportedOsVersions(), deviceType)) {
String msg = "You are trying to create application which has an application release contains invalid or "
+ "unsupported OS versions in the supportedOsVersions section. Hence, please re-evaluate the "
+ "request payload.";
log.error(msg);
throw new BadRequestException(msg);
}
} else if (param instanceof CustomAppReleaseWrapper) {
CustomAppReleaseWrapper customAppReleaseWrapper = (CustomAppReleaseWrapper) param;
if (StringUtils.isEmpty(customAppReleaseWrapper.getVersion())) {
String msg = "Version shouldn't be empty or null for the custom App release creating request.";
log.error(msg);
throw new BadRequestException(msg);
}
if (StringUtils.isEmpty(customAppReleaseWrapper.getPackageName())) {
String msg = "Package name shouldn't be empty or null for the custom App release creating request.";
log.error(msg);
throw new BadRequestException(msg);
}
} else { } else {
String msg = "Invalid payload found with the release creating request. Hence verify the release creating " String msg = "Invalid payload found with the release creating request. Hence verify the release creating "
+ "request payload object."; + "request payload object.";
@ -2814,7 +3027,6 @@ public class ApplicationManagerImpl implements ApplicationManager {
@Override @Override
public void validateBinaryArtifact(Attachment binaryFile) throws RequestValidatingException { public void validateBinaryArtifact(Attachment binaryFile) throws RequestValidatingException {
if (binaryFile == null) { if (binaryFile == null) {
String msg = "Binary file is not found with the application release creating request for ENTERPRISE app " String msg = "Binary file is not found with the application release creating request for ENTERPRISE app "
+ "creating request."; + "creating request.";

@ -143,25 +143,21 @@ public class ApplicationStorageManagerImpl implements ApplicationStorageManager
} }
@Override @Override
public ApplicationReleaseDTO uploadReleaseArtifact(ApplicationReleaseDTO applicationReleaseDTO, public void uploadReleaseArtifact(ApplicationReleaseDTO applicationReleaseDTO,
String deviceType, InputStream binaryFile) throws ResourceManagementException { String deviceType, InputStream binaryFile) throws ResourceManagementException {
try { try {
String artifactDirectoryPath;
String artifactPath;
byte [] content = IOUtils.toByteArray(binaryFile); byte [] content = IOUtils.toByteArray(binaryFile);
String artifactDirectoryPath =
artifactDirectoryPath =
storagePath + applicationReleaseDTO.getAppHashValue() + File.separator + Constants.APP_ARTIFACT; storagePath + applicationReleaseDTO.getAppHashValue() + File.separator + Constants.APP_ARTIFACT;
StorageManagementUtil.createArtifactDirectory(artifactDirectoryPath); StorageManagementUtil.createArtifactDirectory(artifactDirectoryPath);
artifactPath = artifactDirectoryPath + File.separator + applicationReleaseDTO.getInstallerName(); String artifactPath = artifactDirectoryPath + File.separator + applicationReleaseDTO.getInstallerName();
saveFile(new ByteArrayInputStream(content), artifactPath); saveFile(new ByteArrayInputStream(content), artifactPath);
} catch (IOException e) { } catch (IOException e) {
String msg = "IO Exception while saving the release artifacts in the server for the application UUID " String msg = "IO Exception while saving the release artifacts in the server for the application UUID "
+ applicationReleaseDTO.getUuid(); + applicationReleaseDTO.getUuid();
log.error(msg, e); log.error(msg, e);
throw new ApplicationStorageManagementException( msg, e); throw new ResourceManagementException( msg, e);
} }
return applicationReleaseDTO;
} }
@Override @Override

@ -51,8 +51,9 @@ import org.wso2.carbon.device.application.mgt.core.util.HelperUtil;
import org.wso2.carbon.device.mgt.common.Device; import org.wso2.carbon.device.mgt.common.Device;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier; import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import org.wso2.carbon.device.mgt.common.MDMAppConstants; import org.wso2.carbon.device.mgt.common.MDMAppConstants;
import org.wso2.carbon.device.mgt.common.app.mgt.MobileApp; import org.wso2.carbon.device.mgt.common.app.mgt.App;
import org.wso2.carbon.device.mgt.common.app.mgt.MobileAppTypes; import org.wso2.carbon.device.mgt.common.app.mgt.MobileAppTypes;
import org.wso2.carbon.device.mgt.common.app.mgt.android.CustomApplication;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException; import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.exceptions.InvalidDeviceException; import org.wso2.carbon.device.mgt.common.exceptions.InvalidDeviceException;
import org.wso2.carbon.device.mgt.common.exceptions.UnknownApplicationTypeException; import org.wso2.carbon.device.mgt.common.exceptions.UnknownApplicationTypeException;
@ -62,6 +63,7 @@ import org.wso2.carbon.device.mgt.common.operation.mgt.ActivityStatus;
import org.wso2.carbon.device.mgt.common.operation.mgt.Operation; 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.operation.mgt.OperationManagementException;
import org.wso2.carbon.device.mgt.core.dto.DeviceType; import org.wso2.carbon.device.mgt.core.dto.DeviceType;
import org.wso2.carbon.device.mgt.core.operation.mgt.ProfileOperation;
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
import org.wso2.carbon.device.mgt.core.service.GroupManagementProviderService; import org.wso2.carbon.device.mgt.core.service.GroupManagementProviderService;
import org.wso2.carbon.device.mgt.core.util.MDMAndroidOperationUtil; import org.wso2.carbon.device.mgt.core.util.MDMAndroidOperationUtil;
@ -460,16 +462,16 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
private Operation generateOperationPayloadByDeviceType(String deviceType, Application application, String action) private Operation generateOperationPayloadByDeviceType(String deviceType, Application application, String action)
throws ApplicationManagementException { throws ApplicationManagementException {
try { try {
//todo rethink and modify the {@link MobileApp} usage //todo rethink and modify the {@link App} usage
MobileApp mobileApp = new MobileApp(); App app = new App();
MobileAppTypes mobileAppType = MobileAppTypes.valueOf(application.getType()); MobileAppTypes mobileAppType = MobileAppTypes.valueOf(application.getType());
if (DeviceTypes.ANDROID.toString().equalsIgnoreCase(deviceType)) { if (DeviceTypes.ANDROID.toString().equalsIgnoreCase(deviceType)) {
if (SubAction.INSTALL.toString().equalsIgnoreCase(action)) { if (SubAction.INSTALL.toString().equalsIgnoreCase(action)) {
mobileApp.setType(mobileAppType); app.setType(mobileAppType);
mobileApp.setLocation(application.getApplicationReleases().get(0).getInstallerPath()); app.setLocation(application.getApplicationReleases().get(0).getInstallerPath());
return MDMAndroidOperationUtil.createInstallAppOperation(mobileApp); return MDMAndroidOperationUtil.createInstallAppOperation(app);
} else if (SubAction.UNINSTALL.toString().equalsIgnoreCase(action)) { } else if (SubAction.UNINSTALL.toString().equalsIgnoreCase(action)) {
return MDMAndroidOperationUtil.createAppUninstallOperation(mobileApp); return MDMAndroidOperationUtil.createAppUninstallOperation(app);
} else { } else {
String msg = "Invalid Action is found. Action: " + action; String msg = "Invalid Action is found. Action: " + action;
log.error(msg); log.error(msg);
@ -480,15 +482,40 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
String plistDownloadEndpoint = APIUtil.getArtifactDownloadBaseURL() String plistDownloadEndpoint = APIUtil.getArtifactDownloadBaseURL()
+ MDMAppConstants.IOSConstants.PLIST + Constants.FORWARD_SLASH + MDMAppConstants.IOSConstants.PLIST + Constants.FORWARD_SLASH
+ application.getApplicationReleases().get(0).getUuid(); + application.getApplicationReleases().get(0).getUuid();
mobileApp.setType(mobileAppType); app.setType(mobileAppType);
mobileApp.setLocation(plistDownloadEndpoint); app.setLocation(plistDownloadEndpoint);
Properties properties = new Properties(); Properties properties = new Properties();
properties.put(MDMAppConstants.IOSConstants.IS_PREVENT_BACKUP, true); properties.put(MDMAppConstants.IOSConstants.IS_PREVENT_BACKUP, true);
properties.put(MDMAppConstants.IOSConstants.IS_REMOVE_APP, true); properties.put(MDMAppConstants.IOSConstants.IS_REMOVE_APP, true);
mobileApp.setProperties(properties); app.setProperties(properties);
return MDMIOSOperationUtil.createInstallAppOperation(mobileApp); return MDMIOSOperationUtil.createInstallAppOperation(app);
} else if (SubAction.UNINSTALL.toString().equalsIgnoreCase(action)) { } else if (SubAction.UNINSTALL.toString().equalsIgnoreCase(action)) {
return MDMIOSOperationUtil.createAppUninstallOperation(mobileApp); return MDMIOSOperationUtil.createAppUninstallOperation(app);
} else {
String msg = "Invalid Action is found. Action: " + action;
log.error(msg);
throw new ApplicationManagementException(msg);
}
} else {
if (ApplicationType.CUSTOM.toString().equalsIgnoreCase(application.getType())) {
if (SubAction.INSTALL.toString().equalsIgnoreCase(action)) {
ProfileOperation operation = new ProfileOperation();
operation.setCode(MDMAppConstants.AndroidConstants.OPCODE_INSTALL_APPLICATION);
operation.setType(Operation.Type.PROFILE);
CustomApplication customApplication = new CustomApplication();
customApplication.setType(application.getType());
customApplication.setUrl(application.getApplicationReleases().get(0).getInstallerPath());
operation.setPayLoad(customApplication.toJSON());
return operation;
} else if (SubAction.UNINSTALL.toString().equalsIgnoreCase(action)) {
ProfileOperation operation = new ProfileOperation();
operation.setCode(MDMAppConstants.AndroidConstants.OPCODE_UNINSTALL_APPLICATION);
operation.setType(Operation.Type.PROFILE);
CustomApplication customApplication = new CustomApplication();
customApplication.setType(application.getType());
//todo get application package name and set
operation.setPayLoad(customApplication.toJSON());
return MDMAndroidOperationUtil.createAppUninstallOperation(app);
} else { } else {
String msg = "Invalid Action is found. Action: " + action; String msg = "Invalid Action is found. Action: " + action;
log.error(msg); log.error(msg);
@ -499,6 +526,7 @@ 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, e); log.error(msg, e);

@ -32,6 +32,8 @@ 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.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.common.wrapper.CustomAppReleaseWrapper;
import org.wso2.carbon.device.application.mgt.common.wrapper.CustomAppWrapper;
import org.wso2.carbon.device.application.mgt.common.wrapper.EntAppReleaseWrapper; import org.wso2.carbon.device.application.mgt.common.wrapper.EntAppReleaseWrapper;
import org.wso2.carbon.device.application.mgt.common.wrapper.ApplicationWrapper; import org.wso2.carbon.device.application.mgt.common.wrapper.ApplicationWrapper;
import org.wso2.carbon.device.application.mgt.common.wrapper.PublicAppReleaseWrapper; import org.wso2.carbon.device.application.mgt.common.wrapper.PublicAppReleaseWrapper;
@ -266,6 +268,21 @@ public class APIUtil {
List<ApplicationReleaseDTO> applicationReleaseEntities = publicAppWrapper.getPublicAppReleaseWrappers() List<ApplicationReleaseDTO> applicationReleaseEntities = publicAppWrapper.getPublicAppReleaseWrappers()
.stream().map(APIUtil::releaseWrapperToReleaseDTO).collect(Collectors.toList()); .stream().map(APIUtil::releaseWrapperToReleaseDTO).collect(Collectors.toList());
applicationDTO.setApplicationReleaseDTOs(applicationReleaseEntities); applicationDTO.setApplicationReleaseDTOs(applicationReleaseEntities);
} else if (param instanceof CustomAppWrapper){
CustomAppWrapper customAppWrapper = (CustomAppWrapper) param;
DeviceType deviceType = getDeviceTypeData(customAppWrapper.getDeviceType());
applicationDTO.setName(customAppWrapper.getName());
applicationDTO.setDescription(customAppWrapper.getDescription());
applicationDTO.setAppCategories(customAppWrapper.getCategories());
applicationDTO.setType(ApplicationType.CUSTOM.toString());
applicationDTO.setSubType(customAppWrapper.getSubMethod());
applicationDTO.setPaymentCurrency(customAppWrapper.getPaymentCurrency());
applicationDTO.setTags(customAppWrapper.getTags());
applicationDTO.setUnrestrictedRoles(customAppWrapper.getUnrestrictedRoles());
applicationDTO.setDeviceTypeId(deviceType.getId());
List<ApplicationReleaseDTO> applicationReleaseEntities = customAppWrapper.getCustomAppReleaseWrappers()
.stream().map(APIUtil::releaseWrapperToReleaseDTO).collect(Collectors.toList());
applicationDTO.setApplicationReleaseDTOs(applicationReleaseEntities);
} }
return applicationDTO; return applicationDTO;
} }
@ -301,6 +318,15 @@ public class APIUtil {
applicationReleaseDTO.setIsSharedWithAllTenants(publicAppReleaseWrapper.getIsSharedWithAllTenants()); applicationReleaseDTO.setIsSharedWithAllTenants(publicAppReleaseWrapper.getIsSharedWithAllTenants());
applicationReleaseDTO.setMetaData(publicAppReleaseWrapper.getMetaData()); applicationReleaseDTO.setMetaData(publicAppReleaseWrapper.getMetaData());
applicationReleaseDTO.setSupportedOsVersions(publicAppReleaseWrapper.getSupportedOsVersions()); applicationReleaseDTO.setSupportedOsVersions(publicAppReleaseWrapper.getSupportedOsVersions());
} else if (param instanceof CustomAppReleaseWrapper) {
CustomAppReleaseWrapper customAppReleaseWrapper = (CustomAppReleaseWrapper) param;
applicationReleaseDTO.setDescription(customAppReleaseWrapper.getDescription());
applicationReleaseDTO.setReleaseType(customAppReleaseWrapper.getReleaseType());
applicationReleaseDTO.setVersion(customAppReleaseWrapper.getVersion());
applicationReleaseDTO.setPackageName(customAppReleaseWrapper.getPackageName());
applicationReleaseDTO.setPrice(customAppReleaseWrapper.getPrice());
applicationReleaseDTO.setIsSharedWithAllTenants(customAppReleaseWrapper.getIsSharedWithAllTenants());
applicationReleaseDTO.setMetaData(customAppReleaseWrapper.getMetaData());
} }
return applicationReleaseDTO; return applicationReleaseDTO;
} }

@ -39,6 +39,8 @@ import org.wso2.carbon.device.application.mgt.common.LifecycleChanger;
import org.wso2.carbon.device.application.mgt.common.dto.ApplicationDTO; 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.dto.ApplicationReleaseDTO;
import org.wso2.carbon.device.application.mgt.common.response.ApplicationRelease; import org.wso2.carbon.device.application.mgt.common.response.ApplicationRelease;
import org.wso2.carbon.device.application.mgt.common.wrapper.CustomAppReleaseWrapper;
import org.wso2.carbon.device.application.mgt.common.wrapper.CustomAppWrapper;
import org.wso2.carbon.device.application.mgt.common.wrapper.EntAppReleaseWrapper; import org.wso2.carbon.device.application.mgt.common.wrapper.EntAppReleaseWrapper;
import org.wso2.carbon.device.application.mgt.common.wrapper.ApplicationUpdateWrapper; import org.wso2.carbon.device.application.mgt.common.wrapper.ApplicationUpdateWrapper;
import org.wso2.carbon.device.application.mgt.common.wrapper.ApplicationWrapper; import org.wso2.carbon.device.application.mgt.common.wrapper.ApplicationWrapper;
@ -468,9 +470,78 @@ public interface ApplicationManagementPublisherAPI {
); );
@POST @POST
@Path("/custom-app")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Consumes({"multipart/mixed", MediaType.MULTIPART_FORM_DATA}) @Consumes({"multipart/mixed", MediaType.MULTIPART_FORM_DATA})
@Path("/ent-app/{appId}") @ApiOperation(
consumes = MediaType.APPLICATION_JSON,
produces = MediaType.APPLICATION_JSON,
httpMethod = "POST",
value = "Create an custom application",
notes = "This will create a new custom application",
tags = "Application Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = SCOPE, value = "perm:app:publisher:update")
})
}
)
@ApiResponses(
value = {
@ApiResponse(
code = 201,
message = "OK. \n Successfully created an application.",
response = ApplicationDTO.class),
@ApiResponse(
code = 400,
message = "Bad Request. \n " +
"ApplicationDTO creating payload contains unacceptable or vulnerable data"),
@ApiResponse(
code = 500,
message = "Internal Server Error. \n Error occurred while creating the application.",
response = ErrorResponse.class)
})
Response createCustomApp(
@ApiParam(
name = "application",
value = "The application that need to be created.",
required = true)
@Multipart("application") CustomAppWrapper customAppWrapper,
@ApiParam(
name = "binaryFile",
value = "Binary file of uploading application",
required = true)
@Multipart(value = "binaryFile") Attachment binaryFile,
@ApiParam(
name = "icon",
value = "Icon of the uploading application",
required = true)
@Multipart(value = "icon") Attachment iconFile,
@ApiParam(
name = "banner",
value = "Banner of the uploading application")
@Multipart(value = "banner") Attachment bannerFile,
@ApiParam(
name = "screenshot1",
value = "Screen Shots of the uploading application",
required = true)
@Multipart(value = "screenshot1") Attachment screenshot1,
@ApiParam(
name = "screenshot2",
value = "Screen Shots of the uploading application",
required = false)
@Multipart(value = "screenshot2") Attachment screenshot2,
@ApiParam(
name = "screenshot3",
value = "Screen Shots of the uploading application",
required = false)
@Multipart(value = "screenshot3") Attachment screenshot3
);
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes({"multipart/mixed", MediaType.MULTIPART_FORM_DATA})
@Path("/{deviceType}/ent-app/{appId}")
@ApiOperation( @ApiOperation(
consumes = MediaType.APPLICATION_JSON, consumes = MediaType.APPLICATION_JSON,
produces = MediaType.APPLICATION_JSON, produces = MediaType.APPLICATION_JSON,
@ -500,6 +571,11 @@ public interface ApplicationManagementPublisherAPI {
response = ErrorResponse.class) response = ErrorResponse.class)
}) })
Response createEntAppRelease( Response createEntAppRelease(
@ApiParam(
name = "deviceType",
value = "Device type that application is compatible with.",
required = true)
@PathParam("deviceType") String deviceType,
@ApiParam( @ApiParam(
name = "appId", name = "appId",
value = "Id of the application.", value = "Id of the application.",
@ -895,6 +971,77 @@ public interface ApplicationManagementPublisherAPI {
value = "Third screenshot of the uploading application") value = "Third screenshot of the uploading application")
@Multipart(value = "screenshot3") Attachment screenshot3); @Multipart(value = "screenshot3") Attachment screenshot3);
@PUT
@Path("/custom-app-release/{uuid}")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.MULTIPART_FORM_DATA)
@ApiOperation(
consumes = MediaType.MULTIPART_FORM_DATA,
produces = MediaType.APPLICATION_JSON,
httpMethod = "PUT",
value = "Update an custom application release",
notes = "This will update a custom app release",
tags = "Application Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = SCOPE, value = "perm:app:publisher:update")
})
}
)
@ApiResponses(
value = {
@ApiResponse(
code = 201,
message = "OK. \n Successfully created an application release.",
response = ApplicationReleaseDTO.class),
@ApiResponse(
code = 400,
message = "Bad Request. \n " +
"ApplicationDTO release updating payload contains unacceptable or vulnerable data"),
@ApiResponse(
code = 500,
message = "Internal Server Error. \n Error occurred while releasing the application.",
response = ErrorResponse.class)
})
Response updateCustomAppRelease(
@ApiParam(
name = "UUID",
value = "Unique identifier of the ApplicationDTO Release",
required = true)
@PathParam("uuid") String applicationUUID,
@ApiParam(
name = "entAppReleaseWrapper",
value = "Application release wrapper which is going to update.",
required = true)
@Multipart(
value = "entAppReleaseWrapper",
type = "application/json") CustomAppReleaseWrapper customAppReleaseWrapper,
@ApiParam(
name = "binaryFile",
value = "Application installer file.",
required = true)
@Multipart(value = "binaryFile") Attachment binaryFile,
@ApiParam(
name = "icon",
value = "Icon file of the application release.")
@Multipart(value = "icon") Attachment iconFile,
@ApiParam(
name = "banner",
value = "banner file of the application release.")
@Multipart(value = "banner") Attachment bannerFile,
@ApiParam(
name = "screenshot1",
value = "First screenshot of the uploading application")
@Multipart(value = "screenshot1") Attachment screenshot1,
@ApiParam(
name = "screenshot2",
value = "Second screenshot 2 of the uploading application")
@Multipart(value = "screenshot2") Attachment screenshot2,
@ApiParam(
name = "screenshot3",
value = "Third screenshot of the uploading application")
@Multipart(value = "screenshot3") Attachment screenshot3);
@GET @GET
@Path("/life-cycle/state-changes/{uuid}") @Path("/life-cycle/state-changes/{uuid}")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)

@ -29,6 +29,8 @@ import org.wso2.carbon.device.application.mgt.common.response.ApplicationRelease
import org.wso2.carbon.device.application.mgt.common.response.Category; import org.wso2.carbon.device.application.mgt.common.response.Category;
import org.wso2.carbon.device.application.mgt.common.response.Tag; import org.wso2.carbon.device.application.mgt.common.response.Tag;
import org.wso2.carbon.device.application.mgt.common.services.AppmDataHandler; import org.wso2.carbon.device.application.mgt.common.services.AppmDataHandler;
import org.wso2.carbon.device.application.mgt.common.wrapper.CustomAppReleaseWrapper;
import org.wso2.carbon.device.application.mgt.common.wrapper.CustomAppWrapper;
import org.wso2.carbon.device.application.mgt.common.wrapper.EntAppReleaseWrapper; import org.wso2.carbon.device.application.mgt.common.wrapper.EntAppReleaseWrapper;
import org.wso2.carbon.device.application.mgt.common.wrapper.ApplicationUpdateWrapper; import org.wso2.carbon.device.application.mgt.common.wrapper.ApplicationUpdateWrapper;
import org.wso2.carbon.device.application.mgt.common.wrapper.ApplicationWrapper; import org.wso2.carbon.device.application.mgt.common.wrapper.ApplicationWrapper;
@ -40,11 +42,13 @@ import org.wso2.carbon.device.application.mgt.core.exception.BadRequestException
import org.wso2.carbon.device.application.mgt.core.exception.ForbiddenException; import org.wso2.carbon.device.application.mgt.core.exception.ForbiddenException;
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.application.mgt.core.util.APIUtil; import org.wso2.carbon.device.application.mgt.core.util.APIUtil;
import org.wso2.carbon.device.application.mgt.core.util.Constants;
import org.wso2.carbon.device.application.mgt.publisher.api.services.ApplicationManagementPublisherAPI; import org.wso2.carbon.device.application.mgt.publisher.api.services.ApplicationManagementPublisherAPI;
import org.wso2.carbon.device.application.mgt.common.exception.ApplicationManagementException; import org.wso2.carbon.device.application.mgt.common.exception.ApplicationManagementException;
import org.wso2.carbon.device.application.mgt.common.services.ApplicationManager; import org.wso2.carbon.device.application.mgt.common.services.ApplicationManager;
import org.wso2.carbon.device.application.mgt.core.exception.NotFoundException; import org.wso2.carbon.device.application.mgt.core.exception.NotFoundException;
import java.beans.Customizer;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
@ -180,7 +184,8 @@ public class ApplicationManagementPublisherAPIImpl implements ApplicationManagem
List<Attachment> attachmentList = constructAttachmentList(screenshot1, screenshot2, screenshot3); List<Attachment> attachmentList = constructAttachmentList(screenshot1, screenshot2, screenshot3);
try { try {
applicationManager.validateAppCreatingRequest(applicationWrapper); applicationManager.validateAppCreatingRequest(applicationWrapper);
applicationManager.validateReleaseCreatingRequest(applicationWrapper.getEntAppReleaseWrappers().get(0)); applicationManager.validateReleaseCreatingRequest(applicationWrapper.getEntAppReleaseWrappers().get(0),
applicationWrapper.getDeviceType());
applicationManager.validateBinaryArtifact(binaryFile); applicationManager.validateBinaryArtifact(binaryFile);
applicationManager.validateImageArtifacts(iconFile, bannerFile, attachmentList); applicationManager.validateImageArtifacts(iconFile, bannerFile, attachmentList);
@ -195,11 +200,11 @@ public class ApplicationManagementPublisherAPIImpl implements ApplicationManagem
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build(); return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
} }
} catch (ApplicationManagementException e) { } catch (ApplicationManagementException e) {
String msg = "Error occurred while creating the application"; String msg = "Error occurred while creating the ent. application";
log.error(msg, e); log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build(); return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
} catch (RequestValidatingException e) { } catch (RequestValidatingException e) {
String msg = "Error occurred while handling the application creating request"; String msg = "Error occurred while handling the ent. application creating request";
log.error(msg, e); log.error(msg, e);
return Response.status(Response.Status.BAD_REQUEST).entity(msg).build(); return Response.status(Response.Status.BAD_REQUEST).entity(msg).build();
} }
@ -219,7 +224,8 @@ public class ApplicationManagementPublisherAPIImpl implements ApplicationManagem
List<Attachment> attachmentList = constructAttachmentList(screenshot1, screenshot2, screenshot3); List<Attachment> attachmentList = constructAttachmentList(screenshot1, screenshot2, screenshot3);
try { try {
applicationManager.validateAppCreatingRequest(webAppWrapper); applicationManager.validateAppCreatingRequest(webAppWrapper);
applicationManager.validateReleaseCreatingRequest(webAppWrapper.getWebAppReleaseWrappers().get(0)); applicationManager
.validateReleaseCreatingRequest(webAppWrapper.getWebAppReleaseWrappers().get(0), Constants.ANY);
applicationManager.validateImageArtifacts(iconFile, bannerFile, attachmentList); applicationManager.validateImageArtifacts(iconFile, bannerFile, attachmentList);
// Created new Web App // Created new Web App
@ -257,7 +263,8 @@ public class ApplicationManagementPublisherAPIImpl implements ApplicationManagem
List<Attachment> attachmentList = constructAttachmentList(screenshot1, screenshot2, screenshot3); List<Attachment> attachmentList = constructAttachmentList(screenshot1, screenshot2, screenshot3);
try { try {
applicationManager.validateAppCreatingRequest(publicAppWrapper); applicationManager.validateAppCreatingRequest(publicAppWrapper);
applicationManager.validateReleaseCreatingRequest(publicAppWrapper.getPublicAppReleaseWrappers().get(0)); applicationManager.validateReleaseCreatingRequest(publicAppWrapper.getPublicAppReleaseWrappers().get(0),
publicAppWrapper.getDeviceType());
applicationManager.validateImageArtifacts(iconFile, bannerFile, attachmentList); applicationManager.validateImageArtifacts(iconFile, bannerFile, attachmentList);
// Created new Public App // Created new Public App
@ -283,8 +290,50 @@ public class ApplicationManagementPublisherAPIImpl implements ApplicationManagem
@POST @POST
@Consumes({"multipart/mixed", MediaType.MULTIPART_FORM_DATA}) @Consumes({"multipart/mixed", MediaType.MULTIPART_FORM_DATA})
@Path("/ent-app/{appId}") @Path("/custom-app")
public Response createCustomApp(
@Multipart("application") CustomAppWrapper customAppWrapper,
@Multipart("binaryFile") Attachment binaryFile,
@Multipart("icon") Attachment iconFile,
@Multipart(value = "banner", required = false) Attachment bannerFile,
@Multipart("screenshot1") Attachment screenshot1,
@Multipart("screenshot2") Attachment screenshot2,
@Multipart("screenshot3") Attachment screenshot3) {
ApplicationManager applicationManager = APIUtil.getApplicationManager();
List<Attachment> attachmentList = constructAttachmentList(screenshot1, screenshot2, screenshot3);
try {
applicationManager.validateAppCreatingRequest(customAppWrapper);
applicationManager.validateReleaseCreatingRequest(customAppWrapper.getCustomAppReleaseWrappers().get(0),
customAppWrapper.getDeviceType());
applicationManager.validateBinaryArtifact(binaryFile);
applicationManager.validateImageArtifacts(iconFile, bannerFile, attachmentList);
// Created new Ent App
Application application = applicationManager.createCustomApp(customAppWrapper,
constructApplicationArtifact(binaryFile, iconFile, bannerFile, attachmentList));
if (application != null) {
return Response.status(Response.Status.CREATED).entity(application).build();
} else {
String msg = "Application creation is failed";
log.error(msg);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
}
} catch (ApplicationManagementException e) {
String msg = "Error occurred while creating the application";
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
} catch (RequestValidatingException e) {
String msg = "Error occurred while handling the application creating request";
log.error(msg, e);
return Response.status(Response.Status.BAD_REQUEST).entity(msg).build();
}
}
@POST
@Consumes({"multipart/mixed", MediaType.MULTIPART_FORM_DATA})
@Path("/{deviceType}/ent-app/{appId}")
public Response createEntAppRelease( public Response createEntAppRelease(
@PathParam("deviceType") String deviceType,
@PathParam("appId") int appId, @PathParam("appId") int appId,
@Multipart("applicationRelease") EntAppReleaseWrapper entAppReleaseWrapper, @Multipart("applicationRelease") EntAppReleaseWrapper entAppReleaseWrapper,
@Multipart("binaryFile") Attachment binaryFile, @Multipart("binaryFile") Attachment binaryFile,
@ -296,7 +345,7 @@ public class ApplicationManagementPublisherAPIImpl implements ApplicationManagem
ApplicationManager applicationManager = APIUtil.getApplicationManager(); ApplicationManager applicationManager = APIUtil.getApplicationManager();
List<Attachment> attachmentList = constructAttachmentList(screenshot1, screenshot2, screenshot3); List<Attachment> attachmentList = constructAttachmentList(screenshot1, screenshot2, screenshot3);
try { try {
applicationManager.validateReleaseCreatingRequest(entAppReleaseWrapper); applicationManager.validateReleaseCreatingRequest(entAppReleaseWrapper, deviceType);
applicationManager.validateBinaryArtifact(binaryFile); applicationManager.validateBinaryArtifact(binaryFile);
applicationManager.validateImageArtifacts(iconFile, bannerFile, attachmentList); applicationManager.validateImageArtifacts(iconFile, bannerFile, attachmentList);
@ -544,6 +593,52 @@ public class ApplicationManagementPublisherAPIImpl implements ApplicationManagem
} }
} }
@Override
@PUT
@Path("/custom-app-release/{uuid}")
public Response updateCustomAppRelease(
@PathParam("uuid") String applicationUUID,
@Multipart("applicationRelease") CustomAppReleaseWrapper customAppReleaseWrapper,
@Multipart(value = "binaryFile", required = false) Attachment binaryFile,
@Multipart(value = "icon", required = false) Attachment iconFile,
@Multipart(value = "banner", required = false) Attachment bannerFile,
@Multipart(value = "screenshot1", required = false) Attachment screenshot1,
@Multipart(value = "screenshot2", required = false) Attachment screenshot2,
@Multipart(value = "screenshot3", required = false) Attachment screenshot3) {
ApplicationManager applicationManager = APIUtil.getApplicationManager();
List<Attachment> screenshots = constructAttachmentList(screenshot1, screenshot2, screenshot3);
try {
ApplicationRelease applicationRelease = applicationManager
.updateCustomAppRelease(applicationUUID, customAppReleaseWrapper,
constructApplicationArtifact(binaryFile, iconFile, bannerFile, screenshots));
if (applicationRelease == null) {
String msg ="Custom app release updating is failed. Please contact the administrator. Application "
+ "release UUID: " + applicationUUID;
log.error(msg);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
}
return Response.status(Response.Status.OK).entity(applicationRelease).build();
} catch (BadRequestException e) {
String msg =
"Invalid request to update ent app release for application release UUID " + applicationUUID;
log.error(msg, e);
return Response.status(Response.Status.BAD_REQUEST).entity(msg).build();
} catch (NotFoundException e) {
String msg =
"Couldn't found an ent app or ent app release for application release UUID " + applicationUUID;
log.error(msg, e);
return Response.status(Response.Status.NOT_FOUND).entity(msg).build();
} catch (ForbiddenException e) {
String msg = "You don't have require permission to update the ent app release which has UUID "
+ applicationUUID;
log.error(msg, e);
return Response.status(Response.Status.FORBIDDEN).entity(msg).build();
} catch (ApplicationManagementException e) {
String msg = "Error occurred while updating the ent app release which has UUID " + applicationUUID;
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
}
}
@PUT @PUT
@Path("/retire/{appId}") @Path("/retire/{appId}")

@ -66,5 +66,29 @@
"RETIRED": { "RETIRED": {
"text": "The final state of an application, where no transition of states will be allowed after this." "text": "The final state of an application, where no transition of states will be allowed after this."
} }
},
"installationTypes": {
"ENTERPRISE": {
"deviceTypes": [
"android",
"ios"
]
},
"PUBLIC": {
"deviceTypes": [
"android",
"ios"
]
},
"WEB_CLIP": {
"deviceTypes": [
"android",
"ios"
]
},
"CUSTOM": {
"deviceTypes": [
]
}
} }
} }

@ -190,6 +190,7 @@ class AppDetailsDrawer extends React.Component {
}); });
}; };
// change the app name // change the app name
handleNameSave = name => { handleNameSave = name => {
const config = this.props.context; const config = this.props.context;

@ -291,6 +291,7 @@ class FiltersForm extends React.Component {
<Option value="ENTERPRISE">Enterprise</Option> <Option value="ENTERPRISE">Enterprise</Option>
<Option value="PUBLIC">Public</Option> <Option value="PUBLIC">Public</Option>
<Option value="WEB_CLIP">Web APP</Option> <Option value="WEB_CLIP">Web APP</Option>
<Option value="CUSTOM">Custom</Option>
<Option value="ALL">All</Option> <Option value="ALL">All</Option>
</Select> </Select>
)} )}

@ -92,6 +92,20 @@ class EditReleaseModal extends React.Component {
} }
}; };
break; break;
case "CUSTOM":
formConfig.endpoint = "/custom-app-release";
formConfig.specificElements = {
binaryFile: {
required: true
},
packageName: {
required: true
},
version: {
required: true
}
};
break;
} }
this.setState({ this.setState({

@ -42,7 +42,8 @@ class NewAppDetailsForm extends React.Component {
categories: [], categories: [],
tags: [], tags: [],
deviceTypes:[] deviceTypes:[]
} };
} }
@ -146,18 +147,31 @@ class NewAppDetailsForm extends React.Component {
getDeviceTypes = () => { getDeviceTypes = () => {
const config = this.props.context; const config = this.props.context;
const {formConfig} = this.props;
console.log("test");
axios.get( axios.get(
window.location.origin + config.serverConfig.invoker.uri + config.serverConfig.invoker.deviceMgt + "/device-types" window.location.origin + config.serverConfig.invoker.uri + config.serverConfig.invoker.deviceMgt + "/device-types"
).then(res => { ).then(res => {
if (res.status === 200) { if (res.status === 200) {
const deviceTypes = JSON.parse(res.data.data); const allDeviceTypes = JSON.parse(res.data.data);
const whitelistedDeviceTypes = config.installationTypes[formConfig.installationType].deviceTypes;
const allowedDeviceTypes = [];
allDeviceTypes.forEach(deviceType=>{
if(whitelistedDeviceTypes.includes(deviceType.name)){
allowedDeviceTypes.push(deviceType);
}
});
this.setState({ this.setState({
deviceTypes, deviceTypes: allowedDeviceTypes,
loading: false, loading: false,
}); });
} }
}).catch((error) => { }).catch((error) => {
console.log(error);
if (error.hasOwnProperty("response") && error.response.status === 401) { if (error.hasOwnProperty("response") && error.response.status === 401) {
window.location.href = window.location.origin + '/publisher/login'; window.location.href = window.location.origin + '/publisher/login';
} else { } else {
@ -179,6 +193,7 @@ class NewAppDetailsForm extends React.Component {
const {categories, tags, deviceTypes} = this.state; const {categories, tags, deviceTypes} = this.state;
const {getFieldDecorator} = this.props.form; const {getFieldDecorator} = this.props.form;
return ( return (
<div> <div>
<Row> <Row>

@ -77,7 +77,7 @@ class NewAppUploadForm extends React.Component {
releaseType: releaseType releaseType: releaseType
}; };
if (formConfig.installationType !== "WEB_CLIP") { if (formConfig.installationType !== "WEB_CLIP" && formConfig.installationType !== "CUSTOM") {
release.supportedOsVersions = "4.0-10.0"; release.supportedOsVersions = "4.0-10.0";
} }

@ -69,7 +69,7 @@ class AddNewReleaseFormComponent extends React.Component {
handleSubmit = e => { handleSubmit = e => {
const config = this.props.context; const config = this.props.context;
e.preventDefault(); e.preventDefault();
const {appId} = this.props; const {appId, deviceType} = this.props;
this.props.form.validateFields((err, values) => { this.props.form.validateFields((err, values) => {
if (!err) { if (!err) {
@ -104,7 +104,7 @@ class AddNewReleaseFormComponent extends React.Component {
data.append("applicationRelease", blob); data.append("applicationRelease", blob);
const url = window.location.origin+ config.serverConfig.invoker.uri + config.serverConfig.invoker.publisher + "/applications/ent-app/" + appId; const url = window.location.origin+ config.serverConfig.invoker.uri + config.serverConfig.invoker.publisher + "/applications/"+deviceType+"/ent-app/" + appId;
axios.post( axios.post(
url, url,

@ -30,6 +30,7 @@ import './index.css';
import AddNewPublicApp from "./pages/dashboard/add-new-app/AddNewPublicApp"; import AddNewPublicApp from "./pages/dashboard/add-new-app/AddNewPublicApp";
import AddNewWebClip from "./pages/dashboard/add-new-app/AddNewWebClip"; import AddNewWebClip from "./pages/dashboard/add-new-app/AddNewWebClip";
import AddNewRelease from "./pages/dashboard/add-new-release/AddNewRelease"; import AddNewRelease from "./pages/dashboard/add-new-release/AddNewRelease";
import AddNewCustomApp from "./pages/dashboard/add-new-app/AddNewCustomApp";
const routes = [ const routes = [
@ -54,7 +55,7 @@ const routes = [
component: Release component: Release
}, },
{ {
path: '/publisher/apps/:appId/add-release', path: '/publisher/apps/:deviceType/:appId/add-release',
component: AddNewRelease, component: AddNewRelease,
exact: true exact: true
}, },
@ -73,6 +74,11 @@ const routes = [
component: AddNewWebClip, component: AddNewWebClip,
exact: true exact: true
}, },
{
path: '/publisher/add-new-app/custom-app',
component: AddNewCustomApp,
exact: true
},
{ {
path: '/publisher/manage', path: '/publisher/manage',
component: Mange, component: Mange,

@ -147,6 +147,8 @@ class Dashboard extends React.Component {
APP</Link></Menu.Item> APP</Link></Menu.Item>
<Menu.Item key="setting:3"><Link to="/publisher/add-new-app/web-clip">Web <Menu.Item key="setting:3"><Link to="/publisher/add-new-app/web-clip">Web
Clip</Link></Menu.Item> Clip</Link></Menu.Item>
<Menu.Item key="setting:4"><Link to="/publisher/add-new-app/custom-app">Custom
App</Link></Menu.Item>
</SubMenu> </SubMenu>
<Menu.Item key="2"><Link to="/publisher/manage"><Icon <Menu.Item key="2"><Link to="/publisher/manage"><Icon
type="control"/>Manage</Link></Menu.Item> type="control"/>Manage</Link></Menu.Item>

@ -0,0 +1,84 @@
/*
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
*
* Entgra (pvt) Ltd. 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.
*/
import React from "react";
import {
PageHeader,
Typography,
Breadcrumb,
Icon
} from "antd";
import AddNewAppForm from "../../../components/new-app/AddNewAppForm";
import {Link} from "react-router-dom";
const {Paragraph} = Typography;
const formConfig = {
installationType: "CUSTOM",
endpoint: "/custom-app",
jsonPayloadName: "application",
releaseWrapperName: "customAppReleaseWrappers",
specificElements: {
binaryFile: {
required: true
},
packageName : {
required: true
},
version : {
required: true
}
}
};
class AddNewCustomApp extends React.Component {
constructor(props) {
super(props);
this.state = {
current: 0,
categories: []
};
}
render() {
return (
<div>
<PageHeader style={{paddingTop:0}}>
<Breadcrumb style={{paddingBottom:16}}>
<Breadcrumb.Item>
<Link to="/publisher/apps"><Icon type="home"/> Home</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Add New Custom App</Breadcrumb.Item>
</Breadcrumb>
<div className="wrap">
<h3>Add New Custom App</h3>
<Paragraph>Submit and share your own application to the corporate app store.</Paragraph>
</div>
</PageHeader>
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
<AddNewAppForm formConfig={formConfig}/>
</div>
</div>
);
}
}
export default AddNewCustomApp;

@ -39,7 +39,7 @@ class AddNewRelease extends React.Component {
} }
render() { render() {
const {appId} = this.props.match.params; const {appId, deviceType} = this.props.match.params;
return ( return (
<div> <div>
<PageHeader style={{paddingTop: 0}}> <PageHeader style={{paddingTop: 0}}>
@ -51,11 +51,11 @@ class AddNewRelease extends React.Component {
</Breadcrumb> </Breadcrumb>
<div className="wrap"> <div className="wrap">
<h3>Add New Release</h3> <h3>Add New Release</h3>
<Paragraph>Maintain and manage categories and tags here..</Paragraph> <Paragraph>Add new release for the application</Paragraph>
</div> </div>
</PageHeader> </PageHeader>
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}> <div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
<AddNewReleaseForm appId={appId}/> <AddNewReleaseForm deviceType={deviceType} appId={appId}/>
</div> </div>
</div> </div>

@ -21,7 +21,7 @@ package org.wso2.carbon.device.mgt.jaxrs.beans;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier; import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import org.wso2.carbon.device.mgt.common.app.mgt.MobileApp; import org.wso2.carbon.device.mgt.common.app.mgt.App;
import java.util.List; import java.util.List;
@ -53,13 +53,13 @@ public class ApplicationWrapper {
name = "application", name = "application",
value = "Details of the mobile application.", value = "Details of the mobile application.",
required = true) required = true)
private MobileApp application; private App application;
public MobileApp getApplication() { public App getApplication() {
return application; return application;
} }
public void setApplication(MobileApp application) { public void setApplication(App application) {
this.application = application; this.application = application;
} }

@ -34,7 +34,7 @@ import org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtAPIUtils;
import org.wso2.carbon.device.mgt.core.util.MDMAndroidOperationUtil; import org.wso2.carbon.device.mgt.core.util.MDMAndroidOperationUtil;
import org.wso2.carbon.device.mgt.core.util.MDMIOSOperationUtil; import org.wso2.carbon.device.mgt.core.util.MDMIOSOperationUtil;
import org.wso2.carbon.device.mgt.jaxrs.beans.ApplicationWrapper; import org.wso2.carbon.device.mgt.jaxrs.beans.ApplicationWrapper;
import org.wso2.carbon.device.mgt.common.app.mgt.MobileApp; import org.wso2.carbon.device.mgt.common.app.mgt.App;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.POST; import javax.ws.rs.POST;
@ -61,15 +61,15 @@ public class ApplicationManagementAdminServiceImpl implements ApplicationManagem
RequestValidationUtil.validateApplicationInstallationContext(applicationWrapper); RequestValidationUtil.validateApplicationInstallationContext(applicationWrapper);
try { try {
appManagerConnector = DeviceMgtAPIUtils.getAppManagementService(); appManagerConnector = DeviceMgtAPIUtils.getAppManagementService();
MobileApp mobileApp = applicationWrapper.getApplication(); App app = applicationWrapper.getApplication();
if (applicationWrapper.getDeviceIdentifiers() != null) { if (applicationWrapper.getDeviceIdentifiers() != null) {
for (DeviceIdentifier deviceIdentifier : applicationWrapper.getDeviceIdentifiers()) { for (DeviceIdentifier deviceIdentifier : applicationWrapper.getDeviceIdentifiers()) {
String deviceType = deviceIdentifier.getType().toUpperCase(); String deviceType = deviceIdentifier.getType().toUpperCase();
if (Platform.ANDROID.toString().equals(deviceType)) { if (Platform.ANDROID.toString().equals(deviceType)) {
operation = MDMAndroidOperationUtil.createInstallAppOperation(mobileApp); operation = MDMAndroidOperationUtil.createInstallAppOperation(app);
} else if (Platform.IOS.toString().equals(deviceType)) { } else if (Platform.IOS.toString().equals(deviceType)) {
operation = MDMIOSOperationUtil.createInstallAppOperation(mobileApp); operation = MDMIOSOperationUtil.createInstallAppOperation(app);
} }
} }
if (applicationWrapper.getRoleNameList() != null && applicationWrapper.getRoleNameList().size() > 0) { if (applicationWrapper.getRoleNameList() != null && applicationWrapper.getRoleNameList().size() > 0) {
@ -111,15 +111,15 @@ public class ApplicationManagementAdminServiceImpl implements ApplicationManagem
RequestValidationUtil.validateApplicationInstallationContext(applicationWrapper); RequestValidationUtil.validateApplicationInstallationContext(applicationWrapper);
try { try {
appManagerConnector = DeviceMgtAPIUtils.getAppManagementService(); appManagerConnector = DeviceMgtAPIUtils.getAppManagementService();
MobileApp mobileApp = applicationWrapper.getApplication(); App app = applicationWrapper.getApplication();
if (applicationWrapper.getDeviceIdentifiers() != null) { if (applicationWrapper.getDeviceIdentifiers() != null) {
for (DeviceIdentifier deviceIdentifier : applicationWrapper.getDeviceIdentifiers()) { for (DeviceIdentifier deviceIdentifier : applicationWrapper.getDeviceIdentifiers()) {
String deviceType = deviceIdentifier.getType().toUpperCase(); String deviceType = deviceIdentifier.getType().toUpperCase();
if (Platform.ANDROID.toString().equals(deviceType)) { if (Platform.ANDROID.toString().equals(deviceType)) {
operation = MDMAndroidOperationUtil.createAppUninstallOperation(mobileApp); operation = MDMAndroidOperationUtil.createAppUninstallOperation(app);
} else if (deviceType.equals(Platform.IOS.toString())) { } else if (deviceType.equals(Platform.IOS.toString())) {
operation = MDMIOSOperationUtil.createAppUninstallOperation(mobileApp); operation = MDMIOSOperationUtil.createAppUninstallOperation(app);
} }
} }
if (applicationWrapper.getRoleNameList() != null && applicationWrapper.getRoleNameList().size() > 0) { if (applicationWrapper.getRoleNameList() != null && applicationWrapper.getRoleNameList().size() > 0) {

@ -20,7 +20,6 @@ package org.wso2.carbon.device.mgt.common.app.mgt;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import org.wso2.carbon.device.mgt.common.app.mgt.MobileAppTypes;
import java.util.Properties; import java.util.Properties;
@ -29,7 +28,7 @@ import java.util.Properties;
* which is used by AppM. * which is used by AppM.
*/ */
@ApiModel(value = "MobileApp", description = "Details of a mobile application.") @ApiModel(value = "MobileApp", description = "Details of a mobile application.")
public class MobileApp { public class App {
@ApiModelProperty(name = "id", value = "Id of the app used internally.", required = true) @ApiModelProperty(name = "id", value = "Id of the app used internally.", required = true)
private String id; private String id;
@ -153,5 +152,4 @@ public class MobileApp {
public void setProperties(Properties properties) { public void setProperties(Properties properties) {
this.properties = properties; this.properties = properties;
} }
} }

@ -0,0 +1,62 @@
/* Copyright (c) 2019, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. 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.mgt.common.app.mgt.android;
import com.google.gson.Gson;
import java.io.Serializable;
/**
* This class represents the Enterprise AuthenticationImpl information.
*/
public class CustomApplication implements Serializable {
private String type;
private String url;
private String appIdentifier;
public String getAppIdentifier() {
return appIdentifier;
}
public void setAppIdentifier(String appIdentifier) {
this.appIdentifier = appIdentifier;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String toJSON() {
Gson gson = new Gson();
return gson.toJson(this);
}
}

@ -24,7 +24,7 @@ import org.wso2.carbon.device.mgt.common.app.mgt.android.EnterpriseApplication;
import org.wso2.carbon.device.mgt.common.app.mgt.android.WebApplication; import org.wso2.carbon.device.mgt.common.app.mgt.android.WebApplication;
import org.wso2.carbon.device.mgt.common.operation.mgt.Operation; import org.wso2.carbon.device.mgt.common.operation.mgt.Operation;
import org.wso2.carbon.device.mgt.core.operation.mgt.ProfileOperation; import org.wso2.carbon.device.mgt.core.operation.mgt.ProfileOperation;
import org.wso2.carbon.device.mgt.common.app.mgt.MobileApp; import org.wso2.carbon.device.mgt.common.app.mgt.App;
import org.wso2.carbon.device.mgt.common.exceptions.UnknownApplicationTypeException; import org.wso2.carbon.device.mgt.common.exceptions.UnknownApplicationTypeException;
/** /**
@ -40,7 +40,7 @@ public class MDMAndroidOperationUtil {
* @return operation * @return operation
* *
*/ */
public static Operation createInstallAppOperation(MobileApp application) throws UnknownApplicationTypeException { public static Operation createInstallAppOperation(App application) throws UnknownApplicationTypeException {
ProfileOperation operation = new ProfileOperation(); ProfileOperation operation = new ProfileOperation();
operation.setCode(MDMAppConstants.AndroidConstants.OPCODE_INSTALL_APPLICATION); operation.setCode(MDMAppConstants.AndroidConstants.OPCODE_INSTALL_APPLICATION);
@ -79,7 +79,7 @@ public class MDMAndroidOperationUtil {
* @param application MobileApp application * @param application MobileApp application
* @return operation * @return operation
*/ */
public static Operation createAppUninstallOperation(MobileApp application) throws UnknownApplicationTypeException { public static Operation createAppUninstallOperation(App application) throws UnknownApplicationTypeException {
ProfileOperation operation = new ProfileOperation(); ProfileOperation operation = new ProfileOperation();
operation.setCode(MDMAppConstants.AndroidConstants.OPCODE_UNINSTALL_APPLICATION); operation.setCode(MDMAppConstants.AndroidConstants.OPCODE_UNINSTALL_APPLICATION);

@ -23,7 +23,7 @@ import org.wso2.carbon.device.mgt.common.app.mgt.ios.AppStoreApplication;
import org.wso2.carbon.device.mgt.common.app.mgt.ios.EnterpriseApplication; import org.wso2.carbon.device.mgt.common.app.mgt.ios.EnterpriseApplication;
import org.wso2.carbon.device.mgt.common.app.mgt.ios.RemoveApplication; import org.wso2.carbon.device.mgt.common.app.mgt.ios.RemoveApplication;
import org.wso2.carbon.device.mgt.common.app.mgt.ios.WebClip; import org.wso2.carbon.device.mgt.common.app.mgt.ios.WebClip;
import org.wso2.carbon.device.mgt.common.app.mgt.MobileApp; import org.wso2.carbon.device.mgt.common.app.mgt.App;
import org.wso2.carbon.device.mgt.common.operation.mgt.Operation; import org.wso2.carbon.device.mgt.common.operation.mgt.Operation;
import org.wso2.carbon.device.mgt.core.operation.mgt.ProfileOperation; import org.wso2.carbon.device.mgt.core.operation.mgt.ProfileOperation;
@ -40,7 +40,7 @@ public class MDMIOSOperationUtil {
* @param application MobileApp application * @param application MobileApp application
* @return operation * @return operation
*/ */
public static Operation createInstallAppOperation(MobileApp application) { public static Operation createInstallAppOperation(App application) {
ProfileOperation operation = new ProfileOperation(); ProfileOperation operation = new ProfileOperation();
@ -90,7 +90,7 @@ public class MDMIOSOperationUtil {
return operation; return operation;
} }
public static Operation createAppUninstallOperation(MobileApp application) { public static Operation createAppUninstallOperation(App application) {
ProfileOperation operation = new ProfileOperation(); ProfileOperation operation = new ProfileOperation();
operation.setCode(MDMAppConstants.IOSConstants.OPCODE_REMOVE_APPLICATION); operation.setCode(MDMAppConstants.IOSConstants.OPCODE_REMOVE_APPLICATION);

Loading…
Cancel
Save