/**
* Copyright (C) 2011 BonitaSoft S.A.
* BonitaSoft, 31 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.forms.server.provider.impl;
import org.bonitasoft.engine.api.ProcessAPI;
import org.bonitasoft.engine.api.TenantAPIAccessor;
import org.bonitasoft.engine.bpm.actor.ActorCriterion;
import org.bonitasoft.engine.bpm.actor.ActorInstance;
import org.bonitasoft.engine.bpm.bar.BarResource;
import org.bonitasoft.engine.bpm.bar.BusinessArchive;
import org.bonitasoft.engine.bpm.bar.BusinessArchiveBuilder;
import org.bonitasoft.engine.bpm.bar.InvalidBusinessArchiveFormatException;
import org.bonitasoft.engine.bpm.document.DocumentsSearchDescriptor;
import org.bonitasoft.engine.bpm.flownode.ActivityInstanceCriterion;
import org.bonitasoft.engine.bpm.flownode.FlowNodeExecutionException;
import org.bonitasoft.engine.bpm.process.ArchivedProcessInstancesSearchDescriptor;
import org.bonitasoft.engine.bpm.process.DesignProcessDefinition;
import org.bonitasoft.engine.bpm.process.InvalidProcessDefinitionException;
import org.bonitasoft.engine.bpm.process.ProcessActivationException;
import org.bonitasoft.engine.bpm.process.ProcessDefinition;
import org.bonitasoft.engine.bpm.process.ProcessDefinitionNotFoundException;
import org.bonitasoft.engine.bpm.process.ProcessDeployException;
import org.bonitasoft.engine.bpm.process.ProcessEnablementException;
import org.bonitasoft.engine.bpm.process.impl.ProcessDefinitionBuilder;
import org.bonitasoft.engine.exception.AlreadyExistsException;
import org.bonitasoft.engine.exception.CreationException;
import org.bonitasoft.engine.exception.DeletionException;
import org.bonitasoft.engine.exception.UpdateException;
import org.bonitasoft.engine.expression.ExpressionBuilder;
import org.bonitasoft.engine.expression.ExpressionType;
import org.bonitasoft.engine.expression.InvalidExpressionException;
import org.bonitasoft.engine.search.SearchFilterOperation;
import org.bonitasoft.engine.search.SearchOptionsBuilder;
import org.bonitasoft.engine.search.SearchResult;
import org.bonitasoft.engine.search.impl.SearchFilter;
import org.bonitasoft.forms.client.model.Expression;
import org.bonitasoft.forms.client.model.FormFieldValue;
import org.bonitasoft.forms.client.model.FormURLComponents;
import org.bonitasoft.forms.client.model.FormWidget;
import org.bonitasoft.forms.server.FormsTestCase;
import org.bonitasoft.forms.server.WaitUntil;
import org.bonitasoft.forms.server.accessor.IApplicationFormDefAccessor;
import org.bonitasoft.forms.server.api.impl.FormWorkflowAPIImpl;
import org.bonitasoft.forms.server.exception.NoCredentialsInSessionException;
import org.bonitasoft.forms.server.provider.FormServiceProvider;
import org.bonitasoft.forms.server.provider.impl.util.FormServiceProviderFactory;
import org.bonitasoft.forms.server.provider.impl.util.FormServiceProviderUtil;
import org.bonitasoft.test.toolkit.bpm.TestProcess;
import org.bonitasoft.web.rest.model.user.User;
import org.junit.After;
import org.junit.Assert;
import org.junit.Test;
import org.w3c.dom.Document;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
import java.io.InputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author QiXiang Zhang, Yongtao Guo
*/
public class FormServiceProviderImplIT extends FormsTestCase {
protected ProcessDefinition processDefinition;
protected Expression expression = null;
protected ProcessAPI processAPI;
@Override
public void testSetUp() throws Exception {
super.testSetUp();
final ProcessDefinitionBuilder processBuilder = new ProcessDefinitionBuilder().createNewInstance("firstProcess", "1.0");
final ExpressionBuilder expressionBuilder = new ExpressionBuilder();
processBuilder.addData(
"application",
String.class.getName(),
expressionBuilder.createNewInstance("word").setContent("Word").setExpressionType(ExpressionType.TYPE_CONSTANT)
.setReturnType(String.class.getName()).done());
processBuilder.addDocumentDefinition("doc1").addUrl("www.bonitasoft.org");
processBuilder.addDocumentDefinition("doc2").addContentFileName("filename.txt").addFile("barFilename.txt");
processBuilder.addActor("myActor");
processBuilder.addUserTask("Request", "myActor");
processBuilder.addUserTask("Approval", "myActor");
processBuilder.addTransition("Request", "Approval");
final DesignProcessDefinition designProcessDefinition = processBuilder.done();
final BusinessArchiveBuilder businessArchiveBuilder = new BusinessArchiveBuilder().createNewBusinessArchive();
final byte[] content = new byte[] { 5, 0, 1, 4, 6, 5, 2, 3, 1, 5, 6, 8, 4, 6, 6, 3, 2, 4, 5 };
final BarResource barResource = new BarResource("barFilename.txt", content);
businessArchiveBuilder.setFormMappings(TestProcess.createDefaultProcessFormMapping(designProcessDefinition));
businessArchiveBuilder.addDocumentResource(barResource);
final BusinessArchive businessArchive = businessArchiveBuilder.setProcessDefinition(designProcessDefinition).done();
processAPI = TenantAPIAccessor.getProcessAPI(getSession());
processDefinition = processAPI.deploy(businessArchive);
final org.bonitasoft.engine.identity.User user = getInitiator().getUser();
final ActorInstance processActor = processAPI.getActors(processDefinition.getId(), 0, 1, ActorCriterion.NAME_ASC).get(0);
processAPI.addUserToActor(processActor.getId(), user.getId());
processAPI.enableProcess(processDefinition.getId());
processAPI = TenantAPIAccessor.getProcessAPI(getSession());
final List<Expression> dependencies = new ArrayList<Expression>();
dependencies.add(new Expression(null, "field_application", ExpressionType.TYPE_INPUT.name(), String.class.getName(), null, null));
expression = new Expression(null, "\"application:\" + field_application", ExpressionType.TYPE_READ_ONLY_SCRIPT.name(), String.class.getName(),
"GROOVY", dependencies);
}
@After
public void tearDown() throws Exception {
deleteProcess(processDefinition.getId());
}
protected void deleteProcess(final long processDefinitionId) throws ProcessDefinitionNotFoundException, ProcessActivationException, DeletionException {
processAPI.disableProcess(processDefinitionId);
do {
} while (processAPI.deleteProcessInstances(processDefinitionId, 0, 20) > 0);
do {
} while (processAPI.deleteArchivedProcessInstances(processDefinitionId, 0, 20) > 0);
processAPI.deleteProcessDefinition(processDefinitionId);
}
@Test
public void testGetFormDefinitionDocument() throws Exception {
final long processInstanceId = processAPI.startProcess(processDefinition.getId()).getId();
final FormServiceProvider formServiceProvider = FormServiceProviderFactory.getFormServiceProvider(getSession().getTenantId());
final Map<String, Object> urlContext = new HashMap<String, Object>();
urlContext.put(FormServiceProviderUtil.INSTANCE_UUID, processInstanceId);
urlContext.put(FormServiceProviderUtil.LOCALE, Locale.ENGLISH);
final Map<String, Object> context = new HashMap<String, Object>();
context.put(FormServiceProviderUtil.URL_CONTEXT, urlContext);
context.put(FormServiceProviderUtil.LOCALE, Locale.ENGLISH);
context.put(FormServiceProviderUtil.API_SESSION, getSession());
final Document document = formServiceProvider.getFormDefinitionDocument(context);
Assert.assertNotNull(document);
}
@Test(expected = NoCredentialsInSessionException.class)
public void testIsAllowed() throws Exception {
final long processInstanceId = processAPI.startProcess(processDefinition.getId()).getId();
final FormServiceProvider formServiceProvider = FormServiceProviderFactory.getFormServiceProvider(getSession().getTenantId());
final Map<String, Object> urlContext = new HashMap<String, Object>();
urlContext.put(FormServiceProviderUtil.INSTANCE_UUID, processInstanceId);
final User user = new User(getSession().getUserName(), Locale.ENGLISH.toString());
final Map<String, Object> context = new HashMap<String, Object>();
context.put(FormServiceProviderUtil.USER, user);
context.put(FormServiceProviderUtil.URL_CONTEXT, urlContext);
context.put(FormServiceProviderUtil.LOCALE, Locale.ENGLISH);
context.put(FormServiceProviderUtil.API_SESSION, getSession());
// TODO re-establish this once it will be possible to give some access rights to the overview form
// boolean isAllowed1 = formServiceProvider.isAllowed(processDefinitionUUIDStr + FormServiceProviderUtil.FORM_ID_SEPARATOR
// + FormServiceProviderUtil.RECAP_FORM_TYPE, FormServiceProviderUtil.INSTANCE_UUID + "#" + processDefinitionUUIDStr, "6.0", "6.0", context, true);
// Assert.assertEquals(true, isAllowed1);
context.remove(FormServiceProviderUtil.USER);
// expected = NoCredentialsInSessionException.class
formServiceProvider.isAllowed(processDefinition.getName() + "--" + processDefinition.getVersion() + FormServiceProviderUtil.FORM_ID_SEPARATOR
+ FormServiceProviderUtil.RECAP_FORM_TYPE,
FormServiceProviderUtil.PROCESS_UUID + "#" + processDefinition.getId(), "6.0", "6.0", context, true);
}
@Test
public void testResolveExpression() throws Exception {
final long processInstanceId = processAPI.startProcess(processDefinition.getId()).getId();
final FormServiceProvider formServiceProvider = FormServiceProviderFactory.getFormServiceProvider(getSession().getTenantId());
final Map<String, Object> urlContext = new HashMap<String, Object>();
urlContext.put(FormServiceProviderUtil.INSTANCE_UUID, processInstanceId);
urlContext.put(FormServiceProviderUtil.LOCALE, Locale.ENGLISH);
urlContext.put(FormServiceProviderUtil.IS_CURRENT_VALUE, true);
final Map<String, Object> context = new HashMap<String, Object>();
context.put(FormServiceProviderUtil.URL_CONTEXT, urlContext);
context.put(FormServiceProviderUtil.LOCALE, Locale.ENGLISH);
context.put(FormServiceProviderUtil.API_SESSION, getSession());
final Map<String, FormFieldValue> fieldValues = new HashMap<String, FormFieldValue>();
fieldValues.put("application", new FormFieldValue("Excel", String.class.getName()));
context.put(FormServiceProviderUtil.FIELD_VALUES, fieldValues);
final Object result = formServiceProvider.resolveExpression(expression, context);
Assert.assertEquals("application:Excel", result);
}
@Test
public void testResolveExpressions() throws Exception {
final long processInstanceId = processAPI.startProcess(processDefinition.getId()).getId();
final FormServiceProvider formServiceProvider = FormServiceProviderFactory.getFormServiceProvider(getSession().getTenantId());
final Map<String, Object> urlContext = new HashMap<String, Object>();
urlContext.put(FormServiceProviderUtil.INSTANCE_UUID, processInstanceId);
urlContext.put(FormServiceProviderUtil.LOCALE, Locale.ENGLISH);
urlContext.put(FormServiceProviderUtil.IS_CURRENT_VALUE, true);
final Map<String, Object> context = new HashMap<String, Object>();
context.put(FormServiceProviderUtil.URL_CONTEXT, urlContext);
context.put(FormServiceProviderUtil.LOCALE, Locale.ENGLISH);
context.put(FormServiceProviderUtil.API_SESSION, getSession());
final Map<String, FormFieldValue> fieldValues = new HashMap<String, FormFieldValue>();
fieldValues.put("application", new FormFieldValue("Excel", String.class.getName()));
context.put(FormServiceProviderUtil.FIELD_VALUES, fieldValues);
final List<Expression> expressions = new ArrayList<Expression>();
expression.setName("1");
expressions.add(expression);
expressions.add(new Expression("2", "good", "TYPE_CONSTANT", String.class.getName(), null, null));
final Map<String, Serializable> result = formServiceProvider.resolveExpressions(expressions, context);
Assert.assertEquals("application:Excel", result.get("1"));
Assert.assertEquals("good", result.get("2"));
}
@Test
public void testGetDeployementDate() throws Exception {
final FormServiceProvider formServiceProvider = FormServiceProviderFactory.getFormServiceProvider(getSession().getTenantId());
final Map<String, Object> urlContext = new HashMap<String, Object>();
urlContext.put(FormServiceProviderUtil.FORM_ID, processDefinition.getName() + FormWorkflowAPIImpl.UUID_SEPARATOR + processDefinition.getVersion()
+ FormServiceProviderUtil.FORM_ID_SEPARATOR
+ FormServiceProviderUtil.RECAP_FORM_TYPE);
final Map<String, Object> context = new HashMap<String, Object>();
context.put(FormServiceProviderUtil.URL_CONTEXT, urlContext);
context.put(FormServiceProviderUtil.LOCALE, Locale.ENGLISH);
context.put(FormServiceProviderUtil.API_SESSION, getSession());
final Date date = formServiceProvider.getDeployementDate(context);
Assert.assertNotNull(date);
}
@Test
public void testGetAttributesToInsert() throws Exception {
processAPI.startProcess(processDefinition.getId()).getId();
final FormServiceProvider formServiceProvider = FormServiceProviderFactory.getFormServiceProvider(getSession().getTenantId());
final Map<String, Object> urlContext = new HashMap<String, Object>();
final long activityInstanceId = waitForPendingTask();
urlContext.put(FormServiceProviderUtil.TASK_UUID, activityInstanceId);
urlContext.put(FormServiceProviderUtil.LOCALE, Locale.ENGLISH);
final Map<String, Object> context = new HashMap<String, Object>();
context.put(FormServiceProviderUtil.URL_CONTEXT, urlContext);
context.put(FormServiceProviderUtil.LOCALE, Locale.ENGLISH);
context.put(FormServiceProviderUtil.API_SESSION, getSession());
final Map<String, String> attributes = formServiceProvider.getAttributesToInsert(context);
Assert.assertNotNull(attributes);
}
@Test
public void testSkipForm() throws Exception {
processAPI.startProcess(processDefinition.getId()).getId();
final FormServiceProvider formServiceProvider = FormServiceProviderFactory.getFormServiceProvider(getSession().getTenantId());
final Map<String, Object> urlContext = new HashMap<String, Object>();
final long activityInstanceId = waitForPendingTask();
urlContext.put(FormServiceProviderUtil.TASK_UUID, activityInstanceId);
final Map<String, Object> context = new HashMap<String, Object>();
context.put(FormServiceProviderUtil.URL_CONTEXT, urlContext);
context.put(FormServiceProviderUtil.LOCALE, Locale.ENGLISH);
context.put(FormServiceProviderUtil.API_SESSION, getSession());
processAPI.assignUserTask(activityInstanceId, getSession().getUserId());
final Map<String, Object> result = formServiceProvider.skipForm("myProcess--1.0--task1$entry", context);
Assert.assertNotNull(result);
}
@Test
public void testGetApplicationFormDefinitionFromXML() throws Exception {
processAPI.startProcess(processDefinition.getId()).getId();
final FormServiceProvider formServiceProvider = FormServiceProviderFactory.getFormServiceProvider(getSession().getTenantId());
final Map<String, Object> urlContext = new HashMap<String, Object>();
final long activityInstanceId = waitForPendingTask();
final String formId = "firstProcess--1.0--Request$entry";
urlContext.put(FormServiceProviderUtil.FORM_ID, formId);
urlContext.put(FormServiceProviderUtil.TASK_UUID, activityInstanceId);
final Map<String, Object> context = new HashMap<String, Object>();
context.put(FormServiceProviderUtil.URL_CONTEXT, urlContext);
context.put(FormServiceProviderUtil.LOCALE, Locale.ENGLISH);
context.put(FormServiceProviderUtil.API_SESSION, getSession());
final InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("forms.xml");
final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
final Document document = builder.parse(inputStream);
inputStream.close();
final Date deployedDate = processAPI.getProcessDeploymentInfo(processDefinition.getId()).getDeploymentDate();
context.put(FormServiceProviderUtil.APPLICATION_DEPLOYMENT_DATE, deployedDate);
context.put(FormServiceProviderUtil.IS_EDIT_MODE, true);
final IApplicationFormDefAccessor applicationFormDefAccessor = formServiceProvider.getApplicationFormDefinition(formId,
document,
context);
Assert.assertNull("the first page expression should be null because the entry form is empty in the forms.xml",
applicationFormDefAccessor.getFirstPageExpression());
}
@Test
public void testGetApplicationFormDefinitionFromEngine() throws Exception {
processAPI.startProcess(processDefinition.getId()).getId();
long activityInstanceId = waitForPendingTask();
processAPI.assignUserTask(activityInstanceId, getSession().getUserId());
processAPI.executeFlowNode(activityInstanceId);
Assert.assertTrue("no pending user task instances are found", new WaitUntil(50, 3000) {
@Override
protected boolean check() throws Exception {
return processAPI.getPendingHumanTaskInstances(FormServiceProviderImplIT.this.getSession().getUserId(), 0, 10,
null).size() >= 1;
}
}.waitUntil());
activityInstanceId = processAPI.getPendingHumanTaskInstances(getSession().getUserId(), 0, 1, ActivityInstanceCriterion.NAME_ASC).get(0).getId();
final FormServiceProvider formServiceProvider = FormServiceProviderFactory.getFormServiceProvider(getSession().getTenantId());
final Map<String, Object> urlContext = new HashMap<String, Object>();
final String formId = "firstProcess--1.0--Approval$entry";
urlContext.put(FormServiceProviderUtil.FORM_ID, formId);
urlContext.put(FormServiceProviderUtil.TASK_UUID, activityInstanceId);
final Map<String, Object> context = new HashMap<String, Object>();
context.put(FormServiceProviderUtil.URL_CONTEXT, urlContext);
context.put(FormServiceProviderUtil.LOCALE, Locale.ENGLISH);
context.put(FormServiceProviderUtil.API_SESSION, getSession());
final InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("forms.xml");
final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
final Document document = builder.parse(inputStream);
inputStream.close();
final Date deployedDate = processAPI.getProcessDeploymentInfo(processDefinition.getId()).getDeploymentDate();
context.put(FormServiceProviderUtil.APPLICATION_DEPLOYMENT_DATE, deployedDate);
context.put(FormServiceProviderUtil.IS_EDIT_MODE, true);
final IApplicationFormDefAccessor applicationFormDefAccessor = formServiceProvider.getApplicationFormDefinition(formId,
document,
context);
final Expression firstPage = applicationFormDefAccessor.getFirstPageExpression();
Assert.assertNotNull(
"the first page expression should not be null because the entry form is not in the forms.xml, and so it should be generated from the engine",
firstPage);
final List<FormWidget> widgets = applicationFormDefAccessor.getPageWidgets(firstPage.getContent());
Assert.assertEquals("there is only one data in the process so there should be 2 widgets (one for the data and one for the submit button)", 2,
widgets.size());
Assert.assertEquals("application", widgets.get(0).getInitialValueExpression().getContent());
}
@Test
public void testGetAttachmentFormFieldValue() throws Exception {
processAPI.startProcess(processDefinition.getId()).getId();
final FormServiceProvider formServiceProvider = FormServiceProviderFactory.getFormServiceProvider(getSession().getTenantId());
final Map<String, Object> urlContext = new HashMap<String, Object>();
final long activityInstanceId = waitForPendingTask();
urlContext.put(FormServiceProviderUtil.TASK_UUID, activityInstanceId);
final Map<String, Object> context = new HashMap<String, Object>();
context.put(FormServiceProviderUtil.URL_CONTEXT, urlContext);
context.put(FormServiceProviderUtil.LOCALE, Locale.ENGLISH);
context.put(FormServiceProviderUtil.API_SESSION, getSession());
final FormFieldValue urlFieldValue = formServiceProvider.getAttachmentFormFieldValue("doc1", context);
Assert.assertEquals("the value type for a URL document should be a String", String.class.getName(), urlFieldValue.getValueType());
Assert.assertEquals("the URL is not right", "www.bonitasoft.org", urlFieldValue.getValue());
Assert.assertNotSame(0, urlFieldValue.getDocumentId());
final FormFieldValue fileFieldValue = formServiceProvider.getAttachmentFormFieldValue("doc2", context);
Assert.assertEquals("the value type for a File document should be a File", File.class.getName(), fileFieldValue.getValueType());
Assert.assertEquals("the filename is not right", "filename.txt", fileFieldValue.getValue());
Assert.assertNotSame(0, fileFieldValue.getDocumentId());
}
@Test
public void testGetArchivedAttachmentFormFieldValue() throws Exception {
final long processInstanceId = processAPI.startProcess(processDefinition.getId()).getId();
final FormServiceProvider formServiceProvider = FormServiceProviderFactory.getFormServiceProvider(getSession().getTenantId());
final Map<String, Object> urlContext = new HashMap<String, Object>();
terminateProcessInstance(processInstanceId);
urlContext.put(FormServiceProviderUtil.INSTANCE_UUID, processInstanceId);
urlContext.put(FormServiceProviderUtil.RECAP_FORM_TYPE, Boolean.TRUE.toString());
final Map<String, Object> context = new HashMap<String, Object>();
context.put(FormServiceProviderUtil.URL_CONTEXT, urlContext);
context.put(FormServiceProviderUtil.LOCALE, Locale.ENGLISH);
context.put(FormServiceProviderUtil.API_SESSION, getSession());
final FormFieldValue urlFieldValue = formServiceProvider.getAttachmentFormFieldValue("doc1", context);
Assert.assertEquals("the value type for a URL document should be a String", String.class.getName(), urlFieldValue.getValueType());
Assert.assertEquals("the URL is not right", "www.bonitasoft.org", urlFieldValue.getValue());
Assert.assertNotSame(0, urlFieldValue.getDocumentId());
final FormFieldValue fileFieldValue = formServiceProvider.getAttachmentFormFieldValue("doc2", context);
Assert.assertEquals("the value type for a File document should be a File", File.class.getName(), fileFieldValue.getValueType());
Assert.assertEquals("the filename is not right", "filename.txt", fileFieldValue.getValue());
Assert.assertNotSame(0, fileFieldValue.getDocumentId());
}
@Test
public void testGetAttachmentFormFieldValueFromDocument() throws Exception {
final long processInstanceId = processAPI.startProcess(processDefinition.getId()).getId();
final FormServiceProvider formServiceProvider = FormServiceProviderFactory.getFormServiceProvider(getSession().getTenantId());
final Map<String, Object> urlContext = new HashMap<String, Object>();
final long activityInstanceId = waitForPendingTask();
urlContext.put(FormServiceProviderUtil.TASK_UUID, activityInstanceId);
final Map<String, Object> context = new HashMap<String, Object>();
context.put(FormServiceProviderUtil.URL_CONTEXT, urlContext);
context.put(FormServiceProviderUtil.LOCALE, Locale.ENGLISH);
context.put(FormServiceProviderUtil.API_SESSION, getSession());
final SearchOptionsBuilder searchOptionsBuilder = new SearchOptionsBuilder(0, 2);
final List<SearchFilter> filters = new ArrayList<SearchFilter>();
filters.add(new SearchFilter(DocumentsSearchDescriptor.PROCESSINSTANCE_ID, SearchFilterOperation.EQUALS, processInstanceId));
searchOptionsBuilder.setFilters(filters);
final SearchResult<org.bonitasoft.engine.bpm.document.Document> result = processAPI.searchDocuments(searchOptionsBuilder.done());
final List<org.bonitasoft.engine.bpm.document.Document> documents = result.getResult();
Assert.assertEquals(2, documents.size());
for (final org.bonitasoft.engine.bpm.document.Document document : documents) {
if (document.getName().equals("doc1")) {
final FormFieldValue urlFieldValue = formServiceProvider.getAttachmentFormFieldValue(document, context);
Assert.assertEquals("the value type for a URL document should be a String", String.class.getName(), urlFieldValue.getValueType());
Assert.assertEquals("the URL is not right", "www.bonitasoft.org", urlFieldValue.getValue());
Assert.assertNotSame(0, urlFieldValue.getDocumentId());
} else if (document.getName().equals("doc2")) {
final FormFieldValue fileFieldValue = formServiceProvider.getAttachmentFormFieldValue(document, context);
Assert.assertEquals("the value type for a File document should be a File", File.class.getName(), fileFieldValue.getValueType());
Assert.assertEquals("the filename is not right", "filename.txt", fileFieldValue.getValue());
Assert.assertNotSame(0, fileFieldValue.getDocumentId());
} else {
Assert.fail("shouldn't happen.");
}
}
}
@Test
public void testGetNextFormURLParametersFromSubprocessTask() throws Exception {
final org.bonitasoft.engine.identity.User user = getInitiator().getUser();
final ProcessDefinition subProcessDefinition = createSubprocess(user);
final ProcessDefinition intermediateSubProcessDefinition = createIntermediateSubprocess(user);
final ProcessDefinition processDefinition = createParentProcess(user);
processAPI = TenantAPIAccessor.getProcessAPI(getSession());
final long parentProcessInstanceId = processAPI.startProcess(processDefinition.getId()).getId();
try {
final long activityInstanceId = waitForPendingTask();
processAPI.assignUserTask(activityInstanceId, getSession().getUserId());
processAPI.executeFlowNode(activityInstanceId);
final long subprocessActivityInstanceId = waitForPendingTask();
//Create a thread to simulate a call to the forms servlet (and have the task archived)
final Callable<Void> task = new Callable<Void>() {
@Override
public Void call() throws Exception {
final long activityInstanceId = waitForPendingTask();
processAPI.assignUserTask(activityInstanceId, getSession().getUserId());
processAPI.executeFlowNode(activityInstanceId);
return null;
}
};
final ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.submit(task).get();
waitForPendingTask();
final Map<String, Object> urlContext = new HashMap<String, Object>();
final String formId = "subProcess--1.0--Approval$entry";
urlContext.put(FormServiceProviderUtil.FORM_ID, formId);
urlContext.put(FormServiceProviderUtil.TASK_UUID, subprocessActivityInstanceId);
final Map<String, Object> context = new HashMap<String, Object>();
context.put(FormServiceProviderUtil.URL_CONTEXT, urlContext);
context.put(FormServiceProviderUtil.LOCALE, Locale.ENGLISH);
context.put(FormServiceProviderUtil.API_SESSION, getSession());
final FormServiceProvider formServiceProvider = FormServiceProviderFactory.getFormServiceProvider(getSession().getTenantId());
final FormURLComponents formURLComponents = formServiceProvider.getNextFormURLParameters(formId, context);
Assert.assertNotNull(formURLComponents);
Assert.assertEquals("Confirmation", formURLComponents.getTaskName());
} finally {
removeProcessAndSubProcess(subProcessDefinition, intermediateSubProcessDefinition, processDefinition, parentProcessInstanceId);
}
}
@Test
public void testGetNextFormURLParametersFromParentprocessTask() throws Exception {
final org.bonitasoft.engine.identity.User user = getInitiator().getUser();
final ProcessDefinition subProcessDefinition = createSubprocess(user);
final ProcessDefinition intermediateSubProcessDefinition = createIntermediateSubprocess(user);
final ProcessDefinition processDefinition = createParentProcess(user);
processAPI = TenantAPIAccessor.getProcessAPI(getSession());
final long parentProcessInstanceId = processAPI.startProcess(processDefinition.getId()).getId();
try {
final long activityInstanceId = waitForPendingTask();
//Create a thread to simulate a call to the forms servlet (and have the task archived)
final Callable<Void> task = new Callable<Void>() {
@Override
public Void call() throws Exception {
final long activityInstanceId = waitForPendingTask();
processAPI.assignUserTask(activityInstanceId, getSession().getUserId());
processAPI.executeFlowNode(activityInstanceId);
return null;
}
};
final ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.submit(task).get();
waitForPendingTask();
final Map<String, Object> urlContext = new HashMap<String, Object>();
final String formId = "parentProcess--1.0--Request$entry";
urlContext.put(FormServiceProviderUtil.FORM_ID, formId);
urlContext.put(FormServiceProviderUtil.TASK_UUID, activityInstanceId);
final Map<String, Object> context = new HashMap<String, Object>();
context.put(FormServiceProviderUtil.URL_CONTEXT, urlContext);
context.put(FormServiceProviderUtil.LOCALE, Locale.ENGLISH);
context.put(FormServiceProviderUtil.API_SESSION, getSession());
final FormServiceProvider formServiceProvider = FormServiceProviderFactory.getFormServiceProvider(getSession().getTenantId());
final FormURLComponents formURLComponents = formServiceProvider.getNextFormURLParameters(formId, context);
Assert.assertNotNull(formURLComponents);
Assert.assertEquals("Approval", formURLComponents.getTaskName());
} finally {
removeProcessAndSubProcess(subProcessDefinition, intermediateSubProcessDefinition, processDefinition, parentProcessInstanceId);
}
}
@Test
public void testGetNextFormURLParametersFromParentprocessInstance() throws Exception {
final org.bonitasoft.engine.identity.User user = getInitiator().getUser();
final ProcessDefinition subProcessDefinition = createSubprocess(user);
final ProcessDefinition intermediateSubProcessDefinition = createIntermediateSubprocess(user);
final ProcessDefinition processDefinition = createParentProcess(user);
processAPI = TenantAPIAccessor.getProcessAPI(getSession());
//Create a thread to simulate a call to the forms servlet
final Callable<Long> task = new Callable<Long>() {
@Override
public Long call() throws Exception {
return processAPI.startProcess(processDefinition.getId()).getId();
}
};
final ExecutorService executorService = Executors.newSingleThreadExecutor();
final Long parentProcessInstanceId = executorService.submit(task).get();
try {
waitForPendingTask();
final Map<String, Object> urlContext = new HashMap<String, Object>();
final String formId = "parentProcess--1.0$entry";
urlContext.put(FormServiceProviderUtil.FORM_ID, formId);
urlContext.put(FormServiceProviderUtil.INSTANCE_UUID, parentProcessInstanceId);
final Map<String, Object> context = new HashMap<String, Object>();
context.put(FormServiceProviderUtil.URL_CONTEXT, urlContext);
context.put(FormServiceProviderUtil.LOCALE, Locale.ENGLISH);
context.put(FormServiceProviderUtil.API_SESSION, getSession());
final FormServiceProvider formServiceProvider = FormServiceProviderFactory.getFormServiceProvider(getSession().getTenantId());
final FormURLComponents formURLComponents = formServiceProvider.getNextFormURLParameters(formId, context);
Assert.assertNotNull(formURLComponents);
Assert.assertEquals("Request", formURLComponents.getTaskName());
} finally {
removeProcessAndSubProcess(subProcessDefinition, intermediateSubProcessDefinition, processDefinition, parentProcessInstanceId);
}
}
protected void removeProcessAndSubProcess(final ProcessDefinition subProcessDefinition, final ProcessDefinition intermediateSubProcessDefinition,
final ProcessDefinition processDefinition,
final Long parentProcessInstanceId) throws DeletionException, ProcessDefinitionNotFoundException, ProcessActivationException {
deleteProcess(processDefinition.getId());
deleteProcess(intermediateSubProcessDefinition.getId());
deleteProcess(subProcessDefinition.getId());
}
protected ProcessDefinition createParentProcess(final org.bonitasoft.engine.identity.User user) throws InvalidExpressionException,
InvalidProcessDefinitionException, InvalidBusinessArchiveFormatException, AlreadyExistsException, ProcessDeployException, CreationException,
ProcessDefinitionNotFoundException, ProcessEnablementException {
final ProcessDefinitionBuilder processBuilder = new ProcessDefinitionBuilder().createNewInstance("parentProcess", "1.0");
processBuilder.addActor("myActor");
final ExpressionBuilder expressionBuilder = new ExpressionBuilder();
processBuilder.addCallActivity("CallActivity",
expressionBuilder.createNewInstance("processName").setContent("intermediateSubProcess").setExpressionType(ExpressionType.TYPE_CONSTANT)
.setReturnType(String.class.getName()).done(), expressionBuilder.createNewInstance("processVersion").setContent("1.0")
.setExpressionType(ExpressionType.TYPE_CONSTANT)
.setReturnType(String.class.getName()).done());
processBuilder.addUserTask("Request", "myActor");
processBuilder.addTransition("Request", "CallActivity");
processBuilder.addUserTask("Confirmation", "myActor");
processBuilder.addTransition("CallActivity", "Confirmation");
final DesignProcessDefinition designProcessDefinition = processBuilder.done();
final BusinessArchiveBuilder businessArchiveBuilderProcess = new BusinessArchiveBuilder().createNewBusinessArchive();
final BusinessArchive businessArchive = businessArchiveBuilderProcess
.setFormMappings(TestProcess.createDefaultProcessFormMapping(designProcessDefinition))
.setProcessDefinition(designProcessDefinition).done();
final ProcessDefinition processDefinition = processAPI.deploy(businessArchive);
final ActorInstance processActor = processAPI.getActors(processDefinition.getId(), 0, 1, ActorCriterion.NAME_ASC).get(0);
processAPI.addUserToActor(processActor.getId(), user.getId());
processAPI.enableProcess(processDefinition.getId());
return processDefinition;
}
protected ProcessDefinition createIntermediateSubprocess(final org.bonitasoft.engine.identity.User user)
throws InvalidProcessDefinitionException,
InvalidBusinessArchiveFormatException, AlreadyExistsException, ProcessDeployException, CreationException, ProcessDefinitionNotFoundException,
ProcessEnablementException, InvalidExpressionException, IllegalArgumentException {
final ProcessDefinitionBuilder subProcessBuilder = new ProcessDefinitionBuilder().createNewInstance("intermediateSubProcess", "1.0");
final ExpressionBuilder expressionBuilder = new ExpressionBuilder();
subProcessBuilder.addCallActivity("CallActivity",
expressionBuilder.createNewInstance("processName").setContent("subProcess").setExpressionType(ExpressionType.TYPE_CONSTANT)
.setReturnType(String.class.getName()).done(), expressionBuilder.createNewInstance("processVersion").setContent("1.0")
.setExpressionType(ExpressionType.TYPE_CONSTANT)
.setReturnType(String.class.getName()).done());
final DesignProcessDefinition designSubProcessDefinition = subProcessBuilder.done();
final BusinessArchiveBuilder businessArchiveBuilderSubProcess = new BusinessArchiveBuilder().createNewBusinessArchive();
final BusinessArchive businessArchiveSubProcess = businessArchiveBuilderSubProcess.setProcessDefinition(designSubProcessDefinition).done();
final ProcessDefinition subProcessDefinition = processAPI.deploy(businessArchiveSubProcess);
processAPI.enableProcess(subProcessDefinition.getId());
return subProcessDefinition;
}
protected ProcessDefinition createSubprocess(final org.bonitasoft.engine.identity.User user)
throws InvalidProcessDefinitionException,
InvalidBusinessArchiveFormatException, AlreadyExistsException, ProcessDeployException, CreationException, ProcessDefinitionNotFoundException,
ProcessEnablementException {
final ProcessDefinitionBuilder subProcessBuilder = new ProcessDefinitionBuilder().createNewInstance("subProcess", "1.0");
subProcessBuilder.addActor("myActor");
subProcessBuilder.addUserTask("Approval", "myActor");
final DesignProcessDefinition designSubProcessDefinition = subProcessBuilder.done();
final BusinessArchiveBuilder businessArchiveBuilderSubProcess = new BusinessArchiveBuilder().createNewBusinessArchive();
final BusinessArchive businessArchiveSubProcess = businessArchiveBuilderSubProcess
.setFormMappings(TestProcess.createDefaultProcessFormMapping(designSubProcessDefinition))
.setProcessDefinition(designSubProcessDefinition).done();
final ProcessDefinition subProcessDefinition = processAPI.deploy(businessArchiveSubProcess);
final ActorInstance subProcessActor = processAPI.getActors(subProcessDefinition.getId(), 0, 1, ActorCriterion.NAME_ASC).get(0);
processAPI.addUserToActor(subProcessActor.getId(), user.getId());
processAPI.enableProcess(subProcessDefinition.getId());
return subProcessDefinition;
}
protected void terminateProcessInstance(final long processInstanceId) throws Exception, UpdateException, FlowNodeExecutionException {
Assert.assertTrue("no pending user task instances are found", new WaitUntil(50, 3000) {
@Override
protected boolean check() throws Exception {
return processAPI.getPendingHumanTaskInstances(getSession().getUserId(), 0, 10, null).size() >= 1;
}
}.waitUntil());
long activityInstanceId = processAPI.getPendingHumanTaskInstances(getSession().getUserId(), 0, 1, ActivityInstanceCriterion.NAME_ASC).get(0).getId();
processAPI.assignUserTask(activityInstanceId, getSession().getUserId());
processAPI.executeFlowNode(activityInstanceId);
Assert.assertTrue("no pending user task instances are found", new WaitUntil(50, 3000) {
@Override
protected boolean check() throws Exception {
return processAPI.getPendingHumanTaskInstances(getSession().getUserId(), 0, 10, null).size() >= 1;
}
}.waitUntil());
activityInstanceId = processAPI.getPendingHumanTaskInstances(getSession().getUserId(), 0, 1, ActivityInstanceCriterion.NAME_ASC).get(0).getId();
processAPI.assignUserTask(activityInstanceId, getSession().getUserId());
processAPI.executeFlowNode(activityInstanceId);
Assert.assertTrue("no archived process isnatnce was found", new WaitUntil(50, 3000) {
@Override
protected boolean check() throws Exception {
final SearchOptionsBuilder builder = new SearchOptionsBuilder(0, 1);
builder.filter(ArchivedProcessInstancesSearchDescriptor.SOURCE_OBJECT_ID, processInstanceId);
return processAPI.searchArchivedProcessInstances(builder.done()).getCount() == 1;
}
}.waitUntil());
}
protected long waitForPendingTask() throws Exception {
Assert.assertTrue("no pending user task instances are found", new WaitUntil(50, 3000) {
@Override
protected boolean check() throws Exception {
return processAPI.getPendingHumanTaskInstances(getSession().getUserId(), 0, 10,
null).size() >= 1;
}
}.waitUntil());
final long activityInstanceId = processAPI.getPendingHumanTaskInstances(getSession().getUserId(), 0, 1, ActivityInstanceCriterion.NAME_ASC)
.get(0).getId();
return activityInstanceId;
}
}