Access a business data object using the Java API (V 7.1.4)

1
+1
-1

Hello.

I've not found any operation in the Java Engine API to retrieve a business data object associated with a process instance, given its id for example.

The BusinessDataAPI.getProcessBusinessDataReference() doesn't seem to be the good way.

And I've not seen any solution from the ProcessAPI...

Anyone can help me ?

Thanks a lot.

Regards.

Comments

Submitted by antoine.mottier on Tue, 12/29/2015 - 11:33

From which context do you access the Java Engine API?

For example in Bonita BPM Groovy script you have DAO object that let you access business data objects.

Submitted by ephemeris.lappis on Tue, 12/29/2015 - 11:47

Hello.

I'm using the Java API for an external access from our ESB (ServiceMix), not inside the process itself.

The Java API let me access all the processes and tasks data and operations, but I've not found any working way to get their associated business data objects.

I've tried the BusinessDataAPI. Somthing like that, where "p" is a ProcessInstance.

BusinessDataAPI businessDataAPI = TenantAPIAccessor.getBusinessDataAPI(session);
List dataReferences = businessDataAPI.getProcessBusinessDataReferences(p.getId(), 0, Integer.MAX_VALUE);
System.out.println(">>> Data of process " + p.getId());
for (BusinessDataReference dr : dataReferences) {
System.out.println(" > " + dr.getName() + " / " + dr.getType());
}

But an exception is thrown :

Exception in thread "main" com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter$UnknownFieldException: No such field org.bonitasoft.engine.business.data.impl.SimpleBusinessDataReferenceImpl.storageIdAsString
---- Debugging information ----
field : storageIdAsString
class : org.bonitasoft.engine.business.data.impl.SimpleBusinessDataReferenceImpl
required-type : org.bonitasoft.engine.business.data.impl.SimpleBusinessDataReferenceImpl
converter-type : com.thoughtworks.xstream.converters.reflection.ReflectionConverter
path : /list/org.bonitasoft.engine.business.data.impl.SimpleBusinessDataReferenceImpl/storageIdAsString
line number : 7
class[1] : java.util.ArrayList
converter-type[1] : com.thoughtworks.xstream.converters.collections.CollectionConverter

version : null

at org.bonitasoft.engine.api.HTTPServerAPI.invokeMethod(HTTPServerAPI.java:143)
at org.bonitasoft.engine.api.impl.ClientInterceptor.invoke(ClientInterceptor.java:88)
at com.sun.proxy.$Proxy5.getProcessBusinessDataReferences(Unknown Source)
at my.tests.bonita.t1.Test1.main(Test1.java:88)
at  < ========== Beginning of the server stack trace ========== >. ( )
at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.determineType(AbstractReflectionConverter.java:453)
at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:294)
at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:234)
at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72)
at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65)
at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66)
at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:50)
at com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter.readItem(AbstractCollectionConverter.java:71)
at com.thoughtworks.xstream.converters.collections.CollectionConverter.addCurrentElementToCollection(CollectionConverter.java:79)
at com.thoughtworks.xstream.converters.collections.CollectionConverter.populateCollection(CollectionConverter.java:72)
at com.thoughtworks.xstream.converters.collections.CollectionConverter.populateCollection(CollectionConverter.java:66)
at com.thoughtworks.xstream.converters.collections.CollectionConverter.unmarshal(CollectionConverter.java:61)
at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72)
at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65)
at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66)
at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:50)
at com.thoughtworks.xstream.core.TreeUnmarshaller.start(TreeUnmarshaller.java:134)
at com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.unmarshal(AbstractTreeMarshallingStrategy.java:32)
at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1052)
at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1024)
at com.thoughtworks.xstream.XStream$2.readFromStream(XStream.java:1716)
at com.thoughtworks.xstream.core.util.CustomObjectInputStream.readObjectOverride(CustomObjectInputStream.java:104)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:365)
at org.bonitasoft.engine.api.HTTPServerAPI.fromXML(HTTPServerAPI.java:257)
at org.bonitasoft.engine.api.HTTPServerAPI.checkInvokeMethodReturn(HTTPServerAPI.java:152)
at org.bonitasoft.engine.api.HTTPServerAPI.invokeMethod(HTTPServerAPI.java:136)
at org.bonitasoft.engine.api.impl.ClientInterceptor.invoke(ClientInterceptor.java:88)
at com.sun.proxy.$Proxy5.getProcessBusinessDataReferences(Unknown Source)
at my.tests.bonita.t1.Test1.main(Test1.java:88)

