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.
 * 
 * Modified by Matthieu Chaffotte - BonitaSoft S.A.
 **/
package org.ow2.bonita.deployment;

import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.ow2.bonita.connector.core.fileproperties.ConnectorFileProperties;
import org.ow2.bonita.connector.core.fileproperties.ConnectorParameter;
import org.ow2.bonita.definition.ClassData;
import org.ow2.bonita.definition.InternalProcess;
import org.ow2.bonita.facade.def.element.BusinessArchive;
import org.ow2.bonita.facade.def.element.RoleMapperDefinition;
import org.ow2.bonita.facade.def.element.impl.BusinessArchiveImpl;
import org.ow2.bonita.facade.def.majorElement.DataFieldDefinition;
import org.ow2.bonita.facade.def.majorElement.ParticipantDefinition;
import org.ow2.bonita.facade.def.majorElement.ProcessDefinition;
import org.ow2.bonita.facade.def.majorElement.ProcessDefinition.ProcessState;
import org.ow2.bonita.facade.def.majorElement.impl.ProcessDefinitionImpl;
import org.ow2.bonita.facade.exception.DeploymentException;
import org.ow2.bonita.facade.uuid.ProcessDefinitionUUID;
import org.ow2.bonita.rolemapper.LdapRoleMapper;
import org.ow2.bonita.runtime.ClassDataLoader;
import org.ow2.bonita.runtime.InternalInstance;
import org.ow2.bonita.services.LargeDataRepository;
import org.ow2.bonita.services.Querier;
import org.ow2.bonita.services.Recorder;
import org.ow2.bonita.services.Repository;
import org.ow2.bonita.services.handlers.UndeployedProcessHandler;
import org.ow2.bonita.util.ClassDataTool;
import org.ow2.bonita.util.DateUtil;
import org.ow2.bonita.util.EnvTool;
import org.ow2.bonita.util.ExceptionManager;
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 ProcessDefinition deploy(final BusinessArchive businessArchive) throws DeploymentException { final ProcessDefinition process = (ProcessDefinition) businessArchive.getProcessDefinition(); final Recorder recorder = EnvTool.getRecorder(); final LargeDataRepository ldr = EnvTool.getLargeDataRepository(); if (process == null) { throw new DeploymentException("The given bar archive does not contain any process file"); } final ProcessDefinitionUUID processUUID = process.getUUID(); final Map allResources = businessArchive.getAllResources(); final Repository repository = EnvTool.getRepository(); final String lastProcessVersion = repository.getLastProcessVersion(process.getName()); if (lastProcessVersion != null && lastProcessVersion.compareTo(process.getVersion()) >= 0) { String message = ExceptionManager.getInstance().getFullMessage( "bd_D_3", process.getName(), lastProcessVersion, process.getVersion(), lastProcessVersion); throw new DeploymentRuntimeException(message); } try { final Set classes = new HashSet(); if (allResources != null) { try { for (final Map.Entry classData : allResources.entrySet()) { String resourceName = classData.getKey(); byte[] resourceValue = classData.getValue(); String key = resourceName; if (resourceName.endsWith(".class")) { final ClassDataTool.MyVisitor mv = ClassDataTool.visitClass(resourceValue); final String className = mv.getClassName(); key = className; classes.add(className); } ldr.storeData(Misc.getProcessClassDataCategories(processUUID), key, new ClassData(key, resourceValue, processUUID), true); } } catch (final ArrayIndexOutOfBoundsException e) { String message = ExceptionManager.getInstance().getFullMessage("bd_D_4"); throw new DeploymentRuntimeException(message); } } for (final String className : classes) { try { ClassDataLoader.getClass(processUUID, className); } catch (final ClassNotFoundException e) { String message = ExceptionManager.getInstance().getFullMessage("bd_D_5", process.getName(), className); throw new DeploymentRuntimeException(message); } } if (process.getClassDependencies() != null) { for (final String className : process.getClassDependencies()) { Class clazz = null; try { clazz = ClassDataLoader.getClass(process.getUUID(), className); } catch (final ClassNotFoundException e) { String message = ExceptionManager.getInstance().getFullMessage( "bd_D_7", process.getName(), className); throw new DeploymentRuntimeException(message); } if (LdapRoleMapper.class.isAssignableFrom(clazz)) { Set participants = process.getParticipants(); if (participants != null) { for (ParticipantDefinition participant : participants) { RoleMapperDefinition roleMapper = participant.getRoleMapper(); if (roleMapper != null) { Map parameters = roleMapper.getParameters(); if (parameters != null) { for (Entry parameter : parameters.entrySet()) { String variable = (String) parameter.getValue()[0]; String methodName = parameter.getKey(); if (isFileParameters(methodName)) { checkParameterFileProperties(businessArchive, clazz, methodName, variable); } else { checkVariable(methodName, process.getDataFields(), clazz, variable); } } } } } } } } } //check all process dependencies are available Set processDependencies = process.getProcessDependencies(); if (processDependencies != null && !processDependencies.isEmpty()) { for (String processName : processDependencies) { ProcessDefinition subProcess = EnvTool.getJournalQueriers().getLastDeployedProcess(processName, ProcessState.ENABLED); if (subProcess == null) { throw new DeploymentRuntimeException("Unable to find process \"" + processName + "\" used in subFlow. " + "If the subFlow process is in an external package, " + "please check that this package has already been deployed"); } final ProcessDefinition processDef = EnvTool.getJournalQueriers().getProcess(subProcess.getUUID()); if (processDef.getUndeployedBy() != null) { throw new DeploymentRuntimeException("Unable to find process \"" + processName + "\" used in subFlow. "); } } } final InternalProcess internalProcess = PVMProcessBuilder.createProcess(process); Misc.badStateIfNull(process, "PVMProcessBuilder returned null!"); if (LOG.isLoggable(Level.INFO)) { final StringBuilder logMsg = new StringBuilder(); logMsg.append("Process ").append(process.getName()) .append(" deployed (UUID: ") .append(process.getUUID()) .append(")."); LOG.info(logMsg.toString()); } //at the end, stores data ldr.storeData(Misc.getBusinessArchiveCategories(), processUUID.getValue(), businessArchive, true); repository.storeProcess(internalProcess); repository.storeProcessVersion(process.getName(), process.getVersion()); recorder.recordProcessDeployed(process, EnvTool.getUserId()); return new ProcessDefinitionImpl(process); } catch (final RuntimeException re) { if (process != null) { ClassDataLoader.removeProcessClassLoader(process.getUUID()); ldr.deleteData(Misc.getProcessClassDataCategories(process.getUUID())); } throw re; } } public static boolean enableProcess(final ProcessDefinitionUUID processUUID) { Misc.badStateIfNull(processUUID, "Impossible to enable a processUUID from a null uuid"); final Querier journal = EnvTool.getJournalQueriers(); final ProcessDefinition processDef = journal.getProcess(processUUID); if (processDef == null) { String message = ExceptionManager.getInstance().getFullMessage("bd_D_8", processUUID); throw new DeploymentRuntimeException(message); } if (!processDef.getState().equals(ProcessState.DISABLED)) { throw new DeploymentRuntimeException("Impossible to enable a process which is state is not disable"); } else { final Recorder recorder = EnvTool.getRecorder(); recorder.recordProcessEnable(processDef); if (LOG.isLoggable(Level.INFO)) { final StringBuilder logMsg = new StringBuilder(); logMsg.append("Process ") .append(processDef.getName()) .append(" enable (UUID: ") .append(processDef.getUUID()) .append(")."); LOG.info(logMsg.toString()); } return true; } } public static boolean disableProcess(final ProcessDefinitionUUID processUUID) { Misc.badStateIfNull(processUUID, "Impossible to disable a processUUID from a null uuid"); final Querier journal = EnvTool.getJournalQueriers(); final ProcessDefinition processDef = journal.getProcess(processUUID); if (processDef == null) { String message = ExceptionManager.getInstance().getFullMessage("bd_D_8", processUUID); throw new DeploymentRuntimeException(message); } if (!processDef.getState().equals(ProcessState.ENABLED)) { throw new DeploymentRuntimeException("Impossible to disable a process which is state is not enable"); } else { final Repository repository = EnvTool.getRepository(); final Set instances = repository.getInstances(processDef.getUUID()); if (instances != null && !instances.isEmpty()) { String message = ExceptionManager.getInstance().getFullMessage("bd_D_9"); throw new DeploymentRuntimeException(message); } // check if this process is not used by another package // (e.g. external reference, subflow ...) final Set dependentProcesses = journal.getDependentProcesses(processDef.getUUID()); if (dependentProcesses != null && !dependentProcesses.isEmpty()) { //some processes depend on the process being remove. Check if this process has other versions available String processId = processDef.getName(); Set deployedProcessesWithThisProcessId = journal.getProcesses(processId, ProcessState.ENABLED); if (deployedProcessesWithThisProcessId.size() == 1) { String message = ExceptionManager.getInstance().getFullMessage( "bd_D_10", processDef.getUUID(), dependentProcesses ); throw new DeploymentRuntimeException(message); } } final Recorder recorder = EnvTool.getRecorder(); recorder.recordProcessDisable(processDef); if (LOG.isLoggable(Level.INFO)) { final StringBuilder logMsg = new StringBuilder(); logMsg.append("Process ") .append(processDef.getName()) .append(" disable (UUID: ") .append(processDef.getUUID()) .append(")."); LOG.info(logMsg.toString()); } return true; } } public static boolean archiveProcess(final ProcessDefinitionUUID processUUID, final String userId) { Misc.badStateIfNull(processUUID, "Impossible to archive a processUUID from a null uuid"); final Querier journal = EnvTool.getJournalQueriers(); final ProcessDefinition processDef = journal.getProcess(processUUID); if (processDef == null) { String message = ExceptionManager.getInstance().getFullMessage("bd_D_8", processUUID); throw new DeploymentRuntimeException(message); } if (!processDef.getState().equals(ProcessState.DISABLED)) { throw new DeploymentRuntimeException("Impossible to archive a process which its state is not disable"); } else { final Repository repository = EnvTool.getRepository(); // remove from processRepo repository.removeProcess(processDef.getUUID()); //remove from classRepo EnvTool.getLargeDataRepository().deleteData(Misc.getProcessClassDataCategories(processDef.getUUID())); ClassDataLoader.removeProcessClassLoader(processDef.getUUID()); final Recorder recorder = EnvTool.getRecorder(); recorder.recordProcessArchive(processDef, userId); final UndeployedProcessHandler handler = EnvTool.getUndeployedProcessHandler(); handler.handleUndeployedProcess(processDef); if (LOG.isLoggable(Level.INFO)) { final StringBuilder logMsg = new StringBuilder(); logMsg.append("Process ") .append(processDef.getName()) .append(" archive (UUID: ") .append(processDef.getUUID()) .append(")."); LOG.info(logMsg.toString()); } return true; } } /*public static boolean undeployProcess(final ProcessDefinitionUUID processUUID, final String userId) { Misc.badStateIfNull(processUUID, "Impossible to undeploy a processUUID from a null uuid"); final Querier journal = EnvTool.getJournalQueriers(); final ProcessDefinition processDef = journal.getProcess(processUUID); if (processDef == null) { String message = ExceptionManager.getInstance().getFullMessage("bd_D_8", processUUID); throw new DeploymentRuntimeException(message); } removeProcessDependencies(processDef); final Recorder recorder = EnvTool.getRecorder(); recorder.recordProcessUndeployed(processDef, userId); final UndeployedProcessHandler handler = EnvTool.getUndeployedProcessHandler(); handler.handleUndeployedProcess(processDef); if (LOG.isLoggable(Level.INFO)) { final StringBuilder logMsg = new StringBuilder(); logMsg.append("Process ").append(processDef.getName()) .append(" undeployed (UUID: ") .append(processDef.getUUID()) .append(")."); LOG.info(logMsg.toString()); } return true; }*/ public static void removeProcessDependencies(final ProcessDefinition processDef) { final Querier journal = EnvTool.getJournalQueriers(); final Repository repository = EnvTool.getRepository(); final LargeDataRepository ldr = EnvTool.getLargeDataRepository(); final Set instances = repository.getInstances(processDef.getUUID()); if (instances != null && !instances.isEmpty()) { String message = ExceptionManager.getInstance().getFullMessage("bd_D_9"); throw new DeploymentRuntimeException(message); } // check that this process is not used by another package // (e.g. external reference, subflow ...) final Set dependentProcesses = journal.getDependentProcesses(processDef.getUUID()); if (dependentProcesses != null && !dependentProcesses.isEmpty()) { //somes processes depends on the process being remove. Check if this process has other versions available String processId = processDef.getName(); Set deployedProcessesWithThisProcessId = journal.getProcesses(processId, ProcessState.ENABLED); if (deployedProcessesWithThisProcessId.size() == 1) { String message = ExceptionManager.getInstance().getFullMessage( "bd_D_10", processDef.getUUID(), dependentProcesses ); throw new DeploymentRuntimeException(message); } } // remove from processRepo repository.removeProcess(processDef.getUUID()); //remove from classRepo ldr.deleteData(Misc.getProcessClassDataCategories(processDef.getUUID())); ClassDataLoader.removeProcessClassLoader(processDef.getUUID()); } private static boolean isFileParameters(String methodName) { boolean inFile = false; if (methodName.equals("file:") || methodName.equals("bar:") || methodName.equals("resource:")) { inFile = true; } return inFile; } private static void checkParameterFileProperties(BusinessArchive businessArchive, Class clazz, String methodName, String variable) throws DeploymentException { InputStream input = null; if (methodName.equals("file:")) { input = getInputFileParameters(variable); } else if (methodName.equals("bar:")) { byte[] data = businessArchive.getResource(variable); input = new ByteArrayInputStream(data); } else if (methodName.equals("resource:")) { input = getInputFileAsAResource(variable); } ConnectorFileProperties properties; try { properties = new ConnectorFileProperties(input); checkConnectorParameters(clazz, properties.getConnectorProperties()); } catch (Exception e) { throw new DeploymentRuntimeException(e.getMessage()); } } private static InputStream getInputFileParameters(String variable) throws DeploymentException { try { return new FileInputStream(variable); } catch (FileNotFoundException e) { throw new DeploymentRuntimeException( "The file path does not exist!" + variable); } } private static InputStream getInputFileAsAResource(String variable) throws DeploymentException { InputStream input = ClassDataLoader.getCommonClassLoader().getResourceAsStream(variable); if (input == null) { String message = ExceptionManager.getInstance().getFullMessage("bd_D_11", variable); throw new DeploymentRuntimeException(message); } return input; } private static void checkVariable(String methodName, Set dataFields, Class clazz, String variable) throws DeploymentException { String typeClassName = getDataFieldTypeClass(dataFields, variable); Class clas; try { clas = Class.forName(typeClassName); } catch (ClassNotFoundException e1) { throw new DeploymentException("Unable to find class: " + typeClassName, e1); } if (methodName.startsWith("set")) { try { clazz.getMethod(methodName, clas); } catch (NoSuchMethodException e) { String message = ExceptionManager.getInstance().getFullMessage( "bd_D_13", methodName, clas, clazz); throw new DeploymentRuntimeException(message); } } else { Method[] methods = clazz.getDeclaredMethods(); int i = 0; boolean found = false; while (i < methods.length && !found) { String name = methods[i].getName(); Class returns = methods[i].getReturnType(); Class[] pars = methods[i].getParameterTypes(); if (name.equals(methodName) && pars.length == 0 && returns.equals(clas)) { found = true; } i++; } if (!found) { String message = ExceptionManager.getInstance().getFullMessage( "bd_D_14", methodName, clas, clazz); throw new DeploymentRuntimeException(message); } } } private static String getDataFieldTypeClass(Set dataFields, String variable) { Iterator iter = dataFields.iterator(); while (iter.hasNext() ) { DataFieldDefinition dataField = iter.next(); if (dataField.getName().equals(variable)) { return dataField.getDataTypeClassName(); } } return null; } private static void checkConnectorParameters(Class clazz, List parameters) throws DeploymentException { for (ConnectorParameter parameter : parameters) { String setterName = parameter.getSetterName(); String value = parameter.getValue(); String paramType = parameter.getType(); Class paramClass = null; if (paramType.equals("STRING")) { paramClass = String.class; } else if (paramType.equals("INTEGER")) { try { Long.valueOf(value); } catch (NumberFormatException nfe) { String message = ExceptionManager.getInstance().getFullMessage("bd_D_16", value); throw new DeploymentRuntimeException(message); } paramClass = Long.class; } else if (paramType.equals("FLOAT")) { try { Double.valueOf(value); } catch (NumberFormatException nfe) { String message = ExceptionManager.getInstance().getFullMessage("bd_D_17", value); throw new DeploymentRuntimeException(message); } paramClass = Double.class; } else if (paramType.equals("BOOLEAN")) { // No check is performed because if the value // is different from true, Boolean.parse considers that // the value is false paramClass = Boolean.class; } else if (paramType.equals("DATETIME")) { try { DateUtil.parseDate(value); } catch (IllegalArgumentException e) { throw new DeploymentRuntimeException(e.getMessage()); } paramClass = Date.class; } else { String message = ExceptionManager.getInstance().getFullMessage("bd_D_18", paramType); throw new DeploymentRuntimeException(message); } try { clazz.getMethod(setterName, paramClass); } catch (NoSuchMethodException e) { String message = ExceptionManager.getInstance().getFullMessage( "bd_D_19", setterName, paramClass, clazz); throw new DeploymentRuntimeException(message); } } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy