Custom API Rest using Camunda Tasklist

1,806 views
Skip to first unread message

Fer

unread,
Mar 11, 2014, 5:40:57 AM3/11/14
to camunda-...@googlegroups.com
Hello again,

I'm developing a webapp that will be used with Tasklist and Cockpit. I use JPA for my business data and I want to have dynamic forms to manage/show the data as I explained here. I still have some problems to be used in production, but we're working on it. The design solution I chose was to create a custom REST API to manage this data from the database and show it in the embedded forms that are displayed in the user tasks of the business processes of Camunda.

I want to use an integrated jax-rs application with Jersey that will fetch the task ID from the URL, will send this task ID to this custom REST API I want to implement via AJAX, and internally I will communicate with the current Camunda engine (SpringJPAProcessEngine, in this case) and with my business services to retrieve data from the database, convert it to JSON and then return it to the client browser, where Angular.js will process it and show it accordingly. I don't know if this is the best option, because it looks complex, but I don't know how to do it in any other way.

I've checked this example (Embedded Spring REST) and tried to understand how it works, but I don't get how it works internally, so I don't see how I can use that code to implement what I want. Furthermore, you need a vanilla tomcat and I use the prepackaged distribution with changes in the configuration and libraries, so I guess I'll soon face a lot of problems. Anyway, I coded a resource file for the API that should return basic information:

@ApplicationPath("/rest")
@Path("/inventory")
public class InventoryResourceImpl extends Application implements InventoryResourceI {
   
   
@Autowired
   
private InventoryServiceI is;    

   
@GET
   
@Path("/get")
   
@Produces(MediaType.APPLICATION_JSON)
   
public Inventory getInventory() {
       
       
return is.getInventory();
   
}

}

My problem is that I don't know how to set the rest of the configuration and access the URLs of the API endpoints. My web.xml looks like this:

<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"

   
version="3.0">

   
<context-param>
       
<param-name>contextConfigLocation</param-name>
       
<param-value>classpath:/applicationContext.xml</param-value>
   
</context-param>

   
<listener>
       
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
   
</listener>

</web-app>

According to this, the URL should be something like that:
http://{hostname}:{port}/{context_root_of_Web_ module}/{valu...@javax.ws.rs.ApplicationPath}}/{valu...@javax.ws.rs.Path}


Which is the context root of web module with all this configuration? I know the AppPath and the Path itself since I set it in the file above, but I don't know the base URL.

What am I missing and where I can find a specific example of what I want? I could post the whole code if needed (a lot of changes after building the war file are needed), but I think it's not necessary for the moment.


Thanks for your time and I hope this can also helps other people. Regards.

Fer

unread,
Mar 11, 2014, 9:11:06 AM3/11/14
to camunda-...@googlegroups.com
UPDATE: It may seem stupid, but it was not for me in the moment. The base_url I was looking for is the .war filename, since it gets uncompressed and the folder is called like that. What if I would want to change this url slug?

Anyway, I'm dealing with another typical problem: a not injected autowired service, so I get NullPointerException. Somehow, the resource is not getting injected to the Spring configuration. I've tried to add it to the application context config file like this:

    <bean id="InventoryResourceImpl" class="com.gompute.workflow.inventory.InventoryResourceImpl" />


And also tagged the Resource as a @Component (@Service should work too, I think, as far as I know), but I still get the NullPointerException. Would any of you indicate what's wrong with this whole configuration for Camunda?

<beans xmlns="http://www.springframework.org/schema/beans"
       
xmlns:context="http://www.springframework.org/schema/context"
       
xmlns:tx="http://www.springframework.org/schema/tx"
       
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

   
<!-- Separated by commas -->
   
<context:component-scan base-package="es.fergomez.workflow.customer, es.fergomez.workflow.inventory" />
   
   
<!-- Usage of annotations (@Autowired...) -->
   
<context:annotation-config />

   
<bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
       
<property name="driverClass" value="org.h2.Driver" />
       
<property name="url" value="jdbc:h2:mem:camunda;DB_CLOSE_DELAY=1000" />
       
<property name="username" value="sa" />
       
<property name="password" value="" />
   
</bean>

   
<bean id="persistenceUnitManager"
       
class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
       
<property name="persistenceXmlLocation">
           
<value>classpath:/jpa-persistence.xml</value>
       
</property>
   
</bean>

   
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
       
<property name="persistenceUnitManager" ref="persistenceUnitManager" />
   
</bean>

   
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
       
<property name="entityManagerFactory" ref="entityManagerFactory" />
   
</bean>

   
<bean id="processEngineConfiguration" class="org.camunda.bpm.engine.spring.SpringProcessEngineConfiguration">
   
<!-- rename the engine otherwise it is called "default" and clashes with the default one -->
     
<property name="processEngineName" value="SpringJPAProcessEngine" />
     
<property name="databaseType" value="h2" />
     
