Filenet P8 , webservices and Axis 1

Exceptionally, in this post I will speak about Filenet. For one customer I need to publish some Filenet p8 webservices on one Aqualogic Service Bus. Filenet it's a good ECM. However, really I believe that it's power relay in a document concentric BPM issues. For example, Filenet P8 has wizards for ISO-15489 or Moreq and a great designer. This is good. It brings some functionality needed in a lot of scenarios out of the box.

A different matter is using it like an ECM in an integration scenario. It's not a secret that I love Alfresco. Really, for integration and for live in a SOA ecosystem (that it's the task that I'm doing in this moment), Alfresco is most suitable. A very good kit of webservices, REST API, web scripts, for tell some of the features that alfresco bring us. I will try to speak about Alfresco in another post, but with alfresco I feel like if I have a box opened to the world: many manners to connect.
Well, speaking about Filenet P8 I need to make a client with Axis1 (exigency of the script). The concern it's no really difficult if we know some points:

Filenet has two webservices: FNCEWS40SOAP and FNCEWS35DIME for binary files
Filenet use wsse for authentication

With this webservices you can do things like Retrieving Queues , Execute actions , Search, etc. If you want more info look here.

Request and Response


In this example we are going to use the search features of FNCEWS40SOAP. The first thing, we open SoapUI ( it’s great, really) and we will send the following request:

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" soapenv:mustUnderstand="1">
<wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="UsernameToken-1977511">
<wsse:Username>John Doe</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">*****</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>


<soapenv:Body>
<ExecuteSearchRequest xmlns="http://www.filenet.com/ns/fnce/2006/11/ws/schema" xmlns:ns1="http://www.filenet.com/ns/fnce/2006/11/ws/schema" continuable="false" maxElements="3" xsi:type="ns1:RepositorySearch">
<SelectionFilter xmlns="" levelDependents="false" maxElements="3" maxRecursion="0" xsi:type="ns1:PropertyFilterType" />
<SearchScope xmlns="" objectStore="Desarrollo" xsi:type="ns1:ObjectStoreScope"/>
<SearchSQL xmlns="" xsi:type="xsd:string">SELECT d.* FROM Document d WHERE (d.Id='{C2C12200-FB91-40BA-AE92-9EB61FCB8200}')</SearchSQL>
</ExecuteSearchRequest>
</soapenv:Body>
</soapenv:Envelope>


Like we can see, in the header, we must put security issues suchs user and password in a wsse format. For the search is important inform the search scope , the search SQL and some info related.

This request must return something like that response:

<e:Envelope xmlns:e="http://schemas.xmlsoap.org/soap/envelope/" xmlns:d="http://www.w3.org/2001/XMLSchema" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:wn0="http://www.filenet.com/ns/fnce/2005/02/ws/schema">
<e:Body>
<wn0:ExecuteSearchResponse>
<wn0:Object classId="QueryResultRow">
<wn0:Property i:type="wn0:SingletonObject" propertyId="ClassDescription">
<wn0:Value i:type="wn0:ObjectReference" classId="ClassDescription" objectId="{777E0215-02F4-4024-A4A4-E6BEE7B052CD}" objectStore="{1A137D49-54D6-4D3D-BEA6-3E8A71E30A34}"/>
</wn0:Property>
(…)
<wn0:CollectionTerminator i:type="wn0:EndOfCollection"/>
</wn0:ExecuteSearchResponse>
</e:Body>
</e:Envelope>

Creating the client.


Well, now that we know how will react in the server, is time to create the client. Like I tell before we will use Axis 1. For this purpose, the better thing is use eclipse and generate the client with its plugging.

Well, I notice that in the WSDL are missing some types needed for deserialize the response. I modify the WSDL and I added this missing types. Probably, after the generation you will have some compilation problems. In my case, I have it with a method definition in subclasses. I retouch the super class of all the classes having errors, and F5.


At this point we have the most part of the client generated. However, it will don't do nothing if we don't enable the security to the client. For enable the security I use wss4j. It requires some manual modifications to the stub generated by the axis plugging in eclipse:

In the stub (FNCEWS40SoapBindingStub) I modified the method createCall to include the follow:

