Commit 22e6ded4 authored by Romain Bioteau's avatar Romain Bioteau Committed by Adrien

feat(contract) associate contract input with data reference (#1576)

* feat(contract) add matching algo

Closes BST-83
parent 59b2517d
...@@ -160,6 +160,7 @@ ...@@ -160,6 +160,7 @@
containment="true"/> containment="true"/>
<eStructuralFeatures xsi:type="ecore:EReference" name="inputs" upperBound="-1" <eStructuralFeatures xsi:type="ecore:EReference" name="inputs" upperBound="-1"
eType="#//ContractInput" containment="true"/> eType="#//ContractInput" containment="true"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="dataReference" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
</eClassifiers> </eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="ContractConstraint"> <eClassifiers xsi:type="ecore:EClass" name="ContractConstraint">
<eStructuralFeatures xsi:type="ecore:EAttribute" name="expression" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> <eStructuralFeatures xsi:type="ecore:EAttribute" name="expression" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
......
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<genmodel:GenModel xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" <genmodel:GenModel xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore"
xmlns:genmodel="http://www.eclipse.org/emf/2002/GenModel" copyrightText="Copyright (C) 2009-2015 BonitaSoft S.A.&#xD;&#xA;BonitaSoft, 32 rue Gustave Eiffel - 38000 Grenoble&#xD;&#xA;&#xD;&#xA;This program is free software: you can redistribute it and/or modify&#xD;&#xA;it under the terms of the GNU General Public License as published by&#xD;&#xA;the Free Software Foundation, either version 2.0 of the License, or&#xD;&#xA;(at your option) any later version.&#xD;&#xA;&#xD;&#xA;This program is distributed in the hope that it will be useful,&#xD;&#xA;but WITHOUT ANY WARRANTY; without even the implied warranty of&#xD;&#xA;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the&#xD;&#xA;GNU General Public License for more details.&#xD;&#xA;&#xD;&#xA;You should have received a copy of the GNU General Public License&#xD;&#xA;along with this program. If not, see &lt;http://www.gnu.org/licenses/>." xmlns:genmodel="http://www.eclipse.org/emf/2002/GenModel" copyrightText="Copyright (C) 2009-2019 BonitaSoft S.A.&#xD;&#xA;BonitaSoft, 32 rue Gustave Eiffel - 38000 Grenoble&#xD;&#xA;&#xD;&#xA;This program is free software: you can redistribute it and/or modify&#xD;&#xA;it under the terms of the GNU General Public License as published by&#xD;&#xA;the Free Software Foundation, either version 2.0 of the License, or&#xD;&#xA;(at your option) any later version.&#xD;&#xA;&#xD;&#xA;This program is distributed in the hope that it will be useful,&#xD;&#xA;but WITHOUT ANY WARRANTY; without even the implied warranty of&#xD;&#xA;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the&#xD;&#xA;GNU General Public License for more details.&#xD;&#xA;&#xD;&#xA;You should have received a copy of the GNU General Public License&#xD;&#xA;along with this program. If not, see &lt;http://www.gnu.org/licenses/>."
modelDirectory="/org.bonitasoft.studio.model/src" editDirectory="/org.bonitasoft.studio.model.edit/src" modelDirectory="/org.bonitasoft.studio.model/src" editDirectory="/org.bonitasoft.studio.model.edit/src"
modelPluginID="org.bonitasoft.studio.model" templateDirectory="org.bonitasoft.studio-models/EMFTemplates/" modelPluginID="org.bonitasoft.studio.model" templateDirectory="org.bonitasoft.studio-models/EMFTemplates/"
dynamicTemplates="true" redirection="" forceOverwrite="true" modelName="Process" dynamicTemplates="true" redirection="" forceOverwrite="true" modelName="Process"
...@@ -115,8 +115,8 @@ ...@@ -115,8 +115,8 @@
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute expression.ecore#//Expression/returnTypeFixed"/> <genFeatures createChild="false" ecoreFeature="ecore:EAttribute expression.ecore#//Expression/returnTypeFixed"/>
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute expression.ecore#//Expression/automaticDependencies"/> <genFeatures createChild="false" ecoreFeature="ecore:EAttribute expression.ecore#//Expression/automaticDependencies"/>
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute expression.ecore#//Expression/htmlAllowed"/> <genFeatures createChild="false" ecoreFeature="ecore:EAttribute expression.ecore#//Expression/htmlAllowed"/>
<genOperations ecoreOperation="expression.ecore#//Expression/hasContent"/> <genOperations ecoreOperation="expression.ecore#//Expression/hasContent" body="return content != null &amp;&amp; !content.isEmpty();"/>
<genOperations ecoreOperation="expression.ecore#//Expression/hasName"/> <genOperations ecoreOperation="expression.ecore#//Expression/hasName" body="return name != null &amp;&amp; !name.isEmpty();"/>
</genClasses> </genClasses>
<genClasses ecoreClass="expression.ecore#//ListExpression"> <genClasses ecoreClass="expression.ecore#//ListExpression">
<genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference expression.ecore#//ListExpression/expressions"/> <genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference expression.ecore#//ListExpression/expressions"/>
...@@ -348,7 +348,8 @@ ...@@ -348,7 +348,8 @@
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute process.ecore#//ContractInput/multiple"/> <genFeatures createChild="false" ecoreFeature="ecore:EAttribute process.ecore#//ContractInput/multiple"/>
<genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference process.ecore#//ContractInput/mapping"/> <genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference process.ecore#//ContractInput/mapping"/>
<genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference process.ecore#//ContractInput/inputs"/> <genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference process.ecore#//ContractInput/inputs"/>
<genOperations ecoreOperation="process.ecore#//ContractInput/getJavaType"/> <genFeatures createChild="false" ecoreFeature="ecore:EAttribute process.ecore#//ContractInput/dataReference"/>
<genOperations ecoreOperation="process.ecore#//ContractInput/getJavaType" body="switch(getType()){&#xD;&#xA;case BOOLEAN:return java.lang.Boolean.class.getName();&#xD;&#xA;case DATE: return java.util.Date.class.getName();&#xD;&#xA;case LOCALDATE: return java.time.LocalDate.class.getName();&#xD;&#xA;case LOCALDATETIME: return java.time.LocalDateTime.class.getName();&#xD;&#xA;case OFFSETDATETIME: return java.time.OffsetDateTime.class.getName();&#xD;&#xA;case INTEGER: return java.lang.Integer.class.getName();&#xA;case LONG: return java.lang.Long.class.getName();&#xD;&#xA;case DECIMAL: return java.lang.Double.class.getName();&#xD;&#xA;case FILE:return &quot;org.bonitasoft.engine.bpm.contract.FileInputValue&quot;;&#xD;&#xA;case COMPLEX:return java.util.Map.class.getName();&#xD;&#xA;case TEXT:&#xD;&#xA;default: return java.lang.String.class.getName();&#xD;&#xA;}"/>
</genClasses> </genClasses>
<genClasses ecoreClass="process.ecore#//ContractConstraint"> <genClasses ecoreClass="process.ecore#//ContractConstraint">
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute process.ecore#//ContractConstraint/expression"/> <genFeatures createChild="false" ecoreFeature="ecore:EAttribute process.ecore#//ContractConstraint/expression"/>
......
...@@ -14689,5 +14689,50 @@ ...@@ -14689,5 +14689,50 @@
<releases xmi:id="_z5RnUKwvEeiFZ5S8g2gj5Q" date="2018-08-30T11:43:27.494+0200" label="7.8.0-002"> <releases xmi:id="_z5RnUKwvEeiFZ5S8g2gj5Q" date="2018-08-30T11:43:27.494+0200" label="7.8.0-002">
<changes xsi:type="history:MigrationChange" xmi:id="_z5RnUawvEeiFZ5S8g2gj5Q" migration="org.bonitasoft.studio.migration.custom.migration.connector.UpdateRestConnectorVersionTo106"/> <changes xsi:type="history:MigrationChange" xmi:id="_z5RnUawvEeiFZ5S8g2gj5Q" migration="org.bonitasoft.studio.migration.custom.migration.connector.UpdateRestConnectorVersionTo106"/>
</releases> </releases>
<releases xmi:id="_lGPssDBZEemIIINmMdyzoA" date="2019-02-14T10:43:27.494+0100" label="7.9.0-001">
<changes xsi:type="history:OperationChange" xmi:id="_p10aMDBZEemIIINmMdyzoA">
<changes xsi:type="history:Create" xmi:id="_p10aMTBZEemIIINmMdyzoA" referenceName="eStructuralFeatures">
<target href="process.ecore#//ContractInput"/>
<element href="process.ecore#//ContractInput/dataReference"/>
<changes xsi:type="history:Set" xmi:id="_p10aMjBZEemIIINmMdyzoA" featureName="name" dataValue="dataReference">
<element href="process.ecore#//ContractInput/dataReference"/>
</changes>
<changes xsi:type="history:Set" xmi:id="_p10aMzBZEemIIINmMdyzoA" featureName="eType">
<element href="process.ecore#//ContractInput/dataReference"/>
<referenceValue href="http://www.eclipse.org/emf/2002/Ecore#//EString"/>
</changes>
</changes>
<operation xmi:id="_p10aNDBZEemIIINmMdyzoA" name="newAttribute">
<parameters xmi:id="_p10aNTBZEemIIINmMdyzoA" name="eClass">
<referenceValue xmi:id="_p10aNjBZEemIIINmMdyzoA">
<element href="process.ecore#//ContractInput"/>
</referenceValue>
<referenceValue xmi:id="_p10aNzBZEemIIINmMdyzoA">
<element href="process.ecore#//ContractInput"/>
</referenceValue>
</parameters>
<parameters xmi:id="_p10aODBZEemIIINmMdyzoA" name="name">
<dataValue>dataReference</dataValue>
</parameters>
<parameters xmi:id="_p10aOTBZEemIIINmMdyzoA" name="type">
<referenceValue xmi:id="_p10aOjBZEemIIINmMdyzoA">
<element href="http://www.eclipse.org/emf/2002/Ecore#//EString"/>
</referenceValue>
<referenceValue xmi:id="_p10aOzBZEemIIINmMdyzoA">
<element href="http://www.eclipse.org/emf/2002/Ecore#//EString"/>
</referenceValue>
</parameters>
<parameters xmi:id="_p10aPDBZEemIIINmMdyzoA" name="lowerBound">
<dataValue>0</dataValue>
</parameters>
<parameters xmi:id="_p10aPTBZEemIIINmMdyzoA" name="upperBound">
<dataValue>1</dataValue>
</parameters>
<parameters xmi:id="_p10aPjBZEemIIINmMdyzoA" name="defaultValue">
<dataValue xsi:nil="true"/>
</parameters>
</operation>
</changes>
</releases>
<releases xmi:id="_15TmyGnREeaTLbmqFFisdA"/> <releases xmi:id="_15TmyGnREeaTLbmqFFisdA"/>
</history:History> </history:History>
...@@ -176,7 +176,7 @@ public class DeployBDMOperation implements IRunnableWithProgress { ...@@ -176,7 +176,7 @@ public class DeployBDMOperation implements IRunnableWithProgress {
} }
protected IEventBroker eventBroker() { protected IEventBroker eventBroker() {
return (IEventBroker) PlatformUI.getWorkbench().getService(IEventBroker.class); return PlatformUI.getWorkbench().getService(IEventBroker.class);
} }
protected void removeDependency() { protected void removeDependency() {
......
...@@ -347,7 +347,7 @@ public class AttributesTabItemControl extends AbstractTabItemControl { ...@@ -347,7 +347,7 @@ public class AttributesTabItemControl extends AbstractTabItemControl {
final Composite lazyRadioComposite = new Composite(composite, SWT.NONE); final Composite lazyRadioComposite = new Composite(composite, SWT.NONE);
lazyRadioComposite.setLayoutData(GridDataFactory.fillDefaults().grab(true, false).create()); lazyRadioComposite.setLayoutData(GridDataFactory.fillDefaults().grab(true, false).create());
lazyRadioComposite.setLayout(GridLayoutFactory.fillDefaults().numColumns(2).margins(0, 0).spacing(25, 0).create()); lazyRadioComposite.setLayout(GridLayoutFactory.fillDefaults().numColumns(1).margins(0, 0).create());
final Button lazyRadio = new Button(lazyRadioComposite, SWT.RADIO); final Button lazyRadio = new Button(lazyRadioComposite, SWT.RADIO);
lazyRadio.setLayoutData(GridDataFactory.swtDefaults().grab(false, false).create()); lazyRadio.setLayoutData(GridDataFactory.swtDefaults().grab(false, false).create());
...@@ -356,7 +356,6 @@ public class AttributesTabItemControl extends AbstractTabItemControl { ...@@ -356,7 +356,6 @@ public class AttributesTabItemControl extends AbstractTabItemControl {
final ControlDecoration lazyDecorator = new ControlDecoration(lazyRadio, SWT.RIGHT); final ControlDecoration lazyDecorator = new ControlDecoration(lazyRadio, SWT.RIGHT);
lazyDecorator.setImage(Pics.getImage(PicsConstants.hint)); lazyDecorator.setImage(Pics.getImage(PicsConstants.hint));
lazyDecorator.setDescriptionText(Messages.loadOnDemandHint); lazyDecorator.setDescriptionText(Messages.loadOnDemandHint);
lazyDecorator.setMarginWidth(-5);
final Button eagerRadio = new Button(lazyRadioComposite, SWT.RADIO); final Button eagerRadio = new Button(lazyRadioComposite, SWT.RADIO);
eagerRadio.setLayoutData(GridDataFactory.swtDefaults().grab(false, false).create()); eagerRadio.setLayoutData(GridDataFactory.swtDefaults().grab(false, false).create());
...@@ -364,7 +363,6 @@ public class AttributesTabItemControl extends AbstractTabItemControl { ...@@ -364,7 +363,6 @@ public class AttributesTabItemControl extends AbstractTabItemControl {
final ControlDecoration eagerDecorator = new ControlDecoration(eagerRadio, SWT.RIGHT); final ControlDecoration eagerDecorator = new ControlDecoration(eagerRadio, SWT.RIGHT);
eagerDecorator.setImage(Pics.getImage(PicsConstants.hint)); eagerDecorator.setImage(Pics.getImage(PicsConstants.hint));
eagerDecorator.setMarginWidth(-5);
viewerObservableValue.addValueChangeListener(new IValueChangeListener() { viewerObservableValue.addValueChangeListener(new IValueChangeListener() {
@Override @Override
......
...@@ -147,16 +147,17 @@ public class ExpressionHelper { ...@@ -147,16 +147,17 @@ public class ExpressionHelper {
return createSearchIndexDependency(dependency); return createSearchIndexDependency(dependency);
} }
if (dependency instanceof ContractInput) { if (dependency instanceof ContractInput) {
return createContractInputependency(dependency); return createContractInputDependency(dependency);
} }
return EcoreUtil.copy(dependency); return EcoreUtil.copy(dependency);
} }
private static EObject createContractInputependency(EObject dependency) { private static EObject createContractInputDependency(EObject dependency) {
final ContractInput contractInputDependency = (ContractInput) EcoreUtil.copy(dependency); final ContractInput contractInputDependency = (ContractInput) EcoreUtil.copy(dependency);
if (contractInputDependency.getType() == ContractInputType.COMPLEX) { if (contractInputDependency.getType() == ContractInputType.COMPLEX) {
contractInputDependency.getInputs().clear(); contractInputDependency.getInputs().clear();
} }
contractInputDependency.setDataReference(null);
return contractInputDependency; return contractInputDependency;
} }
......
...@@ -58,7 +58,18 @@ Require-Bundle: org.eclipse.core.runtime;bundle-version="3.9.0", ...@@ -58,7 +58,18 @@ Require-Bundle: org.eclipse.core.runtime;bundle-version="3.9.0",
org.bonitasoft.studio.businessobject, org.bonitasoft.studio.businessobject,
org.bonitasoft.studio.document, org.bonitasoft.studio.document,
org.bonitasoft.studio.ui;bundle-version="7.6.0", org.bonitasoft.studio.ui;bundle-version="7.6.0",
org.eclipse.core.databinding.property;bundle-version="1.6.100" org.eclipse.core.databinding.property;bundle-version="1.6.100",
org.restlet.ext.jackson;bundle-version="2.2.3",
com.fasterxml.jackson.core.jackson-annotations;bundle-version="2.4.4",
com.fasterxml.jackson.core.jackson-core;bundle-version="2.4.4",
com.fasterxml.jackson.core.jackson-databind;bundle-version="2.4.4",
com.fasterxml.jackson.dataformat.jackson-dataformat-csv;bundle-version="2.4.4",
com.fasterxml.jackson.dataformat.jackson-dataformat-smile;bundle-version="2.4.4",
com.fasterxml.jackson.dataformat.jackson-dataformat-xml;bundle-version="2.4.4",
com.fasterxml.jackson.dataformat.jackson-dataformat-yaml;bundle-version="2.4.4",
com.fasterxml.jackson.module.jackson-module-jaxb-annotations;bundle-version="2.4.4",
org.restlet;bundle-version="2.3.0",
org.json;bundle-version="1.0.0"
Bundle-Activator: org.bonitasoft.studio.contract.ContractPlugin Bundle-Activator: org.bonitasoft.studio.contract.ContractPlugin
Bundle-ActivationPolicy: lazy Bundle-ActivationPolicy: lazy
Export-Package: org.bonitasoft.studio.contract.core, Export-Package: org.bonitasoft.studio.contract.core,
......
...@@ -97,4 +97,5 @@ longConversionWarning=Due to inter-operability issue between Java Long type and ...@@ -97,4 +97,5 @@ longConversionWarning=Due to inter-operability issue between Java Long type and
creatingMappingOperation=Creating mapping operation for %s creatingMappingOperation=Creating mapping operation for %s
saving=Saving... saving=Saving...
taskBdmTips=You can first define <a>business variables</a> and/or <a>documents</a>, and then click on "Add from data...".\nIt will automatically map contract inputs to data, and create operations to update data with contract values. taskBdmTips=You can first define <a>business variables</a> and/or <a>documents</a>, and then click on "Add from data...".\nIt will automatically map contract inputs to data, and create operations to update data with contract values.
poolBdmTips=You can first define <a>business variables</a> and/or <a>documents</a>, and then click on "Add from data...".\nIt will automatically map contract inputs to data, and initialize data with contract values. poolBdmTips=You can first define <a>business variables</a> and/or <a>documents</a>, and then click on "Add from data...".\nIt will automatically map contract inputs to data, and initialize data with contract values.
\ No newline at end of file creatingNewForm=Creating new form...
\ No newline at end of file
...@@ -64,6 +64,11 @@ ...@@ -64,6 +64,11 @@
class="org.bonitasoft.studio.contract.core.TaskContractEngineDefinitionBuilder"> class="org.bonitasoft.studio.contract.core.TaskContractEngineDefinitionBuilder">
</EngineDefinitionBuilder> </EngineDefinitionBuilder>
</extension> </extension>
<extension
point="org.bonitasoft.studio.designer.formOperationFactory">
<factory
class="org.bonitasoft.studio.contract.core.operation.NewFormFromContractOperationFactory"></factory>
</extension>
</plugin> </plugin>
package org.bonitasoft.studio.contract.core.mapping.treeMaching;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
import static org.bonitasoft.studio.model.businessObject.BusinessObjectBuilder.aBO;
import static org.bonitasoft.studio.model.process.builders.ContractInputBuilder.aContractInput;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.bonitasoft.engine.bdm.model.field.RelationField;
import org.bonitasoft.studio.model.businessObject.FieldBuilder.RelationFieldBuilder;
import org.bonitasoft.studio.model.businessObject.FieldBuilder.SimpleFieldBuilder;
import org.bonitasoft.studio.model.process.BusinessObjectData;
import org.bonitasoft.studio.model.process.Contract;
import org.bonitasoft.studio.model.process.ContractInputType;
import org.bonitasoft.studio.model.process.ProcessFactory;
import org.bonitasoft.studio.model.process.builders.ContractBuilder;
import org.junit.Before;
import org.junit.Test;
public class TreeBuilderTest {
private BusinessDataStore store;
private List<BusinessObjectData> businessData = new ArrayList<>();
@Before
public void setUp() {
store = mock(BusinessDataStore.class);
businessData.add(aData("myData", "org.test.Employee"));
when(store.getBusinessData()).thenReturn(businessData);
RelationField addressField = RelationFieldBuilder.aCompositionField("address", aBO("org.test.Address")
.withField(SimpleFieldBuilder.aStringField("street").build())
.build());
addressField.setCollection(true);
when(store.getBusinessObject("org.test.Employee")).thenReturn(Optional.of(aBO("org.test.Employee")
.withField(SimpleFieldBuilder.aStringField("firstName").build())
.withField(SimpleFieldBuilder.aDateOnlyField("birthDate").build())
.withField(addressField)
.build()));
}
@Test
public void should_build_tree() throws Exception {
TreeBuilder treeBuilder = new TreeBuilder(store);
Contract contract = createMatchingContract();
TreeNode node = treeBuilder.buildBusinessObjectTree(businessData.get(0), contract.getInputs().get(0));
assertThat(node.getInput().getName()).isEqualTo("myDataInput");
assertThat(node.getRef().getName()).isEqualTo("myData");
assertThat(node.getChildren()).extracting("input.name", "ref.name").contains(tuple("address", "address"));
assertThat(node.getChildren().get(0).getChildren()).isEmpty();
}
@SuppressWarnings("unchecked")
private Contract createMatchingContract() {
return ContractBuilder.aContract()
.havingInput(aContractInput()
.withName("myDataInput")
.withType(ContractInputType.COMPLEX)
.havingInput(aContractInput().withName("firstName").withType(ContractInputType.TEXT),
aContractInput().withName("birthDate").withType(ContractInputType.LOCALDATE),
aContractInput().withName("address").withType(ContractInputType.COMPLEX)
.havingInput(aContractInput().withName("street").withType(ContractInputType.TEXT),
aContractInput().withName("city").withType(ContractInputType.TEXT))))
.build();
}
private BusinessObjectData aData(String name, String type) {
BusinessObjectData data = ProcessFactory.eINSTANCE.createBusinessObjectData();
data.setName(name);
data.setClassName(type);
return data;
}
}