<property name="dataSource" ref="dataSource" />
     
<property name="transactionManager" ref="transactionManager" />
     
<property name="databaseSchemaUpdate" value="true" />
     
<property name="jpaEntityManagerFactory" ref="entityManagerFactory" />
     
<property name="jpaHandleTransaction" value="true" />
     
<property name="jpaCloseEntityManager" value="true" />
     
<property name="jobExecutorActivate" value="false" />
     
<property name="deploymentResources" value="classpath*:diagrams/*.bpmn"/>
   
</bean>

   
<!-- use the managed process engine factory to register with the platform -->
   
<bean id="processEngine" class="org.camunda.bpm.engine.spring.container.ManagedProcessEngineFactoryBean">
     
<property name="processEngineConfiguration" ref="processEngineConfiguration" />
   
</bean>
   
<bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService" />
   
<bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService" />
   
<bean id="taskService" factory-bean="processEngine" factory-method="getTaskService" />
   
<bean id="historyService" factory-bean="processEngine"  factory-method="getHistoryService" />
   
<bean id="managementService" factory-bean="processEngine" factory-method="getManagementService" />
   
<bean id="formService" factory-bean="processEngine" factory-method="getFormService" />
   
   
<bean id="customerVariable" class="com.gompute.workflow.customer.CustomerVariable" />
   
<bean id="retrieveCustomerServiceTask" class="com.gompute.workflow.customer.RetrieveCustomerServiceTask" />
   
<bean id="retrieveAssetListServiceTask" class="com.gompute.workflow.inventory.RetrieveAssetListServiceTask" />
   
   
<bean class="com.gompute.workflow.inventory.InventoryResourceImpl" />

<!-- commented for tests, uncommented for tomcat -->
<!--   <bean id="processApplication" class="org.camunda.bpm.engine.spring.application.SpringServletProcessApplication"/> -->

</beans>

Thank you.
http://{hostname}:{port}/{context_root_of_Web_ module}/{valu...@javax.ws.rs.ApplicationPath}}/{value_o...@javax.ws.rs.Path}

Christian Lipphardt

unread,
Mar 11, 2014, 11:14:42 AM3/11/14
to camunda-...@googlegroups.com
Hi Fer,

Did you adjust the package names of

<!-- Separated by commas -->
   
<context:component-scan base-package="es.fergomez.workflow.customer, es.fergomez.workflow.inventory" />

to match your current packages?

Cheers,
Christian

Fer

unread,
Mar 11, 2014, 11:15:46 AM3/11/14
to camunda-...@googlegroups.com
Yes, everything works fine in the regular tests for JPA and so on, in fact.

Christian Lipphardt

unread,
Mar 11, 2014, 11:56:49 AM3/11/14
to camunda-...@googlegroups.com
So where do you get the problem? Inside UnitTests or when you deploy it
on the server?
Is the bean correctly referenced as an expression / delegate expression
inside the bpmn model xml?

Cheers
Christian

Fer

unread,
Mar 11, 2014, 12:10:26 PM3/11/14
to camunda-...@googlegroups.com
I have a logger attached to the function, so I can check if the Inventory Service is null or not. When I build the project and the .war file is created, I get no error and the logs say "Not null". Once I deploy the whole system and I try to run the corresponding URL, I get this:


HTTP Status 500 -

type
Exception report

message

description
The server encountered an internal error that prevented it from fulfilling this request.

exception java
.lang.NullPointerException
 es
.fergomez.workflow.inventory.InventoryResourceImpl.getInventory(InventoryResourceImpl.java:35)
 sun
.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 sun
.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
 sun
.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 java
.lang.reflect.Method.invoke(Method.java:616)
 com
.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60)
 com
.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$TypeOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:185)
 com
.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75)
 com
.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:302)
 com
.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
 com
.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:108)
 com
.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
 com
.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:84)
 com
.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1542)
 com
.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1473)
 com
.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1419)
 com
.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1409)
 com
.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:409)
 com
.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:540)
 com
.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:715)
 javax
.servlet.http.HttpServlet.service(HttpServlet.java:728)



Checking catalina.out:



 11 Mar 2014 16:57:41,330 [http-bio-8421-exec-3] INFO es.fergomez.workflow.inventory.InventoryResourceImpl:33 - NULL
Mar 11, 2014 4:57:41 PM com.sun.jersey.spi.container.ContainerResponse mapMappableContainerException
SEVERE
: The RuntimeException could not be mapped to a response, re-throwing to the HTTP container
java
.lang.NullPointerException
 at es
.fergomez.workflow.inventory.InventoryResourceImpl.getInventory(InventoryResourceImpl.java:35)
 at sun
.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun
.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
 at sun
.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 at java
.lang.reflect.Method.invoke(Method.java:616)
 at com
.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60)
 at com
.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$TypeOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:185)
 at com
.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75)
 at com
.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:302)
 at com