_call.setProperty(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
_call.setProperty(UsernameToken.PASSWORD_TYPE, WSConstants.PW_TEXT);
_call.setProperty(WSHandlerConstants.USER, "P8Bea");
_call.setProperty(WSHandlerConstants.PW_CALLBACK_REF, new PWCBHandler());
_call.setProperty(WSHandlerConstants.TIMESTAMP_PRECISION,"0");
_call.setClientHandlers(new org.apache.ws.axis.security.WSDoAllSender(), null);


For use wss4j you need configure the security. I use the follow client conf:

<deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<transport name="http" pivot="java:org.apache.axis.transport.http.HTTPSender"/>
<service name="FNCEWS35">
<requestFlow >
<handler type="java:org.apache.ws.axis.security.WSDoAllSender" >
<parameter name="action" value="UsernameToken"/>
<parameter name="user" value="John Doe"/>
<parameter name="passwordCallbackClass" value="es.in2.aca.test.ws.PWCBHandler"/>
<parameter name="passwordType" value="PasswordText"/>
</handler>
</requestFlow >
</service >
</deployment>


The callback class is not more interesting:

public class PWCBHandler implements CallbackHandler {
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
for (int i = 0; i < callbacks.length; i++) {
if (callbacks[i] instanceof WSPasswordCallback) {
WSPasswordCallback pc = (WSPasswordCallback)callbacks[i];
System.out.println("callbak");
if ("John Doe".equals(pc.getIdentifer())) {
pc.setPassword("******");
} } else {
throw new UnsupportedCallbackException(callbacks[i], "Unrecognized Callback");
} } }}


At the end, the client call:

// taking the configuration
EngineConfiguration config = new FileProvider("resources/client.conf");
FNCEWS40Service locator = new FNCEWS40ServiceLocator(config);
Remote remote;
remote = locator.getPort(FNCEWS40SoapBindingStub.class);
FNCEWS40SoapBindingStub axisPort = (FNCEWS40SoapBindingStub) remote;
// The object store
ObjectStoreScope oss = new ObjectStoreScope();
oss.setObjectStore("Desarrollo");
// Define the Search
RepositorySearch srt = new RepositorySearch();
srt.setContinuable(false);
PropertyFilterType pft = new PropertyFilterType();
pft.setMaxRecursion(0);
pft.setMaxElements(3);
srt.setSelectionFilter(pft);
srt.setMaxElements(3);
srt.setSearchScope(oss);
srt.setSearchSQL("SELECT d.* FROM Document d WHERE (d.Id='{C2C42000-FB91-40CA-AE92-9EB61FCB8200}')");
// Try the search
ObjectSetType ost = axisPort.executeSearch(srt);

Like you can see, the more difficult is understand the WSDL ;)

3 comentarios:

Anónimo dijo...

Hello,

Intersting, I am doing the same of one of my cutomer. I am using Axis 1.4 do generate the client but as you said it seems that wsdl2java does not retrieve all of the types.
Do you mind sending me a copy of the changes you have done in the generated classes?
My email is rlv200@scarlet.be
By the way nice blog!
Ob

ob dijo...

Hello,

Do you still remember what you have changed in the generated classes. Because, I think I am facing the same problem. I am able to perform a query but I get an exception when axis tries to deserialize de the Response. I guess, I am missing some types.
Do you min sending me the missing ones? Thank you

Wkr, ob (rvl200@scarlet.be)

Jose Carrasco dijo...

OB,
I think that the manual changes I did to the the generated classes were the follow:


method createCall:

_call.setProperty(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
_call.setProperty(UsernameToken.PASSWORD_TYPE, WSConstants.PW_TEXT);
_call.setProperty(WSHandlerConstants.USER, "P8Bea");
_call.setProperty(WSHandlerConstants.PW_CALLBACK_REF, new PWCBHandler());
_call.setProperty(WSHandlerConstants.TIMESTAMP_PRECISION,"0");
_call.setClientHandlers(new org.apache.ws.axis.security.WSDoAllSender(), null);

Nothing more. About the generated classes... now rest in peace at one customer' subversion... sorry. I hope this help you.

Publicar un comentario