Any idea about this exception, or another way of retrieving data from ProcessInstance ?

Thanks again.

Regards.

4 answers

1
+2
-1

Hi Pedro,

In Bonita versions 7.8+... there are several options to retrieve those jar files bdm-dao.jar and bdm-model.jar:

Hope this helps,

Emmanuel

1
+2
-1

**Edit**: my initial answer was incorrect, here is a solution to access a business data object using Bonita BPM Java client library configured to access Bonita BPM Engine over HTTP.

This Java code use BusinessDataAPI and DAO classes to access Business Data variables content:

// bonita-client library configuration to connect to Bonita BPM Engine
Map<String, String> map = new HashMap<>();
map.put("server.url", "http://localhost:8080/");
map.put("application.name", "bonita");
APITypeManager.setAPITypeAndParams(ApiAccessType.HTTP, map);

// Login
LoginAPI loginAPI = TenantAPIAccessor.getLoginAPI();
APISession session = loginAPI.login("walter.bates", "bpm");

// Get a reference to BusinessDataAPI
BusinessDataAPI businessDataAPI = TenantAPIAccessor.getBusinessDataAPI(session);

// Use BusinessDataAPI to retrieve the process instance business variable
// We need to cast it to the appropriate class (SimpleBusinessDataReference or MultipleBusinessDataReference)
SimpleBusinessDataReference businessDataReference = (SimpleBusinessDataReference)businessDataAPI.getProcessBusinessDataReference("vacationAvailable", 2);

// Get storage id (i.e. persistence id) of the business variable
Long storageId = businessDataReference.getStorageId();

// Create DAO for the business data
BusinessObjectDAOFactory daoFactory = new BusinessObjectDAOFactory();
VacationAvailableDAO vacationAvailableDAO = daoFactory.createDAO(session, VacationAvailableDAO.class);

// Use DAO to find the business variable using the storage id (i.e. persistence id)
VacationAvailable vacationAvailable = vacationAvailableDAO.findByPersistenceId(storageId);

In your project dependencies you need:

<dependency>
<groupId>org.bonitasoft.bdm</groupId>
<artifactId>bdm-dao</artifactId>
<version>0.0.2-SNAPSHOT</version>
<scope>system</scope>
<systemPath>/path/to/bdm-dao.jar</systemPath>
</dependency>
<dependency>
<groupId>org.bonitasoft.bdm</groupId>
<artifactId>bdm-model</artifactId>
<version>0.0.2-SNAPSHOT</version>
<scope>system</scope>
<systemPath>/path/to/bdm-model.jar</systemPath>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.18.1-GA</version>
</dependency>
<dependency>
<groupId>org.bonitasoft.engine</groupId>
<artifactId>bonita-client</artifactId>
<version>7.1.4</version>
</dependency>

You can get bdm-dao.jar and bdm-model.jar in BONITA_HOME/engine-server/work/tenants/1/data-management-client/client-bdm.zip file.

The DAO classes benefit from Bonita Java client library to access to remote engine.

Comments

Submitted by ephemeris.lappis on Tue, 12/29/2015 - 12:26

Hello.
Your answer is a bit surprising !
What does the BusinessDataAPI actually does or aims to do ?
The REST API seems no to be so easy to integrate, and needs wrapping code while the Java API is ready to use.
Is there an example of business data access in Java code using any of the APIs ?
Thanks again.

Submitted by antoine.mottier on Fri, 01/08/2016 - 14:26

Actually I was wrong and I just update my answer with a solution to use BusinessDataAPI to get the business variable information of a process instance (id of the instance is static in my example: 2) and DAO to get the actual value of the variable.

Hope this helps.

Submitted by amitroyes3 on Fri, 01/15/2016 - 07:06

hello ,
i tried same code and i have this error

result = businessDataAPI.getProcessBusinessDataReferences(pendingTask.getParentProcessInstanceId(), 0, 100);
BusinessObjectDAOFactory daoFactory = new BusinessObjectDAOFactory();
SurgeryDAO sD = daoFactory.createDAO(session, SurgeryDAO.class);
SimpleBusinessDataReference sbdr=(SimpleBusinessDataReference)result[0];

        try{
             Surgery ks= sD.findByPersistenceId(sbdr.getStorageId())

        }catch(Exception e){

        }

