/* * Copyright (c) 2010-2015, 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.bpel.core.ode.integration.store; import org.apache.axis2.context.ConfigurationContext; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.ode.bpel.compiler.api.CompilationException; import org.apache.ode.bpel.dd.DeployDocument; import org.apache.ode.bpel.dd.TAnalyticsServerProfiles; import org.apache.ode.bpel.dd.TDeployment; import org.apache.ode.bpel.dd.TProvide; import org.apache.ode.bpel.engine.BpelServerImpl; import org.apache.ode.bpel.iapi.ContextException; import org.apache.ode.bpel.iapi.ProcessConf; import org.apache.ode.bpel.iapi.ProcessState; import org.apache.ode.store.DeploymentUnitDAO; import org.apache.ode.store.DeploymentUnitDir; import org.apache.ode.store.ProcessConfDAO; import org.wso2.carbon.application.deployer.AppDeployerUtils; import org.wso2.carbon.bpel.common.config.EndpointConfiguration; import org.wso2.carbon.bpel.core.BPELConstants; import org.wso2.carbon.bpel.core.internal.BPELServiceComponent; import org.wso2.carbon.bpel.core.ode.integration.BPELServerImpl; import org.wso2.carbon.bpel.core.ode.integration.config.analytics.AnalyticsServerProfile; import org.wso2.carbon.bpel.core.ode.integration.config.analytics.AnalyticsServerProfileBuilder; import org.wso2.carbon.bpel.core.ode.integration.store.clustering.BPELProcessStateChangedCommand; import org.wso2.carbon.bpel.core.ode.integration.store.repository.BPELPackageInfo; import org.wso2.carbon.bpel.core.ode.integration.store.repository.BPELPackageRepository; import org.wso2.carbon.bpel.core.ode.integration.store.repository.BPELPackageRepositoryUtils; import org.wso2.carbon.bpel.skeleton.ode.integration.mgt.services.ProcessManagementException; import org.wso2.carbon.context.CarbonContext; import org.wso2.carbon.registry.core.Registry; import org.wso2.carbon.registry.core.RegistryConstants; import org.wso2.carbon.registry.core.config.RegistryContext; import org.wso2.carbon.registry.core.exceptions.RegistryException; import org.wso2.carbon.registry.core.utils.RegistryClientUtils; import org.wso2.carbon.unifiedendpoint.core.UnifiedEndpointConstants; import org.wso2.carbon.utils.FileManipulator; import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.xml.namespace.QName; /** * Tenant specific process store. * Contains all the information about tenant's BPEL packages and processes. */ public class TenantProcessStoreImpl implements TenantProcessStore { private static final Log log = LogFactory.getLog(TenantProcessStoreImpl.class); private static final Log deploymentLog = LogFactory.getLog(BPELConstants.LOGGER_DEPLOYMENT); // ID of the tenant who owns this process store private Integer tenantId; // Tenant's Configuration context private ConfigurationContext tenantConfigContext; // Tenant's configuration registry private Registry tenantConfigRegistry; // Parent process store private ProcessStoreImpl parentProcessStore; // BPEL Deployment units available for this tenant private final Map<String, DeploymentUnitDir> deploymentUnits = new ConcurrentHashMap<String, DeploymentUnitDir>(); // BPEL Processes in this tenant private final Map<QName, ProcessConfigurationImpl> processConfigMap = new ConcurrentHashMap<QName, ProcessConfigurationImpl>(); private final Map<String, List<QName>> processesInDeploymentUnit = new ConcurrentHashMap<String, List<QName>>(); private BPELPackageRepository repository; // Tenant's BPEL deployment unit repository private File bpelDURepo; // Axis2 bpel deployment repository where we put BPEL archive artifacts private File bpelArchiveRepo; // Holds the BAM server profiles private final Map<String, AnalyticsServerProfile> analyticsProfiles = new ConcurrentHashMap<String, AnalyticsServerProfile>(); private final Map<String, Object> dataPublisherMap = new ConcurrentHashMap<String, Object>(); public TenantProcessStoreImpl(ConfigurationContext configContext, ProcessStoreImpl parent) throws RegistryException { tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId(); tenantConfigContext = configContext; tenantConfigRegistry = BPELServiceComponent.getRegistryService().getConfigSystemRegistry(tenantId); parentProcessStore = parent; } public void init() throws Exception { bpelDURepo = new File(parentProcessStore.getLocalDeploymentUnitRepo(), tenantId.toString()); if (!bpelDURepo.exists() && !bpelDURepo.mkdirs()) { log.warn("Cannot create tenant " + tenantId + " BPEL deployment unit repository."); } repository = new BPELPackageRepository(tenantConfigRegistry, bpelDURepo, bpelArchiveRepo); repository.init(); } public void handleNewBPELPackageDeploymentNotification(String bpelPackageName) { // Copy archive to file system // Write the deployment logic to handle that. try { repository.restoreBPELArchive(repository.getBPELPackageInfo( BPELConstants.REG_PATH_OF_BPEL_PACKAGES + bpelPackageName)); } catch (Exception e) { log.error("Error occurred while deploying: " + bpelPackageName, e); } } public void handleBPELPackageUndeploymentNotification(String bpelPackageName, List<String> versionsOfPackage) { updateLocalInstanceWithUndeployment(bpelPackageName, versionsOfPackage); } public void handleBPELProcessStateChangedNotification(QName pid, ProcessState processState) { if (log.isDebugEnabled()) { log.debug("Changing state of the process " + pid + " to " + processState); } if (!isProcessExist(pid)) { String errMsg = "Process " + pid + " not found. Process state change failed."; log.error(errMsg); return; } if (processState == null) { String errMessage = "Process State cannot be null. Process state change failed"; log.error(errMessage); return; } parentProcessStore.updateLocalInstanceWithStateChange(pid, processState); } /** * Deploy processes in given BPEL archive in ODE. * <p/> * Deployment flow: * - Get the current version from ODE(This version number is global to ODE.) * - Create the deployment context(@see BPELDeploymentContext) * - Check for existing BPEL archives with the same name(use when updating BPEL packages) * - If this is a new deployment or update, extract the archive and deploy processes * - If this is a reload(at startup) handle the reload. * <p/> * Process Versioning: * Process version is a single, sequentially incremented number. All deployed packages share * the same sequence. All processes in a bundle share the same version number and it's * the number of their bundle. * * @param bpelArchive BPEL package directory * @throws RegistryException */ public void deploy(File bpelArchive) throws Exception { log.info("Deploying BPEL archive: " + bpelArchive.getName()); long versionForThisDeployment = parentProcessStore.getCurrentVersion(); BPELDeploymentContext deploymentContext = new BPELDeploymentContext( tenantId, parentProcessStore.getLocalDeploymentUnitRepo().getAbsolutePath(), bpelArchive, versionForThisDeployment); boolean isExistingPackage = repository.isExistingBPELPackage(deploymentContext); boolean isLoadOnly = repository.isBPELPackageReload(deploymentContext); deploymentContext.setExistingPackage(isExistingPackage); if (deploymentLog.isDebugEnabled()) { deploymentLog.debug("Package: " + deploymentContext.getBpelPackageName() + (isExistingPackage ? " is already available" : "is a new deployment")); deploymentLog.debug("Package: " + deploymentContext.getBpelPackageName() + (isLoadOnly ? " has already deployed. Therefore the package is reloaded" : " is found as a new deployment")); } if (isExistingPackage && isLoadOnly) { // This is either a restart of the node or a new package deployment on the non master nodes reloadExistingVersionsOfBPELPackage(deploymentContext); // No need to execute further as we have taken care of retiring the older versions and activating the last // version, hence return return; } if (isConfigRegistryReadOnly()) { // We do not allow packages to be deployed on slave node first in-order to have correct versioning accross // the cluster. Hence a package should be deployed on master node first. log.warn("This node is a slave node as the configuration registry is in read-only mode, " + "hence processes cannot be directly deployed in this node. " + "Please deploy the process in Master node first."); return; } try { Utils.extractBPELArchive(deploymentContext); } catch (Exception exception) { String errMsg = "Error extracting BPEL archive " + deploymentContext.getBpelArchive() + "."; deploymentContext.setDeploymentFailureCause(errMsg); deploymentContext.setStackTrace(exception); deploymentContext.setFailed(true); handleDeploymentError(deploymentContext); throw exception; } if (!validateBPELPackage(deploymentContext, isExistingPackage)) { deploymentContext.setFailed(true); handleDeploymentError(deploymentContext); // Exit from the normal processing flow on bpel package validation error return; } // Deploy our newly deployed bpel package in ode deployBPELPackageInODE(deploymentContext); if (isExistingPackage) { repository.handleBPELPackageUpdate(deploymentContext); } else { repository.handleNewBPELPackageAddition(deploymentContext); } } private boolean isConfigRegistryReadOnly() { RegistryContext context = tenantConfigRegistry.getRegistryContext(); try { if (context != null) { return context.isReadOnly(); } } catch (Exception e) { log.error("An error occurred while obtaining registry instance", e); } return false; } /** * Undeploying BPEL package. * * @param bpelPackageName Name of the BPEL package which going to be undeployed */ public void undeploy(String bpelPackageName) throws RegistryException, BPELUIException { if (log.isDebugEnabled()) { log.debug("Un-deploying BPEL package " + bpelPackageName + " ...."); } if (!repository.isExistingBPELPackage(bpelPackageName)) { // This can be a situation where we un-deploy the archive through management console, // so that, the archive is deleted from the repo. As a result this method get invoked. // to handle this case we just log the message but does not throw an exception. final String warningMsg = "Cannot find BPEL package with name " + bpelPackageName + " in the repository. If the bpel package is un-deployed through the management" + " console or if this node is a member of a cluster, please ignore this warning."; if (isConfigRegistryReadOnly()) { // This is for the deployment synchronizer scenarios where package un-deployment on a worker node // has to remove the deployed bpel package from the memory and remove associated services handleUndeployOnSlaveNode(bpelPackageName); } else { log.warn(warningMsg); } return; } if (repository.isExistingBPELPackage(bpelPackageName) && isConfigRegistryReadOnly()) { log.warn("This node seems to be a slave, since the configuration registry is in read-only mode, hence " + "processes cannot be directly undeployed from this node. Please undeploy the process in Master " + "node first."); return; } List<String> versionsOfThePackage; try { versionsOfThePackage = repository.getAllVersionsForPackage(bpelPackageName); } catch (RegistryException re) { String errMessage = "Cannot get all versions of the package " + bpelPackageName + " from registry."; log.error(errMessage); throw re; } //check the instance count to be deleted long instanceCount = getInstanceCountForPackage(versionsOfThePackage); if (instanceCount > BPELServerImpl.getInstance().getBpelServerConfiguration().getBpelInstanceDeletionLimit()) { throw new BPELUIException("Instance deletion limit reached."); } for (String nameWithVersion : versionsOfThePackage) { parentProcessStore.deleteDeploymentUnitDataFromDB(nameWithVersion); Utils.deleteInstances(getProcessesInPackage(nameWithVersion)); //location for extracted BPEL package String bpelPackageLocation = parentProcessStore.getLocalDeploymentUnitRepo().getAbsolutePath() + File .separator + tenantId + File.separator + nameWithVersion; File bpelPackage = new File(bpelPackageLocation); //removing extracted bpel package at repository/bpel/0/ deleteBpelPackageFromRepo(bpelPackage); for (QName pid : getProcessesInPackage(nameWithVersion)) { ProcessConfigurationImpl processConf = (ProcessConfigurationImpl) getProcessConfiguration(pid); // This property is read when we removing the axis service for this process. // So that we can decide whether we should persist service QOS configs processConf.setUndeploying(true); } } try { repository.handleBPELPackageUndeploy(bpelPackageName); } catch (RegistryException re) { String errMessage = "Cannot update the BPEL package repository for undeployment of" + "package " + bpelPackageName + "."; log.error(errMessage); throw re; } updateLocalInstanceWithUndeployment(bpelPackageName, versionsOfThePackage); // We should use the deployment synchronizer, instead of the code below. // parentProcessStore.sendProcessDeploymentNotificationsToCluster( // new BPELPackageUndeployedCommand(versionsOfThePackage, bpelPackageName, tenantId), // configurationContext); } private int getInstanceCountForPackage(List<String> versionsOfThePackage) { int count = 0; for (String versionName : versionsOfThePackage) { count += Utils.getInstanceCountForProcess(getProcessesInPackage(versionName)); } return count; } /** * Undeployment scenario in a worker node( Slave ) in the clustered setup * When the BPELDeployer get called for undeploying the bpel package, following has already taken place. * The package information stored in the registry as well as the zip archive is deleted * Process, Instance information have been removed from the ODE database * However, on the slave node, the bpel process and the web services associated with the bpel process * is still in memory. We need to unload the bpel process and the associated web services * * @param bpelPackageName bpel package name * @return */ private int handleUndeployOnSlaveNode(String bpelPackageName) { List<String> packageList = findMatchingProcessByPackageName(bpelPackageName); if (packageList.size() < 1) { log.debug("Handling un-deploy operation on salve (worker) node : package list is empty"); return -1; } for (String packageName : packageList) { //location for extracted BPEL package String bpelPackageLocation = parentProcessStore.getLocalDeploymentUnitRepo().getAbsolutePath() + File.separator + tenantId + File.separator + packageName; File bpelPackage = new File(bpelPackageLocation); //removing extracted bpel package at repository/bpel/tenantID/ deleteBpelPackageFromRepo(bpelPackage); for (QName pid : getProcessesInPackage(packageName)) { ProcessConfigurationImpl processConf = (ProcessConfigurationImpl) getProcessConfiguration(pid); // This property is read when we removing the axis service for this process. // So that we can decide whether we should persist service QOS configs processConf.setUndeploying(true); } } Collection<QName> undeployedProcesses = new ArrayList<QName>(); for (String nameWithVersion : packageList) { undeploySpecificVersionOfBPELPackage(nameWithVersion, undeployedProcesses); } BPELServerImpl instance = BPELServerImpl.getInstance(); BpelServerImpl odeBpelServer = instance.getODEBPELServer(); for (QName pid : undeployedProcesses) { odeBpelServer.unregister(pid); ProcessConf pConf = parentProcessStore.getProcessConfiguration(pid); if (pConf != null) { if (log.isDebugEnabled()) { log.debug("Cancelling all cron scheduled jobs for process " + pid); } odeBpelServer.getContexts().cronScheduler.cancelProcessCronJobs( pid, true); } log.info("Process " + pid + " un-deployed."); } parentProcessStore.updateProcessAndDUMapsForSalve(tenantId, bpelPackageName, undeployedProcesses); return 0; } private List<String> findMatchingProcessByPackageName(String packageName) { List<String> stringList = new ArrayList<String>(); Set<String> strings = processesInDeploymentUnit.keySet(); String regexPattern = packageName + "-(\\d*)"; Pattern pattern = Pattern.compile(regexPattern); Iterator<String> iterator = strings.iterator(); while (iterator.hasNext()) { String next = iterator.next(); Matcher matcher = pattern.matcher(next); if (matcher.matches()) { stringList.add(next); } } return stringList; } private void deleteBpelPackageFromRepo(File bpelPackage) { log.info("Undeploying BPEL package. " + "Deleting " + bpelPackage + " BPEL package"); if (bpelPackage.exists()) { FileManipulator.deleteDir(bpelPackage); } else { log.warn("BPEL package " + bpelPackage.getAbsolutePath() + " not found. This can happen if you delete " + "the BPEL package from the file system."); } } /** * Update the local instance of the BPS server regarding the undeployment of the bpel package. * * @param bpelPackageName Name of the BPEL package * @param versionsOfThePackage List of deployed versions of the package */ public void updateLocalInstanceWithUndeployment(String bpelPackageName, List<String> versionsOfThePackage) { // Delete the package from the file repository deleteBpelArchive(bpelPackageName); Collection<QName> undeployedProcesses = new ArrayList<QName>(); for (String nameWithVersion : versionsOfThePackage) { undeploySpecificVersionOfBPELPackage(nameWithVersion, undeployedProcesses); } parentProcessStore.updateMapsAndFireStateChangeEventsForUndeployedProcesses(tenantId, bpelPackageName, undeployedProcesses); } /** * Delete BPEL Archive from the BPEL repository of the file system. * * @param bpelPackageName Name of the BPEL package */ private void deleteBpelArchive(String bpelPackageName) { String bpelArchiveLocation = tenantConfigContext.getAxisConfiguration().getRepository(). getPath() + File.separator + BPELConstants.BPEL_REPO_DIRECTORY + File.separator + bpelPackageName + "." + BPELConstants.BPEL_PACKAGE_EXTENSION; log.info("Undeploying BPEL package " + bpelPackageName + ". Deleting BPEL archive " + bpelArchiveLocation + "...."); File bpelArchive = new File(bpelArchiveLocation); if (bpelArchive.exists()) { if (!bpelArchive.delete()) { //For windows bpelArchive.deleteOnExit(); } } else { log.warn("BPEL archive " + bpelArchive.getAbsolutePath() + " not found. This can happen if you delete " + "the BPEL archive from the file system."); } } private void undeploySpecificVersionOfBPELPackage(final String packageName, final Collection<QName> undeployedProcesses) { DeploymentUnitDir du = deploymentUnits.remove(packageName); processesInDeploymentUnit.remove(packageName); if (du != null) { long version = du.getVersion(); for (QName name : du.getProcessNames()) { QName pid = Utils.toPid(name, version); undeployedProcesses.add(pid); } } } public void handleTenantUnload() { } public void hydrate() { } public ProcessConf getProcessConfiguration(QName pid) { return processConfigMap.get(pid); } public void setState(QName pid, ProcessState processState) throws Exception { if (log.isDebugEnabled()) { log.debug("Changing state of the process " + pid + " to " + processState); } if (!isProcessExist(pid)) { String errMsg = "Process " + pid + " not found."; log.error(errMsg); // TODO : Introduce hierarchical exceptions to ODE integration layer. throw new Exception(errMsg); } if (processState == null) { String errMessage = "Process State cannot be null."; log.error(errMessage); throw new Exception(errMessage); } parentProcessStore.setState(pid, processState); parentProcessStore.sendProcessDeploymentNotificationsToCluster( new BPELProcessStateChangedCommand(pid, processState, tenantId)); } private Boolean isProcessExist(QName pid) { return processConfigMap.containsKey(pid); } public BPELPackageRepository getBPELPackageRepository() { return repository; } public Map<QName, ProcessConfigurationImpl> getProcessConfigMap() { return processConfigMap; } public ProcessConf removeProcessConfiguration(QName pid) { return processConfigMap.remove(pid); } public List<QName> getProcessesInPackage(String packageName) { List<QName> processes = processesInDeploymentUnit.get(packageName); if (processes == null) { processes = Collections.EMPTY_LIST; } return processes; } public Boolean containsProcess(QName pid) { return processConfigMap.containsKey(pid); } public void setBpelArchiveRepo(File bpelArchiveRepo) { this.bpelArchiveRepo = bpelArchiveRepo; } /** * Log and store the information to registry on BPEL deployment error. * * @param deploymentContext information about current deployment * @throws RegistryException on error accessing registry for persisting information. */ private void handleDeploymentError(BPELDeploymentContext deploymentContext) throws Exception { if (deploymentContext.getStackTrace() != null) { log.error(deploymentContext.getDeploymentFailureCause(), deploymentContext.getStackTrace()); } else { log.error(deploymentContext.getDeploymentFailureCause()); } // Stop writing the error condition to the registry. //repository.handleBPELPackageDeploymentError(deploymentContext); } /** * Reload old versions of BPEL package. This is used to handle restart of BPS server. * At restart based on the last modified time of the BPEL archives we'll reload all the versions * of that BPEL archive. * * @param deploymentContext information about current deployment * @throws RegistryException on error loading * resources from registry. * @throws org.wso2.carbon.bpel.skeleton.ode.integration.mgt.services.ProcessManagementException */ private void reloadExistingVersionsOfBPELPackage(BPELDeploymentContext deploymentContext) throws RegistryException, ProcessManagementException { BPELPackageInfo bpelPackage = repository.getBPELPackageInfo(deploymentContext); String lastActivePackageName = null; for (String packageName : bpelPackage.getAvailableVersions()) { if (deploymentUnits.containsKey(packageName)) { lastActivePackageName = packageName; } else { // This is to avoid the scenario where slave node is loading the package and not deactivating the older // version of the package if (null != lastActivePackageName && isConfigRegistryReadOnly()) { loadExistingBPELPackage(lastActivePackageName); } loadExistingBPELPackage(packageName); } } } /** * Deploy BPEL package in ODE and add process configuration objects to necessary maps in process * store. * * @param deploymentContext information about current deployment * @throws Exception in case of duplicate deployment unit or if error occurred during deploying package in ODE */ private void deployBPELPackageInODE(BPELDeploymentContext deploymentContext) throws Exception { File bpelPackage = deploymentContext.getBPELPackageContent(); log.info("Starting deployment of processes from directory " + bpelPackage.getAbsolutePath()); final Date deployDate = new Date(); // Create the DU and compile/scan it before doing any other work. final DeploymentUnitDir deploymentUnitDir = new DeploymentUnitDir(bpelPackage); // Before coming to this stage, we create the bpel package directory with the static version // so we don't need to get the version from database. We can directly use static version // calculated from bpel package directory name. deploymentUnitDir.setVersion(deploymentUnitDir.getStaticVersion()); try { deploymentUnitDir.compile(); } catch (CompilationException ce) { String logMessage = "Deployment failed due to compilation issues. " + ce.getMessage(); log.error(logMessage, ce); deploymentContext.setFailed(true); deploymentContext.setDeploymentFailureCause(logMessage); deploymentContext.setStackTrace(ce); handleDeploymentError(deploymentContext); throw new BPELDeploymentException(logMessage, ce); } deploymentUnitDir.scan(); DeployDocument deployDocument = deploymentUnitDir.getDeploymentDescriptor(); List<ProcessConfigurationImpl> processConfs = new ArrayList<ProcessConfigurationImpl>(); List<QName> processIds = new ArrayList<QName>(); if (deploymentUnits.containsKey(deploymentUnitDir.getName())) { String logMessage = "Aborting deployment. Duplicate Deployment unit " + deploymentUnitDir.getName() + "."; log.error(logMessage); deploymentContext.setFailed(true); deploymentContext.setDeploymentFailureCause(logMessage); handleDeploymentError(deploymentContext); throw new BPELDeploymentException(logMessage); } // Validate BPEL package partially before retiring old versions. validateBPELPackage(deploymentUnitDir); if (deploymentContext.isExistingPackage()) { reloadExistingVersionsOfBPELPackage(deploymentContext); } // Before updating a BPEL package we need to retire processes in old version retirePreviousPackageVersions(deploymentUnitDir); for (TDeployment.Process processDD : deployDocument.getDeploy().getProcessList()) { QName processId = Utils.toPid(processDD.getName(), deploymentUnitDir.getVersion()); ProcessConfigurationImpl processConf = new ProcessConfigurationImpl( tenantId, processDD, deploymentUnitDir, deployDate, parentProcessStore.getEndpointReferenceContext(), tenantConfigContext); processConf.setAbsolutePathForBpelArchive(deploymentContext.getBpelArchive().getAbsolutePath()); processIds.add(processId); processConfs.add(processConf); readAnalyticsServerProfiles(processDD, deploymentUnitDir); } deploymentUnits.put(deploymentUnitDir.getName(), deploymentUnitDir); processesInDeploymentUnit.put(deploymentUnitDir.getName(), processIds); for (ProcessConfigurationImpl processConf : processConfs) { processConfigMap.put(processConf.getProcessId(), processConf); deploymentContext.addProcessId(processConf.getProcessId()); } try { parentProcessStore.onBPELPackageDeployment( tenantId, deploymentUnitDir.getName(), BPELPackageRepositoryUtils.getResourcePathForBPELPackageContent(deploymentContext), processConfs); } catch (ContextException ce) { deploymentContext.setDeploymentFailureCause("BPEL Package deployment failed at " + "ODE layer. Possible cause: " + ce.getMessage()); deploymentContext.setStackTrace(ce); deploymentContext.setFailed(true); handleDeploymentError(deploymentContext); throw ce; } } /** * Check whether processes in this package are already available in the process store or check * whether processes are correctly compiled. * * @param du BPEL deployment unit * @throws BPELDeploymentException if there's a error in BPEL package */ private void validateBPELPackage(DeploymentUnitDir du) throws BPELDeploymentException { DeployDocument dd = du.getDeploymentDescriptor(); for (TDeployment.Process processDD : dd.getDeploy().getProcessList()) { QName processId = Utils.toPid(processDD.getName(), du.getVersion()); if (processConfigMap.containsKey(processId)) { String logMessage = "Aborting deployment. Duplicate process ID " + processId + "."; log.error(logMessage); throw new BPELDeploymentException(logMessage); } QName processType = Utils.getProcessType(processDD); DeploymentUnitDir.CBPInfo cbpInfo = du.getCBPInfo(processType); if (cbpInfo == null) { //removeDeploymentArtifacts(deploymentContext, du); String logMessage = "Aborting deployment. Cannot find Process definition for type " + processType + "."; log.error(logMessage); throw new BPELDeploymentException(logMessage); } } } private void handleDeploymentErrorsAtODELayer(BPELDeploymentContext deploymentContext, String duName) { deploymentUnits.remove(duName); processesInDeploymentUnit.remove(duName); for (QName pid : deploymentContext.getProcessIdsForCurrentDeployment()) { processConfigMap.remove(pid); } } private void loadExistingBPELPackage(String bpelPackageName) throws RegistryException, ProcessManagementException, BPELDeploymentException { DeploymentUnitDAO duDAO = parentProcessStore.getDeploymentUnitDAO(bpelPackageName); if (duDAO == null) { String errMsg = "Cannot find DeploymentUnitDAO instance for package " + bpelPackageName + "."; log.error(errMsg); throw new BPELDeploymentException(errMsg); } File bpelPackage = findBPELPackageInFileSystem(duDAO); if (bpelPackage == null || !bpelPackage.exists()) { throw new BPELDeploymentException("Deployed directory " + bpelPackage + " no longer there!"); } DeploymentUnitDir du = new DeploymentUnitDir(bpelPackage); du.setVersion(du.getStaticVersion()); du.scan(); List<ProcessConfigurationImpl> loaded = new ArrayList<ProcessConfigurationImpl>(); List<QName> processIds = new ArrayList<QName>(); for (ProcessConfDAO pConfDAO : duDAO.getProcesses()) { TDeployment.Process processDD = du.getProcessDeployInfo(pConfDAO.getType()); if (processDD == null) { log.warn("Cannot load " + pConfDAO.getPID() + "; cannot find descriptor."); continue; } // TODO: update the props based on the values in the DB. ProcessConfigurationImpl pConf = new ProcessConfigurationImpl( tenantId, processDD, du, duDAO.getDeployDate(), parentProcessStore.getEndpointReferenceContext(), tenantConfigContext); pConf.setAbsolutePathForBpelArchive(bpelPackage.getAbsolutePath()); pConf.setState(pConfDAO.getState()); processIds.add(pConfDAO.getPID()); // if the deployment descriptor is updated at runtime, first load the updated data in // registry and use them with the specific process repository.readPropertiesOfUpdatedDeploymentInfo(pConf, bpelPackageName); readAnalyticsServerProfiles(processDD, du); processConfigMap.put(pConf.getProcessId(), pConf); loaded.add(pConf); } deploymentUnits.put(du.getName(), du); processesInDeploymentUnit.put(du.getName(), processIds); parentProcessStore.onBPELPackageReload(tenantId, du.getName(), loaded); } private void readAnalyticsServerProfiles(TDeployment.Process processDD, DeploymentUnitDir du) { TAnalyticsServerProfiles analyticsServerProfiles = processDD.getAnalyticsServerProfiles(); if (analyticsServerProfiles != null) { for (TAnalyticsServerProfiles.Profile analyticsServerProfile : analyticsServerProfiles.getProfileList()) { String location = analyticsServerProfile.getLocation(); if (location.startsWith(UnifiedEndpointConstants.VIRTUAL_FILE)) { if (!EndpointConfiguration.isAbsolutePath( location.substring(UnifiedEndpointConstants.VIRTUAL_FILE.length()))) { location = EndpointConfiguration.getAbsolutePath( du.getDeployDir().getAbsolutePath(), location.substring(UnifiedEndpointConstants.VIRTUAL_FILE.length())); } } else if ((!location.startsWith(UnifiedEndpointConstants.VIRTUAL_CONF_REG) && !location.startsWith(UnifiedEndpointConstants.VIRTUAL_GOV_REG) && !location.startsWith(UnifiedEndpointConstants.VIRTUAL_REG))) { if (EndpointConfiguration.isAbsolutePath(location)) { location = UnifiedEndpointConstants.VIRTUAL_FILE + location; } else { location = EndpointConfiguration.getAbsolutePath(du.getDeployDir().getAbsolutePath(), location); location = UnifiedEndpointConstants.VIRTUAL_FILE + location; } } AnalyticsServerProfileBuilder builder = new AnalyticsServerProfileBuilder(location, tenantId); AnalyticsServerProfile profile = builder.build(); addAnalyticsServerProfile(profile.getName(), profile); } } } private File findBPELPackageInFileSystem(DeploymentUnitDAO dudao) { String duName = dudao.getName(); // Done: Fix the logic to handle registry log.info("Looking for BPEL package in file system for deployment unit " + duName); File bpelDUDirectory = new File(bpelDURepo, duName); if (bpelDUDirectory.exists()) { return bpelDUDirectory; } else { String registryCollectionPath = dudao.getDeploymentUnitDir(); try { if (tenantConfigRegistry.resourceExists(registryCollectionPath)) { if (!bpelDUDirectory.exists() && !bpelDUDirectory.mkdirs()) { String errMsg = "Error creating BPEL deployment unit repository for " + "tenant " + tenantId; log.error(errMsg); log.error("Failed to load BPEL deployment unit " + duName + " due to above error."); throw new BPELDeploymentException(errMsg); } boolean deployedOnCarbon310 = false; //Check whether the registry repo is of type carbon 3.1.0 if (tenantConfigRegistry.resourceExists(registryCollectionPath + RegistryConstants.PATH_SEPARATOR + duName)) { registryCollectionPath += RegistryConstants.PATH_SEPARATOR + duName; deployedOnCarbon310 = true; if (log.isDebugEnabled()) { log.debug("Found a carbon 3.1.0 compatible deployment unit at " + registryCollectionPath); } } RegistryClientUtils.exportFromRegistry(bpelDUDirectory, registryCollectionPath, tenantConfigRegistry); if (deployedOnCarbon310) { if (log.isDebugEnabled()) { log.debug("Recompiling the carbon 3.1.0 compatible deployment unit at " + bpelDUDirectory); } //Re-compiling to get rid of binary compatibility issues. DeploymentUnitDir du = new DeploymentUnitDir(bpelDUDirectory); for (File file : du.allFiles()) { if (file.getAbsolutePath().endsWith(".cbp") && !file.delete()) { log.warn("Unable to delete " + file); } } du.compile(); } return bpelDUDirectory; } else { String errMsg = "Expected resource: " + registryCollectionPath + " not found in the registry"; log.error(errMsg); throw new BPELDeploymentException(errMsg); } } catch (RegistryException re) { String errMsg = "Error while exporting deployment unit: " + duName + " to file system from the registry."; log.error(errMsg, re); throw new BPELDeploymentException(errMsg, re); } } } /** * Retire all the other versions of the same DU: * first take the DU name and insert version regexp, * than try to match the this string against names of already deployed DUs. * For instance if we are deploying DU "AbsenceRequest-2/AbsenceRequest.ode" and * there's already version 2 than regexp * "AbsenceRequest([-\\.](\d)+)?/AbsenceRequest.ode" will be matched against * "AbsenceRequest-2/AbsenceRequest.ode" and setRetirePackage() will be called accordingly. * * @param du DeploymentUnitDir object containing in-memory representation of BPEL package. */ private void retirePreviousPackageVersions(DeploymentUnitDir du) { //retire all the other versions of the same DU String[] nameParts = du.getName().split("/"); /* Replace the version number (if any) with regexp to match any version number */ nameParts[0] = nameParts[0].replaceAll("([-\\Q.\\E](\\d)+)?\\z", ""); nameParts[0] += "([-\\Q.\\E](\\d)+)?"; StringBuilder duNameRegExp = new StringBuilder(du.getName().length() * 2); for (int i = 0, n = nameParts.length; i < n; i++) { if (i > 0) { duNameRegExp.append("/"); } duNameRegExp.append(nameParts[i]); } Pattern duNamePattern = Pattern.compile(duNameRegExp.toString()); for (String deployedDUname : deploymentUnits.keySet()) { Matcher matcher = duNamePattern.matcher(deployedDUname); if (matcher.matches()) { parentProcessStore.setRetiredPackage(deployedDUname, true); } } } private boolean validateBPELPackage(BPELDeploymentContext bpelDeploymentContext, boolean isExistingPackage) { DeploymentUnitDir du; try { du = new DeploymentUnitDir(bpelDeploymentContext.getBPELPackageContent()); } catch (IllegalArgumentException e) { bpelDeploymentContext.setDeploymentFailureCause(e.getMessage()); bpelDeploymentContext.setStackTrace(e); return false; } if (!isExistingPackage) { DeployDocument deployDocument = du.getDeploymentDescriptor(); List<TDeployment.Process> processList = deployDocument.getDeploy().getProcessList(); for (TDeployment.Process process : processList) { List<TProvide> provideList = process.getProvideList(); for (TProvide provide : provideList) { if (getDeployedServices().containsKey(provide.getService().getName())) { String errMsg = "Service: " + provide.getService().getName() + " already " + "used by another process. Try again with a different " + "service name"; bpelDeploymentContext.setDeploymentFailureCause(errMsg); return false; } } } } return true; } /** * Current bpel package can be coming from a cApp. If that is the case, we have to attach * this process with its owner cApp. * * @param bpelArchiveName - file name of the BPEL package * @param bpelPackageName - package name extracted out of the archive name * @param tenantId - current tenant id */ private void attachWithCapp(String bpelArchiveName, String bpelPackageName, int tenantId) { // attach with cApp AppDeployerUtils.attachArtifactToOwnerApp(bpelArchiveName, BPELConstants.BPEL_TYPE, bpelPackageName, tenantId); } public Map<QName, Object> getDeployedServices() { return parentProcessStore.getServicesPublishedByTenant(tenantId); } public void addAnalyticsServerProfile(String name, AnalyticsServerProfile profile) { analyticsProfiles.put(name, profile); } public AnalyticsServerProfile getAnalyticsServerProfile(String name) { return analyticsProfiles.get(name); } public synchronized void addDataPublisher(String processName, Object publisher) { dataPublisherMap.put(processName, publisher); } public Object getDataPublisher(String processName) { return dataPublisherMap.get(processName); } public Map getDataPublisherMap() { return dataPublisherMap; } public DeploymentUnitDir getDeploymentUnitDir(QName pid) { for (String du : processesInDeploymentUnit.keySet()) { if (processesInDeploymentUnit.get(du) != null) { if (processesInDeploymentUnit.get(du).contains(pid)) { return deploymentUnits.get(du); } } } return null; } }