Simon Fell > Its just code > Axis2 with Sforce

Sunday, May 7, 2006

Axis2 1.0 was recently released, whoever is in charge of release numbers needs firing, why isn't it just Axis 2.0?, now we have Axis(1) 1.4 and Axis(2) 1.0, anyway I digress, I've been following the earlier builds and RCs, I haven't had too much time to try it out with all the sforce stuff yet, but here's a few pointers to keep you on the straight and narrow.

  • the default ADB databinding will not work with the sforce enterprise WSDL, because it can't handle complex types extensions, unfortunately it won't tell you this at WSDL2Java time, you get a rather more cryptic error at runtime, use the XMLBeans option instead (this is unfortunate because the xmlbeans model is even more verbose to use than ADB).
  • It supports HTTP compression out of the box (thanks Dims!), but I couldn't find any docs on how to turn it on, digging around, I got this to work.
    SforceServiceStub stub = new SforceServiceStub();
    stub._getServiceClient().getOptions().setProperty(HTTPConstants.MC_ACCEPT_GZIP, Boolean.TRUE);
    stub._getServiceClient().getOptions().setProperty(HTTPConstants.MC_GZIP_REQUEST, Boolean.TRUE);
  • You have to be careful with the order in which you put together your xmlbean instances (I don't know if this is an Axis2 thing, or an xmlbean thing, either way it seems fairly idiotic to me), e.g.
    LoginDocument ld = LoginDocument.Factory.newInstance();
    Login l = Login.Factory.newInstance();
    ld.setLogin(l);
    l.setUsername(args[0]);
    l.setPassword(args[1]);
    LoginResult lr = stub.login(ld).getLoginResponse().getResult();
    
    will fail because the generated message doesn't contain the username or password (does setLogin copy the Login instance passed in?), you need to do this.
    LoginDocument ld = LoginDocument.Factory.newInstance();
    Login l = Login.Factory.newInstance();
    l.setUsername(args[0]);
    l.setPassword(args[1]);
    ld.setLogin(l);
    LoginResult lr = stub.login(ld).getLoginResponse().getResult();
    
  • The stub no longer tracks the state of soap headers for you, you need to do this yourself and pass the relevant headers on each operation call, here's a quick sample that calls login, handles the redirect and sessionHeader, then calls query.
    SforceServiceStub stub = new SforceServiceStub();
    stub._getServiceClient().getOptions().setProperty(HTTPConstants.MC_ACCEPT_GZIP, Boolean.TRUE);
    stub._getServiceClient().getOptions().setProperty(HTTPConstants.MC_GZIP_REQUEST, Boolean.TRUE);
    		
    LoginDocument ld = LoginDocument.Factory.newInstance();
    Login l = Login.Factory.newInstance();
    l.setUsername(args[0]);
    l.setPassword(args[1]);
    ld.setLogin(l);
    LoginResult lr = stub.login(ld).getLoginResponse().getResult();
    		
    System.out.println(lr.getServerUrl());
    System.out.println(lr.getSessionId());
    	
    stub = new SforceServiceStub(lr.getServerUrl());
    stub._getServiceClient().getOptions().setProperty(HTTPConstants.MC_ACCEPT_GZIP, Boolean.TRUE);
    stub._getServiceClient().getOptions().setProperty(HTTPConstants.MC_GZIP_REQUEST, Boolean.TRUE);
    		
    SessionHeader sh = SessionHeader.Factory.newInstance();
    sh.setSessionId(lr.getSessionId());
    SessionHeaderDocument sd = SessionHeaderDocument.Factory.newInstance();
    sd.setSessionHeader(sh);
    		
    QueryDocument qd = QueryDocument.Factory.newInstance();
    Query q = Query.Factory.newInstance();
    q.setQueryString("select id, name, accountNumber from Account");
    qd.setQuery(q);
    		
    QueryResult qr = stub.query(qd, sd, null).getQueryResponse().getResult();
    		
    System.out.println("Query has " + qr.getSize() + " records total");
    Account a = (Account)qr.getRecordsArray(0);
    System.out.println(a.getId() + " " + a.getName() + " " + a.getAccountNumber());

I'll keep trying stuff out including the partner WSDL (which i'm hopeful will work with ADB), and keep you posted.