WARNING: Exception or error caught in server resource
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
C:\BonitaBPMSubscription-7.1.0\workspace\tomcat\bonita\client\tenants\1\work\pages\custompage_datasource\Peningtask.groovy: 21: unable to resolve class com.company.model.SurgeryDAO
@ line 21, column 1.
import com.company.model.SurgeryDAO;
^

C:\BonitaBPMSubscription-7.1.0\workspace\tomcat\bonita\client\tenants\1\work\pages\custompage_datasource\Peningtask.groovy: 20: unable to resolve class com.company.model.Surgery
@ line 20, column 1.
import com.company.model.Surgery;
^

Submitted by antoine.mottier on Mon, 01/18/2016 - 09:01

Your Business Object definition (the Java class com.company.model.SurgeryDAO) is packaged in the bdm-model.jar and required DAO implementation is packaged in bdm-dao.jar.

So you need to includes those to JAR files in your application classloader.

You can get those jar files in client-bdm.zipfile located in BonitaBPMCommunity-7.1.5/workspace/tomcat/bonita/engine-server/work/tenants/1/data-management-client (when Studio is running)

Submitted by pedrociarlini on Fri, 04/24/2020 - 20:21

Hi everyone. Thanks for your answer, Antoine.

I'm trying to do the same on Bonita Studio 7.10.3.

At this version, the bdm-dao.jar and bdm-model.jar files appears to be missing with these names. I found at "/workspace/tomcat/server/temp/bonita_engine_@.local/platform/classloaders/local/TENANT/1/" the file named "BDR.jar.nnnn.jar", with "Entity**DAOImpl", "Entity**DAO" and "Entity**" classes.

This is the way for this version?

1
0
-1

Hello Antoine.

First, thanks for your new answer.

I've already seen the kind of integration example you explain. I've already had a look at the location and content of the DAO JARs in my studio folders.

It seems a bit difficult to go on this way, mainly because of the integration process that makes java code of our ESB modules depending on generated JARs that may change often during the cycles of an agile project. More, the DAO dependencies are not easy to manage when several persons both work on Bonita processes design and ESB services code.

I think I will try the solution you describe to evaluate it, but te REST API, despite my first idea, seems to be the preferred way to access business objects. It doesn't constrain services development with instable DAO code. Although it needs a bit of wrapping code (for example using Spring RestTemplate), it also avoids the packaging of the Bonita Java dependencies.

I go on testing both solutions, and come back to give you feedback about my results.

Any advice from you is welcome !

Thanks again.

Regards.

1
-1
-1

thanks for your reply but i have added those two jar to project by buildpath and maven try with both the ways still it gives exception when i deploy it to portal and call that api

Comments

Submitted by antoine.mottier on Mon, 01/25/2016 - 11:08

Can you share all your project files so I can take a look and maybe figure out the issue?

Also please reply using the "Add new comment" link below as you are not posting a new answer to the original question.

Submitted by amitroyes3 on Wed, 01/27/2016 - 10:59

pending task groovy

import groovy.json.JsonBuilder;
import groovy.sql.Sql;

import java.util.logging.Logger;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;

import org.bonitasoft.console.common.server.page.*;
import org.bonitasoft.engine.api.*;
import org.bonitasoft.engine.bdm.*;
import org.bonitasoft.engine.bpm.flownode.ActivityInstanceCriterion;
import org.bonitasoft.engine.bpm.flownode.HumanTaskInstance;
import org.bonitasoft.engine.business.data.SimpleBusinessDataReference;
import org.bonitasoft.engine.session.APISession;

import com.company.model.KneeSurgery;
import com.company.model.KneeSurgeryDAO;
//import com.company.model.KneeSurgeryDAO;

