org.wso2.carbon.appmgt.rest.api.store.impl.AppsApiServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.wso2.carbon.appmgt.rest.api.store.impl.AppsApiServiceImpl.java

Source

/*
 * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 * WSO2 Inc. licenses this file to you under the Apache License,
 * Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License.
 * you may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.wso2.carbon.appmgt.rest.api.store.impl;

import com.google.gson.JsonObject;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.javascript.NativeObject;
import org.wso2.carbon.appmgt.api.APIConsumer;
import org.wso2.carbon.appmgt.api.APIProvider;
import org.wso2.carbon.appmgt.api.AppManagementException;
import org.wso2.carbon.appmgt.api.model.APIIdentifier;
import org.wso2.carbon.appmgt.api.model.APIStatus;
import org.wso2.carbon.appmgt.api.model.App;
import org.wso2.carbon.appmgt.api.model.Documentation;
import org.wso2.carbon.appmgt.api.model.FileContent;
import org.wso2.carbon.appmgt.api.model.MobileApp;
import org.wso2.carbon.appmgt.api.model.OneTimeDownloadLink;
import org.wso2.carbon.appmgt.api.model.PlistTemplateContext;
import org.wso2.carbon.appmgt.api.model.Subscriber;
import org.wso2.carbon.appmgt.api.model.Subscription;
import org.wso2.carbon.appmgt.api.model.Tag;
import org.wso2.carbon.appmgt.api.model.WebApp;
import org.wso2.carbon.appmgt.impl.AppMConstants;
import org.wso2.carbon.appmgt.impl.AppRepository;
import org.wso2.carbon.appmgt.impl.DefaultAppRepository;
import org.wso2.carbon.appmgt.impl.service.ServiceReferenceHolder;
import org.wso2.carbon.appmgt.impl.utils.AppManagerUtil;
import org.wso2.carbon.appmgt.impl.workflow.WorkflowConstants;
import org.wso2.carbon.appmgt.impl.workflow.WorkflowException;
import org.wso2.carbon.appmgt.impl.workflow.WorkflowExecutor;
import org.wso2.carbon.appmgt.impl.workflow.WorkflowExecutorFactory;
import org.wso2.carbon.appmgt.mobile.store.Operations;
import org.wso2.carbon.appmgt.mobile.utils.HostResolver;
import org.wso2.carbon.appmgt.mobile.utils.MobileApplicationException;
import org.wso2.carbon.appmgt.mobile.utils.MobileConfigurations;
import org.wso2.carbon.appmgt.rest.api.store.AppsApiService;
import org.wso2.carbon.appmgt.rest.api.store.dto.AppDTO;
import org.wso2.carbon.appmgt.rest.api.store.dto.AppListDTO;
import org.wso2.carbon.appmgt.rest.api.store.dto.AppRatingInfoDTO;
import org.wso2.carbon.appmgt.rest.api.store.dto.AppRatingListDTO;
import org.wso2.carbon.appmgt.rest.api.store.dto.DocumentDTO;
import org.wso2.carbon.appmgt.rest.api.store.dto.DocumentListDTO;
import org.wso2.carbon.appmgt.rest.api.store.dto.EventsDTO;
import org.wso2.carbon.appmgt.rest.api.store.dto.FavouritePageDTO;
import org.wso2.carbon.appmgt.rest.api.store.dto.InstallDTO;
import org.wso2.carbon.appmgt.rest.api.store.dto.ScheduleDTO;
import org.wso2.carbon.appmgt.rest.api.store.dto.TagListDTO;
import org.wso2.carbon.appmgt.rest.api.store.dto.UserIdListDTO;
import org.wso2.carbon.appmgt.rest.api.store.utils.mappings.APPMappingUtil;
import org.wso2.carbon.appmgt.rest.api.store.utils.mappings.DocumentationMappingUtil;
import org.wso2.carbon.appmgt.rest.api.util.RestApiConstants;
import org.wso2.carbon.appmgt.rest.api.util.utils.RestApiUtil;
import org.wso2.carbon.appmgt.rest.api.util.validation.BeanValidator;
import org.wso2.carbon.appmgt.rest.api.util.validation.CommonValidator;
import org.wso2.carbon.appmgt.usage.publisher.AppMUIActivitiesDASDataPublisher;
import org.wso2.carbon.base.MultitenantConstants;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.social.core.SocialActivityException;
import org.wso2.carbon.social.core.service.SocialActivityService;
import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.utils.multitenancy.MultitenantUtils;
import org.wso2.mobile.utils.utilities.PlistTemplateBuilder;

import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class AppsApiServiceImpl extends AppsApiService {

    private static final Log log = LogFactory.getLog(AppsApiServiceImpl.class);
    private static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ssXXX";

    BeanValidator beanValidator;

    /**
     * Download/Install mobile application
     *
     * @param contentType
     * @param install     InstallDTO
     * @return
     */

    @Override
    public Response appsDownloadPost(String contentType, InstallDTO install) {
        String username = RestApiUtil.getLoggedInUsername();
        try {
            APIProvider appProvider = RestApiUtil.getLoggedInUserProvider();
            String tenantDomainName = MultitenantUtils.getTenantDomain(username);
            int tenantId = ServiceReferenceHolder.getInstance().getRealmService().getTenantManager()
                    .getTenantId(tenantDomainName);
            String tenantUserName = MultitenantUtils.getTenantAwareUsername(username);
            String appId = install.getAppId();
            MobileApp mobileApp = appProvider.getMobileApp(appId);
            if (mobileApp == null) {
                RestApiUtil.handleResourceNotFoundError("Mobile Application", appId, log);
            }
            if (!APIStatus.PUBLISHED.getStatus().equals(mobileApp.getLifeCycleStatus().getStatus())) {
                RestApiUtil.handleBadRequest("Mobile application with uuid '" + appId + "' is not in '"
                        + APIStatus.PUBLISHED + "' state", log);
            }
            Operations mobileOperation = new Operations();
            String action = "install";
            String[] parameters = null;

            if ("user".equals(install.getType())) {
                parameters = new String[1];
                parameters[0] = username;
            } else if ("device".equals(install.getType())) {
                parameters = Arrays.copyOf(install.getDeviceIds().toArray(),
                        install.getDeviceIds().toArray().length, String[].class);
                if (parameters == null) {
                    RestApiUtil.handleBadRequest("Device IDs should be provided to perform device app installation",
                            log);
                }
            } else {
                RestApiUtil.handleBadRequest("Invalid installation type.", log);
            }

            //TODO:Operations.performAction expects the user to be passed as a stringified object, so that
            //TODO:We are prviding a stringified user here
            JSONObject user = new JSONObject();
            user.put("username", tenantUserName);
            user.put("tenantDomain", tenantDomainName);
            user.put("tenantId", tenantId);
            //Check for app existance and app state

            appProvider.subscribeMobileApp(username, appId);
            String activityId = mobileOperation.performAction(user.toString(), action, tenantId, install.getType(),
                    appId, parameters, null, null);

            JSONObject response = new JSONObject();
            response.put("activityId", activityId);
            //mobileOperation.performAction(user.toString(), action, tenantId, appId, install.getType(), parameters, null);
            return Response.ok().entity(response.toString()).build();

        } catch (AppManagementException e) {
            RestApiUtil.handleInternalServerError("Internal Error occurred while installing", e, log);
        } catch (MobileApplicationException e) {
            RestApiUtil.handleBadRequest(e.getMessage(), log);
        } catch (UserStoreException e) {
            RestApiUtil.handleInternalServerError("User store related Error occurred while installing", e, log);
        } catch (JSONException e) {
            RestApiUtil.handleInternalServerError("Json casting Error occurred while installing", e, log);
        }
        return Response.serverError().build();

    }

    /**
     *
     * @param appId
     * @param contentType
     * @return
     */
    @Override
    public Response appsMobileIdAppIdDownloadPost(String appId, String contentType) {
        String username = RestApiUtil.getLoggedInUsername();
        Map<String, String> appURLResponse = new HashMap<>();
        String appURL = null;

        try {
            APIProvider appProvider = RestApiUtil.getLoggedInUserProvider();
            MobileApp mobileApp = appProvider.getMobileApp(appId);
            if (mobileApp == null) {
                RestApiUtil.handleResourceNotFoundError("Mobile Application", appId, log);
            }
            if (!APIStatus.PUBLISHED.getStatus().equals(mobileApp.getLifeCycleStatus().getStatus())) {
                RestApiUtil.handleBadRequest("Mobile application with uuid '" + appId + "' is not in '"
                        + APIStatus.PUBLISHED + "' state", log);
            }

            //Make user subscription, it the subscription is not available
            appProvider.subscribeMobileApp(username, appId);

            if (AppMConstants.MobileAppTypes.ENTERPRISE.equals(mobileApp.getType())) {
                String oneTimeDownloadUUID = appProvider.generateOneTimeDownloadLink(appId);
                if (AppMConstants.MOBILE_APPS_PLATFORM_ANDROID.equals(mobileApp.getPlatform())) {
                    appURL = HostResolver
                            .getHost(MobileConfigurations.getInstance().getMDMConfigs()
                                    .get(MobileConfigurations.APP_DOWNLOAD_URL_HOST))
                            + RestApiUtil.getStoreRESTAPIContextPath()
                            + AppMConstants.MOBILE_ONE_TIME_DOWNLOAD_API_PATH + File.separator
                            + oneTimeDownloadUUID;
                } else if (AppMConstants.MOBILE_APPS_PLATFORM_IOS.equals(mobileApp.getPlatform())) {
                    appURL = HostResolver
                            .getHost(MobileConfigurations.getInstance().getMDMConfigs()
                                    .get(MobileConfigurations.APP_DOWNLOAD_URL_HOST))
                            + RestApiUtil.getStoreRESTAPIContextPath() + AppMConstants.MOBILE_PLIST_API_PATH
                            + File.separator + appId + File.separator + oneTimeDownloadUUID;
                }
            } else if (AppMConstants.MOBILE_APPS_PLATFORM_WEBAPP.equals(mobileApp.getType())
                    || AppMConstants.MobileAppTypes.PUBLIC.equals(mobileApp.getType())) {
                appURL = mobileApp.getAppUrl();
            }
            Map<String, String> response = new HashMap<>();
            response.put("appUrl", appURL);
            return Response.ok().entity(response).build();
        } catch (AppManagementException e) {
            if (RestApiUtil.isDueToResourceNotFound(e) || RestApiUtil.isDueToAuthorizationFailure(e)) {
                RestApiUtil.handleResourceNotFoundError(AppMConstants.MOBILE_ASSET_TYPE, appId, e, log);
            } else {
                RestApiUtil.handleInternalServerError(
                        "Error occurred while subscribing to mobile app with uuid : " + appId, e, log);
            }
        }
        return null;

    }

    @Override
    public Response appsEventPublishPost(EventsDTO events, String contentType) {
        beanValidator = new BeanValidator();
        //Validate common mandatory fields for mobile and webapp
        beanValidator.validate(events);

        if (events.getEvents().size() == 0) {
            RestApiUtil.handleBadRequest("Invalid event stream", log);
        }
        AppMUIActivitiesDASDataPublisher appMgtBAMPublishObj = new AppMUIActivitiesDASDataPublisher();

        NativeObject[] statsObjectArr = new NativeObject[events.getEvents().size()];
        for (int i = 0; i < events.getEvents().size(); i++) {
            HashMap statMap = ((HashMap) (events.getEvents().get(i)));
            NativeObject statObj = new NativeObject();
            statObj.put("action", statObj, statMap.get("action"));
            statObj.put("item", statObj, statMap.get("item"));
            statObj.put("timestamp", statObj, statMap.get("timestamp"));
            statObj.put("appId", statObj, statMap.get("appId"));
            statObj.put("userId", statObj, statMap.get("userId"));
            statObj.put("tenantId", statObj, statMap.get("tenantId"));
            statObj.put("appName", statObj, statMap.get("appName"));
            statObj.put("appVersion", statObj, statMap.get("appVersion"));
            statObj.put("context", statObj, statMap.get("context"));

            statsObjectArr[i] = statObj;
        }
        //Pass data to java class to save
        appMgtBAMPublishObj.processUiActivityObject(statsObjectArr);
        return Response.accepted().build();
    }

    /**
     * Get Favourite home page in App Store
     *
     * @param accept
     * @param ifNoneMatch
     * @return
     */
    @Override
    public Response appsFavouritePageGet(String accept, String ifNoneMatch) {
        FavouritePageDTO favouritePageDTO = new FavouritePageDTO();
        boolean isTenantFlowStarted = false;
        try {
            String username = RestApiUtil.getLoggedInUsername();
            String tenantDomainOfUser = RestApiUtil.getLoggedInUserTenantDomain();
            int tenantIdOfUser = ServiceReferenceHolder.getInstance().getRealmService().getTenantManager()
                    .getTenantId(tenantDomainOfUser);
            if (tenantDomainOfUser != null
                    && !MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomainOfUser)) {
                isTenantFlowStarted = true;
                PrivilegedCarbonContext.startTenantFlow();
                PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomainOfUser, true);
            }
            int tenantIdOFStore = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId();
            APIConsumer apiConsumer = RestApiUtil.getLoggedInUserConsumer();
            boolean hasFavouritePage = apiConsumer.hasFavouritePage(username, tenantIdOfUser, tenantIdOFStore);
            favouritePageDTO.setIsDefaultPage(hasFavouritePage);
        } catch (UserStoreException e) {
            RestApiUtil.handleInternalServerError(
                    "User Store Error occurred while retrieving Favourite page details", e, log);
        } catch (AppManagementException e) {
            RestApiUtil.handleInternalServerError("Internal Error occurred while retrieving Favourite page details",
                    e, log);
        } finally {
            if (isTenantFlowStarted) {
                PrivilegedCarbonContext.endTenantFlow();
            }
        }
        return Response.ok().entity(favouritePageDTO).build();
    }

    /**
     * Set favourite page for currently logged in user in App Store
     *
     * @return
     */
    @Override
    public Response appsFavouritePagePost() {
        boolean isTenantFlowStarted = false;
        try {
            String username = RestApiUtil.getLoggedInUsername();
            String tenantDomainOfUser = RestApiUtil.getLoggedInUserTenantDomain();
            int tenantIdOfUser = ServiceReferenceHolder.getInstance().getRealmService().getTenantManager()
                    .getTenantId(tenantDomainOfUser);
            if (tenantDomainOfUser != null
                    && !MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomainOfUser)) {
                isTenantFlowStarted = true;
                PrivilegedCarbonContext.startTenantFlow();
                PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomainOfUser, true);
            }
            int tenantIdOFStore = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId();
            APIConsumer apiConsumer = RestApiUtil.getLoggedInUserConsumer();
            apiConsumer.setFavouritePage(username, tenantIdOfUser, tenantIdOFStore);
        } catch (UserStoreException e) {
            RestApiUtil.handleInternalServerError("User Store Error occurred while saving Favourite page", e, log);
        } catch (AppManagementException e) {
            RestApiUtil.handleInternalServerError("Internal Error occurred while saving Favourite page", e, log);
        } finally {
            if (isTenantFlowStarted) {
                PrivilegedCarbonContext.endTenantFlow();
            }
        }
        return Response.ok().build();
    }

    /**
     * Remove favourite page of the currently logged i user in App Store
     *
     * @return
     */
    @Override
    public Response appsFavouritePageDelete() {
        boolean isTenantFlowStarted = false;
        try {
            String username = RestApiUtil.getLoggedInUsername();
            String tenantDomainOfUser = RestApiUtil.getLoggedInUserTenantDomain();
            int tenantIdOfUser = ServiceReferenceHolder.getInstance().getRealmService().getTenantManager()
                    .getTenantId(tenantDomainOfUser);
            if (tenantDomainOfUser != null
                    && !MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomainOfUser)) {
                isTenantFlowStarted = true;
                PrivilegedCarbonContext.startTenantFlow();
                PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomainOfUser, true);
            }
            int tenantIdOFStore = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId();
            APIConsumer apiConsumer = RestApiUtil.getLoggedInUserConsumer();
            apiConsumer.removeFavouritePage(username, tenantIdOfUser, tenantIdOFStore);
        } catch (UserStoreException e) {
            RestApiUtil.handleInternalServerError("User Store Error occurred while removing Favourite page", e,
                    log);
        } catch (AppManagementException e) {
            RestApiUtil.handleInternalServerError("Internal Error occurred while removing Favourite page", e, log);
        } finally {
            if (isTenantFlowStarted) {
                PrivilegedCarbonContext.endTenantFlow();
            }
        }
        return Response.ok().build();
    }

    /**
     * Retrieve mobile binary from storage
     *
     * @param fileName          binary file name
     * @param ifMatch
     * @param ifUnmodifiedSince
     * @return mobile app binary file content
     */
    @Override
    public Response appsMobileBinariesFileNameGet(String fileName, String ifMatch, String ifUnmodifiedSince) {
        File binaryFile = null;
        String contentType = null;
        try {

            if (!RestApiUtil.isValidFileName(fileName)) {
                RestApiUtil.handleBadRequest("Invalid file '" + fileName + "' is provided", log);
            }

            String fileExtension = FilenameUtils.getExtension(fileName);
            if (AppMConstants.MOBILE_APPS_ANDROID_EXT.equals(fileExtension)
                    || AppMConstants.MOBILE_APPS_IOS_EXT.equals(fileExtension)) {

                binaryFile = RestApiUtil.readFileFromStorage(fileName);

                contentType = RestApiUtil.readFileContentType(binaryFile.getAbsolutePath());
                if (!contentType.startsWith("application")) {
                    RestApiUtil.handleBadRequest(
                            "Invalid file '" + fileName + "' with unsupported file type requested", log);
                }
            } else {
                RestApiUtil.handleBadRequest(
                        "Invalid file '" + fileName + "' with unsupported media type is requested", log);
            }
        } catch (AppManagementException e) {
            if (RestApiUtil.isDueToResourceNotFound(e) || RestApiUtil.isDueToAuthorizationFailure(e)) {
                RestApiUtil.handleResourceNotFoundError("Static Content", fileName, e, log);
            } else {
                RestApiUtil.handleInternalServerError(
                        "Error occurred while retrieving mobile binary : " + fileName + "from storage", e, log);
            }
        }
        Response.ResponseBuilder response = Response.ok((Object) binaryFile);
        response.header(RestApiConstants.HEADER_CONTENT_DISPOSITION, RestApiConstants.CONTENT_DISPOSITION_ATTACHMENT
                + "; " + RestApiConstants.CONTENT_DISPOSITION_FILENAME + "=\"" + fileName + "\"");
        response.header(RestApiConstants.HEADER_CONTENT_TYPE, contentType);
        return response.build();
    }

    /**
     * Mobile app one-time download API
     *
     * @param uuid              one-time download link uuid
     * @param ifMatch
     * @param ifUnmodifiedSince
     * @return
     */
    @Override
    public Response appsMobileBinariesOneTimeUuidGet(String uuid, String ifMatch, String ifUnmodifiedSince) {
        File binaryFile = null;
        String contentType = null;
        try {
            APIProvider appProvider = RestApiUtil.getLoggedInUserProvider();
            OneTimeDownloadLink oneTimeDownloadLink = appProvider.getOneTimeDownloadLinkDetails(uuid);
            if (oneTimeDownloadLink.isDownloaded()) {
                RestApiUtil.handleForbiddenRequest(
                        "App binary one-time download API resource access with uuid '" + uuid + "' is forbidden",
                        log);
            }
            String fileName = oneTimeDownloadLink.getFileName();
            binaryFile = RestApiUtil.readFileFromStorage(fileName);
            contentType = RestApiUtil.readFileContentType(binaryFile.getAbsolutePath());
            if (!contentType.startsWith("application")) {
                RestApiUtil.handleBadRequest("Invalid file '" + fileName + "' with unsupported file type requested",
                        log);
            }
            Response.ResponseBuilder response = Response.ok((Object) binaryFile);
            response.header(RestApiConstants.HEADER_CONTENT_DISPOSITION,
                    RestApiConstants.CONTENT_DISPOSITION_ATTACHMENT + "; "
                            + RestApiConstants.CONTENT_DISPOSITION_FILENAME + "=\"" + fileName + "\"");
            response.header(RestApiConstants.HEADER_CONTENT_TYPE, contentType);
            oneTimeDownloadLink.setDownloaded(true);
            appProvider.updateOneTimeDownloadLinkStatus(oneTimeDownloadLink);
            return response.build();
        } catch (AppManagementException e) {
            if (RestApiUtil.isDueToResourceNotFound(e) || RestApiUtil.isDueToAuthorizationFailure(e)) {
                RestApiUtil.handleResourceNotFoundError("Invalid downloadable link uuid", uuid, e, log);
            } else {
                RestApiUtil.handleInternalServerError(
                        "Error occurred while retrieving mobile binary via one-time download link with uuid" + uuid,
                        e, log);
            }
        }
        return null;
    }

    /**
     * @param appId
     * @param uuid
     * @param ifMatch
     * @param ifUnmodifiedSince
     * @return
     */
    @Override
    public Response appsMobilePlistAppIdUuidGet(String appId, String uuid, String ifMatch,
            String ifUnmodifiedSince) {

        try {
            APIProvider appProvider = RestApiUtil.getLoggedInUserProvider();
            OneTimeDownloadLink oneTimeDownloadLink = appProvider.getOneTimeDownloadLinkDetails(uuid);
            if (oneTimeDownloadLink == null) {
                RestApiUtil.handleResourceNotFoundError("one-time download link uuid", uuid, log);
            }
            PrivilegedCarbonContext carbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext();
            carbonContext.setUsername(oneTimeDownloadLink.getCreatedUserName());
            carbonContext.setTenantDomain(
                    org.wso2.carbon.utils.multitenancy.MultitenantConstants.SUPER_TENANT_DOMAIN_NAME);
            carbonContext.setTenantId(oneTimeDownloadLink.getCreatedTenantID());
            appProvider = RestApiUtil.getLoggedInUserProvider();
            MobileApp mobileApp = appProvider.getMobileApp(appId);
            if (mobileApp == null) {
                RestApiUtil.handleResourceNotFoundError("Mobile Application", appId, log);
            }
            if (!APIStatus.PUBLISHED.getStatus().equals(mobileApp.getLifeCycleStatus().getStatus())) {
                RestApiUtil.handleBadRequest("Mobile application with uuid '" + appId + "' is not in '"
                        + APIStatus.PUBLISHED + "' state", log);
            }
            String oneTimeDownloadLinkAPIPath = HostResolver
                    .getHost(MobileConfigurations.getInstance().getMDMConfigs()
                            .get(MobileConfigurations.APP_DOWNLOAD_URL_HOST))
                    + RestApiUtil.getStoreRESTAPIContextPath() + AppMConstants.MOBILE_ONE_TIME_DOWNLOAD_API_PATH
                    + File.separator + uuid;
            PlistTemplateContext plistTemplateContext = new PlistTemplateContext();
            plistTemplateContext.setAppName(mobileApp.getAppName());
            plistTemplateContext.setBundleVersion(mobileApp.getBundleVersion());
            plistTemplateContext.setPackageName(mobileApp.getPackageName());
            plistTemplateContext.setOneTimeDownloadUrl(oneTimeDownloadLinkAPIPath);
            PlistTemplateBuilder plistTemplateBuilder = new PlistTemplateBuilder();
            String plistFileContent = plistTemplateBuilder.generatePlistConfig(plistTemplateContext);
            return Response.ok().entity(plistFileContent).build();
        } catch (AppManagementException e) {
            if (RestApiUtil.isDueToResourceNotFound(e) || RestApiUtil.isDueToAuthorizationFailure(e)) {
                RestApiUtil.handleResourceNotFoundError("Invalid plist retrieval", appId, e, log);
            } else {
                RestApiUtil.handleInternalServerError(
                        "Error occurred while retrieving plist configuration for IOS mobile app '" + appId
                                + "' installation",
                        e, log);
            }
        }
        return null;
    }

    /**
     * Retrieve a given static content from storage
     *
     * @param fileName          request file name
     * @param ifMatch
     * @param ifUnmodifiedSince
     * @return
     */
    @Override
    public Response appsStaticContentsFileNameGet(String appType, String fileName, String ifMatch,
            String ifUnmodifiedSince) {
        CommonValidator.isValidAppType(appType);
        File staticContentFile = null;
        String contentType = null;

        try {
            if (AppMConstants.MOBILE_ASSET_TYPE.equals(appType)) {
                staticContentFile = RestApiUtil.readFileFromStorage(fileName);
                contentType = RestApiUtil.readFileContentType(staticContentFile.getAbsolutePath());
            } else if (AppMConstants.WEBAPP_ASSET_TYPE.equals(appType)) {
                OutputStream outputStream = null;
                AppRepository appRepository = new DefaultAppRepository(null);
                try {
                    FileContent fileContent = appRepository.getStaticContent(fileName);
                    staticContentFile = File.createTempFile("temp", ".tmp");
                    outputStream = new FileOutputStream(staticContentFile);
                    IOUtils.copy(fileContent.getContent(), outputStream);
                    contentType = fileContent.getContentType();
                } catch (IOException e) {
                    RestApiUtil.handleInternalServerError(
                            "Error occurred while retrieving static content '" + fileName + "'", e, log);
                }
            }
            if (staticContentFile == null || !staticContentFile.exists()) {
                RestApiUtil.handleResourceNotFoundError("Static Content", fileName, log);
            }
            if (contentType != null && !contentType.startsWith("image")) {
                RestApiUtil.handleBadRequest("Invalid file '" + fileName + "'with unsupported file type requested",
                        log);
            }

            Response.ResponseBuilder response = Response.ok((Object) staticContentFile);
            response.header(RestApiConstants.HEADER_CONTENT_DISPOSITION,
                    RestApiConstants.CONTENT_DISPOSITION_ATTACHMENT + "; "
                            + RestApiConstants.CONTENT_DISPOSITION_FILENAME + "=\"" + fileName + "\"");
            response.header(RestApiConstants.HEADER_CONTENT_TYPE, contentType);
            return response.build();
        } catch (AppManagementException e) {
            if (RestApiUtil.isDueToResourceNotFound(e) || RestApiUtil.isDueToAuthorizationFailure(e)) {
                RestApiUtil.handleResourceNotFoundError("Static Content", fileName, e, log);
            } else {
                RestApiUtil.handleInternalServerError(
                        "Error occurred while retrieving static content : " + fileName + "from storage", e, log);
            }
        }
        return null;
    }

    @Override
    public Response appsUninstallationPost(String contentType, InstallDTO install) {
        String tenantDomain = RestApiUtil.getLoggedInUserTenantDomain();
        String username = RestApiUtil.getLoggedInUsername();
        try {

            APIProvider appProvider = RestApiUtil.getLoggedInUserProvider();
            String tenantDomainName = MultitenantUtils.getTenantDomain(username);
            int tenantId = 0;
            tenantId = ServiceReferenceHolder.getInstance().getRealmService().getTenantManager()
                    .getTenantId(tenantDomainName);

            String tenantUserName = MultitenantUtils.getTenantAwareUsername(username);
            String appId = install.getAppId();

            Map<String, String> searchTerms = new HashMap<String, String>();
            searchTerms.put("id", appId);
            List<App> result = appProvider.searchApps(AppMConstants.MOBILE_ASSET_TYPE, searchTerms);
            if (result.isEmpty()) {
                String errorMessage = "Could not find requested application.";
                return RestApiUtil.buildNotFoundException(errorMessage, appId).getResponse();
            }

            Operations mobileOperation = new Operations();
            String action = "uninstall";
            String[] parameters = null;

            if ("user".equals(install.getType())) {
                parameters = new String[1];
                parameters[0] = username;
            } else if ("device".equals(install.getType())) {
                parameters = Arrays.copyOf(install.getDeviceIds().toArray(),
                        install.getDeviceIds().toArray().length, String[].class);
                if (parameters == null) {
                    RestApiUtil.handleBadRequest("Device IDs should be provided to perform device app installation",
                            log);
                }
            } else {
                RestApiUtil.handleBadRequest("Invalid installation type.", log);
            }

            //TODO:Operations.performAction expects the user to be passed as a stringified object, so that
            //TODO:We are prviding a stringified user here
            JSONObject user = new JSONObject();
            user.put("username", tenantUserName);
            user.put("tenantDomain", tenantDomainName);
            user.put("tenantId", tenantId);

            boolean isUnSubscribed = appProvider.unSubscribeMobileApp(username, appId);
            if (!isUnSubscribed) {
                RestApiUtil
                        .handlePreconditionFailedRequest("Application is not installed yet. Application with id : "
                                + appId + "must be installed prior to uninstall.", log);
            }
            String activityId = mobileOperation.performAction(user.toString(), action, tenantId, install.getType(),
                    appId, parameters, null, null);

            JSONObject response = new JSONObject();
            response.put("activityId", activityId);

            return Response.ok().entity(response.toString()).build();

        } catch (AppManagementException e) {
            // mobileOperation.performAction(user.toString(), action, tenantId, appId, install.getType(), parameters, null);
            RestApiUtil.handleInternalServerError("Internal Error occurred while uninstalling", e, log);
        } catch (MobileApplicationException e) {
            RestApiUtil.handleBadRequest(e.getMessage(), log);
        } catch (UserStoreException e) {
            RestApiUtil.handleInternalServerError("User Store related Error occurred while uninstalling", e, log);
        } catch (JSONException e) {
            RestApiUtil.handleInternalServerError("JSON casting related Error occurred while uninstalling", e, log);
        }
        return Response.serverError().build();
    }

    @Override
    public Response appsAppTypeGet(String appType, String query, String fieldFilter, Integer limit, Integer offset,
            String accept, String ifNoneMatch) {

        //setting default limit and offset values if they are not set
        limit = limit != null ? limit : RestApiConstants.PAGINATION_LIMIT_DEFAULT;
        offset = offset != null ? offset : RestApiConstants.PAGINATION_OFFSET_DEFAULT;
        query = query == null ? "" : query;

        try {
            //check if a valid asset type is provided
            CommonValidator.isValidAppType(appType);

            /*
            // If the asset type is 'site' we need to add the registry attribute filtering and make the appType as webapp
            // due to, publisher side we don't have separate asset type as 'site' rather then a flag as 'treatAsASite'
            // to the webapp asset type.
            */

            //Building registry filtering field.
            query = APPMappingUtil.buildQuery(appType, query);
            //Make the asset type as 'webapp'.
            appType = APPMappingUtil.updateAssetType(appType);

            APIProvider apiProvider = RestApiUtil.getLoggedInUserProvider();

            List<App> result = apiProvider.searchPublishedApps(appType, RestApiUtil.getSearchTerms(query));

            AppListDTO appListDTO = null;
            if (fieldFilter == null || "BASIC".equalsIgnoreCase(fieldFilter)) {
                appListDTO = APPMappingUtil.getAppListDTOWithBasicFields(result, offset, limit);

            } else {
                appListDTO = APPMappingUtil.getAppListDTOWithAllFields(result, offset, limit);
            }

            APPMappingUtil.setPaginationParams(appListDTO, query, offset, limit, result.size());
            return Response.ok().entity(appListDTO).build();
        } catch (AppManagementException e) {
            String errorMessage = "Error while retrieving Apps";
            RestApiUtil.handleInternalServerError(errorMessage, e, log);
        }
        return null;
    }

    @Override
    public Response appsAppTypeIdAppIdGet(String appType, String appId, String accept, String ifNoneMatch,
            String ifModifiedSince) {
        AppDTO appToReturn = null;
        String query = "";
        try {
            //check if a valid asset type is provided
            CommonValidator.isValidAppType(appType);

            /*
            // If the asset type is 'site' we need to add the registry attribute filtering and make the appType as webapp
            // since the publisher side we don't have separate asset type as 'site' rather then a flag as 'treatAsASite'
            // to the webapp asset type.
            */

            //Building registry filtering field.
            query = APPMappingUtil.buildQuery(appType, query);
            //Make the asset type as 'webapp'.
            appType = APPMappingUtil.updateAssetType(appType);

            Map<String, String> searchTerms = new HashMap<String, String>();
            searchTerms.put("id", appId);
            searchTerms.putAll(RestApiUtil.getSearchTerms(query));

            APIProvider apiProvider = RestApiUtil.getLoggedInUserProvider();
            List<App> result = apiProvider.searchApps(appType, searchTerms);
            if (result.isEmpty()) {
                String errorMessage = "Could not find requested application.";
                return RestApiUtil.buildNotFoundException(errorMessage, appId).getResponse();
            }
            appToReturn = APPMappingUtil.fromAppToDTO(result.get(0));
            if (appToReturn == null) {
                String errorMessage = "Could not find requested application.";
                return RestApiUtil.buildNotFoundException(errorMessage, appId).getResponse();
            }

        } catch (AppManagementException e) {
            //Auth failure occurs when cross tenant accessing APIs. Sends 404, since we don't need to expose the
            // existence of the resource
            if (RestApiUtil.isDueToResourceNotFound(e) || RestApiUtil.isDueToAuthorizationFailure(e)) {
                RestApiUtil.handleResourceNotFoundError(RestApiConstants.RESOURCE_API, appId, e, log);
            } else {
                String errorMessage = "Error while retrieving App : " + appId;
                RestApiUtil.handleInternalServerError(errorMessage, e, log);
            }
        }
        return Response.ok().entity(appToReturn).build();
    }

    @Override
    public Response appsAppTypeIdAppIdFavouriteAppPost(String appType, String appId, String contentType) {
        boolean isTenantFlowStarted = false;
        String query = "";
        try {
            //check if a valid asset type is provided. Currently support only webapps
            if (!(appType.equalsIgnoreCase(AppMConstants.WEBAPP_ASSET_TYPE)
                    || appType.equalsIgnoreCase(AppMConstants.SITE_ASSET_TYPE))) {
                String errorMessage = "Invalid Asset Type : " + appType;
                RestApiUtil.handleBadRequest(errorMessage, log);
            }

            /*
            // If the asset type is 'site' we need to add the registry attribute filtering and make the appType as webapp
            // since the publisher side we don't have separate asset type as 'site' rather then a flag as 'treatAsASite'
            // to the webapp asset type.
            */

            //Building registry filtering field.
            query = APPMappingUtil.buildQuery(appType, query);
            //Make the asset type as 'webapp'.
            appType = APPMappingUtil.updateAssetType(appType);

            //logged user's username
            String username = RestApiUtil.getLoggedInUsername();
            //logged user's tenant domain
            String tenantDomainOfUser = RestApiUtil.getLoggedInUserTenantDomain();
            //logged user's tenant id
            int tenantIdOfUser = ServiceReferenceHolder.getInstance().getRealmService().getTenantManager()
                    .getTenantId(tenantDomainOfUser);
            if (tenantDomainOfUser != null
                    && !MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomainOfUser)) {
                isTenantFlowStarted = true;
                PrivilegedCarbonContext.startTenantFlow();
                PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomainOfUser, true);
            }
            //tenant id of the store
            int tenantIdOFStore = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId();
            APIConsumer apiConsumer = RestApiUtil.getLoggedInUserConsumer();
            APIProvider apiProvider = RestApiUtil.getLoggedInUserProvider();

            Map<String, String> searchTerms = new HashMap<String, String>();
            searchTerms.put("id", appId);
            searchTerms.putAll(RestApiUtil.getSearchTerms(query));

            //get app details by id
            List<App> result = apiProvider.searchApps(appType, searchTerms);
            //check if it's valid app
            if (result.isEmpty() || result.size() == 0) {
                String errorMessage = "Could not find requested application.";
                return RestApiUtil.buildNotFoundException(errorMessage, appId).getResponse();
            }
            AppDTO appDTO = APPMappingUtil.fromAppToDTO(result.get(0));
            if (appDTO == null) {
                String errorMessage = "Could not find requested application.";
                return RestApiUtil.buildNotFoundException(errorMessage, appId).getResponse();
            }
            String providerName = appDTO.getProvider();
            String apiName = appDTO.getName();
            String version = appDTO.getVersion();

            APIIdentifier identifier = new APIIdentifier(providerName, apiName, version);
            boolean isFavouriteApp = apiConsumer.isFavouriteApp(identifier, username, tenantIdOfUser,
                    tenantIdOFStore);

            //add to favourite if it is not already added
            if (!isFavouriteApp) {
                apiConsumer.addToFavouriteApps(identifier, username, tenantIdOfUser, tenantIdOFStore);
            }
        } catch (UserStoreException e) {
            RestApiUtil.handleInternalServerError("User Store Error occurred while adding as Favourite", e, log);
        } catch (AppManagementException e) {
            RestApiUtil.handleInternalServerError("Internal Error occurred while adding as Favourite", e, log);
        } finally {
            if (isTenantFlowStarted) {
                PrivilegedCarbonContext.endTenantFlow();
            }
        }
        return Response.ok().build();
    }

    @Override
    public Response appsAppTypeIdAppIdFavouriteAppDelete(String appType, String appId, String contentType) {
        boolean isTenantFlowStarted = false;
        String query = "";
        try {
            //check if a valid asset type is provided. Currently support only webapps
            if (!(appType.equalsIgnoreCase(AppMConstants.WEBAPP_ASSET_TYPE)
                    || appType.equalsIgnoreCase(AppMConstants.SITE_ASSET_TYPE))) {
                String errorMessage = "Invalid Asset Type : " + appType;
                RestApiUtil.handleBadRequest(errorMessage, log);
            }

            /*
            // If the asset type is 'site' we need to add the registry attribute filtering and make the appType as webapp
            // since the publisher side we don't have separate asset type as 'site' rather then a flag as 'treatAsASite'
            // to the webapp asset type.
            */

            //Building registry filtering field.
            query = APPMappingUtil.buildQuery(appType, query);
            //Make the asset type as 'webapp'.
            appType = APPMappingUtil.updateAssetType(appType);

            //logged user's username
            String username = RestApiUtil.getLoggedInUsername();
            //logged user's tenant domain
            String tenantDomainOfUser = RestApiUtil.getLoggedInUserTenantDomain();
            //logged user's tenant id
            int tenantIdOfUser = ServiceReferenceHolder.getInstance().getRealmService().getTenantManager()
                    .getTenantId(tenantDomainOfUser);
            if (tenantDomainOfUser != null
                    && !MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomainOfUser)) {
                isTenantFlowStarted = true;
                PrivilegedCarbonContext.startTenantFlow();
                PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomainOfUser, true);
            }
            //tenant id of the store
            int tenantIdOFStore = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId();
            APIConsumer apiConsumer = RestApiUtil.getLoggedInUserConsumer();
            APIProvider apiProvider = RestApiUtil.getLoggedInUserProvider();

            Map<String, String> searchTerms = new HashMap<String, String>();
            searchTerms.put("id", appId);
            searchTerms.putAll(RestApiUtil.getSearchTerms(query));

            //get app details by id
            List<App> result = apiProvider.searchApps(appType, searchTerms);
            //check if it's valid app
            if (result.isEmpty() || result.size() == 0) {
                String errorMessage = "Could not find requested application.";
                return RestApiUtil.buildNotFoundException(errorMessage, appId).getResponse();
            }
            AppDTO appDTO = APPMappingUtil.fromAppToDTO(result.get(0));
            if (appDTO == null) {
                String errorMessage = "Could not find requested application.";
                return RestApiUtil.buildNotFoundException(errorMessage, appId).getResponse();
            }
            String providerName = appDTO.getProvider();
            String apiName = appDTO.getName();
            String version = appDTO.getVersion();

            APIIdentifier identifier = new APIIdentifier(providerName, apiName, version);
            boolean isFavouriteApp = apiConsumer.isFavouriteApp(identifier, username, tenantIdOfUser,
                    tenantIdOFStore);

            //remove from favourite if is it a favourite app
            if (isFavouriteApp) {
                apiConsumer.removeFromFavouriteApps(identifier, username, tenantIdOfUser, tenantIdOFStore);
            }
        } catch (UserStoreException e) {
            RestApiUtil.handleInternalServerError("User Store Error occurred while adding as Favourite", e, log);
        } catch (AppManagementException e) {
            RestApiUtil.handleInternalServerError("Internal Error occurred while adding as Favourite", e, log);
        } finally {
            if (isTenantFlowStarted) {
                PrivilegedCarbonContext.endTenantFlow();
            }
        }
        return Response.ok().build();
    }

    @Override
    public Response appsAppTypeIdAppIdRateGet(String appType, String appId, Integer limit, Integer offset,
            String accept, String ifNoneMatch, String ifModifiedSince) {
        AppRatingListDTO appRatingListDTO = new AppRatingListDTO();
        limit = limit != null ? limit : RestApiConstants.PAGINATION_LIMIT_DEFAULT;
        offset = offset != null ? offset : RestApiConstants.PAGINATION_OFFSET_DEFAULT;
        String query = "";
        try {
            //check if a valid asset type is provided
            CommonValidator.isValidAppType(appType);

            /*
            // If the asset type is 'site' we need to add the registry attribute filtering and make the appType as webapp
            // since the publisher side we don't have separate asset type as 'site' rather then a flag as 'treatAsASite'
            // to the webapp asset type.
            */

            //Building registry filtering field.
            query = APPMappingUtil.buildQuery(appType, query);
            //Make the asset type as 'webapp'.
            appType = APPMappingUtil.updateAssetType(appType);

            //check App Id validity
            Map<String, String> searchTerms = new HashMap<String, String>();
            searchTerms.put("id", appId);
            searchTerms.putAll(RestApiUtil.getSearchTerms(query));

            APIProvider apiProvider = RestApiUtil.getLoggedInUserProvider();
            List<App> result = apiProvider.searchApps(appType, searchTerms);
            if (result.isEmpty()) {
                String errorMessage = "Could not find requested application.";
                return RestApiUtil.buildNotFoundException(errorMessage, appId).getResponse();
            }

            PrivilegedCarbonContext carbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext();
            SocialActivityService socialActivityService = (SocialActivityService) carbonContext
                    .getOSGiService(org.wso2.carbon.social.core.service.SocialActivityService.class, null);
            JsonObject rating = socialActivityService.getRating(appType + ":" + appId);
            if (rating != null && rating.get("rating") != null) {
                appRatingListDTO.setOverallRating(rating.get("rating").getAsBigDecimal());

                JSONObject socialObj;
                socialObj = new JSONObject(
                        socialActivityService.getSocialObjectJson(appType + ":" + appId, "asc", offset, limit));
                org.json.JSONArray socialArr = socialObj.getJSONArray("attachments");
                List<AppRatingInfoDTO> appRatingInfoDTOList = new ArrayList<>();
                for (int i = 0; i < socialArr.length(); i++) {
                    AppRatingInfoDTO appRatingInfoDTO = new AppRatingInfoDTO();
                    JSONObject ratingObj = (JSONObject) ((JSONObject) socialArr.get(i)).get("object");
                    appRatingInfoDTO.setRating(Integer.parseInt(ratingObj.get("rating").toString()));
                    appRatingInfoDTO.setId(Integer.parseInt(ratingObj.get("id").toString()));
                    appRatingInfoDTO.setReview(ratingObj.get("content").toString());
                    appRatingInfoDTO.setLikes(
                            Integer.parseInt(((JSONObject) (ratingObj.get("likes"))).get("totalItems").toString()));
                    appRatingInfoDTO.setDislikes(Integer
                            .parseInt(((JSONObject) (ratingObj.get("dislikes"))).get("totalItems").toString()));
                    appRatingInfoDTOList.add(appRatingInfoDTO);
                }
                int totalRecords = rating.get("count").getAsInt();
                APPMappingUtil.setAppRatingPaginationParams(appRatingListDTO, offset, limit, totalRecords);
                appRatingListDTO.setRatingDetails(appRatingInfoDTOList);
                appRatingListDTO.setCount(appRatingInfoDTOList.size());
            } else {
                return RestApiUtil.buildNotFoundException("Rating", appId).getResponse();
            }
        } catch (SocialActivityException e) {
            String errorMessage = String.format("Can't get the rating for the app '%s:%s'", appType, appId);
            RestApiUtil.handleInternalServerError(errorMessage, e, log);
        } catch (AppManagementException e) {
            String errorMessage = String.format("Internal error while retrieving the rating for the app '%s:%s'",
                    appType, appId);
            RestApiUtil.handleInternalServerError(errorMessage, e, log);
        } catch (JSONException e) {
            String errorMessage = String.format(
                    "JSONException occurred while casting. Can't get the rating for the app '%s:%s'", appType,
                    appId);
            RestApiUtil.handleInternalServerError(errorMessage, e, log);
        }
        return Response.ok().entity(appRatingListDTO).build();
    }

    @Override
    public Response appsAppTypeIdAppIdRatePut(String appType, String appId, AppRatingInfoDTO rating,
            String contentType, String ifMatch, String ifUnmodifiedSince) {
        AppRatingInfoDTO appRatingInfoDTO = new AppRatingInfoDTO();
        String query = "";
        try {
            //check if a valid asset type is provided
            CommonValidator.isValidAppType(appType);

            /*
            // If the asset type is 'site' we need to add the registry attribute filtering and make the appType as webapp
            // since the publisher side we don't have separate asset type as 'site' rather then a flag as 'treatAsASite'
            // to the webapp asset type.
            */

            //Building registry filtering field.
            query = APPMappingUtil.buildQuery(appType, query);
            //Make the asset type as 'webapp'.
            appType = APPMappingUtil.updateAssetType(appType);

            //check App Id validity
            Map<String, String> searchTerms = new HashMap<String, String>();
            searchTerms.put("id", appId);
            searchTerms.putAll(RestApiUtil.getSearchTerms(query));

            APIProvider apiProvider = RestApiUtil.getLoggedInUserProvider();
            List<App> result = apiProvider.searchApps(appType, searchTerms);
            if (result.isEmpty()) {
                String errorMessage = "Could not find requested application.";
                return RestApiUtil.buildNotFoundException(errorMessage, appId).getResponse();
            }
            String tenantUserName = RestApiUtil.getLoggedInUsername() + "@"
                    + RestApiUtil.getLoggedInUserTenantDomain();
            PrivilegedCarbonContext carbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext();
            SocialActivityService socialActivityService = (SocialActivityService) carbonContext
                    .getOSGiService(org.wso2.carbon.social.core.service.SocialActivityService.class, null);
            String activity = "{\"verb\":\"post\",\"object\":{\"objectType\":\"review\",\"content\":"
                    + rating.getReview() + "," + "\"rating\":" + rating.getRating()
                    + ",\"likes\":{\"totalItems\":0},\"dislikes\":{\"totalItems\":0}}," + "\"target\":{\"id\":"
                    + "\"" + appType + ":" + appId + "\"" + "},\"actor\":{\"id\":" + tenantUserName + "\","
                    + "objectType\":\"person\"}}";

            long id = socialActivityService.publish(activity);
            appRatingInfoDTO.setId((int) id);
            appRatingInfoDTO.setRating(rating.getRating());
            appRatingInfoDTO.setReview(rating.getReview());

        } catch (AppManagementException e) {
            String errorMessage = String.format("Internal error while saving the rating for the app '%s:%s'",
                    appType, appId);
            RestApiUtil.handleInternalServerError(errorMessage, e, log);
        } catch (SocialActivityException e) {
            String errorMessage = String
                    .format("Social component error while saving the rating for the app '%s:%s'", appType, appId);
            RestApiUtil.handleInternalServerError(errorMessage, e, log);
        }
        return Response.ok().entity(appRatingInfoDTO).build();
    }

    @Override
    public Response appsAppTypeIdAppIdStorageFileNameGet(String appType, String appId, String fileName,
            String ifMatch, String ifUnmodifiedSince) {
        return null;
    }

    /**
     * Retrieve subscription of the given user for a given app
     *
     * @param appType
     * @param appId
     * @param accept
     * @param ifNoneMatch
     * @param ifModifiedSince
     * @return
     */
    @Override
    public Response appsAppTypeIdAppIdSubscriptionGet(String appType, String appId, String accept,
            String ifNoneMatch, String ifModifiedSince) {

        APIConsumer apiConsumer = null;
        Map<String, String> subscriptionData = new HashMap<>();
        boolean isTenantFlowStarted = false;
        String username = AppManagerUtil.replaceEmailDomain(RestApiUtil.getLoggedInUsername());
        try {
            apiConsumer = RestApiUtil.getLoggedInUserConsumer();

            String tenantDomain = RestApiUtil.getLoggedInUserTenantDomain();
            int tenantId = AppManagerUtil.getTenantId(username);
            if (tenantDomain != null && !MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
                isTenantFlowStarted = true;
                PrivilegedCarbonContext.startTenantFlow();
                PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain, true);
            }

            WebApp webApp = apiConsumer.getWebApp(appId);
            APIIdentifier appIdentifier = webApp.getId();
            int applicationId = AppManagerUtil.getApplicationId(AppMConstants.DEFAULT_APPLICATION_NAME, username);

            Subscription subscription = apiConsumer.getSubscription(appIdentifier, applicationId,
                    Subscription.SUBSCRIPTION_TYPE_INDIVIDUAL);
            if (subscription != null) {
                subscriptionData.put("SubscriptionId", String.valueOf(subscription.getSubscriptionId()));
                subscriptionData.put("SubscriptionType", subscription.getSubscriptionType());
                subscriptionData.put("Status", subscription.getSubscriptionStatus());
                subscriptionData.put("SubscriptionTime", subscription.getSubscriptionTime());
                subscriptionData.put("SubscribedUser", subscription.getUserId());
            }
        } catch (AppManagementException e) {
            RestApiUtil.handleInternalServerError(
                    "Error occurred while retrieving subscription details of webapp with id : " + appId
                            + " for user " + username,
                    e, log);
        } finally {
            if (isTenantFlowStarted) {
                PrivilegedCarbonContext.endTenantFlow();
            }
        }
        return Response.ok().entity(subscriptionData).build();
    }

    /**
     * Adding subscription for a given app
     *
     * @param appType     application type ie: webapp, mobileapp
     * @param appId       application uuid
     * @param contentType
     * @return
     */
    @Override
    public Response appsAppTypeIdAppIdSubscriptionPost(String appType, String appId, String contentType) {

        APIConsumer apiConsumer = null;
        boolean isTenantFlowStarted = false;
        String userName = AppManagerUtil.replaceEmailDomain(RestApiUtil.getLoggedInUsername());
        try {
            apiConsumer = RestApiUtil.getLoggedInUserConsumer();
            String tenantDomain = RestApiUtil.getLoggedInUserTenantDomain();
            int tenantId = AppManagerUtil.getTenantId(userName);

            if (AppManagerUtil.isSelfSubscriptionEnable() || AppManagerUtil.isEnterpriseSubscriptionEnable()) {
                //Check for subscriber existence
                Subscriber subscriber = apiConsumer.getSubscriber(userName);
                if (subscriber == null) {
                    subscriber = new Subscriber(userName);
                    subscriber.setSubscribedDate(new Date());
                    subscriber.setEmail("");
                    subscriber.setTenantId(tenantId);
                    apiConsumer.addSubscriber(subscriber);
                }

                if (tenantDomain != null && !MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
                    isTenantFlowStarted = true;
                    PrivilegedCarbonContext.startTenantFlow();
                    PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain, true);
                }
                WebApp webApp = apiConsumer.getWebApp(appId);
                APIIdentifier appIdentifier = webApp.getId();
                appIdentifier.setTier(AppMConstants.UNLIMITED_TIER);

                /* Tenant based validation for subscription*/
                String userDomain = MultitenantUtils.getTenantDomain(userName);
                boolean subscriptionAllowed = false;
                if (!userDomain.equals(tenantDomain)) {
                    String subscriptionAvailability = webApp.getSubscriptionAvailability();
                    if (AppMConstants.SUBSCRIPTION_TO_ALL_TENANTS.equals(subscriptionAvailability)) {
                        subscriptionAllowed = true;
                    } else if (AppMConstants.SUBSCRIPTION_TO_SPECIFIC_TENANTS.equals(subscriptionAvailability)) {
                        String subscriptionAllowedTenants = webApp.getSubscriptionAvailableTenants();
                        String allowedTenants[] = null;
                        if (subscriptionAllowedTenants != null) {
                            allowedTenants = subscriptionAllowedTenants.split(",");
                            if (allowedTenants != null) {
                                for (String tenant : allowedTenants) {
                                    if (tenant != null && userDomain.equals(tenant.trim())) {
                                        subscriptionAllowed = true;
                                        break;
                                    }
                                }
                            }
                        }
                    }
                } else {
                    subscriptionAllowed = true;
                }

                if (!subscriptionAllowed) {
                    throw new AppManagementException("Subscription is not allowed for " + userDomain);
                }
                int applicationId = AppManagerUtil.getApplicationId(AppMConstants.DEFAULT_APPLICATION_NAME,
                        userName);
                //TODO: Handle enterprise subscription
                String subscriptionStatus = apiConsumer.addSubscription(appIdentifier, "INDIVIDUAL", userName,
                        applicationId, null);
            } else {
                RestApiUtil.handleBadRequest("Subscription is disabled", log);
            }
        } catch (AppManagementException e) {
            RestApiUtil.handleBadRequest(
                    "Error while subscribing the user:" + userName + " for " + appType + " with appId :" + appId,
                    log);
        } finally {
            if (isTenantFlowStarted) {
                PrivilegedCarbonContext.endTenantFlow();
            }
        }
        return Response.ok().build();
    }

    @Override
    public Response appsAppTypeIdAppIdSubscriptionWorkflowPost(String appType, String appId, String contentType) {
        WorkflowExecutor workflowExecutor = null;
        try {
            workflowExecutor = WorkflowExecutorFactory.getInstance()
                    .getWorkflowExecutor(WorkflowConstants.WF_TYPE_AM_SUBSCRIPTION_CREATION);
        } catch (WorkflowException e) {
            RestApiUtil.handleInternalServerError("Error occurred while retrieving subscription workflow status", e,
                    log);
        }
        boolean isAsynchronousFlow = workflowExecutor.isAsynchronus();
        return Response.ok().entity(isAsynchronousFlow).build();
    }

    /**
     * @param appType
     * @param appId
     * @param accept
     * @param ifNoneMatch
     * @param ifModifiedSince
     * @return
     */
    @Override
    public Response appsAppTypeIdAppIdSubscriptionUsersGet(String appType, String appId, String accept,
            String ifNoneMatch, String ifModifiedSince) {
        UserIdListDTO userIdListDTO = new UserIdListDTO();
        try {
            APIProvider appProvider = RestApiUtil.getLoggedInUserProvider();
            if (AppMConstants.WEBAPP_ASSET_TYPE.equals(appType) || AppMConstants.SITE_ASSET_TYPE.equals(appType)) {
                if (AppManagerUtil.isSelfSubscriptionEnable() || AppManagerUtil.isEnterpriseSubscriptionEnable()) {
                    WebApp webApp = appProvider.getAppDetailsFromUUID(appId);
                    Set<Subscriber> subscriberSet = appProvider.getSubscribersOfAPI(webApp.getId());
                    userIdListDTO.setUserIds(subscriberSet);
                } else {
                    RestApiUtil.handleBadRequest("Subscription is disabled", log);
                }
            } else {
                RestApiUtil.handleBadRequest("Unsupported application type '" + appType + "' provided", log);
            }
        } catch (AppManagementException e) {
            if (RestApiUtil.isDueToResourceNotFound(e) || RestApiUtil.isDueToAuthorizationFailure(e)) {
                RestApiUtil.handleResourceNotFoundError(RestApiConstants.RESOURCE_API, appId, e, log);
            } else {
                String errorMessage = "Error while changing lifecycle state of app with id : " + appId;
                RestApiUtil.handleInternalServerError(errorMessage, e, log);
            }
        }
        return Response.ok().entity(userIdListDTO).build();
    }

    /**
     * Remove subscription of a given user for a given application
     *
     * @param appType
     * @param appId
     * @param contentType
     * @return
     */
    @Override
    public Response appsAppTypeIdAppIdUnsubscriptionPost(String appType, String appId, String contentType) {

        APIConsumer apiConsumer = null;
        boolean isTenantFlowStarted = false;
        String username = AppManagerUtil.replaceEmailDomain(RestApiUtil.getLoggedInUsername());
        try {
            apiConsumer = RestApiUtil.getLoggedInUserConsumer();
            String tenantDomain = RestApiUtil.getLoggedInUserTenantDomain();

            if (tenantDomain != null && !MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
                isTenantFlowStarted = true;
                PrivilegedCarbonContext.startTenantFlow();
                PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain, true);
            }
            WebApp webApp = apiConsumer.getWebApp(appId);
            APIIdentifier appIdentifier = webApp.getId();
            apiConsumer.removeAPISubscription(appIdentifier, username, AppMConstants.DEFAULT_APPLICATION_NAME);
        } catch (AppManagementException e) {
            RestApiUtil.handleBadRequest("Error occurred while removing subscription user '" + username
                    + "' for webapp with id " + appId, log);
        } finally {
            if (isTenantFlowStarted) {
                PrivilegedCarbonContext.endTenantFlow();
            }
        }
        return Response.ok().build();
    }

    @Override
    public Response appsAppTypeTagsGet(String appType, String accept, String ifNoneMatch) {
        TagListDTO tagListDTO = new TagListDTO();
        try {
            CommonValidator.isValidAppType(appType);

            APIConsumer appConsumer = RestApiUtil.getLoggedInUserConsumer();
            String tenantDomain = RestApiUtil.getLoggedInUserTenantDomain();
            Map<String, String> attributeMap = new HashMap<>();
            if (AppMConstants.SITE_ASSET_TYPE.equalsIgnoreCase(appType)) {
                attributeMap.put(AppMConstants.APP_OVERVIEW_TREAT_AS_A_SITE, "TRUE");
            } else if (AppMConstants.WEBAPP_ASSET_TYPE.equalsIgnoreCase(appType)) {
                attributeMap.put(AppMConstants.APP_OVERVIEW_TREAT_AS_A_SITE, "FALSE");
            }

            //Make the asset type as 'webapp'.
            appType = APPMappingUtil.updateAssetType(appType);

            List<String> tagList = new ArrayList<>();
            Iterator tagIterator = appConsumer.getAllTags(tenantDomain, appType, attributeMap).iterator();
            if (!tagIterator.hasNext()) {
                return RestApiUtil.buildNotFoundException("Tags", null).getResponse();
            }
            while (tagIterator.hasNext()) {
                Tag tag = (Tag) tagIterator.next();
                tagList.add(tag.getName());
            }
            tagListDTO.setTags(tagList);
        } catch (AppManagementException e) {
            String errorMessage = "Error retrieving tags for " + appType + "s.";
            RestApiUtil.handleInternalServerError(errorMessage, e, log);
        }
        return Response.ok().entity(tagListDTO).build();
    }

    @Override
    public Response appsMobileScheduleInstallPost(String contentType, ScheduleDTO schedule,
            SecurityContext securityContext) {
        String username = RestApiUtil.getLoggedInUsername();
        try {
            Map<String, String> searchTerms = new HashMap<String, String>();
            searchTerms.put("id", schedule.getAppId());

            APIProvider apiProvider = RestApiUtil.getLoggedInUserProvider();
            List<App> result = apiProvider.searchApps(AppMConstants.MOBILE_ASSET_TYPE, searchTerms);
            if (result.isEmpty()) {
                String errorMessage = "Could not find requested application.";
                return RestApiUtil.buildNotFoundException(errorMessage, schedule.getAppId()).getResponse();
            }

            String tenantDomainName = MultitenantUtils.getTenantDomain(username);
            int tenantId = ServiceReferenceHolder.getInstance().getRealmService().getTenantManager()
                    .getTenantId(tenantDomainName);
            String tenantUserName = MultitenantUtils.getTenantAwareUsername(username);
            String appId = schedule.getAppId();
            Operations mobileOperation = new Operations();
            String action = "install";
            String type = "device";
            String[] parameters;
            parameters = Arrays.copyOf(schedule.getDeviceIds().toArray(), schedule.getDeviceIds().toArray().length,
                    String[].class);
            if (parameters == null) {
                RestApiUtil.handleBadRequest("Device IDs should be provided to perform device app installation",
                        log);
            }
            String scheduleTime = schedule.getScheduleTime();

            SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
            sdf.setLenient(false);
            Date date = sdf.parse(scheduleTime);

            JSONObject user = new JSONObject();
            user.put("username", tenantUserName);
            user.put("tenantDomain", tenantDomainName);
            user.put("tenantId", tenantId);

            String activityId = mobileOperation.performAction(user.toString(), action, tenantId, type, appId,
                    parameters, scheduleTime, null);

            JSONObject response = new JSONObject();
            response.put("activityId", activityId);

            return Response.ok().entity(response.toString()).build();

        } catch (AppManagementException e) {
            RestApiUtil.handleInternalServerError("Internal Error occurred while installing", e, log);
        } catch (MobileApplicationException e) {
            RestApiUtil.handleBadRequest(e.getMessage(), log);
        } catch (UserStoreException e) {
            RestApiUtil.handleInternalServerError("User store related Error occurred while installing", e, log);
        } catch (JSONException e) {
            RestApiUtil.handleInternalServerError("Json casting Error occurred while installing", e, log);
        } catch (ParseException e) {
            RestApiUtil.handleBadRequest("Invalid schedule date format", log);
        }
        return Response.ok().build();
    }

    /**
     * Document Content retrieve
     * @param appId  id of the application
     * @param documentId id of the documentation
     * @param appType type of the application
     * @param accept
     * @param ifNoneMatch
     * @param ifModifiedSince
     * @return
     */
    @Override
    public Response appsAppTypeIdAppIdDocsDocumentIdContentGet(String appId, String documentId, String appType,
            String accept, String ifNoneMatch, String ifModifiedSince) {

        Documentation documentation;
        try {
            if (AppMConstants.WEBAPP_ASSET_TYPE.equals(appType) || AppMConstants.SITE_ASSET_TYPE.equals(appType)) {

                String username = RestApiUtil.getLoggedInUsername();
                APIProvider appProvider = RestApiUtil.getLoggedInUserProvider();
                String tenantDomain = RestApiUtil.getLoggedInUserTenantDomain();

                WebApp webApp = appProvider.getWebApp(appId);
                APIIdentifier appIdentifier = webApp.getId();
                documentation = appProvider.getDocumentation(documentId, tenantDomain);
                if (documentation == null) {
                    RestApiUtil.handleResourceNotFoundError(RestApiConstants.RESOURCE_DOCUMENTATION, documentId,
                            log);
                    return null;
                }

                //gets the content depending on the type of the document
                if (documentation.getSourceType().equals(Documentation.DocumentSourceType.FILE)) {
                    String resource = documentation.getFilePath();
                    Map<String, Object> docResourceMap = AppManagerUtil.getDocument(username, resource,
                            tenantDomain);
                    Object fileDataStream = docResourceMap.get(AppMConstants.DOCUMENTATION_RESOURCE_MAP_DATA);
                    Object contentType = docResourceMap.get(AppMConstants.DOCUMENTATION_RESOURCE_MAP_CONTENT_TYPE);
                    contentType = contentType == null ? RestApiConstants.APPLICATION_OCTET_STREAM : contentType;
                    String name = docResourceMap.get(AppMConstants.DOCUMENTATION_RESOURCE_MAP_NAME).toString();
                    return Response.ok(fileDataStream).header(RestApiConstants.HEADER_CONTENT_TYPE, contentType)
                            .header(RestApiConstants.HEADER_CONTENT_DISPOSITION,
                                    "attachment; filename=\"" + name + "\"")
                            .build();
                } else if (documentation.getSourceType().equals(Documentation.DocumentSourceType.INLINE)) {
                    String content = appProvider.getDocumentationContent(appIdentifier, documentation.getName());
                    return Response.ok(content).header(RestApiConstants.HEADER_CONTENT_TYPE,
                            AppMConstants.DOCUMENTATION_INLINE_CONTENT_TYPE).build();
                } else if (documentation.getSourceType().equals(Documentation.DocumentSourceType.URL)) {
                    String sourceUrl = documentation.getSourceUrl();
                    return Response.seeOther(new URI(sourceUrl)).build();
                }
            } else {
                RestApiUtil.handleBadRequest("App type " + appType + " is not supported", log);
            }
        } catch (AppManagementException e) {
            if (RestApiUtil.isDueToResourceNotFound(e) || RestApiUtil.isDueToAuthorizationFailure(e)) {
                RestApiUtil.handleResourceNotFoundError(appType, appId, e, log);
            } else {
                String errorMessage = "Error while retrieving document " + documentId + " of the " + appType
                        + " with id : " + appId;
                RestApiUtil.handleInternalServerError(errorMessage, e, log);
            }
        } catch (URISyntaxException e) {
            String errorMessage = "Error while retrieving source URI location of " + documentId;
            RestApiUtil.handleInternalServerError(errorMessage, e, log);
        }
        return null;
    }

    /**
     * Retrieve documentation for a given documentationId and for a given app id
     * @param appType application type ie: webapp,mobileapp
     * @param appId application uuid
     * @param documentId  documentID
     * @param ifMatch
     * @param ifUnmodifiedSince
     * @return
     */
    @Override
    public Response appsAppTypeIdAppIdDocsDocumentIdGet(String appType, String appId, String documentId,
            String ifMatch, String ifUnmodifiedSince) {
        Documentation documentation;
        DocumentDTO documentDTO = null;
        try {
            if (AppMConstants.WEBAPP_ASSET_TYPE.equals(appType) || AppMConstants.SITE_ASSET_TYPE.equals(appType)) {
                //TODO:Check App access prmissions
                APIProvider appProvider = RestApiUtil.getLoggedInUserProvider();
                String tenantDomain = RestApiUtil.getLoggedInUserTenantDomain();
                documentation = appProvider.getDocumentation(documentId, tenantDomain);
                if (documentation == null) {
                    RestApiUtil.handleResourceNotFoundError(RestApiConstants.RESOURCE_DOCUMENTATION, documentId,
                            log);
                }
                documentDTO = DocumentationMappingUtil.fromDocumentationToDTO(documentation);
            } else {
                RestApiUtil.handleBadRequest("App type " + appType + " is not supported", log);
            }
        } catch (AppManagementException e) {
            //Auth failure occurs when cross tenant accessing APIs. Sends 404, since we don't need to expose the existence of the resource
            if (RestApiUtil.isDueToResourceNotFound(e) || RestApiUtil.isDueToAuthorizationFailure(e)) {
                RestApiUtil.handleResourceNotFoundError(appType, appId, e, log);
            } else {
                String errorMessage = "Error while retrieving document : " + documentId;
                RestApiUtil.handleInternalServerError(errorMessage, e, log);
            }
        }
        return Response.ok().entity(documentDTO).build();
    }

    /**
     *  Returns all the documents of the given APP uuid that matches to the search condition
     *
     * @param appType application type ie:webapp,mobileapp
     * @param appId application identifier
     * @param limit
     * @param offset
     * @param accept
     * @param ifNoneMatch
     * @return matched documents as a list if DocumentDTOs
     */
    @Override
    public Response appsAppTypeIdAppIdDocsGet(String appType, String appId, Integer limit, Integer offset,
            String accept, String ifNoneMatch) {
        //pre-processing
        //setting default limit and offset values if they are not set
        limit = limit != null ? limit : RestApiConstants.PAGINATION_LIMIT_DEFAULT;
        offset = offset != null ? offset : RestApiConstants.PAGINATION_OFFSET_DEFAULT;

        try {
            if (AppMConstants.WEBAPP_ASSET_TYPE.equals(appType) || AppMConstants.SITE_ASSET_TYPE.equals(appType)) {
                APIProvider appProvider = RestApiUtil.getLoggedInUserProvider();
                String tenantDomain = RestApiUtil.getLoggedInUserTenantDomain();
                //this will fail if user does not have access to the API or the API does not exist

                WebApp webApp = appProvider.getWebApp(appId);
                APIIdentifier appIdentifier = webApp.getId();

                List<Documentation> allDocumentation = appProvider.getAllDocumentation(appIdentifier);
                DocumentListDTO documentListDTO = DocumentationMappingUtil
                        .fromDocumentationListToDTO(allDocumentation, offset, limit);
                DocumentationMappingUtil.setPaginationParams(documentListDTO, appId, offset, limit,
                        allDocumentation.size());
                return Response.ok().entity(documentListDTO).build();
            } else {
                RestApiUtil.handleBadRequest("App type " + appType + " is not supported", log);
            }
        } catch (AppManagementException e) {
            //Auth failure occurs when cross tenant accessing APIs. Sends 404, since we don't need to expose the existence of the resource
            if (RestApiUtil.isDueToResourceNotFound(e) || RestApiUtil.isDueToAuthorizationFailure(e)) {
                RestApiUtil.handleResourceNotFoundError(appType, appId, e, log);
            } else {
                String msg = "Error while retrieving documents of App " + appType + " with appId " + appId;
                RestApiUtil.handleInternalServerError(msg, e, log);
            }
        }
        return null;
    }

    @Override
    public Response appsMobileScheduleUpdatePost(String contentType, ScheduleDTO schedule,
            SecurityContext securityContext) {
        String username = RestApiUtil.getLoggedInUsername();
        try {
            Map<String, String> searchTerms = new HashMap<String, String>();
            searchTerms.put("id", schedule.getAppId());

            APIProvider apiProvider = RestApiUtil.getLoggedInUserProvider();
            List<App> result = apiProvider.searchApps(AppMConstants.MOBILE_ASSET_TYPE, searchTerms);
            if (result.isEmpty()) {
                String errorMessage = "Could not find requested application.";
                return RestApiUtil.buildNotFoundException(errorMessage, schedule.getAppId()).getResponse();
            }

            String tenantDomainName = MultitenantUtils.getTenantDomain(username);
            int tenantId = ServiceReferenceHolder.getInstance().getRealmService().getTenantManager()
                    .getTenantId(tenantDomainName);
            String tenantUserName = MultitenantUtils.getTenantAwareUsername(username);
            String appId = schedule.getAppId();
            Operations mobileOperation = new Operations();
            String action = "update";
            String type = "device";
            String[] parameters;
            parameters = Arrays.copyOf(schedule.getDeviceIds().toArray(), schedule.getDeviceIds().toArray().length,
                    String[].class);
            if (parameters == null) {
                RestApiUtil.handleBadRequest("Device IDs should be provided to perform device app installation",
                        log);
            }
            String scheduleTime = schedule.getScheduleTime();

            SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
            sdf.setLenient(false);
            Date date = sdf.parse(scheduleTime);

            JSONObject user = new JSONObject();
            user.put("username", tenantUserName);
            user.put("tenantDomain", tenantDomainName);
            user.put("tenantId", tenantId);

            String activityId = mobileOperation.performAction(user.toString(), action, tenantId, type, appId,
                    parameters, scheduleTime, null);
            JSONObject response = new JSONObject();
            response.put("activityId", activityId);

            return Response.ok().entity(response.toString()).build();

        } catch (AppManagementException e) {
            RestApiUtil.handleInternalServerError("Internal Error occurred while installing", e, log);
        } catch (MobileApplicationException e) {
            RestApiUtil.handleBadRequest(e.getMessage(), log);
        } catch (UserStoreException e) {
            RestApiUtil.handleInternalServerError("User store related Error occurred while installing", e, log);
        } catch (JSONException e) {
            RestApiUtil.handleInternalServerError("Json casting Error occurred while installing", e, log);
        } catch (ParseException e) {
            RestApiUtil.handleBadRequest("Invalid schedule date format", log);
        }
        return Response.ok().build();
    }

}