Commit 7f5c5421 authored by Aurelien Pupier's avatar Aurelien Pupier
Browse files

Merge pull request #243 from bonitasoft/bs-14002_customConnectorNotWorkingV2

Bs 14002 custom connector not working v2
parents 109074fd 19ad0e8f
/**
* Copyright (C) 2015 Bonitasoft S.A.
* Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2.0 of the License, or
* (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.bonitasoft.studio.connectors.configuration;
import static org.assertj.core.api.Assertions.assertThat;
import static org.bonitasoft.studio.model.configuration.builders.ConfigurationBuilder.aConfiguration;
import static org.bonitasoft.studio.model.configuration.builders.DefinitionMappingBuilder.aDefinitionMapping;
import static org.bonitasoft.studio.model.configuration.builders.FragmentBuilder.aFragment;
import static org.bonitasoft.studio.model.configuration.builders.FragmentContainerBuilder.aFragmentContainer;
import static org.bonitasoft.studio.model.process.builders.PoolBuilder.aPool;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Collections;
import org.bonitasoft.engine.bpm.bar.BarResource;
import org.bonitasoft.engine.bpm.bar.BusinessArchiveBuilder;
import org.bonitasoft.studio.common.FragmentTypes;
import org.bonitasoft.studio.common.NamingUtils;
import org.bonitasoft.studio.common.repository.RepositoryAccessor;
import org.bonitasoft.studio.common.repository.filestore.PackageFileStore;
import org.bonitasoft.studio.connector.model.implementation.ConnectorImplementation;
import org.bonitasoft.studio.connector.model.implementation.ConnectorImplementationFactory;
import org.bonitasoft.studio.connectors.repository.ConnectorImplFileStore;
import org.bonitasoft.studio.connectors.repository.ConnectorImplRepositoryStore;
import org.bonitasoft.studio.connectors.repository.ConnectorSourceRepositoryStore;
import org.bonitasoft.studio.dependencies.repository.DependencyFileStore;
import org.bonitasoft.studio.dependencies.repository.DependencyRepositoryStore;
import org.bonitasoft.studio.model.configuration.Configuration;
import org.eclipse.emf.ecore.EObject;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
/**
* @author aurelie
*/
@RunWith(MockitoJUnitRunner.class)
public class ConnectorBarResourceProviderTest {
@Mock
private ConnectorImplRepositoryStore connectorImplStore;
@Mock
private DependencyRepositoryStore depStore;
@Mock
private ConnectorSourceRepositoryStore connectorSourceStore;
@Mock
private RepositoryAccessor repositoryAccessor;
@Mock
private ConnectorImplFileStore myConnectorImplFileStore;
@Mock
private PackageFileStore connectorSourceFileStore;
@Rule
public TemporaryFolder fileRule = new TemporaryFolder();
@Mock
private DependencyFileStore libFileStore;
@Before
public void initRepositoryAccessor() throws Exception {
when(repositoryAccessor.getRepositoryStore(ConnectorImplRepositoryStore.class)).thenReturn(connectorImplStore);
when(repositoryAccessor.getRepositoryStore(DependencyRepositoryStore.class)).thenReturn(depStore);
when(repositoryAccessor.getRepositoryStore(ConnectorSourceRepositoryStore.class)).thenReturn(connectorSourceStore);
}
@Test
public void should_add_implementation_jar_in_bar_resource_from_source() throws Exception {
final ConnectorBarResourceProvider provider = spy(new ConnectorBarResourceProvider(repositoryAccessor));
doReturn(fileRule.newFile("myConnectorImpl-1.0.0.jar")).when(provider).exportJar(anyString(), any(PackageFileStore.class));
when(myConnectorImplFileStore.getContent()).thenReturn(aConnectorImplementation("myConnectorDef", "1.0.0", "myConnectorImpl", "1.0.0",
"org.test.MyConnector"));
when(myConnectorImplFileStore.canBeShared()).thenReturn(true);
when(connectorSourceStore.getChild("org.test")).thenReturn(connectorSourceFileStore);
when(connectorImplStore.getImplementationFileStore("myConnectorImpl", "1.0.0")).thenReturn(myConnectorImplFileStore);
when(connectorImplStore.getImplementation("myConnectorImpl", "1.0.0")).thenReturn(
aConnectorImplementation("myConnectorDef", "1.0.0", "myConnectorImpl", "1.0.0",
"org.test.MyConnector"));
final BusinessArchiveBuilder builder = mock(BusinessArchiveBuilder.class);
provider.addResourcesForConfiguration(builder, aPool().build(), connectorConfiguration("myConnectorDef", "1.0.0", "myConnectorImpl", "1.0.0"),
Collections.<EObject> emptySet());
final ArgumentCaptor<BarResource> barResourceCaptor = ArgumentCaptor.forClass(BarResource.class);
verify(builder).addClasspathResource(barResourceCaptor.capture());
assertThat(barResourceCaptor.getValue().getName()).isEqualTo("myConnectorImpl-1.0.0.jar");
}
@Test
public void should_add_implementation_jar_in_bar_resource_from_dependency_store() throws Exception {
final ConnectorBarResourceProvider provider = spy(new ConnectorBarResourceProvider(repositoryAccessor));
doReturn(fileRule.newFile("myConnectorImpl-1.0.0.jar")).when(provider).exportJar(anyString(), any(PackageFileStore.class));
when(myConnectorImplFileStore.getContent()).thenReturn(aConnectorImplementation("myConnectorDef", "1.0.0", "myConnectorImpl", "1.0.0",
"org.test.MyConnector"));
when(myConnectorImplFileStore.canBeShared()).thenReturn(true);
when(libFileStore.getName()).thenReturn("myConnectorImpl-1.0.0.jar");
when(depStore.getChild("myConnectorImpl-1.0.0.jar")).thenReturn(libFileStore);
when(connectorImplStore.getImplementationFileStore("myConnectorImpl", "1.0.0")).thenReturn(myConnectorImplFileStore);
final BusinessArchiveBuilder builder = mock(BusinessArchiveBuilder.class);
provider.addResourcesForConfiguration(builder, aPool().build(), connectorConfiguration("myConnectorDef", "1.0.0", "myConnectorImpl", "1.0.0"),
Collections.<EObject> emptySet());
final ArgumentCaptor<BarResource> barResourceCaptor = ArgumentCaptor.forClass(BarResource.class);
verify(builder).addClasspathResource(barResourceCaptor.capture());
assertThat(barResourceCaptor.getValue().getName()).isEqualTo("myConnectorImpl-1.0.0.jar");
}
private ConnectorImplementation aConnectorImplementation(final String definitionId,
final String definitionVersion,
final String implementationId,
final String implementationVersion,
final String className) {
final ConnectorImplementation connectorImplementation = ConnectorImplementationFactory.eINSTANCE.createConnectorImplementation();
connectorImplementation.setDefinitionId(definitionId);
connectorImplementation.setDefinitionId(definitionVersion);
connectorImplementation.setImplementationId(implementationId);
connectorImplementation.setImplementationVersion(implementationVersion);
connectorImplementation.setImplementationClassname(className);
return connectorImplementation;
}
private Configuration connectorConfiguration(final String defId,
final String defVersion,
final String implId,
final String implVersion) {
return aConfiguration()
.havingDefinitionMappings(aDefinitionMapping()
.withDefinitionId(defId)
.withDefinitionVersion(defVersion)
.withImplementationId(implId)
.withImplementationVersion(implVersion)
.withType(FragmentTypes.CONNECTOR))
.havingProcessDependencies(
aFragmentContainer(FragmentTypes.CONNECTOR)
.havingChildren(
aFragmentContainer(NamingUtils.toConnectorImplementationFilename(implId, implVersion, false)).havingFragments(
aFragment().withValue(NamingUtils.toConnectorImplementationFilename(implId, implVersion, false) + ".jar")
.exported()))).build();
}
}
......@@ -14,23 +14,32 @@
*/
package org.bonitasoft.studio.connectors.configuration;
import static com.google.common.base.Predicates.and;
import static com.google.common.base.Strings.isNullOrEmpty;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.io.Files.toByteArray;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.inject.Inject;
import org.bonitasoft.engine.bpm.bar.BarResource;
import org.bonitasoft.engine.bpm.bar.BusinessArchiveBuilder;
import org.bonitasoft.studio.common.FragmentTypes;
import org.bonitasoft.studio.common.NamingUtils;
import org.bonitasoft.studio.common.ProjectUtil;
import org.bonitasoft.studio.common.extension.BARResourcesProvider;
import org.bonitasoft.studio.common.log.BonitaStudioLog;
import org.bonitasoft.studio.common.repository.RepositoryManager;
import org.bonitasoft.studio.common.repository.RepositoryAccessor;
import org.bonitasoft.studio.common.repository.filestore.EMFFileStore;
import org.bonitasoft.studio.common.repository.filestore.PackageFileStore;
import org.bonitasoft.studio.common.repository.model.IRepositoryFileStore;
import org.bonitasoft.studio.common.repository.store.SourceRepositoryStore;
import org.bonitasoft.studio.connector.model.implementation.ConnectorImplementation;
import org.bonitasoft.studio.connectors.repository.ConnectorImplRepositoryStore;
import org.bonitasoft.studio.connectors.repository.ConnectorSourceRepositoryStore;
......@@ -40,115 +49,185 @@ import org.bonitasoft.studio.model.configuration.DefinitionMapping;
import org.bonitasoft.studio.model.configuration.Fragment;
import org.bonitasoft.studio.model.configuration.FragmentContainer;
import org.bonitasoft.studio.model.process.AbstractProcess;
import org.eclipse.core.runtime.Assert;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import com.google.common.io.Files;
import com.google.common.base.Predicate;
/**
* @author Romain Bioteau
*/
public class ConnectorBarResourceProvider implements BARResourcesProvider {
protected final RepositoryAccessor repositoryAccessor;
@Inject
public ConnectorBarResourceProvider(final RepositoryAccessor repositoryAccessor) {
this.repositoryAccessor = repositoryAccessor;
}
@Override
public void addResourcesForConfiguration(final BusinessArchiveBuilder builder, final AbstractProcess process, final Configuration configuration,
final Set<EObject> excludedObjects) {
final Set<EObject> excludedObjects) throws IOException, InvocationTargetException, InterruptedException {
if (configuration == null) {
return;
}
final List<BarResource> resources = new ArrayList<BarResource>();
final DependencyRepositoryStore libStore = RepositoryManager.getInstance().getRepositoryStore(DependencyRepositoryStore.class);
final ConnectorImplRepositoryStore implStore = RepositoryManager.getInstance().getRepositoryStore(ConnectorImplRepositoryStore.class);
for (final DefinitionMapping association : configuration.getDefinitionMappings()) {
if (association.getType().equals(FragmentTypes.CONNECTOR)) {
final String implId = association.getImplementationId();
final String implVersion = association.getImplementationVersion();
if (implId != null && implVersion != null) {
final ConnectorImplementation implementation = implStore.getImplementation(implId, implVersion);
if (implementation == null) {
throw new RuntimeException(implId + "(" + implVersion + ") not found in repository");
}
final String fileName = URI.decode(implementation.eResource().getURI().lastSegment());
final EMFFileStore file = implStore.getChild(fileName);
Assert.isNotNull(file);
final boolean isUserImplementation = file.canBeShared();
try {
File implementationFile = file.getResource().getLocation().toFile();
if (!implementationFile.exists()) {
implementationFile = new File(URI.decode(file.getEMFResource().getURI().toFileString()));
}
final FileInputStream fis = new FileInputStream(implementationFile);
final byte[] content = new byte[fis.available()];
fis.read(content);
fis.close();
builder.addConnectorImplementation(new BarResource(NamingUtils.toConnectorImplementationFilename(implId, implVersion, true), content));
//Add jar dependencies
for (final FragmentContainer fc : configuration.getProcessDependencies()) {
if (fc.getId().equals(FragmentTypes.CONNECTOR)) {
for (final FragmentContainer connector : fc.getChildren()) {
if (connector.getId().equals(NamingUtils.toConnectorImplementationFilename(implId, implVersion, false))) {
for (final Fragment fragment : connector.getFragments()) {
final String jarName = fragment.getValue();
if (jarName.endsWith(".jar") && fragment.isExported()) {
if (isUserImplementation
&& NamingUtils.toConnectorImplementationJarName(implementation).equals(fragment.getValue())) { //Generate jar from source file
addImplementationJar(builder, implementation);
} else {
final IRepositoryFileStore jarFileStore = libStore.getChild(jarName);
if (jarFileStore != null) {
final File jarFile = jarFileStore.getResource().getLocation().toFile();
resources.add(new BarResource(jarFile.getName(), Files.toByteArray(jarFile)));
}
}
}
}
final DependencyRepositoryStore libStore = getDependencyRepositoryStore();
final ConnectorImplRepositoryStore implStore = getImplementationStore();
for (final DefinitionMapping association : filter(configuration.getDefinitionMappings(), and(actorFilterMappings(), withImplementation()))) {
final String connectorImplementationFilename = NamingUtils.toConnectorImplementationFilename(
association.getImplementationId(),
association.getImplementationVersion(), true);
final String implId = association.getImplementationId();
final String implVersion = association.getImplementationVersion();
final EMFFileStore implementationFileStore = (EMFFileStore) implStore.getImplementationFileStore(implId, implVersion);
if (implementationFileStore == null) {
throw new FileNotFoundException(String.format("%s (%s) not found in repository", association.getImplementationId(),
association.getImplementationVersion()));
}
addImplementation(builder, connectorImplementationFilename, implementationFileStore);
final ConnectorImplementation connectorImplementation = (ConnectorImplementation) implementationFileStore.getContent();
addProcessDependencies(builder, configuration, resources, libStore, association.getImplementationId(), association.getImplementationVersion(),
connectorImplementation, implementationFileStore.canBeShared());
}
for (final BarResource barResource : resources) {
builder.addClasspathResource(barResource);
}
}
private Predicate<DefinitionMapping> withImplementation() {
return new Predicate<DefinitionMapping>() {
@Override
public boolean apply(final DefinitionMapping mapping) {
return !isNullOrEmpty(mapping.getImplementationId()) && !isNullOrEmpty(mapping.getDefinitionVersion());
}
};
}
private Predicate<DefinitionMapping> actorFilterMappings() {
return new Predicate<DefinitionMapping>() {
@Override
public boolean apply(final DefinitionMapping mapping) {
return getFragmentType().equals(mapping.getType());
}
};
}
protected String getFragmentType() {
return FragmentTypes.CONNECTOR;
}
/**
* @return
*/
protected DependencyRepositoryStore getDependencyRepositoryStore() {
return repositoryAccessor.getRepositoryStore(DependencyRepositoryStore.class);
}
/**
* @return
*/
protected ConnectorImplRepositoryStore getImplementationStore() {
return repositoryAccessor.getRepositoryStore(ConnectorImplRepositoryStore.class);
}
/**
* @param builder
* @param configuration
* @param resources
* @param libStore
* @param implId
* @param implVersion
* @param implementation
* @param isUserImplementation
* @throws IOException
* @throws InterruptedException
* @throws InvocationTargetException
*/
protected void addProcessDependencies(final BusinessArchiveBuilder builder, final Configuration configuration, final List<BarResource> resources,
final DependencyRepositoryStore libStore, final String implId, final String implVersion, final ConnectorImplementation implementation,
final boolean isUserImplementation) throws IOException, InvocationTargetException, InterruptedException {
for (final FragmentContainer fc : configuration.getProcessDependencies()) {
if (fc.getId().equals(FragmentTypes.CONNECTOR)) {
for (final FragmentContainer connector : fc.getChildren()) {
if (connector.getId().equals(NamingUtils.toConnectorImplementationFilename(implId, implVersion, false))) {
for (final Fragment fragment : connector.getFragments()) {
final String jarName = fragment.getValue();
if (jarName.endsWith(".jar") && fragment.isExported()) {
if (isUserImplementation
&& NamingUtils.toConnectorImplementationJarName(implementation).equals(fragment.getValue())) { //Generate jar from source file
if (!addImplementationJar(builder, implementation)) {
addResource(resources, libStore, jarName);
}
} else {
addResource(resources, libStore, jarName);
}
}
}
} catch (final Exception e) {
BonitaStudioLog.error(e);
}
}
}
}
for (final BarResource barResource : resources) {
builder.addClasspathResource(barResource);
}
/**
* @param resources
* @param libStore
* @param jarName
* @throws IOException
*/
protected void addResource(final List<BarResource> resources, final DependencyRepositoryStore libStore, final String jarName) throws IOException {
final IRepositoryFileStore jarFileStore = libStore.getChild(jarName);
if (jarFileStore != null) {
resources.add(new BarResource(jarFileStore.getName(), jarFileStore.toByteArray()));
}
}
private void addImplementationJar(final BusinessArchiveBuilder builder, final ConnectorImplementation impl) {
final ConnectorSourceRepositoryStore sourceStore = RepositoryManager.getInstance().getRepositoryStore(ConnectorSourceRepositoryStore.class);
private boolean addImplementationJar(final BusinessArchiveBuilder builder, final ConnectorImplementation impl) throws InvocationTargetException,
InterruptedException, IOException {
final SourceRepositoryStore<?> sourceStore = getSourceStore();
final String connectorJarName = NamingUtils.toConnectorImplementationJarName(impl);
final String qualifiedClassName = impl.getImplementationClassname();
String packageName = "";
if (qualifiedClassName.indexOf(".") != -1) {
packageName = qualifiedClassName.substring(0, qualifiedClassName.lastIndexOf("."));
}
final PackageFileStore file = (PackageFileStore) sourceStore.getChild(packageName);
if (file != null) {
final File tmpFile = new File(ProjectUtil.getBonitaStudioWorkFolder(), connectorJarName);
if (file == null) {
return false;
}
final File tmpFile = exportJar(connectorJarName, file);
try {
builder.addClasspathResource(new BarResource(connectorJarName, toByteArray(tmpFile)));
} finally {
tmpFile.delete();
try {
file.exportAsJar(tmpFile.getAbsolutePath(), false);
final FileInputStream fis = new FileInputStream(tmpFile);
final byte[] content = new byte[fis.available()];
fis.read(content);
fis.close();
tmpFile.delete();
builder.addClasspathResource(new BarResource(connectorJarName, content));
} catch (final Exception e) {
BonitaStudioLog.error(e);
}
}
return true;
}
protected File exportJar(final String connectorJarName, final PackageFileStore file) throws InvocationTargetException, InterruptedException {
final File tmpFile = new File(ProjectUtil.getBonitaStudioWorkFolder(), connectorJarName);
tmpFile.delete();
file.exportAsJar(tmpFile.getAbsolutePath(), false);
return tmpFile;
}
protected SourceRepositoryStore<?> getSourceStore() {
return repositoryAccessor.getRepositoryStore(ConnectorSourceRepositoryStore.class);
}
protected void addImplementation(final BusinessArchiveBuilder builder, final String connectorImplementationFilename,
final EMFFileStore implementationFileStore)
throws IOException {
builder.addConnectorImplementation(new BarResource(connectorImplementationFilename, implementationFileStore.toByteArray()));
}
}
......@@ -14,8 +14,11 @@
*/
package org.bonitasoft.studio.model.configuration.builders;
import org.bonitasoft.studio.model.Buildable;
import org.bonitasoft.studio.model.configuration.Configuration;
import org.bonitasoft.studio.model.configuration.ConfigurationFactory;
import org.bonitasoft.studio.model.configuration.DefinitionMapping;
import org.bonitasoft.studio.model.configuration.FragmentContainer;
/**
* @author Romain Bioteau
......@@ -67,6 +70,27 @@ public class ConfigurationBuilder {
return this;
}
public ConfigurationBuilder havingDefinitionMappings(final Buildable<? extends DefinitionMapping>... defMappings) {
for (final Buildable<? extends DefinitionMapping> def : defMappings) {
configuration.getDefinitionMappings().add(def.build());
}
return this;
}
public ConfigurationBuilder havingProcessDependencies(final Buildable<? extends FragmentContainer>... dependencies) {
for (final Buildable<? extends FragmentContainer> dep : dependencies) {
configuration.getProcessDependencies().add(dep.build());
}
return this;
}
public ConfigurationBuilder havingApplicationDependencies(final Buildable<? extends FragmentContainer>... dependencies) {
for (final Buildable<? extends FragmentContainer> dep : dependencies) {
configuration.getApplicationDependencies().add(dep.build());
}
return this;
}
public Configuration build() {
return configuration;
}
......
/**
* Copyright (C) 2015 Bonitasoft S.A.
* Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2.0 of the License, or
* (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.bonitasoft.studio.model.configuration.builders;
import org.bonitasoft.studio.model.Buildable;
import org.bonitasoft.studio.model.configuration.ConfigurationFactory;
import org.bonitasoft.studio.model.configuration.DefinitionMapping;
/**
* @author aurelie