class Peningtask implements RestApiController {

RestApiResponse doHandle(HttpServletRequest request, PageResourceProvider pageResourceProvider, PageContext pageContext, RestApiResponseBuilder apiResponseBuilder, RestApiUtil restApiUtil) {
     List<HumanTaskInstance> pendingTasks= new ArrayList();
     List result=new ArrayList();
     final LoginAPI loginAPI = TenantAPIAccessor.getLoginAPI();


 //System.out.println("login with install//install");
 final APISession session = pageContext.getApiSession();

/*  final ProcessAPI processAPI = TenantAPIAccessor.getProcessAPI();
    final List<HumanTaskInstance> pendingTasks =processAPI.getPendingHumanTaskInstances(3,
        0, 20, ActivityInstanceCriterion.PRIORITY_ASC);*/

// System.out.println("Pending tasks for user " + session.getUserName() + ": " + pendingTasks);

    try{


    final ProcessAPI processAPI=TenantAPIAccessor.getProcessAPI(session);
    pendingTasks =processAPI.getAssignedHumanTaskInstances(session.getUserId(),
        0, 20, ActivityInstanceCriterion.PRIORITY_ASC);

    //buildErrorResponse(apiResponseBuilder, "getProcessInstance="+processAPI.getProcessInstance(pendingTask.getParentProcessInstanceId()).toString(), restApiUtil.logger);
    for ( HumanTaskInstance pendingTask : pendingTasks) {
        buildErrorResponse(apiResponseBuilder, "For loop="+processAPI.getProcessInstance(pendingTask.getParentProcessInstanceId()).toString(), restApiUtil.logger);

            BusinessDataAPI businessDataAPI = TenantAPIAccessor.getBusinessDataAPI(session);
            result = businessDataAPI.getProcessBusinessDataReferences(pendingTask.getParentProcessInstanceId(), 0, 100);
            BusinessObjectDAOFactory daoFactory = new BusinessObjectDAOFactory();
            KneeSurgeryDAO ksD = daoFactory.createDAO(session, KneeSurgeryDAO.class);
            SimpleBusinessDataReference sbdr=(SimpleBusinessDataReference)result[0];
            buildErrorResponse(apiResponseBuilder, "SimpleBusinessDataReference="+sbdr, restApiUtil.logger);

        //KneeSurgery ks = KneeSurgeryDAO.findByPersistenceId
        try{
             KneeSurgery ks= ksD.findByPersistenceId(sbdr.getStorageId())
         buildErrorResponse(apiResponseBuilder, "KneeSurgery="+ks, restApiUtil.logger);
        }catch(Exception e){
        buildErrorResponse(apiResponseBuilder, "Kneesurgery Error="+e.getMessage(), restApiUtil.logger);
        continue;
        }
         //findByPersistenceId(sbdr.getStorageId());
                    //  KneeSurgeryDAO ks=
        //processAPI.getProcessDataInstance("kneeReplacementInput",pendingTask.parentProcessInstanceId);
        //AccessorUtil.getQueryDefinitionAPI().getProcessDataField(uuid,varName)
        buildErrorResponse(apiResponseBuilder, "result="+result, restApiUtil.logger);
        }



    }catch(Exception e){
        return buildErrorResponse(apiResponseBuilder, "Error="+e.getMessage(), restApiUtil.logger)
    }
    //System.out.println("logged out");


     /*

    String queryId = request.getParameter "queryId"
    if (queryId == null) {
        return buildErrorResponse(apiResponseBuilder, "the parameter queryId is missing",restApiUtil.logger)
    }
    String query = getQuery queryId, pageResourceProvider
    if (query == null) {
        return buildErrorResponse(apiResponseBuilder, "the queryId does not refer to an existing query", restApiUtil.logger)
    }
    Map<String, String> params = getSqlParameters request
    Sql sql = buildSql pageResourceProvider*/
    try {
        def rows =pendingTasks+result;//"hello world";// params.isEmpty() ? sql.rows(query) : sql.rows(query, params)
        JsonBuilder builder = new JsonBuilder(rows)
        String table = builder.toPrettyString()
        return buildResponse(apiResponseBuilder, table)
    } finally {
       // sql.close()
    }
}

protected RestApiResponse buildErrorResponse(RestApiResponseBuilder apiResponseBuilder, String message, Logger logger ) {
    logger.severe message

    Map<String, String> result = [:]
    result.put "error", message
    apiResponseBuilder.withResponseStatus(HttpServletResponse.SC_BAD_REQUEST)
    buildResponse apiResponseBuilder, result
}

protected RestApiResponse buildResponse(RestApiResponseBuilder apiResponseBuilder, Serializable result) {
    apiResponseBuilder.with {
        withResponse(result)
        build()
    }
}

}

displayName=Rest API extension - Generic DataSource
name=custompage_datasource
description=Rest API extension - Generic DataSource

zip is a rest api extension

contentType=apiExtension

list of api extension in zip