.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
 at com
.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:108)
 at com
.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
 at com
.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:84)
 at com
.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1542)
 at com
.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1473)
 at com
.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1419)
 at com
.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1409)
 at com
.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:409)
 at com
.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:540)
 at com
.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:715)
 at javax
.servlet.http.HttpServlet.service(HttpServlet.java:728)
 at org
.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
 at org
.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
 at org
.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
 at org
.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
 at org
.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
 at org
.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
 at org
.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
 at org
.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
 at org
.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
 at org
.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
 at org
.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
 at org
.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
 at org
.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
 at java
.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1146)
 at java
.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
 at java
.lang.Thread.run(Thread.java:679)
Mar 11, 2014 4:57:41 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE
: Servlet.service() for servlet [es.fergomez.workflow.inventory.InventoryResourceImpl] in context with path [/workflow-processes-0.0.2-SNAPSHOT] threw exception
java
.lang.NullPointerException
 at es
.fergomez.workflow.inventory.InventoryResourceImpl.getInventory(InventoryResourceImpl.java:35)
 at sun
.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun
.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
 at sun
.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 at java
.lang.reflect.Method.invoke(Method.java:616)
 at com
.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60)
 at com
.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$TypeOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:185)
 at com
.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75)
 at com
.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:302)
 at com
.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
 at com
.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:108)
 at com
.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
 at com
.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:84)
 at com
.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1542)
 at com
.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1473)
 at com
.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1419)
 at com
.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1409)
 at com
.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:409)
 at com
.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:540)
 at com
.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:715)
 at javax
.servlet.http.HttpServlet.service(HttpServlet.java:728)
 at org
.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
 at org
.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
 at org
.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
 at org
.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
 at org
.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
 at org
.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
 at org
.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
 at org
.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
 at org
.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
 at org
.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
 at org
.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
 at org
.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
 at org
.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
 at java
.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1146)
 at java
.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
 at java
.lang.Thread.run(Thread.java:679)




Any clue?

Christian Lipphardt

unread,
Mar 11, 2014, 3:58:28 PM3/11/14
to camunda-...@googlegroups.com
Hi Fer,

The problem is not related to camunda bpm, because I see you are using jersey as the JAX-RS implementation. If I remember correctly, you have to use some kind of jersey-spring dependency and some setup stuff in web.xml to make Jersey work with Spring Beans.

Cheers,
Christian

Fer

unread,
Mar 12, 2014, 11:28:54 AM3/12/14
to camunda-...@googlegroups.com
Hello,

I've already tried all that, check all the pages in Google (until the end!) and StackOverflow, with no luck. I was thinking that it really is a related problem to the configuration used with Camunda BPM, since JAX-RS works fine if I don't use the autowired service (no beans injected) and also if I don't deploy it in the prepackaged of Tomcat with Camunda BPM (the service is not null during the tests!). That may be due to the fact that when I deploy it in Tomcat to use it with Tasklist/Cockpit, I have to uncomment this in the applicationContext.xml:


<!--   <bean id="processApplication" class="org.camunda.bpm.engine.spring.application.SpringServletProcessApplication"/> -->

So during the tests there is another process application that is bound and allows the injection, but afterwords in Tomcat, with that bean declared in order to make it work with Tasklist or Cockpit, that process application does not bind it.

I've tried to autowire it manually like this in the empty constructor I added to the InventoryResource:
        org.camunda.bpm.engine.spring.application.SpringServletProcessApplication pa = new org.camunda.bpm.engine.spring.application.SpringServletProcessApplication();
        pa.getApplicationContext().getAutowireCapableBeanFactory().autowireBean(this);

But this does not make sense, because I'm creating a new one, and we need to get the current one (I don't know how). I'm really out of ideas, so I was just guessing. Could I get the current process application somehow and try to add the bean manually? I'm really lost and I've already checked the user guide twice:

http://docs.camunda.org/latest/guides/user-guide/#process-applications


I attach the .war file of the project so anybody can try to make it work if desired. Thank you and best regards.
workflow.war

Christian Lipphardt

unread,
Mar 12, 2014, 2:26:20 PM3/12/14
to camunda-...@googlegroups.com
Hi Fer,

I did a lot of modifications to your project, please use a diff tool like meld or winmerge to compare the two projects and see the differences, because there are so many.
I updated the testsuite, so the SpringServletProcessApplication is used and must not be commented anymore.

Cheers,
Christian
community-users-fer.zip

Fer

unread,
Mar 13, 2014, 8:43:51 AM3/13/14
to camunda-...@googlegroups.com
Hello, Christian,

After some modifications looking at your project I finally made it work! Thank you very much!

On the other hand, although I'm happy to have the project working, I also would like a brief explanation in order to understand it, so I can figure it out next time I face something similar. Could you tell us why you changed all that?


Thanks.
Reply all
Reply to author
Forward
0 new messages