WebServicesImplementation
|
In EmForge-0.22 we implemented new web-services for working with BPM information in EmForge (tasks, workflows and so on). Major idea was to implement one service, used in both - GUI (as standard Java class) and External Tools (via Web-Service wrappers). CXF
allowed us ealily do it.
These tutorials helped us very much - and, actually, here we will only discuss some special issues like:
All other implementation got from these tutorials.
First of all - need to add incubator repository:
<repositories>
<!-- Apache repository required for CXF -->
<repository>
<id>apache-snapshots</id>
<name>Apache SNAPSHOT Repository</name>
<url>http://people.apache.org/repo/m2-snapshot-repository/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>apache-incubating</id>
<name>Apache Incubating Repository</name>
<url>http://people.apache.org/repo/m2-incubating-repository/</url>
</repository>
<!-- for jaxb-impl -->
<repository>
<id>java.net</id>
<url>http://download.java.net/maven/1/</url>
<layout>legacy</layout>
</repository>
</repositories>
Second - add dependencies. In our case project splitted into 2 subprojects:
- declared service interface and Transfer Objects used in this interface
- EmForge with Web-Services implementation.
Actually, emforge-api declared java-interfaces and POJOs, so, in most cases no any extra dependencies is required, but - since we are using followed annotations:
we need to add dependency to ws-metadata (these annotations are included into J2SE 6.0, so, if you are using only Java 6+ - it is not required)
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-ws-metadata_2.0_spec</artifactId>
<version>1.1.1</version>
</dependency>
Plus, in our POJO we are using @XmlTransient annotation, so, jaxb-api is required (EmForge used jaxb for data-binding, not aegis like used tutorials)
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.0</version>
</dependency>
At implementation side we used followed versions:
This bug is already fixed in XmlSchema trunk, but still not released. So, we build own version from trunk and placed into own maven repository
So, to use these dependencies you need add emforge repository (to get fixed version of XmlSchema):
<repository>
<id>emforge.org</id>
<url>http://svn.emforge.org/svn/emforge/mvnrepo</url>
</repository>
and add followed dependencies:
<dependency>
<groupId>xalan</groupId>
<artifactId>xalan</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>org.apache.ws.commons.schema</groupId>
<artifactId>XmlSchema</artifactId>
<version>1.3.2.emforge</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>2.0.5</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</exclusion>
<!-- Seems we do not need all these geromino staff for now -->
<exclusion>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-activation_1.1_spec</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-annotation_1.0_spec</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-javamail_1.4_spec</artifactId>
</exclusion>
<exclusion>
<groupId>geronimo-spec</groupId>
<artifactId>geronimo-spec-jta</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>2.0.5</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</exclusion>
<!-- Seems we do not need all these geromino staff for now -->
<exclusion>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-activation_1.1_spec</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-annotation_1.0_spec</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-javamail_1.4_spec</artifactId>
</exclusion>
<exclusion>
<groupId>geronimo-spec</groupId>
<artifactId>geronimo-spec-jta</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-ws-security</artifactId>
<version>2.0.5</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</exclusion>
<!-- Seems we do not need all these geromino staff for now -->
<exclusion>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-activation_1.1_spec</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-annotation_1.0_spec</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-javamail_1.4_spec</artifactId>
</exclusion>
<exclusion>
<groupId>geronimo-spec</groupId>
<artifactId>geronimo-spec-jta</artifactId>
</exclusion>
</exclusions>
</dependency>
(We excluded different geronimo-specs dependencies seems we did not need them in our case).
For integrating with Acegi we needed to implement own CallbackHandler
performed authentication with using Acegi Authentication Manager:
else if (pc.getUsage() == WSPasswordCallback.USERNAME_TOKEN_UNKNOWN) {
// performs Authentication
try {
Authentication authentication = new UsernamePasswordAuthenticationToken(pc.getIdentifer(), pc.getPassword());
authentication = authenticationManager.authenticate(authentication);
SecurityContextHolder.getContext().setAuthentication(authentication);
} catch (AuthenticationException ex) {
throw new IOException("password incorrect for user: " + pc.getIdentifer());
}
log.debug("user logged in via web-service: " + pc.getIdentifer());
pc.setPassword(pc.getPassword());
}
Declare this callback as bean in spring context:
<bean id="wsPasswordCallback" class="ru.emdev.EmForge.security.WsCallbackHandler">
<property name="authenticationManager" ref="authenticationManager"/>
</bean>
And add it into wss4j configuration:
<jaxws:endpoint id="bpmWsService"
implementorClass="org.emforge.jbpm.BpmServiceImpl"
implementor="#bpmService"
address="/org.emforge.BpmService">
<jaxws:inInterceptors>
<bean class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor"/>
<ref bean="wss4jInConfiguration"/>
</jaxws:inInterceptors>
</jaxws:endpoint>
<bean id="wss4jInConfiguration" class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
<property name="properties">
<map>
<entry key="action" value="UsernameToken Timestamp Signature"/>
<entry key="passwordType" value="PasswordText"/>
<entry key="passwordCallbackRef" value-ref="wsPasswordCallback"/>
<entry key="signaturePropFile" value="server_sign.properties"/>
</map>
</property>
</bean>
Quite easy!
So, we created new project - emforge-service-tests
, depended from emforge-api (since it will use BpmService interface and Transfer Objects).
Added dependencies to CXF like in emforge-web project and specified BpmService as ws-client in spring-context:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<!-- Declaring Client -->
<bean id="bpmServiceClient" class="org.emforge.BpmService" factory-bean="bpmClientFactory" factory-method="create"/>
<bean id="bpmClientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
<property name="serviceClass" value="org.emforge.BpmService"/>
<property name="address" value="${application.path}/ws/org.emforge.BpmService"/>
<property name="outInterceptors">
<list>
<bean class="org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor" />
<ref bean="wss4jOutConfiguration" />
</list>
</property>
</bean>
<bean id="wss4jOutConfiguration" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
<property name="properties">
<map>
<entry key="action" value="UsernameToken Timestamp Signature"/>
<entry key="user" value="${user.name}" />
<entry key="passwordType" value="PasswordText" />
<entry key="passwordCallbackRef" value-ref="passwordCallback" />
<entry key="signaturePropFile" value="client_sign.properties"/>
</map>
</property>
</bean>
<bean id="passwordCallback" class="org.emforge.test.PasswordCallbackHandler">
<property name="password" value="${user.password}"/>
</bean>
</beans>
${application.path}, ${user.name} and ${user.password} - properties defined path to the server, username and password we should use for login.
Now, we can write Unit-Test:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:/META-INF/emforge-ws-config-test.xml",
"classpath:/META-INF/emforge-ws-test.xml"})
public class BpmServiceTest {
private final Log log = LogFactory.getLog(getClass());
@Autowired
private BpmService bpmServiceClient;
@Test
public void testSomething() {
}
}
object, inplemented BPMService and worked with server via web-services will be initialized and injected into test by Spring, so you can use it for testing different methods.
Only one note - unit-tests, included into emforge-web always worked with clean database - they initialize database, do everything in transaction, so, they do not depend from any previously created data and do not pass any changes into really used database.
This tests are worked with server - so, they depend from data, already exist in the database, and all changes done by tests will come into database. So, be careful with this way of testing!
In future, we have plans to run emforge with jetty:run target in maven and run unit-tests against this internally run server (we can configure it to run with using memory-based HSQL). In this case these unit-tests will work as unit-tests should work: do not depend from external software and current data in database, do not leave any changes there.
Then it will be done - new tutorial will be written.
| Last Modified by szakusov 5 months ago |