/** * Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * Licensed 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.bpmn.core.deployment; import org.apache.axis2.context.ConfigurationContext; import org.apache.axis2.deployment.AbstractDeployer; import org.apache.axis2.deployment.DeploymentException; import org.apache.axis2.deployment.repository.util.DeploymentFileData; import org.apache.commons.io.FilenameUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.bpmn.core.BPMNConstants; import org.wso2.carbon.bpmn.core.BPMNServerHolder; import org.wso2.carbon.bpmn.core.BPSFault; import org.wso2.carbon.context.CarbonContext; import org.wso2.carbon.registry.core.exceptions.RegistryException; import org.wso2.carbon.registry.core.service.RegistryService; import org.wso2.carbon.utils.CarbonUtils; import java.io.File; /** * Deployer implementation for BPMN Packages. This deployer is associated with bpmn directory * under repository/deployment/server directory. Currently associated file extension is .bar. * Separate deployer instance is created for each tenant. * Activiti Engine versions same package if deployed twice. In order to overcome this issue, * we are using an additional table which will keep track of the deployed package's md5sum in-order to * identify the deployment of a new package. * */ public class BPMNDeployer extends AbstractDeployer { private static Log log = LogFactory.getLog(BPMNDeployer.class); private TenantRepository tenantRepository = null; /** * Initializes the deployment per tenant * * @param configurationContext axis2 configurationContext */ @Override public void init(ConfigurationContext configurationContext) { Integer tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId(); log.info("Initializing BPMN Deployer for tenant " + tenantId + "."); try { File tenantRepoFolder = createTenantRepo(configurationContext); tenantRepository = BPMNServerHolder.getInstance().getTenantManager().createTenantRepository(tenantId); tenantRepository.setRepoFolder(tenantRepoFolder); //This is to check whether the user have added resolveDeploymentAtStartup system property to true if need // for resolving deployment to avoid inconsistencies boolean fixDeployments = true; if (System.getProperty(BPMNConstants.RESOLVE_DEPLOYMENT_SYS_PROP) != null && !Boolean.parseBoolean(System.getProperty(BPMNConstants.RESOLVE_DEPLOYMENT_SYS_PROP))) { fixDeployments = false; log.info("BPMN deployment inconsistencies will not resolved"); } if (!isWorkerNode() && fixDeployments) { log.info("Resolving BPMN deployments to avoid inconsistencies"); tenantRepository.fixDeployments(); } } catch (BPSFault e) { String msg = "Tenant Error: " + tenantId; log.error(msg, e); } } /** * Deploys a given bpmn package in acitiviti bpmn engine. * @param deploymentFileData Provide information about the deployment file * @throws DeploymentException On failure , deployment exception is thrown */ public void deploy(DeploymentFileData deploymentFileData) throws DeploymentException { // Deployment logic is dependent on whether a given node is a worker node or not.Since process // information is shared though a persistence db and process is stored into the database, there // is no need to deploy process in worker nodes. // Worker nodes cannot deploy BPMN packages, hence return if (isWorkerNode()) { return; } Integer tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId(); log.info("Deploying BPMN archive " + deploymentFileData.getFile().getName() + " for tenant: " + tenantId); try { BPMNDeploymentContext deploymentContext = new BPMNDeploymentContext(tenantId); deploymentContext.setBpmnArchive(deploymentFileData.getFile()); tenantRepository.deploy(deploymentContext); //log.info( "Deployment Status " + deploymentFileData.getFile() + " deployed = " + deployed ); } catch (DeploymentException e) { String errorMessage = "Failed to deploy the archive: " + deploymentFileData.getAbsolutePath(); throw new DeploymentException(errorMessage, e); } } /** * Undeployment operation for Bpmn Deployer * * @param bpmnArchivePath archivePatch * @throws DeploymentException Deployment failure will result in this exception */ public void undeploy(String bpmnArchivePath) throws DeploymentException { // Worker nodes does not perform any action related to bpmn undeployment, manager node takes // care of all deployment/undeployment actions if (isWorkerNode()) { return; } File bpmnArchiveFile = new File(bpmnArchivePath); if (bpmnArchiveFile.exists()) { if (log.isTraceEnabled()) { log.trace("BPMN package: " + bpmnArchivePath + " exists in the deployment folder. " + "Therefore, this can be an update of the package and the undeployment will be aborted."); } return; } Integer tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId(); log.info("Undeploying BPMN archive " + bpmnArchivePath + " for tenant: " + tenantId); String deploymentName = FilenameUtils.getBaseName(bpmnArchivePath); try { tenantRepository.undeploy(deploymentName, true); } catch (BPSFault be) { String errorMsg = "Error un deploying BPMN Package " + deploymentName; throw new DeploymentException(errorMsg, be); } } /** * * @param configurationContext axis2 configurationContext * @return bpmn repo file * @throws BPSFault repo creation failure will result in this xception */ private File createTenantRepo(ConfigurationContext configurationContext) throws BPSFault { String axisRepoPath = configurationContext.getAxisConfiguration().getRepository().getPath(); if (CarbonUtils.isURL(axisRepoPath)) { String msg = "URL Repositories are not supported: " + axisRepoPath; throw new BPSFault(msg); } File tenantsRepository = new File(axisRepoPath); File bpmnRepo = new File(tenantsRepository, BPMNConstants.BPMN_REPO_NAME); if (!bpmnRepo.exists()) { boolean status = bpmnRepo.mkdir(); if (!status) { String msg = "Failed to create BPMN repository folder " + bpmnRepo.getAbsolutePath() + "."; throw new BPSFault(msg); } } return bpmnRepo; } @Override public void setDirectory(String s) { } @Override public void setExtension(String s) { } /** * Whether a bps node is worker ( a node that does not participate in archive deployment and only handles * input/output . This is determined by looking at the registry read/only property * @return */ private boolean isWorkerNode() { RegistryService registryService = BPMNServerHolder.getInstance().getRegistryService(); boolean isWorker = true; try { isWorker = (registryService.getConfigSystemRegistry().getRegistryContext().isReadOnly()); } catch (RegistryException e) { log.error("Error accessing the configuration registry"); } return isWorker; } }