SugarCRM Web Services: Build a Apache CXF Client

SugarCRM[1] espone all’esterno il core delle proprie funzionalità pubblicandole come Web Services, quindi niente di più semplice che creare un client Java, C#, C++, PHP e chi più ne ha più ne metta per interagire con essi; non sempre però la questione è così semplice !!!

Chi lavora pesantemente con la tecnologia dei Web Services è cosciente del fatto che gli standard esistenti lasciano un notevole grado di libertà tale per cui possono essere interpretati diversamente dalle varie case produttrici di software, con la conseguenza di non garantire in alcuni casi l’interoperabilità. Potrebbe cioè essere impossibile, ad esempio, accedere ad un web service creato con Axis (Java) utilizzando .NET (Microsoft).  E’ stato creato un comitato denominato WS-I (Web Services Interoperability) con l’obiettivo di risolvere i problemi legati  l’interoperabilità.

SugarCRM dichiara di essere compliant WS-I 1.0 Basic Profile[2] , ciò significa che dovremmo essere  in grado d’interagire con i servizi web di SugarCRM attraverso client generati (a partire dal documento WSDL) con Apache Axis, JAX-WS, Apache CXF, etc…

Prima di andar sul pratico, desidero fare un breve refresh su style binding use.  Il documento WSDL[3] descrive il servizio web, in particolare, l’elemento binding costituisce la specifica concreta di protocollo (in particolare il protocollo SOAP) e formato dati, relativa a un elemento portType. Il SOAP binding, che definisce il modello di messaging, può essere:

mentre la modalità di codifica dei dati specificata dall’attributo use, può essere, encoded o literal. Sintetizzando, esistono quattro diverse combinazioni di stile e codifica, sulle quali entrambe le parti coinvolte devono convenire prima d’iniziare lo scambio di informazioni: per esempio, un server che supporta soltanto la codifica letterale per lo scambio dei documenti non sarà mai in grado di comunicare con un client che utilizza il modello RPC con la codifica encoded. L’elenco a seguire mostra un riepilogo delle possibili combinazioni:

  • Document/Literal;
  • Document/Encoded;
  • RPC/Literal;
  • RPC/Encoded.
Nelle successive figure ho evidenziato style e use nelle due combinazioni RPC. L’estratto mostrato fa riferimento al documento WSDL di SugarCRM (Community Edition versione 6.4).
WSDL Web Services di SugarCRM RPC/Encoded

WSDL Web Services di SugarCRM RPC/Encoded

RPC Literal

WSDL Web Services di SugarCRM RPC/Literal

Dalla documentazione di SugarCRM risultano supportate le due combinazioni RPC, quella di default è RPC/Encoded. Le URL per accedere al documento WSDL per le due combinazioni sono:

  • RPC/Encoded: http://<hostname>:<port>/service/v2/soap.php?wsdl
  • RPC/Literal: http://<hostname>:<port>/service/v2/soap.php?wsdl&style=rpc&use=literal

Build del Client

In precedenti articoli pubblicati su questo blog sono stati affrontati temi circa lo sviluppo di client per i servizi web di SugarCRM, sia utilizzando il linguaggio Java (tramite il framework Apache Axis 1.4) sia utilizzando .NET Framework. In questo caso creeremo il client utilizzando Apache CXF[4]. I requisiti minimi per portar a casa il risultato sono:

  • Installazione e Configurazione del framework Apache CXF 2.2.x (o 2.5.x)
  • Ant 1.7
  • JDK 1.6

Qualora fosse necessario consiglio di  fare riferimento alla documentazione ufficiale di ogni componente indicato nel precedente elenco.

Costruiremo il client a partire dal documento WSDL di SugarCRM, in particolare faremo riferimento alla versione 4 delle API di SugarCRM Community Edition 6.4. Nella successiva tabella sono indicate le versioni delle API e la relative versioni di SugarCRM.

API Version SugarCRM Version
V2 5.5.0
V3 6.1.0
V3_1 6.1.0
V4 6.2 e successive
Tabella 1. Versioni delle API

L’URL di accesso ai servizi rispetta il pattern http://<hostname>:<port>/service/vX/soap.php, dove X indica la versione delle API indicata in Tabella 1 (prima colonna).

Per generare il client utilizzeremo il tool wsdl2java locato in $CXF_HOME/bin, specificando l’URL del documento WSDL e un serie di altri parametri.  E’ utile ricordare che Apache CXF supporta la combinazione RPC/Literal e non quella di default di SugarCRM RPC/Encoded. Per questo motivo, l’URL del WSDL da fornire a Apache CXF è il seguente:

  • http://<hostname>:<port>/service/v4/soap.php?wsdl&style=rpc&use=literal

Qualora forniate l’URL non corretta ad Apache CXF in fase di generazione del client, riceverete il seguente errore:

Il comando per generare il client è il seguente:

Il tool creerà all’interno della directory specificata dal parametro -d tutti i sorgenti Java del client + il file build.xml di Ant che potrete utilizzare per fare il build e test del client. Se non diversamente specificato, il client sarà creato utilizzando JAX-WS come FrontEnd e JAX-B come DataBinding, il vantaggio di questa soluzione è rappresentato dal fatto che sarete in grado di eseguire il client senza la necessità di librerie aggiuntive, basta la sola JDK/JRE.

Apache CXF, oltre a creare tutte le classi Java a supporto, crea inoltre una classe di test da completare oltre che a poter eseguire la classe stessa via Ant. Il nome della classe di test  è:

  • com.sugarcrm.sugarcrm.SugarsoapPortType_SugarsoapPort_Client.java

una volta che avrete completato la classe con qualche prova di chiamata a uno o più metodi esposti dal servizio, potrete verificare il risultato eseguendo il comando:

ottenendo (come nel mio caso) un risultato del genere:

Ho completato la classe test in modo da eseguire le operazioni di ServerInfo, Login, GetUserId e Logout. A questo punto il gioco è fatto. Consiglio di realizzare un bel jar del client appena creato per utilizzarlo ovunque sia necessario accedere ai dati del CRM di Sugar.

Risorse

Quanto realizzato per la stesura di questo articolo è stato pubblicato sul mio Repository GitHub raggiungibile all’indirizzo https://github.com/amusarra/SugarCRMCE64v4SOAPLibrary

Il repository contiene:

  • Il progetto Eclipse chiamato SugarCRMCE64v4SOAPLibray
  • Il documento WSDL (RPC/Literal) del servizio (in resources/wsdl)
  • Il documento XSD del servizio (in resources/xsd)
  • Il Jar SugarCRMCE64v4SOAPLibrary.jar del client (in build)

Riferimenti

David A. Chappell, T. J. (2002). Java Web Services. O’REILLY.

Antonio Musarra. (4 Aprile 2011). Costruire un client Java per SugarCRM

Antonio Musarra. (15 Novembre 2011). Building a Client .NET for SugarCRM

[1] SugarCRM Web Service Overview

[2] Chris Ferris. (1 Ottobre 2002). First look at the WS-I Basic Profile 1.0

[3] Russell Butek. (31 Ottobre 2003). Which style of WSDL should I use?

[4] The Apache Software Foundation. Apache CXF: An Open-Source Services Framework

Antonio Musarra

