Add new application type

Add new application type for IoT use cases. Further, it is named as CUSTOM
feature/appm-store/pbac
lasanthaDLPDS 5 years ago
parent bf67894924
commit cfd0f709ef

@ -23,6 +23,6 @@ package org.wso2.carbon.device.application.mgt.common;
* Application Types.
*/
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.Category;
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.ApplicationUpdateWrapper;
import org.wso2.carbon.device.application.mgt.common.wrapper.ApplicationWrapper;
@ -63,6 +65,9 @@ public interface ApplicationManager {
Application createPublicApp(PublicAppWrapper publicAppWrapper, ApplicationArtifact applicationArtifact)
throws ApplicationManagementException;
Application createCustomApp(CustomAppWrapper customAppWrapper, ApplicationArtifact applicationArtifact)
throws ApplicationManagementException;
/**
* Updates an already existing application.
*
@ -203,6 +208,9 @@ public interface ApplicationManager {
ApplicationRelease updateWebAppRelease(String releaseUuid, WebAppReleaseWrapper webAppReleaseWrapper,
ApplicationArtifact applicationArtifact) throws ApplicationManagementException;
ApplicationRelease updateCustomAppRelease(String releaseUuid, CustomAppReleaseWrapper customAppReleaseWrapper,
ApplicationArtifact applicationArtifact) throws ApplicationManagementException;
/***
* 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 deviceType Compatible device tipe of the application.
* @param deviceType Compatible device type of the application.
* @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,
InputStream binaryFile) throws ResourceManagementException;
void uploadReleaseArtifact(ApplicationReleaseDTO applicationRelease, String deviceType, InputStream binaryFile)
throws ResourceManagementException;
/**
* 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.services.ApplicationManager;
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.ApplicationUpdateWrapper;
import org.wso2.carbon.device.application.mgt.common.wrapper.ApplicationWrapper;
@ -133,49 +135,31 @@ public class ApplicationManagerImpl implements ApplicationManager {
@Override
public Application createEntApp(ApplicationWrapper applicationWrapper,
ApplicationArtifact applicationArtifact) throws ApplicationManagementException {
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true);
String userName = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername();
if (log.isDebugEnabled()) {
log.debug("Application create request is received for the tenant : " + tenantId + " and the user: "
+ userName);
log.debug("Ent. Application create request is received. Application name: " + applicationWrapper.getName()
+ " Device type: " + applicationWrapper.getDeviceType());
}
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
applicationReleaseDTO = uploadEntAppReleaseArtifacts(applicationReleaseDTO, applicationArtifact,
ApplicationReleaseDTO applicationReleaseDTO = uploadEntAppReleaseArtifacts(
applicationDTO.getApplicationReleaseDTOs().get(0), applicationArtifact,
applicationWrapper.getDeviceType(), false);
applicationDTO.getApplicationReleaseDTOs().clear();
applicationDTO.getApplicationReleaseDTOs().add(applicationReleaseDTO);
return addAppDataIntoDB(applicationDTO, tenantId);
return addAppDataIntoDB(applicationDTO);
}
@Override
public Application createWebClip(WebAppWrapper webAppWrapper, ApplicationArtifact applicationArtifact)
throws ApplicationManagementException {
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true);
String userName = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername();
if (log.isDebugEnabled()) {
log.debug("Web clip create request is received for the tenant : " + tenantId + " From" + " the user : "
+ userName);
log.debug("Web clip create request is received. App name: " + webAppWrapper.getName() + " Device type: "
+ Constants.ANY);
}
ApplicationDTO applicationDTO = APIUtil.convertToAppDTO(webAppWrapper);
ApplicationReleaseDTO applicationReleaseDTO = applicationDTO.getApplicationReleaseDTOs().get(0);
String uuid = UUID.randomUUID().toString();
String md5 = DigestUtils.md5Hex(applicationReleaseDTO.getInstallerName());
applicationReleaseDTO.setUuid(uuid);
applicationReleaseDTO.setAppHashValue(md5);
applicationReleaseDTO.setUuid(UUID.randomUUID().toString());
applicationReleaseDTO.setAppHashValue(DigestUtils.md5Hex(applicationReleaseDTO.getInstallerName()));
//uploading application artifacts
try {
applicationDTO.getApplicationReleaseDTOs().clear();
@ -185,46 +169,31 @@ public class ApplicationManagerImpl implements ApplicationManager {
log.error(msg);
throw new ApplicationManagementException(msg, e);
}
//insert application data into database
return addAppDataIntoDB(applicationDTO, tenantId);
return addAppDataIntoDB(applicationDTO);
}
@Override
public Application createPublicApp(PublicAppWrapper publicAppWrapper, ApplicationArtifact applicationArtifact)
throws ApplicationManagementException {
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true);
String userName = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername();
String publicAppStorePath = "";
if (log.isDebugEnabled()) {
log.debug("Public app creating request is received for the tenant : " + tenantId + " From" + " the user : "
+ userName);
}
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);
log.debug("Public app creating request is received. App name: " + publicAppWrapper.getName()
+ " Device Type: " + publicAppWrapper.getDeviceType());
}
String publicAppStorePath = "";
if (DeviceTypes.ANDROID.toString().equals(publicAppWrapper.getDeviceType())) {
publicAppStorePath = Constants.GOOGLE_PLAY_STORE_URL;
} else if (DeviceTypes.IOS.toString().equals(publicAppWrapper.getDeviceType())) {
publicAppStorePath = Constants.APPLE_STORE_URL;
}
ApplicationDTO applicationDTO = APIUtil.convertToAppDTO(publicAppWrapper);
ApplicationReleaseDTO applicationReleaseDTO = applicationDTO.getApplicationReleaseDTOs().get(0);
String uuid = UUID.randomUUID().toString();
String appInstallerUrl = publicAppStorePath + applicationReleaseDTO.getPackageName();
//todo check app package name exist or not, do it in validation method
applicationReleaseDTO.setInstallerName(appInstallerUrl);
String md5 = DigestUtils.md5Hex(appInstallerUrl);
applicationReleaseDTO.setUuid(uuid);
applicationReleaseDTO.setAppHashValue(md5);
applicationReleaseDTO.setUuid(UUID.randomUUID().toString());
applicationReleaseDTO.setAppHashValue(DigestUtils.md5Hex(appInstallerUrl));
//uploading application artifacts
try {
applicationDTO.getApplicationReleaseDTOs().clear();
@ -235,9 +204,70 @@ public class ApplicationManagerImpl implements ApplicationManager {
log.error(msg, e);
throw new ApplicationManagementException(msg, e);
}
//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 {
@ -264,9 +294,7 @@ public class ApplicationManagerImpl implements ApplicationManager {
// The application executable artifacts such as apks are uploaded.
try {
byte[] content = IOUtils.toByteArray(applicationArtifact.getInstallerStream());
applicationReleaseDTO.setInstallerName(applicationArtifact.getInstallerName());
try (ByteArrayInputStream binary = new ByteArrayInputStream(content)) {
ApplicationInstaller applicationInstaller = applicationStorageManager
.getAppInstallerData(binary, deviceType);
@ -286,7 +314,6 @@ public class ApplicationManagerImpl implements ApplicationManager {
}
applicationReleaseDTO.setVersion(applicationInstaller.getVersion());
applicationReleaseDTO.setPackageName(packagename);
String md5OfApp = StorageManagementUtil.getMD5(new ByteArrayInputStream(content));
if (md5OfApp == null) {
String msg = "Error occurred while md5sum value retrieving process: application UUID "
@ -303,7 +330,7 @@ public class ApplicationManagerImpl implements ApplicationManager {
applicationReleaseDTO.setAppHashValue(md5OfApp);
try (ByteArrayInputStream binaryDuplicate = new ByteArrayInputStream(content)) {
applicationReleaseDTO = applicationStorageManager
applicationStorageManager
.uploadReleaseArtifact(applicationReleaseDTO, deviceType, binaryDuplicate);
}
} catch (DBConnectionException e) {
@ -384,7 +411,7 @@ public class ApplicationManagerImpl implements ApplicationManager {
String deletingAppHashValue = applicationReleaseDTO.getAppHashValue();
applicationReleaseDTO.setAppHashValue(md5OfApp);
try (ByteArrayInputStream binaryDuplicate = new ByteArrayInputStream(content)) {
applicationReleaseDTO = applicationStorageManager
applicationStorageManager
.uploadReleaseArtifact(applicationReleaseDTO, deviceType, binaryDuplicate);
applicationStorageManager.copyImageArtifactsAndDeleteInstaller(deletingAppHashValue,
applicationReleaseDTO);
@ -624,12 +651,11 @@ public class ApplicationManagerImpl implements ApplicationManager {
* required to do the validation of request and check the existence of application releaseDTO.
*
* @param applicationDTO Application DTO object.
* @param tenantId Tenant Id
* @return {@link Application}
* @throws ApplicationManagementException which throws if error occurs while during application management.
*/
private Application addAppDataIntoDB(ApplicationDTO applicationDTO, int tenantId)
throws ApplicationManagementException {
private Application addAppDataIntoDB(ApplicationDTO applicationDTO) throws ApplicationManagementException {
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true);
ApplicationStorageManager applicationStorageManager = DAOUtil.getApplicationStorageManager();
List<String> unrestrictedRoles = applicationDTO.getUnrestrictedRoles();
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)
throws ApplicationManagementException {
if (applicationDTO == null) {
@ -2660,6 +2810,43 @@ public class ApplicationManagerImpl implements ApplicationManager {
throw new BadRequestException(msg);
}
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 {
String msg = "Invalid payload found with the request. Hence verify the request payload object.";
log.error(msg);
@ -2738,7 +2925,7 @@ public class ApplicationManagerImpl implements ApplicationManager {
}
@Override
public <T> void validateReleaseCreatingRequest(T param) throws ApplicationManagementException {
public <T> void validateReleaseCreatingRequest(T param, String deviceType) throws ApplicationManagementException {
if (param == null) {
String msg = "In order to validate release creating request param shouldn't be null.";
log.error(msg);
@ -2746,12 +2933,20 @@ public class ApplicationManagerImpl implements ApplicationManager {
}
if (param instanceof EntAppReleaseWrapper) {
EntAppReleaseWrapper entAppReleaseWrapper = (EntAppReleaseWrapper) param;
if (StringUtils.isEmpty(entAppReleaseWrapper.getSupportedOsVersions())) {
AtomicReference<EntAppReleaseWrapper> entAppReleaseWrapper = new AtomicReference<>(
(EntAppReleaseWrapper) param);
if (StringUtils.isEmpty(entAppReleaseWrapper.get().getSupportedOsVersions())) {
String msg = "Supported OS Version shouldn't be null or empty.";
log.error(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) {
WebAppReleaseWrapper webAppReleaseWrapper = (WebAppReleaseWrapper) param;
UrlValidator urlValidator = new UrlValidator();
@ -2788,7 +2983,25 @@ public class ApplicationManagerImpl implements ApplicationManager {
log.error(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 {
String msg = "Invalid payload found with the release creating request. Hence verify the release creating "
+ "request payload object.";
@ -2814,7 +3027,6 @@ public class ApplicationManagerImpl implements ApplicationManager {
@Override
public void validateBinaryArtifact(Attachment binaryFile) throws RequestValidatingException {
if (binaryFile == null) {
String msg = "Binary file is not found with the application release creating request for ENTERPRISE app "
+ "creating request.";

@ -143,25 +143,21 @@ public class ApplicationStorageManagerImpl implements ApplicationStorageManager
}
@Override
public ApplicationReleaseDTO uploadReleaseArtifact(ApplicationReleaseDTO applicationReleaseDTO,
public void uploadReleaseArtifact(ApplicationReleaseDTO applicationReleaseDTO,
String deviceType, InputStream binaryFile) throws ResourceManagementException {
try {
String artifactDirectoryPath;
String artifactPath;
byte [] content = IOUtils.toByteArray(binaryFile);
artifactDirectoryPath =
String artifactDirectoryPath =
storagePath + applicationReleaseDTO.getAppHashValue() + File.separator + Constants.APP_ARTIFACT;
StorageManagementUtil.createArtifactDirectory(artifactDirectoryPath);
artifactPath = artifactDirectoryPath + File.separator + applicationReleaseDTO.getInstallerName();
String artifactPath = artifactDirectoryPath + File.separator + applicationReleaseDTO.getInstallerName();
saveFile(new ByteArrayInputStream(content), artifactPath);
} catch (IOException e) {
String msg = "IO Exception while saving the release artifacts in the server for the application UUID "
+ applicationReleaseDTO.getUuid();
log.error(msg, e);
throw new ApplicationStorageManagementException( msg, e);
throw new ResourceManagementException( msg, e);
}
return applicationReleaseDTO;
}
@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.DeviceIdentifier;
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.android.CustomApplication;
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.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.OperationManagementException;
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.GroupManagementProviderService;
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)
throws ApplicationManagementException {
try {
//todo rethink and modify the {@link MobileApp} usage
MobileApp mobileApp = new MobileApp();
//todo rethink and modify the {@link App} usage
App app = new App();
MobileAppTypes mobileAppType = MobileAppTypes.valueOf(application.getType());
if (DeviceTypes.ANDROID.toString().equalsIgnoreCase(deviceType)) {
if (SubAction.INSTALL.toString().equalsIgnoreCase(action)) {
mobileApp.setType(mobileAppType);
mobileApp.setLocation(application.getApplicationReleases().get(0).getInstallerPath());
return MDMAndroidOperationUtil.createInstallAppOperation(mobileApp);
app.setType(mobileAppType);
app.setLocation(application.getApplicationReleases().get(0).getInstallerPath());
return MDMAndroidOperationUtil.createInstallAppOperation(app);
} else if (SubAction.UNINSTALL.toString().equalsIgnoreCase(action)) {
return MDMAndroidOperationUtil.createAppUninstallOperation(mobileApp);
return MDMAndroidOperationUtil.createAppUninstallOperation(app);
} else {
String msg = "Invalid Action is found. Action: " + action;
log.error(msg);
@ -480,24 +482,50 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
String plistDownloadEndpoint = APIUtil.getArtifactDownloadBaseURL()
+ MDMAppConstants.IOSConstants.PLIST + Constants.FORWARD_SLASH
+ application.getApplicationReleases().get(0).getUuid();
mobileApp.setType(mobileAppType);
mobileApp.setLocation(plistDownloadEndpoint);
app.setType(mobileAppType);
app.setLocation(plistDownloadEndpoint);
Properties properties = new Properties();
properties.put(MDMAppConstants.IOSConstants.IS_PREVENT_BACKUP, true);
properties.put(MDMAppConstants.IOSConstants.IS_REMOVE_APP, true);
mobileApp.setProperties(properties);
return MDMIOSOperationUtil.createInstallAppOperation(mobileApp);
app.setProperties(properties);
return MDMIOSOperationUtil.createInstallAppOperation(app);
} 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 {
String msg = "Invalid device type is found. Device Type: " + deviceType;
log.error(msg);
throw new ApplicationManagementException(msg);
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 {
String msg = "Invalid Action is found. Action: " + action;
log.error(msg);
throw new ApplicationManagementException(msg);
}
} else {
String msg = "Invalid device type is found. Device Type: " + deviceType;
log.error(msg);
throw new ApplicationManagementException(msg);
}
}
} catch (UnknownApplicationTypeException e) {
String msg = "Unknown Application type is found.";

@ -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.services.*;
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.ApplicationWrapper;
import org.wso2.carbon.device.application.mgt.common.wrapper.PublicAppReleaseWrapper;
@ -266,6 +268,21 @@ public class APIUtil {
List<ApplicationReleaseDTO> applicationReleaseEntities = publicAppWrapper.getPublicAppReleaseWrappers()
.stream().map(APIUtil::releaseWrapperToReleaseDTO).collect(Collectors.toList());
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;
}
@ -301,6 +318,15 @@ public class APIUtil {
applicationReleaseDTO.setIsSharedWithAllTenants(publicAppReleaseWrapper.getIsSharedWithAllTenants());
applicationReleaseDTO.setMetaData(publicAppReleaseWrapper.getMetaData());
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;
}

@ -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.ApplicationReleaseDTO;
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.ApplicationUpdateWrapper;
import org.wso2.carbon.device.application.mgt.common.wrapper.ApplicationWrapper;
@ -468,9 +470,78 @@ public interface ApplicationManagementPublisherAPI {
);
@POST
@Path("/custom-app")
@Produces(MediaType.APPLICATION_JSON)
@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(
consumes = MediaType.APPLICATION_JSON,
produces = MediaType.APPLICATION_JSON,
@ -500,6 +571,11 @@ public interface ApplicationManagementPublisherAPI {
response = ErrorResponse.class)
})
Response createEntAppRelease(
@ApiParam(
name = "deviceType",
value = "Device type that application is compatible with.",
required = true)
@PathParam("deviceType") String deviceType,
@ApiParam(
name = "appId",
value = "Id of the application.",
@ -895,6 +971,77 @@ public interface ApplicationManagementPublisherAPI {
value = "Third screenshot of the uploading application")
@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
@Path("/life-cycle/state-changes/{uuid}")
@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.Tag;
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.ApplicationUpdateWrapper;
import org.wso2.carbon.device.application.mgt.common.wrapper.ApplicationWrapper;
@ -40,6 +42,7 @@ 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.UnexpectedServerErrorException;
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.common.exception.ApplicationManagementException;
import org.wso2.carbon.device.application.mgt.common.services.ApplicationManager;
@ -180,7 +183,8 @@ public class ApplicationManagementPublisherAPIImpl implements ApplicationManagem
List<Attachment> attachmentList = constructAttachmentList(screenshot1, screenshot2, screenshot3);
try {
applicationManager.validateAppCreatingRequest(applicationWrapper);
applicationManager.validateReleaseCreatingRequest(applicationWrapper.getEntAppReleaseWrappers().get(0));
applicationManager.validateReleaseCreatingRequest(applicationWrapper.getEntAppReleaseWrappers().get(0),
applicationWrapper.getDeviceType());
applicationManager.validateBinaryArtifact(binaryFile);
applicationManager.validateImageArtifacts(iconFile, bannerFile, attachmentList);
@ -195,11 +199,11 @@ public class ApplicationManagementPublisherAPIImpl implements ApplicationManagem
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
}
} catch (ApplicationManagementException e) {
String msg = "Error occurred while creating the application";
String msg = "Error occurred while creating the ent. 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";
String msg = "Error occurred while handling the ent. application creating request";
log.error(msg, e);
return Response.status(Response.Status.BAD_REQUEST).entity(msg).build();
}
@ -219,7 +223,8 @@ public class ApplicationManagementPublisherAPIImpl implements ApplicationManagem
List<Attachment> attachmentList = constructAttachmentList(screenshot1, screenshot2, screenshot3);
try {
applicationManager.validateAppCreatingRequest(webAppWrapper);
applicationManager.validateReleaseCreatingRequest(webAppWrapper.getWebAppReleaseWrappers().get(0));
applicationManager
.validateReleaseCreatingRequest(webAppWrapper.getWebAppReleaseWrappers().get(0), Constants.ANY);
applicationManager.validateImageArtifacts(iconFile, bannerFile, attachmentList);
// Created new Web App
@ -257,7 +262,8 @@ public class ApplicationManagementPublisherAPIImpl implements ApplicationManagem
List<Attachment> attachmentList = constructAttachmentList(screenshot1, screenshot2, screenshot3);
try {
applicationManager.validateAppCreatingRequest(publicAppWrapper);
applicationManager.validateReleaseCreatingRequest(publicAppWrapper.getPublicAppReleaseWrappers().get(0));
applicationManager.validateReleaseCreatingRequest(publicAppWrapper.getPublicAppReleaseWrappers().get(0),
publicAppWrapper.getDeviceType());
applicationManager.validateImageArtifacts(iconFile, bannerFile, attachmentList);
// Created new Public App
@ -283,8 +289,50 @@ public class ApplicationManagementPublisherAPIImpl implements ApplicationManagem
@POST
@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(
@PathParam("deviceType") String deviceType,
@PathParam("appId") int appId,
@Multipart("applicationRelease") EntAppReleaseWrapper entAppReleaseWrapper,
@Multipart("binaryFile") Attachment binaryFile,
@ -296,7 +344,7 @@ public class ApplicationManagementPublisherAPIImpl implements ApplicationManagem
ApplicationManager applicationManager = APIUtil.getApplicationManager();
List<Attachment> attachmentList = constructAttachmentList(screenshot1, screenshot2, screenshot3);
try {
applicationManager.validateReleaseCreatingRequest(entAppReleaseWrapper);
applicationManager.validateReleaseCreatingRequest(entAppReleaseWrapper, deviceType);
applicationManager.validateBinaryArtifact(binaryFile);
applicationManager.validateImageArtifacts(iconFile, bannerFile, attachmentList);
@ -544,6 +592,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
@Path("/retire/{appId}")

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

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

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

@ -67,6 +67,8 @@ class Dashboard extends React.Component {
APP</Link></Menu.Item>
<Menu.Item key="setting:3"><Link to="/publisher/add-new-app/web-clip">Web
Clip</Link></Menu.Item>
<Menu.Item key="setting:4"><Link to="/publisher/add-new-app/custom-app">Custom
App</Link></Menu.Item>
</SubMenu>
<Menu.Item key="2"><Link to="/publisher/manage"><Icon
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;

@ -21,7 +21,7 @@ package org.wso2.carbon.device.mgt.jaxrs.beans;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
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;
@ -53,13 +53,13 @@ public class ApplicationWrapper {
name = "application",
value = "Details of the mobile application.",
required = true)
private MobileApp application;
private App application;
public MobileApp getApplication() {
public App getApplication() {
return application;
}
public void setApplication(MobileApp application) {
public void setApplication(App 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.MDMIOSOperationUtil;
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.POST;
@ -61,15 +61,15 @@ public class ApplicationManagementAdminServiceImpl implements ApplicationManagem
RequestValidationUtil.validateApplicationInstallationContext(applicationWrapper);
try {
appManagerConnector = DeviceMgtAPIUtils.getAppManagementService();
MobileApp mobileApp = applicationWrapper.getApplication();
App app = applicationWrapper.getApplication();
if (applicationWrapper.getDeviceIdentifiers() != null) {
for (DeviceIdentifier deviceIdentifier : applicationWrapper.getDeviceIdentifiers()) {
String deviceType = deviceIdentifier.getType().toUpperCase();
if (Platform.ANDROID.toString().equals(deviceType)) {
operation = MDMAndroidOperationUtil.createInstallAppOperation(mobileApp);
operation = MDMAndroidOperationUtil.createInstallAppOperation(app);
} else if (Platform.IOS.toString().equals(deviceType)) {
operation = MDMIOSOperationUtil.createInstallAppOperation(mobileApp);
operation = MDMIOSOperationUtil.createInstallAppOperation(app);
}
}
if (applicationWrapper.getRoleNameList() != null && applicationWrapper.getRoleNameList().size() > 0) {
@ -111,15 +111,15 @@ public class ApplicationManagementAdminServiceImpl implements ApplicationManagem
RequestValidationUtil.validateApplicationInstallationContext(applicationWrapper);
try {
appManagerConnector = DeviceMgtAPIUtils.getAppManagementService();
MobileApp mobileApp = applicationWrapper.getApplication();
App app = applicationWrapper.getApplication();
if (applicationWrapper.getDeviceIdentifiers() != null) {
for (DeviceIdentifier deviceIdentifier : applicationWrapper.getDeviceIdentifiers()) {
String deviceType = deviceIdentifier.getType().toUpperCase();
if (Platform.ANDROID.toString().equals(deviceType)) {
operation = MDMAndroidOperationUtil.createAppUninstallOperation(mobileApp);
operation = MDMAndroidOperationUtil.createAppUninstallOperation(app);
} else if (deviceType.equals(Platform.IOS.toString())) {
operation = MDMIOSOperationUtil.createAppUninstallOperation(mobileApp);
operation = MDMIOSOperationUtil.createAppUninstallOperation(app);
}
}
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.ApiModelProperty;
import org.wso2.carbon.device.mgt.common.app.mgt.MobileAppTypes;
import java.util.Properties;
@ -29,7 +28,7 @@ import java.util.Properties;
* which is used by AppM.
*/
@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)
private String id;
@ -153,5 +152,4 @@ public class MobileApp {
public void setProperties(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.operation.mgt.Operation;
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;
/**
@ -40,7 +40,7 @@ public class MDMAndroidOperationUtil {
* @return operation
*
*/
public static Operation createInstallAppOperation(MobileApp application) throws UnknownApplicationTypeException {
public static Operation createInstallAppOperation(App application) throws UnknownApplicationTypeException {
ProfileOperation operation = new ProfileOperation();
operation.setCode(MDMAppConstants.AndroidConstants.OPCODE_INSTALL_APPLICATION);
@ -79,7 +79,7 @@ public class MDMAndroidOperationUtil {
* @param application MobileApp application
* @return operation
*/
public static Operation createAppUninstallOperation(MobileApp application) throws UnknownApplicationTypeException {
public static Operation createAppUninstallOperation(App application) throws UnknownApplicationTypeException {
ProfileOperation operation = new ProfileOperation();
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.RemoveApplication;
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.core.operation.mgt.ProfileOperation;
@ -40,7 +40,7 @@ public class MDMIOSOperationUtil {
* @param application MobileApp application
* @return operation
*/
public static Operation createInstallAppOperation(MobileApp application) {
public static Operation createInstallAppOperation(App application) {
ProfileOperation operation = new ProfileOperation();
@ -90,7 +90,7 @@ public class MDMIOSOperationUtil {
return operation;
}
public static Operation createAppUninstallOperation(MobileApp application) {
public static Operation createAppUninstallOperation(App application) {
ProfileOperation operation = new ProfileOperation();
operation.setCode(MDMAppConstants.IOSConstants.OPCODE_REMOVE_APPLICATION);

Loading…
Cancel
Save