Skip to content

Commit

Permalink
JBPM-5535: Stunner - get ProcessId's from indexes for Reusable Subpro…
Browse files Browse the repository at this point in the history
…cess CalledElement property (#643)
  • Loading branch information
Jeremy Lindop authored and manstis committed Jan 23, 2017
1 parent e82648d commit 260b99e
Show file tree
Hide file tree
Showing 19 changed files with 2,524 additions and 210 deletions.
Expand Up @@ -92,6 +92,21 @@
<artifactId>kie-wb-common-refactoring-backend</artifactId>
</dependency>

<dependency>
<groupId>org.kie.workbench.services</groupId>
<artifactId>kie-wb-common-services-backend</artifactId>
</dependency>

<dependency>
<groupId>org.kie.workbench.services</groupId>
<artifactId>kie-wb-common-services-api</artifactId>
</dependency>

<dependency>
<groupId>org.guvnor</groupId>
<artifactId>guvnor-project-api</artifactId>
</dependency>

<dependency>
<groupId>org.jboss.errai</groupId>
<artifactId>errai-bus</artifactId>
Expand Down Expand Up @@ -147,12 +162,52 @@
<artifactId>uberfire-io</artifactId>
</dependency>

<dependency>
<groupId>org.uberfire</groupId>
<artifactId>uberfire-metadata-api</artifactId>
</dependency>

<dependency>
<groupId>org.jboss.spec.javax.servlet</groupId>
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.jbpm</groupId>
<artifactId>jbpm-flow</artifactId>
</dependency>

<dependency>
<groupId>org.jbpm</groupId>
<artifactId>jbpm-flow-builder</artifactId>
</dependency>

<dependency>
<groupId>org.jbpm</groupId>
<artifactId>jbpm-bpmn2</artifactId>
</dependency>

<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
</dependency>

<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-core</artifactId>
</dependency>

<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-api</artifactId>
</dependency>

<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-internal</artifactId>
</dependency>

<!-- Required for supporting legacy jbpm-designer marshallers/unmarshallers. -->
<dependency>
<groupId>org.jbpm</groupId>
Expand Down Expand Up @@ -261,12 +316,25 @@
<type>test-jar</type>
</dependency>

<dependency>
<groupId>org.kie.workbench.services</groupId>
<artifactId>kie-wb-common-refactoring-backend</artifactId>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.uberfire</groupId>
<artifactId>uberfire-testing-utils</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.uberfire</groupId>
<artifactId>uberfire-metadata-commons-io</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
Expand Down
Expand Up @@ -15,33 +15,60 @@
*/
package org.kie.workbench.common.stunner.bpmn.backend.dataproviders;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import javax.inject.Inject;

import org.kie.workbench.common.forms.dynamic.model.config.SelectorData;
import org.kie.workbench.common.forms.dynamic.model.config.SelectorDataProvider;
import org.kie.workbench.common.forms.dynamic.service.shared.FormRenderingContext;
import org.kie.workbench.common.services.refactoring.model.index.terms.valueterms.ValueIndexTerm;
import org.kie.workbench.common.services.refactoring.model.index.terms.valueterms.ValueResourceIndexTerm;
import org.kie.workbench.common.services.refactoring.model.query.RefactoringPageRow;
import org.kie.workbench.common.services.refactoring.service.RefactoringQueryService;
import org.kie.workbench.common.services.refactoring.service.ResourceType;
import org.kie.workbench.common.stunner.bpmn.backend.query.FindBpmnProcessIdsQuery;
import org.uberfire.backend.vfs.Path;

public class CalledElementFormProvider implements SelectorDataProvider {
// NOTE - this provides dummy data for now until integration with
// workbench is complete

@Inject
protected RefactoringQueryService queryService;

@Override
public String getProviderName() {
return getClass().getSimpleName();
}

public void setQueryService(RefactoringQueryService queryService) {
this.queryService = queryService;
}

@Override
@SuppressWarnings("unchecked")
public SelectorData getSelectorData(final FormRenderingContext context) {
Map<Object, String> values = new TreeMap<>();
values.put("/my/samples/businessprocess1.bpmn2",
"/my/samples/businessprocess1.bpmn2");
values.put("/my/samples/businessprocess2.bpmn2",
"/my/samples/businessprocess2.bpmn2");
values.put("/my/samples/businessprocess3.bpmn2",
"/my/samples/businessprocess3.bpmn2");
return new SelectorData(values,
null);
public SelectorData getSelectorData(FormRenderingContext context) {
return new SelectorData(getBusinessProcessIDs(), null);
}

public Map<Object, String> getBusinessProcessIDs() {
final Set<ValueIndexTerm> queryTerms = new HashSet<ValueIndexTerm>() {{
add(new ValueResourceIndexTerm("*", ResourceType.BPMN2, ValueIndexTerm.TermSearchType.WILDCARD));
}};
List<RefactoringPageRow> results = queryService.query(
FindBpmnProcessIdsQuery.NAME,
queryTerms);

Map<Object, String> businessProcessIDs = new TreeMap<Object, String>();

for (RefactoringPageRow row : results) {
Map<String, Path> mapRow = (Map<String, Path>) row.getValue();
for (String rKey : mapRow.keySet()) {
businessProcessIDs.put(rKey, rKey);
}
}

return businessProcessIDs;
}
}
@@ -0,0 +1,216 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates.
*
* 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.kie.workbench.common.stunner.bpmn.backend.indexing;

import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;

import org.apache.commons.lang3.StringUtils;
import org.drools.compiler.builder.impl.KnowledgeBuilderConfigurationImpl;
import org.drools.core.io.impl.ByteArrayResource;
import org.drools.core.io.impl.ReaderResource;
import org.drools.core.xml.SemanticModules;
import org.guvnor.common.services.project.model.Package;
import org.guvnor.common.services.project.model.Project;
import org.jbpm.bpmn2.xml.BPMNDISemanticModule;
import org.jbpm.bpmn2.xml.BPMNExtensionsSemanticModule;
import org.jbpm.bpmn2.xml.BPMNSemanticModule;
import org.jbpm.compiler.xml.XmlProcessReader;
import org.jbpm.process.core.validation.ProcessValidationError;
import org.jbpm.process.core.validation.ProcessValidator;
import org.jbpm.process.core.validation.ProcessValidatorRegistry;
import org.kie.api.definition.process.Process;
import org.kie.api.io.Resource;
import org.kie.api.io.ResourceType;
import org.kie.internal.builder.KnowledgeBuilder;
import org.kie.internal.builder.KnowledgeBuilderError;
import org.kie.internal.builder.KnowledgeBuilderFactory;
import org.kie.workbench.common.services.backend.project.ProjectClassLoaderHelper;
import org.kie.workbench.common.services.refactoring.backend.server.indexing.AbstractFileIndexer;
import org.kie.workbench.common.services.refactoring.backend.server.indexing.DefaultIndexBuilder;
import org.kie.workbench.common.services.shared.project.KieProject;
import org.kie.workbench.common.stunner.bpmn.resource.BPMNDefinitionSetResourceType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.uberfire.backend.server.util.Paths;
import org.uberfire.java.nio.file.Path;

@ApplicationScoped
public class BpmnFileIndexer extends AbstractFileIndexer {

private static final Logger logger = LoggerFactory.getLogger(BpmnFileIndexer.class);

private static final SemanticModules modules = new SemanticModules();

static {
modules.addSemanticModule(new BPMNSemanticModule());
modules.addSemanticModule(new BPMNDISemanticModule());
modules.addSemanticModule(new BPMNExtensionsSemanticModule());
}

@Inject
protected BPMNDefinitionSetResourceType bpmnTypeDefinition;

@Inject
protected ProjectClassLoaderHelper classLoaderHelper;

@Override
public boolean supportsPath(Path path) {
return bpmnTypeDefinition.accept(Paths.convert(path));
}

/* (non-Javadoc)
* @see org.kie.workbench.common.services.refactoring.backend.server.indexing.AbstractFileIndexer#fillIndexBuilder(org.uberfire.java.nio.file.Path)
*/
@Override
protected DefaultIndexBuilder fillIndexBuilder(Path path) throws Exception {
final KieProject project = projectService.resolveProject(Paths.convert(path));
if (project == null) {
logger.error("Unable to index " + path.toUri().toString() + ": project could not be resolved.");
return null;
}

// responsible for basic index info: project name, branch, etc
final DefaultIndexBuilder builder = getIndexBuilder(path, project);
String bpmnStr = ioService.readAllString(path);
ClassLoader projectClassLoader = getProjectClassLoader(project);

try {
List<BpmnProcessDataEventListener> processDataList = buildProcessDefinition(bpmnStr, path, projectClassLoader);
if (processDataList != null) {
for (BpmnProcessDataEventListener processData : processDataList) {
addReferencedResourcesToIndexBuilder(builder, processData);
builder.setPackageName(processData.getProcess().getPackageName());
}
}
} catch (Exception e) {
// log and ignore
logger.info("Indexing hampered because BPMN2 compilation failed [" + path.toString() + "]: " + e.getMessage());
}

/**
* IMPORTANT: sometimes the build of the BPMN2 might fail for minor reasons, including things like
* a bad script in a script task
*
* When this happens, we (re)parse the process definition, but do not completely "build" it
* (as in, what org.jbpm.compiler.ProcessBuilderImpl.buildProcess(Process, Resource) does).
*
*
* It *would* be more efficient to basically copy/paste the
* jbpm-flow-builder org.jbpm.compiler.ProcessBuilderImpl.addProcessFromXml(Resource) logic here,
* so that we do something like:
*
* 1. Use the XmlProcessReader to create a process
* 2. *try* to build the rest of the process (and fail safely if not)
* 3. do XmlProcessReader.getProcessBuildData().onBuildComplete(process)
* to complete collecting the information
*
* But... that's a high maintenance cost for this piece of software
*
* So until we can refactor the ProcessBuilderImpl logic (using functional logic for conditional handling?)
* to be used here, let's keep it simple (as in, parsing the BPMN2 a second time when the build fails..)
*/

// parse process definitions
XmlProcessReader processReader = new XmlProcessReader(modules, projectClassLoader);
List<Process> processes = Collections.emptyList();
try {
processes = processReader.read(new StringReader(bpmnStr));
} catch (Exception e) {
logger.info("Unable to index because BPMN2 parsing failed [" + path.toString() + "]: " + e.getMessage());
}

// complete process definition processing
if (processes != null) {
for (Process process : processes) {
Resource resource = new ReaderResource(new StringReader(bpmnStr));
ProcessValidationError[] errors;

ProcessValidator validator = ProcessValidatorRegistry.getInstance().getValidator(process, resource);
errors = validator.validateProcess(process);
if (errors.length > 0) {
logger.error("Trying to finish indexing process '" + process.getId() + "/" + process.getName() + "' despite " + errors.length + " validation errors.");
}
processReader.getProcessBuildData().onBuildComplete(process);

BpmnProcessDataEventListener helper = (BpmnProcessDataEventListener) process.getMetaData().get(BpmnProcessDataEventListener.NAME);
addReferencedResourcesToIndexBuilder(builder, helper);
}
} else {
logger.warn("No process was found in file: " + path.toUri());
}

return builder;
}

// Protected method for testing
protected ClassLoader getProjectClassLoader(final KieProject project) {
return classLoaderHelper.getProjectClassLoader(project);
}

private List<BpmnProcessDataEventListener> buildProcessDefinition(String bpmn2Content, Path path, ClassLoader projectClassLoader) throws IllegalArgumentException {
if (StringUtils.isEmpty(bpmn2Content)) {
return null;
}

// Set class loader
KnowledgeBuilder kbuilder = null;
if (projectClassLoader != null) {
KnowledgeBuilderConfigurationImpl pconf = new KnowledgeBuilderConfigurationImpl(projectClassLoader);
kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(pconf);
} else {
kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
}

// Build
kbuilder.add(new ByteArrayResource(bpmn2Content.getBytes()), ResourceType.BPMN2);
if (kbuilder.hasErrors()) {
for (KnowledgeBuilderError error : kbuilder.getErrors()) {
logger.error("Error: {}", error.getMessage());
}
logger.debug("Process Cannot be Parsed! \n {} \n", bpmn2Content);
return null;
}

// Retrieve ProcessInfoHolder
List<BpmnProcessDataEventListener> processDataList = new ArrayList<>();
kbuilder.getKnowledgePackages().forEach(
pkg -> {
pkg.getProcesses().forEach(
p -> {
BpmnProcessDataEventListener processData
= (BpmnProcessDataEventListener) p.getMetaData().get(BpmnProcessDataEventListener.NAME);
processDataList.add(processData);
});
});
return processDataList;
}

protected DefaultIndexBuilder getIndexBuilder(Path path, Project project) {
final Package pkg = projectService.resolvePackage(Paths.convert(path));
if (pkg == null) {
logger.error("Unable to index " + path.toUri().toString() + ": package could not be resolved.");
return null;
}

// responsible for basic index info: project name, branch, etc
return new DefaultIndexBuilder(project, pkg);
}
}

0 comments on commit 260b99e

Please sign in to comment.