I began my journey into the world of computing from an Olivetti M24 PC (http://it.wikipedia.org/wiki/Olivetti_M24) bought by my father for his work. Day after day, quickly taking control until … Now doing business consulting for projects in the enterprise application development using web-oriented technologies such as J2EE, Web Services, ESB, TIBCO, PHP.

Potrebbero interessarti anche...

  • Pingback: Problem creating client from WSDL()

  • Pingback: Maven Project for SugarCRM Java Web Services Client « Antonio Musarra's Blog()

  • Pingback: Axis2 - Developer Tutorial()

  • Pingback: Released the first version of SugarCRM Java Client « Antonio Musarra's Blog()

  • Marco

    Awesome post.. just a question.
    How can I iterate module list, getting name and fields?
    I use this snippet:
    ——————————–
    System.out.println(“Invoking getAvailableModules…”);
    String _getAvailableModules_session = sessionID;
    String _getAvailableModules_filter = “all”;
    ModuleList availableModules = port .getAvailableModules(_getAvailableModules_session,
    _getAvailableModules_filter);
    ModuleListArray modules = availableModules.getModules();
    ——————————–

    Thanks in advance

    • Hi Marco,
      Thanks for the appreciation. This weekend I’m off for a Trek on horseback. Now from memory I don’t remember well the get method of the modules. Just return I send you the code.

      Bye.
      Antonio.

  • Marco

    Hi Antonio,
    wow!! A trek on horseback!! Have a nice weekend.
    Thanks for your reply, I look forward to hearing from you.

    • Marco

      Hi Antonio,
      I solved my problem, achieving to iterate module list:
      Iterator it = modules.getAny().iterator();
      and obtain module info, considering Object as Element.

      I proceed by trial and error, your post is almost unique.
      Now I’m trying to implement getEntryList, encountering some problems.
      Could you write me an example to do this, expecially how to set SelectFields and LinkNamesToFieldsArray, parameters of getEntryList service?

      Thanks

      • Hi Marco,
        should be a code like this:

        try {
        SelectFields selectFields = new SelectFields();
        LinkNameToFieldsArray linkNameToFieldsArray = new LinkNameToFieldsArray();
        LinkNamesToFieldsArray linkNamesToFieldsArray = new LinkNamesToFieldsArray();

        Document doc = DocumentBuilderFactory.newInstance()
        .newDocumentBuilder().newDocument();

        Element fieldId = doc.createElement("item");
        fieldId.setTextContent("id");

        Element fieldName = doc.createElement("item");
        fieldName.setTextContent("name");

        Element fieldBillingCity = doc.createElement("item");
        fieldBillingCity.setTextContent("billing_address_city");

        selectFields.setArrayType("xsd:string[]");
        selectFields.getAny().add((Element)fieldId);
        selectFields.getAny().add((Element)fieldName);
        selectFields.getAny().add((Element)fieldBillingCity);

        linkNamesToFieldsArray.setArrayType("ns1:link_name_to_fields_array[]");

        GetEntryListResultVersion2 resultList =
        port.getEntryList(sessionID, "Accounts",
        "", "",
        20, selectFields, linkNamesToFieldsArray,
        100, 0, false);

        System.out.println("Total Count: " + resultList.getTotalCount());
        System.out.println("Result Count: " + resultList.getResultCount());

        EntryList entryList = resultList.getEntryList();
        List entryValue = entryList.getAny();

        for (Iterator iterator = entryValue.iterator(); iterator
        .hasNext();) {
        Object object = iterator.next();
        System.out.println(object.toString());
        }
        } catch (Exception e) {
        System.err.println("Get Entry failed: " + e.getMessage());
        System.exit(-2);
        }

        However I think there is some problem with the SOAP-ENC: Array. Just a few minutes I’ll try to do some investigation.

        Bye,
        Antonio.

  • Marco

    Hi Antonio,
    after reading your snippet, I saw to go in the right direction.
    You removed my doubts. I tried your code and finally getEntryList method gave me correct results.
    Thank you so much, thanks for you time!!

    Ciao

    • Ciao Marco,
      Could you post the final code you used to read items that are returned by the get_entry_list method?

      Soon I’ll have a few minutes I will update the post with some examples.

      Thank you.

  • Antonio,
    I have been following your sugarcrm Java soap articles with great interest. They have been very helpful for a project I’m working on which requires using an Apache CXF client. Thank you so much for providing the information.

    In going through this article and trying the other comments to it, I’m unable to see how to pull out actual values for individual entries. I can get the total counts and result counts, but for object iteration I get [item: null]

    I didn’t know if that might have something to do with the “problem with the SOAP-ENC: Array” you mentioned in one thread, or if it is something else. I have the same problem trying to iterate through a module list that Marco mentions in his comments, but I haven’t been able to make the code work based on his hints either.

    Any thoughts?

    Thanks…jack

    • Hi Jack,
      sorry for the late reply. So, I got to check that they actually returned values ​​for each item are all null (see debug). The SOAP response returned by the service is correct (see image by Wireshark). I assume that the problem is the data types SOAP-ENC: Array. Performing the validation of the WSDL using Apache CXF get the error: “Error WSDLToJava: Schema Error: src-resolve: Can not resolve the name ‘SOAP-ENC: Array’ to a (n) ‘type definition’ component.”.
      I also wanted to check the validation of the WSDL Document / Literal getting the error: “WSDLToJava Error: WSI-BP-1.0 R2716 violation: Operation ‘login’ SOAPBody MUST NOT have namespace attribute”.
      I think you should use Axis 1.4, it seems it is the only library that works with the services of SugarCRM. To use Apache CXF web services with SugarCRM, Sugar, must ensure that the web services are Document / Literal (removing the SOAP-ENC: Array) and at least standard compliant WSI-BP-1.0.

      Bye and thanks for the appreciation.
      Antonio M.

      XML SOAP Respone
      Iterate over ModuleList

      • Antonio,

        Thanks for confirming what I was seeing. I have come up with a work around, which requires editing a local copy of the generated wsdl. Arrays sent to SugarCRM are left as SOAP-ENC:Array, but arrays returned from SugarCRM are converted to a sequence. This still results in the wsdl2java -validate failing, but I have been able to make it work in both directions this way.

        This is the link to a reference on how to change a local copy of the wsdl:

        http://www.ws-i.org/profiles/basicprofile-1.1.html#soapenc_Array

        I’ll see if I can email you directly the wsdl file I used and some screen shots, along with sample code on accessing the elements.

        …jack

        • Hi Jack,
          editing the WSDL (local) for the SOAP-ENC: Array is a technique used in the past on other projects. Sugar would be nice if that would make the web services interoperable, standards-compliant WS-I. If you can send the WSDL and the piece of code used, so maybe do the integration of the article and if I can I would also make the translation of the article in English.

          Thank you and see you soon,
          Antonio.

          • Antonio,
            Can you send me an email address or someplace to upload so I can send you some files directly? I don’t see how to attach to the blog or respond to the blog notifications via email (it bounced when I tried that).

            Thanks…jack

          • Hi Jack,
            the my email address is antonio.musarra@gmail.com

            Bye,
            Antonio

  • Chirag Shah

    I thought this article is in English but it is not.. Please correct the same

    • Antonio Musarra

      Hi.
      I’m sorry but at the moment I do not have the time you do the translation of the article.

      Bye,
      Antonio.