Open-Xchange-SOAP-WSDL2JAVA
How to provision Open-Xchange with Java and SOAP
Overview
We use Apache CXF as framework to implement SOAP with Java.
Apache CXF comes with a tool called wsdl2java which reads the WSDL published by an OX App Suite installation and generates classes which represent corresponding SOAP objects and method calls.
So the general procedure is:
- Setup OX including the SOAP admin interface
- Create classes with wsdl2java
- Use these classes in your Java code to make SOAP calls
Generating code with wsdl2java from Apache CXF
See the sample script below on how to generate stubs for the Open-Xchange provisioning APIs.
#!/bin/bash # 1. download apache-cxf tarball, extract it and "cd" into the directory # (this script has been developed and verified with CXF versions 3.0 and 3.1) # 2. change variables CODEBASE, JAVA_HOME and WSDLURL # 3. run this script "bash oxaas-wsdl2java" export JAVA_HOME="/usr/lib/jvm/java-1.7.0-openjdk-amd64" CODEBASE="./codebase" WSDLURL="http://192.168.101.84/webservices" CXF_HOME=/opt/apache-cxf-3.0.5 rm -rf $CODEBASE frontend=jaxws21 dbinding=jaxb JAXBTMP=/tmp/jaxb$$.xml rm -f $JAXBTMP cat<<EOF > $JAXBTMP <jaxb:bindings version="2.1" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <jaxb:globalBindings generateElementProperty="false"/> </jaxb:bindings> EOF for class in Context User Group Resource; do lname=$(echo $class | tr '[:upper:]' '[:lower:]') pname="com.openexchange.$lname" $CXF_HOME/bin/wsdl2java -databinding $dbinding -frontend $frontend -client -impl -d $CODEBASE -keep -b $JAXBTMP \ -p "http://soap.admin.openexchange.com=admin.soap.${lname}" \ -p "http://dataobjects.soap.admin.openexchange.com/xsd=${pname}.soap.dataobjects" \ -p "http://dataobjects.rmi.admin.openexchange.com/xsd=${pname}.rmi.dataobjects" \ -p "http://exceptions.rmi.admin.openexchange.com/xsd=${pname}.rmi.exceptions" \ -p "http://rmi.java/xsd=${pname}.java.rmi" \ -p "http://io.java/xsd=${pname}.java.io" \ ${WSDLURL}/OX${class}Service?wsdl done rm -f $JAXBTMP
The script generates stubs for each of the Context, User, Group and Resource API within a separate subdirectory of the $CODEBASE directory.
Example Code
Building the example code given below either requires some build tool / IDE of your choice (whose configuration is out of scope of this article) or you can build and run the example code manually like
# clean up old stuff from previous run rm -rf codebase *.class # generate java classes and compile them ./ox-wsdl2java find codebase -name \*.java | xargs javac # compile and run sample program javac -cp codebase MyContextClientExample.java MyUserClientExample.java java -cp .:codebase MyContextClientExample java -cp .:codebase MyUserClientExample
Sample client code follows below.
MyContextClientExample.java shows createcontext, listcontext, deletecontext:
import admin.soap.context.*; import com.openexchange.context.rmi.dataobjects.Credentials; import com.openexchange.context.soap.dataobjects.Context; import com.openexchange.context.soap.dataobjects.User; import javax.xml.namespace.QName; import java.io.IOException; import java.util.List; /* * Example SOAP client for OXContextService * * creates a context, calls listcontext, deletes the context again */ public class MyContextClientExample { private static final QName SERVICE_NAME = new QName("http://soap.admin.openexchange.com", "OXContextService"); public static void main(String[] args) { final String subadminname = "oxadminmaster"; final String subadminpw = "secret"; final String ctxname = "soapcontext"; Credentials creds = new Credentials(); Context ctx = new Context(); User oxadmin = new User(); OXContextService contextservice = new OXContextService(OXContextService.WSDL_LOCATION, SERVICE_NAME); OXContextServicePortType contextport = contextservice.getOXContextServiceHttpsEndpoint(); creds.setLogin(subadminname); creds.setPassword(subadminpw); ctx.setName(ctxname); ctx.setMaxQuota(10000l); ctx.setId(10001); final String adminEmail = "oxadmin@example.com"; final String ctxadmname = "oxadmin"; final String ctxadmpw = "secret"; oxadmin.setName(ctxadmname); oxadmin.setPassword(ctxadmpw); oxadmin.setDisplayName("OX Admin"); oxadmin.setSurName("OX"); oxadmin.setGivenName("Admin"); oxadmin.setPrimaryEmail(adminEmail); oxadmin.setEmail1(adminEmail); oxadmin.setDefaultSenderAddress(adminEmail); oxadmin.setLanguage("en_US"); oxadmin.setTimezone("Europe/Berlin"); CreateModuleAccessByName cmab = new CreateModuleAccessByName(); cmab.setAccessCombinationName("groupware_premium"); cmab.setAdminUser(oxadmin); cmab.setAuth(creds); cmab.setCtx(ctx); try { Context ret = contextport.createModuleAccessByName(ctx, oxadmin, "groupware_premium", creds); System.out.println("created context with id=" + ret.getId()); System.out.println("existing contexts:"); List<Context> allctxs = contextport.listAll(creds); for (final Context c : allctxs) { System.out.println(c.getName() + " with id=" + c.getId()); } System.out.println("hit enter to continue"); System.in.read(); System.out.println("deleting created context again"); Delete del = new Delete(); del.setAuth(creds); del.setCtx(ctx); contextport.delete(del); } catch (RemoteExceptionException e) { e.printStackTrace(); } catch (StorageExceptionException e) { e.printStackTrace(); } catch (InvalidCredentialsExceptionException e) { e.printStackTrace(); } catch (InvalidDataExceptionException e) { e.printStackTrace(); } catch (ContextExistsExceptionException e) { e.printStackTrace(); } catch (NoSuchContextExceptionException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (DatabaseUpdateExceptionException e) { e.printStackTrace(); } } }
MyUserClientExample.java shows createuser, deleteuser:
import admin.soap.user.*; import com.openexchange.user.rmi.dataobjects.Credentials; import com.openexchange.user.soap.dataobjects.Context; import com.openexchange.user.soap.dataobjects.User; import javax.xml.namespace.QName; import java.io.IOException; /* * Example SOAP client for OXUserService * * Create a user and delete it again * */ public class MyUserClientExample { private static final QName SERVICE_NAME = new QName("http://soap.admin.openexchange.com", "OXUserService"); public static void main(String[] args) { final String adminname = "oxadmin"; final String adminpw = "secret"; final int ctxid = 10001; Credentials creds = new Credentials(); Context ctx = new Context(); User oxuser = new User(); OXUserService userservice = new OXUserService(OXUserService.WSDL_LOCATION, SERVICE_NAME); OXUserServicePortType userport = userservice.getOXUserServiceHttpsEndpoint(); creds.setLogin(adminname); creds.setPassword(adminpw); ctx.setId(ctxid); oxuser.setName("oxuser1"); oxuser.setPassword("secret"); oxuser.setDisplayName("OX User 1"); oxuser.setSurName("OX"); oxuser.setGivenName("User 1"); oxuser.setPrimaryEmail("oxuser1@soapcontext"); oxuser.setEmail1("oxuser1@soapcontext"); oxuser.setDefaultSenderAddress("oxuser1@soapcontext"); oxuser.setImapLogin("oxuser1@soapcontext"); oxuser.setImapServer("localhost"); oxuser.setSmtpServer("localhost"); oxuser.setLanguage("en_US"); oxuser.setTimezone("Europe/Berlin"); try { User ret = userport.createByModuleAccessName(ctx, oxuser, "groupware_premium", creds); System.out.println("created user with id=" + ret.getId()); System.out.println("hit enter to continue"); System.in.read(); System.out.println("deleting created user again"); Delete del = new Delete(); del.setAuth(creds); del.setCtx(ctx); del.setUser(oxuser); userport.delete(del); } catch (RemoteExceptionException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (DatabaseUpdateExceptionException e) { e.printStackTrace(); } catch (StorageExceptionException e) { e.printStackTrace(); } catch (InvalidCredentialsExceptionException e) { e.printStackTrace(); } catch (InvalidDataExceptionException e) { e.printStackTrace(); } catch (NoSuchContextExceptionException e) { e.printStackTrace(); } catch (NoSuchUserExceptionException e) { e.printStackTrace(); } } }
Finally sometimes it is required to not directly make a SOAP call, but to generate the request body separately. One example therefore are gatling performance tests, where we can make SOAP tests if we just generate the SOAP (=HTTP POST) bodies separately and make, from the gatling point of view, simple HTTP POST requests.
Full working code therefore can be found in our gatling git repo, see gatling for details. The relevant steps to create the SOAP body itself are given below. It is scala code; how to translate it to Java (if required) should be straightforward.
import admin.soap.context.{ CreateModuleAccessByName, CreateModuleAccessByNameResponse } import com.openexchange.context.rmi.dataobjects.Credentials import com.openexchange.context.soap.dataobjects.{Context, Database, User} import java.io.{ByteArrayInputStream, ByteArrayOutputStream} import javax.xml.bind.{JAXBContext, Marshaller, Unmarshaller} import javax.xml.parsers.DocumentBuilderFactory import javax.xml.soap.{MessageFactory, SOAPMessage} import org.w3c.dom.Document val creds: Credentials = new Credentials val ctx: Context = new Context val oxadmin: User = new User // fill relevant fields of the creds, ctx, oxadmin oxbjects val cmab: CreateModuleAccessByName = new CreateModuleAccessByName cmab.setAccessCombinationName("all") cmab.setAdminUser(oxadmin) cmab.setAuth(creds) cmab.setCtx(ctx) val jaxbContext: JAXBContext = JAXBContext.newInstance(classOf[CreateModuleAccessByName]) val jaxbMarshaller: Marshaller = jaxbContext.createMarshaller jaxbMarshaller.setProperty(Marshaller.JAXB_FRAGMENT, true) val document: Document = DocumentBuilderFactory.newInstance.newDocumentBuilder.newDocument jaxbMarshaller.marshal(cmab, document) val soapMessage: SOAPMessage = MessageFactory.newInstance.createMessage // optional cosmetic: change namespace from SOAP-ENV to soap to match other conventions soapMessage.getSOAPPart().getEnvelope().removeNamespaceDeclaration("SOAP-ENV") soapMessage.getSOAPPart().getEnvelope().addNamespaceDeclaration("soap", "http://www.w3.org/2001/12/soap-envelope") soapMessage.getSOAPPart().getEnvelope().setPrefix("soap") soapMessage.getSOAPHeader().setPrefix("soap") soapMessage.getSOAPBody().setPrefix("soap") // optional cosmetic end soapMessage.getSOAPBody.addDocument(document) val outputStream: ByteArrayOutputStream = new ByteArrayOutputStream(); soapMessage.writeTo(outputStream); val soapBody: String = outputStream.toString()