
org.bonitasoft.engine.api.impl.resolver.DependencyResolver Maven / Gradle / Ivy
/**
* Copyright (C) 2013 BonitaSoft S.A.
* BonitaSoft, 32 rue Gustave Eiffel - 38000 Grenoble
* 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.bonitasoft.engine.api.impl.resolver;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.io.FileUtils;
import org.bonitasoft.engine.api.ProcessAPI;
import org.bonitasoft.engine.api.impl.transaction.dependency.AddSDependency;
import org.bonitasoft.engine.bpm.bar.BusinessArchive;
import org.bonitasoft.engine.bpm.process.ConfigurationState;
import org.bonitasoft.engine.bpm.process.ProcessDeployException;
import org.bonitasoft.engine.commons.exceptions.SBonitaException;
import org.bonitasoft.engine.commons.transaction.TransactionExecutor;
import org.bonitasoft.engine.core.process.definition.ProcessDefinitionService;
import org.bonitasoft.engine.core.process.definition.model.SProcessDefinition;
import org.bonitasoft.engine.core.process.definition.model.SProcessDefinitionDeployInfo;
import org.bonitasoft.engine.dependency.DependencyService;
import org.bonitasoft.engine.dependency.SDependencyCreationException;
import org.bonitasoft.engine.dependency.SDependencyException;
import org.bonitasoft.engine.dependency.model.SDependency;
import org.bonitasoft.engine.dependency.model.builder.DependencyBuilderAccessor;
import org.bonitasoft.engine.exception.BonitaException;
import org.bonitasoft.engine.exception.BonitaHomeNotSetException;
import org.bonitasoft.engine.exception.BonitaRuntimeException;
import org.bonitasoft.engine.home.BonitaHomeServer;
import org.bonitasoft.engine.log.technical.TechnicalLogSeverity;
import org.bonitasoft.engine.log.technical.TechnicalLoggerService;
import org.bonitasoft.engine.persistence.QueryOptions;
import org.bonitasoft.engine.recorder.model.EntityUpdateDescriptor;
import org.bonitasoft.engine.service.TenantServiceAccessor;
import org.bonitasoft.engine.transaction.STransactionException;
/**
* Handles the resolution of Process Dependencies. A process can have a list of ProcessDependencyResolver
s which validates different aspects of the
* process to validate (or "resolve")
*
* @author Emmanuel Duchastenier
* @author Matthieu Chaffotte
*/
public class DependencyResolver {
private final List dependencyResolvers;
public DependencyResolver(final List dependencyResolvers) {
this.dependencyResolvers = dependencyResolvers;
}
public boolean resolveDependencies(final ProcessAPI processAPI, final BusinessArchive businessArchive, final TenantServiceAccessor tenantAccessor,
final SProcessDefinition sDefinition) throws ProcessDeployException {
final List resolvers = getResolvers();
boolean resolved = true;
for (final ProcessDependencyResolver resolver : resolvers) {
try {
resolved &= resolver.resolve(processAPI, tenantAccessor, businessArchive, sDefinition);
} catch (final BonitaException e) {
// not logged, we will check later why the process is not resolved
resolved = false;
}
}
return resolved;
}
/*
* Done in a separated transaction
* We try here to check if now the process is resolved so it must not be done in the same transaction that did the modification
* this does not throw exception, it only log because it can be retried after.
*/
public void resolveDependencies(final long processDefinitionId, final TenantServiceAccessor tenantAccessor) throws SBonitaException {
final List resolvers = getResolvers();
resolveDependencies(processDefinitionId, tenantAccessor, resolvers.toArray(new ProcessDependencyResolver[resolvers.size()]));
}
public void resolveDependencies(final long processDefinitionId, final TenantServiceAccessor tenantAccessor, final ProcessDependencyResolver... resolvers) {
final TransactionExecutor transactionExecutor = tenantAccessor.getTransactionExecutor();
final TechnicalLoggerService loggerService = tenantAccessor.getTechnicalLoggerService();
final ProcessDefinitionService processDefinitionService = tenantAccessor.getProcessDefinitionService();
final DependencyService dependencyService = tenantAccessor.getDependencyService();
final DependencyBuilderAccessor dependencyBuilderAccessor = tenantAccessor.getDependencyBuilderAccessor();
try {
final boolean txOpened = transactionExecutor.openTransaction();
try {
boolean resolved = true;
for (final ProcessDependencyResolver dependencyResolver : resolvers) {
final SProcessDefinition processDefinition = processDefinitionService.getProcessDefinition(processDefinitionId);
resolved &= dependencyResolver.checkResolution(tenantAccessor, processDefinition).isEmpty();
}
changeResolutionStatus(processDefinitionId, tenantAccessor, processDefinitionService, dependencyService, dependencyBuilderAccessor, resolved);
} catch (final SBonitaException e) {
transactionExecutor.setTransactionRollback();
loggerService.log(DependencyResolver.class, TechnicalLogSeverity.DEBUG, e);
loggerService.log(DependencyResolver.class, TechnicalLogSeverity.WARNING, "Unable to resolve dependencies after they were modified because of "
+ e.getMessage() + ". Please retry it manually");
} catch (final BonitaHomeNotSetException e) {
throw new BonitaRuntimeException("Bonita home not set", e);
} finally {
transactionExecutor.completeTransaction(txOpened);
}
} catch (final STransactionException e) {
loggerService.log(DependencyResolver.class, TechnicalLogSeverity.DEBUG, e);
loggerService.log(DependencyResolver.class, TechnicalLogSeverity.WARNING,
"Unable to resolve dependencies after they were modified. Please retry it manually");
}
}
private void changeResolutionStatus(final long processDefinitionId, final TenantServiceAccessor tenantAccessor,
final ProcessDefinitionService processDefinitionService, final DependencyService dependencyService,
final DependencyBuilderAccessor dependencyBuilderAccessor, final boolean resolved) throws SBonitaException, BonitaHomeNotSetException {
final SProcessDefinitionDeployInfo processDefinitionDeployInfo = processDefinitionService.getProcessDeploymentInfo(processDefinitionId);
if (resolved) {
if (ConfigurationState.UNRESOLVED.name().equals(processDefinitionDeployInfo.getConfigurationState())) {
resolveAndCreateDependencies(
new File(new File(BonitaHomeServer.getInstance().getProcessesFolder(tenantAccessor.getTenantId())), String.valueOf(processDefinitionId)),
processDefinitionService, dependencyService, dependencyBuilderAccessor, processDefinitionId);
}
} else {
if (ConfigurationState.RESOLVED.name().equals(processDefinitionDeployInfo.getConfigurationState())) {
final EntityUpdateDescriptor updateDescriptor = tenantAccessor.getBPMDefinitionBuilders().getProcessDefinitionDeployInfoUpdateBuilder()
.updateConfigurationState(ConfigurationState.UNRESOLVED).done();
processDefinitionService.updateProcessDefinitionDeployInfo(processDefinitionId, updateDescriptor);
}
}
}
/**
* create dependencies based on the bonita home (the process folder)
*
* @param processFolder
* @param processDefinitionService
* @param dependencyService
* @param dependencyBuilderAccessor
* @param processDefinitionId
* @throws SBonitaException
*/
public void resolveAndCreateDependencies(final File processFolder, final ProcessDefinitionService processDefinitionService,
final DependencyService dependencyService, final DependencyBuilderAccessor dependencyBuilderAccessor, final long processDefinitionId)
throws SBonitaException {
final Map resources = new HashMap();
final File file = new File(processFolder, "classpath");
if (file.exists() && file.isDirectory()) {
final File[] listFiles = file.listFiles();
for (final File jarFile : listFiles) {
final String name = jarFile.getName();
try {
final byte[] jarContent = FileUtils.readFileToByteArray(jarFile);
resources.put(getDependencyName(processDefinitionId, name), jarContent);
} catch (final IOException e) {
throw new SDependencyCreationException(e);
}
}
}
addDependencies(resources, dependencyService, dependencyBuilderAccessor, processDefinitionId);
processDefinitionService.resolveProcess(processDefinitionId);
}
private String getDependencyName(final long processDefinitionId, final String name) {
return processDefinitionId + "_" + name;
}
private void addDependencies(final Map resources, final DependencyService dependencyService,
final DependencyBuilderAccessor dependencyBuilderAccessor, final long processDefinitionId) throws SBonitaException {
final List dependencyIds = getDependencyMappingsOfProcess(dependencyService, processDefinitionId);
final List dependencies = getDependenciesOfProcess(dependencyService, dependencyIds);
final Iterator> iterator = resources.entrySet().iterator();
while (iterator.hasNext()) {
final Map.Entry entry = iterator.next();
if (!dependencies.contains(entry.getKey())) {
addDependency(entry.getKey(), entry.getValue(), dependencyService, dependencyBuilderAccessor, processDefinitionId);
}
}
}
private List getDependenciesOfProcess(final DependencyService dependencyService, final List dependencyIds) throws SBonitaException {
if (dependencyIds.isEmpty()) {
return Collections.emptyList();
}
final List dependencies = dependencyService.getDependencies(dependencyIds);
final ArrayList dependencyNames = new ArrayList(dependencies.size());
for (final SDependency sDependency : dependencies) {
dependencyNames.add(sDependency.getName());
}
return dependencyNames;
}
private List getDependencyMappingsOfProcess(final DependencyService dependencyService, final long processDefinitionId) throws SDependencyException {
final List dependencyIds = new ArrayList();
QueryOptions queryOptions = QueryOptions.defaultQueryOptions();
List currentPage;
do {
currentPage = dependencyService.getDependencyIds(processDefinitionId, "process", queryOptions);
dependencyIds.addAll(currentPage);
queryOptions = QueryOptions.getNextPage(queryOptions);
} while (currentPage.size() == QueryOptions.DEFAULT_NUMBER_OF_RESULTS);
return dependencyIds;
}
/**
* create dependencies based on the business archive
*
* @param businessArchive
* @param processDefinitionService
* @param dependencyService
* @param dependencyBuilderAccessor
* @param sDefinition
* @throws SBonitaException
*/
public void resolveAndCreateDependencies(final BusinessArchive businessArchive, final ProcessDefinitionService processDefinitionService,
final DependencyService dependencyService, final DependencyBuilderAccessor dependencyBuilderAccessor, final SProcessDefinition sDefinition)
throws SBonitaException {
final Long processDefinitionId = sDefinition.getId();
if (businessArchive != null) {
final Map resources = businessArchive.getResources("^classpath/.*$");
// remove the classpath/ on path of dependencies
final Map resourcesWithRealName = new HashMap(resources.size());
for (final Entry resource : resources.entrySet()) {
final String name = resource.getKey().substring(10);
final byte[] jarContent = resource.getValue();
resourcesWithRealName.put(getDependencyName(processDefinitionId, name), jarContent);
}
addDependencies(resourcesWithRealName, dependencyService, dependencyBuilderAccessor, sDefinition.getId());
}
processDefinitionService.resolveProcess(processDefinitionId);
}
private void addDependency(final String name, final byte[] jarContent, final DependencyService dependencyService,
final DependencyBuilderAccessor dependencyBuilderAccessor, final long processdefinitionId) throws SDependencyException {
final AddSDependency addSDependency = new AddSDependency(dependencyService, dependencyBuilderAccessor, name, jarContent, processdefinitionId, "process");
addSDependency.execute();
}
public List getResolvers() {
return dependencyResolvers;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy