
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