All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ow2.bonita.deployment.Deployer Maven / Gradle / Ivy

/**
 * Copyright (C) 2007  Bull S. A. S.
 * Bull, Rue Jean Jaures, B.P.68, 78340, Les Clayes-sous-Bois
 * This library is free software; you can redistribute it and/or modify it under the terms
 * of the GNU Lesser General Public License as published by the Free Software Foundation
 * version 2.1 of the License.
 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 * You should have received a copy of the GNU Lesser General Public License along with this
 * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
 * Floor, Boston, MA  02110-1301, USA.
 **/
package org.ow2.bonita.deployment;

import java.io.ByteArrayInputStream;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.ow2.bonita.pvm.internal.xml.Parse;
import org.ow2.bonita.definition.Hook;
import org.ow2.bonita.definition.PackageClassData;
import org.ow2.bonita.definition.TxHook;
import org.ow2.bonita.definition.XpdlProcess;
import org.ow2.bonita.facade.def.element.BusinessArchive;
import org.ow2.bonita.facade.def.element.HookDefinition;
import org.ow2.bonita.facade.def.element.Resource;
import org.ow2.bonita.facade.def.majorElement.ActivityDefinition;
import org.ow2.bonita.facade.def.majorElement.PackageFullDefinition;
import org.ow2.bonita.facade.def.majorElement.ProcessDefinition;
import org.ow2.bonita.facade.def.majorElement.ProcessFullDefinition;
import org.ow2.bonita.facade.def.majorElement.impl.ProcessDefinitionImpl;
import org.ow2.bonita.facade.exception.DeploymentException;
import org.ow2.bonita.facade.uuid.PackageDefinitionUUID;
import org.ow2.bonita.parsing.XpdlParser;
import org.ow2.bonita.runtime.ClassDataLoader;
import org.ow2.bonita.runtime.XpdlInstance;
import org.ow2.bonita.services.Querier;
import org.ow2.bonita.services.Recorder;
import org.ow2.bonita.services.Repository;
import org.ow2.bonita.services.handlers.UndeployedPackageHandler;
import org.ow2.bonita.util.ClassDataTool;
import org.ow2.bonita.util.EngineEnvTool;
import org.ow2.bonita.util.Misc;