apiExtensions = datasource

datasource.method = GET
datasource.pathTemplate = pendingtask
datasource.classFileName = Peningtask.groovy
datasource.permissions = demoPermission

pom.xml

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
org.bonitasoft.example
rest-api-sql-datasource
1.0-SNAPSHOT

jar <bonita.version>7.0.1</bonita.version>
<groovy.version>2.4.3-01</groovy.version>


maven-restlet
Public online Restlet repository
http://maven.restlet.com




javax.servlet
servlet-api
2.5
provided


org.bonitasoft.engine
bonita-client
${bonita.version}
compile

    <dependency>
        <groupId>org.bonitasoft.engine</groupId>
        <artifactId>bonita-server</artifactId>
        <version>7.1.5</version>
    </dependency>


    <!-- test -->
    <dependency>
        <groupId>org.restlet.jse</groupId>
        <artifactId>org.restlet</artifactId>
        <version>2.1.7</version>
        <scope>test</scope>
    </dependency>
    <!-- <dependency> <groupId>org.spockframework</groupId> <artifactId>spock-core</artifactId> 
        <version>0.7-groovy-1.8</version> <scope>test</scope> </dependency> -->

    <dependency>
        <groupId>org.spockframework</groupId>
        <artifactId>spock-core</artifactId>
        <version>1.0-groovy-2.4</version>
    </dependency>


    <dependency> <!-- enables mocking of classes (in addition to interfaces) -->
        <groupId>cglib</groupId>
        <artifactId>cglib-nodep</artifactId>
        <version>2.2</version>
        <scope>test</scope>
    </dependency>
    <dependency> <!-- enables mocking of classes without default constructor (together with 
            CGLIB) -->
        <groupId>org.objenesis</groupId>
        <artifactId>objenesis</artifactId>
        <version>1.2</version>
        <scope>test</scope>
    </dependency>


    <!--........................................................... -->

    <dependency>
        <groupId>org.bonitasoft.bdm</groupId>
        <artifactId>bdm-client-pojo</artifactId>
        <version>0.0.2-SNAPSHOT</version>
        <scope>system</scope>
        <systemPath>C:\BonitaBPMSubscription-7.1.0\workspace\BonitaCareCoordination\lib</systemPath>
    </dependency>
    <dependency>
        <groupId>org.bonitasoft.bdm</groupId>
        <artifactId>bdm-model</artifactId>
        <version>0.0.2-SNAPSHOT</version>
        <scope>system</scope>
        <systemPath>D:/bdm-model.jar</systemPath>
    </dependency>
    <dependency>
        <groupId>org.javassist</groupId>
        <artifactId>javassist</artifactId>
        <version>3.18.1-GA</version>
    </dependency>
    <dependency>
        <groupId>org.bonitasoft.engine</groupId>
        <artifactId>bonita-client</artifactId>
        <version>7.1.4</version>
    </dependency>


    <!-- .......................................................... -->
</dependencies>

<build>
    <finalName>${project.artifactId}</finalName>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
        </resource>
    </resources>

    <sourceDirectory>src/main/groovy</sourceDirectory>
    <testSourceDirectory>src/test/groovy</testSourceDirectory>

    <plugins>

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.3</version>
            <configuration>
                <source>1.7</source>
                <target>1.7</target>
                <compilerId>groovy-eclipse-compiler</compilerId>
            </configuration>
            <dependencies>
                <dependency>
                    <groupId>org.codehaus.groovy</groupId>
                    <artifactId>groovy-eclipse-compiler</artifactId>
                    <version>2.9.2-01</version>
                </dependency>
                <dependency>
                    <groupId>org.codehaus.groovy</groupId>
                    <artifactId>groovy-eclipse-batch</artifactId>
                    <version>${groovy.version}</version>
                </dependency>
            </dependencies>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.4.1</version>
            <executions>
                <execution>
                    <id>page-content</id>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                    <inherited>false</inherited>
                    <configuration>
                        <ignoreDirFormatExtensions>true</ignoreDirFormatExtensions>
                        <appendAssemblyId>false</appendAssemblyId>
                        <descriptors>
                            <descriptor>content.xml</descriptor>
                        </descriptors>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Submitted by antoine.mottier on Wed, 01/27/2016 - 11:03

Can you please share all that using Dropbox or Google Drive?

That is not really readable when posted in the forum.

Thanks

Notifications