/**
 * takes {@link BusinessArchiveImpl}s as input, parses the contents into a
 * {@link WorkflowProcess}, stores the {@link WorkflowProcess} into the
 * {@link Repository}
 *
 * 

* This class is thread safe and can be shared between multiple threads. *

* * @author Marc Blachon, Guillaume Porcher, Charles Souillard, Miguel Valdes, Pierre Vigneras */ public final class Deployer { private static final Logger LOG = Logger.getLogger(Deployer.class.getName()); private Deployer() { } public static Map deploy(final BusinessArchive businessArchive, final String userId) throws DeploymentException { PackageFullDefinition packageDef = null; try { final Parse parse = new XpdlParser().createParse(); parse.pushObject(businessArchive); // now the xpdl process will be parsed. Resource xpdlResource = businessArchive.getXpdlFile(); if (xpdlResource == null) { throw new DeploymentException("The given bar archive does not contain any '.xpdl' file"); } final byte[] xpdl = xpdlResource.getData(); final Collection classes = businessArchive.getClasses(); final Repository repository = EngineEnvTool.getRepository(); // make the xpdl package is available to the xpdl parser by pushing it // on the object stack in the parse. parse.setInputStream(new ByteArrayInputStream(xpdl)); packageDef = (PackageFullDefinition) parse.execute().getDocumentObject(); //CHECK EVERYTING IS OK parse.checkProblems("xpdl file"); parse.popObject(); Misc.badStateIfNull(packageDef, "Ouch! The returned PackageFullDefinition is null!"); final Set processes = packageDef.getProcesses(); //check package and processes versions are OK final String packageId = packageDef.getPackageId(); final String packageVersion = packageDef.getVersion(); final String lastPackageVersion = repository.getLastPackageVersion(packageId); if (lastPackageVersion != null && lastPackageVersion.compareTo(packageVersion) >= 0) { throw new DeploymentRuntimeException("A package with id = " + packageId + " has already been deployed with version = " + lastPackageVersion + ". The given package version (" + packageVersion + ") is not lexicographically upper. Please change the version of the package to follow " + lastPackageVersion); } for (final ProcessFullDefinition process : processes) { final String processId = process.getProcessId(); final String processVersion = process.getVersion(); final String lastProcessVersion = repository.getLastProcessVersion(processId, packageId); if (lastProcessVersion != null && lastProcessVersion.compareTo(processVersion) >= 0) { throw new DeploymentRuntimeException("A process with id = " + processId + " has already been deployed with version = " + lastProcessVersion + ". The given process version (" + processVersion + ") is not lexicographically upper. Please change the version of the process to follow " + lastProcessVersion); } } final Map map = new HashMap(); if (classes != null) { try { for (final Resource resource : classes) { final byte[] data = resource.getData(); final ClassDataTool.MyVisitor mv = ClassDataTool.visitClass(data); final String className = mv.getClassName(); map.put(className, data); } } catch (final ArrayIndexOutOfBoundsException e) { throw new DeploymentRuntimeException("Error when getting class names from classes (Set of byte[])."); } } final PackageClassData packageClassData = new PackageClassData(packageDef.getUUID(), map); repository.storePackageClassData(packageClassData); for (final String className : map.keySet()) { Class< ? > clazz = null; try { clazz = ClassDataLoader.getClass(packageDef.getUUID(), className); } catch (final ClassNotFoundException e) { throw new DeploymentRuntimeException("Problem while deploying package: " + packageId + ". No Class available with classname: " + className); } if (TxHook.class.isAssignableFrom(clazz)) { for (final ProcessFullDefinition process : processes) { final Set activities = process.getActivities(); if (activities != null) { for (final ActivityDefinition activity : activities) { final Set hooks = activity.getHooks(); if (hooks != null) { for (final HookDefinition hookDef : hooks) { if (hookDef.getClassName().equals(className) && !hookDef.isThrowingException()) { throw new DeploymentRuntimeException("Hook : " + hookDef.getClassName() + " defined on activity " + activity.getActivityId() + " in process " + process.getProcessId() + " is defined as a 'non rollback' hook but the given class (" + className + ") is a " + TxHook.class + ". This is not possible. Please, give a class that only implements " + Hook.class + " or change the process to define a rollback hook."); } } } } } } } } if (packageDef.getClassDependencies() != null) { for (final String className : packageDef.getClassDependencies()) { try { ClassDataLoader.getClass(packageDef.getUUID(), className); } catch (final ClassNotFoundException e) { throw new DeploymentRuntimeException("Problem while deploying package: " + packageId + ". No Class available with classname: " + className); } } } repository.addPackageDependencies(packageDef.getUUID(), packageDef.getClassDependencies()); repository.storePackageVersion(packageId, packageVersion); for (final ProcessFullDefinition workflowProcess : packageDef.getProcesses()) { final XpdlProcess xpdlProcess = XpdlProcessBuilder.createXpdlProcess(packageDef, workflowProcess); Misc.badStateIfNull(xpdlProcess, "XpdlProcessBuilder returned null!"); repository.storeXpdlProcess(xpdlProcess); repository.storeProcessVersion(workflowProcess.getProcessId(), workflowProcess.getVersion(), packageDef.getPackageId()); } final Recorder recorder = EngineEnvTool.getRecorder(); recorder.recordPackageDeployed(packageDef); final Map result = new HashMap(); for (final ProcessDefinition process : processes) { result.put(process.getProcessId(), new ProcessDefinitionImpl(process)); } if (LOG.isLoggable(Level.INFO)) { final StringBuilder logMsg = new StringBuilder(); logMsg.append("Package ").append(packageDef.getPackageId()) .append(" deployed (UUID: ") .append(packageDef.getUUID()) .append(")."); LOG.info(logMsg.toString()); } if (LOG.isLoggable(Level.FINE)) { if (!processes.isEmpty()) { final StringBuilder logMsg = new StringBuilder(); logMsg.append("Package ").append(packageDef.getPackageId()).append(" contains following processes : "); boolean first = true; for (final ProcessDefinition process : processes) { if (!first) { logMsg.append(", "); } else { first = false; } logMsg.append(process.getProcessId()).append("(UUID: ").append(process.getUUID()).append(")"); } LOG.fine(logMsg.toString()); } } return result; } catch (final RuntimeException re) { if (packageDef != null) { ClassDataLoader.removePackageClassLoader(packageDef.getUUID()); } throw re; } } public static boolean undeployPackage(final PackageDefinitionUUID packageUUID, final String userId) { Misc.badStateIfNull(packageUUID, "Impossible to undeploy a package from a null uuid"); final Querier journal = EngineEnvTool.getJournalQueriers(); final PackageFullDefinition packageDef = journal.getPackage(packageUUID); if (packageDef == null) { throw new DeploymentRuntimeException("Error during undeployment: package " + packageUUID + " not found in journal!"); } removePackageDependencies(packageDef); final Recorder recorder = EngineEnvTool.getRecorder(); recorder.recordPackageUndeployed(packageDef, userId); final UndeployedPackageHandler handler = EngineEnvTool.getUndeployedPackageHandler(); handler.handleUndeployedPackage(packageDef); if (LOG.isLoggable(Level.INFO)) { final StringBuilder logMsg = new StringBuilder(); logMsg.append("Package ").append(packageDef.getPackageId()) .append(" undeployed (UUID: ") .append(packageDef.getUUID()) .append(")."); LOG.info(logMsg.toString()); } return true; } public static void removePackageDependencies(final PackageFullDefinition packageDef) { final Querier journal = EngineEnvTool.getJournalQueriers(); final Repository repository = EngineEnvTool.getRepository(); final PackageDefinitionUUID packageUUID = packageDef.getUUID(); if (packageDef.getProcesses() != null) { for (final ProcessFullDefinition process : packageDef.getProcesses()) { final Set instances = repository.getXpdlInstances(process.getUUID()); if (instances != null && !instances.isEmpty()) { throw new DeploymentRuntimeException("Error during undeployment: there are still running instances"); } } } // check that this package is not used by another package // (e.g. external reference, subflow ...) final Set dependentPackages = journal.getDependentPackages(packageDef.getUUID()); if (dependentPackages != null && !dependentPackages.isEmpty()) { throw new DeploymentRuntimeException("Error during undeployment: these packages depends on " + "package '" + packageUUID + "': " + dependentPackages); } // remove from processRepo if (packageDef.getProcesses() != null) { for (final ProcessFullDefinition process : packageDef.getProcesses()) { repository.removeXpdlProcess(process.getUUID()); } } //remove from classRepo repository.removePackageClassData(packageUUID); ClassDataLoader.removePackageClassLoader(packageDef.getUUID()); repository.removePackageDependencies(packageDef.getUUID()); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy