(Italiano) Liferay 7: Come realizzare un client SOAP con Apache CXF in OSGi Style
L'argomento integrazione è il mio forte e per questo primo mio vero articolo su Liferay 7 ho deciso di trattare l'argomento Web Services dal punto di vista del consumer. Senza dubbio scrivere su questa tematica significa aprire tanti altri punti da approfondire e magari con i prossimi articoli.
Qualcuno di voi chiederà a se stesso: ma esistono ancora e sono utilizzati i Web Services SOAP? La risposta è affermativa, continuate quindi la lettura.
1. Qual'è lo scenario e l'obiettivo
Immaginate il caso che dal vostro portale Liferay abbiate la necessità di dover integrare i dati dei vostri utenti con informazioni provenienti dal vostro sistema di CRM (Customer Relationship Management). Il sistema di CRM espone l'accesso ai propri dati attraverso un interfaccia SOAP, occorre quindi realizzare un client che risiederà sul Liferay 7 e che consenta l'interazione con il CRM.
Immaginato lo scenario (mostrato in Figura 1), l'obiettivo di questo articolo è quello di mostrare step-by-step quali sono i componenti che andranno installati sul Liferay 7 e come ad alto livello è composta l'applicazione che realizza il colloquio via SOAP con il sistema di CRM all'interno del contesto OSGi di Liferay.
Il diagramma di Figura 2 mostra il dettaglio dello scenario e in particolare la composizione dell'applicazione CRM Application che consta di tre moduli e il noto framework Apache CXF che sarà il nostro punto di riferimento per quel che riguarda il supporto ai Web Service SOAP.
L'applicazione CRM Application è stata già realizzata e disponibile sul Repository OSGi e Liferay 7 creato in occasione del primo Liferay User Group Italiano a Bologna #LRBO16. Sul repository git l'applicazione CRM Application corrisponde al modulo webservices-client.
2. Requisiti
Per seguire in modo efficace il contenuto di questo articolo è necessario avere: una conoscenza base di Liferay 7 e OSGi e la disponibilità dentro la vostra "borsa degli attrezzi" questi pezzi:
- Liferay 7.0.1 Community Edition GA2 (installata e in esecuzione) consigliato il bundle basato su tomcat
- Git Tools
- Gradle (versione >= 2.12)
- Telnet (come installare su Windows, sui sistemi *nix o Unix-like non serve installazione)
- Liferay IDE 3.0.1 GA2 (opzionale)
- Text Editor (opzionale)
- Apache CXF 3.1.6 (opzionale)
Il primo elemento e l'ultimo sono gli unici requisiti necessari per l'esecuzione dell'applicazione CRM Application.
Per i novizi di Liferay 7 consiglio la lettura della presentazione
3. Installazione del framework Apache CXF
Apache CXF è in genere il punto di riferimento come framework per quel che riguarda i Web Services. L'applicazione CRM Application adotta Apache CXF come framework a supporto dello sviluppo del client SOAP, è quindi indispensabile installare sull'istanza Liferay 7 alcuni dei componenti del framework affinché l'applicazione sia in grado di funzionare.
Liferay 7 supporta gli standard JAX-WS e JAX-RS tramite l'adozione del framework Apache CXF (versione 3.0.3) che esporta in parte tramite il bundle che si chiama Liferay Portal Remote CXF Common, e per vostra curiosità potreste vedere il file bnd dove sono evidenti gli Export-Package di Apache CXF. Nulla vieta quindi l'utilizzo del bundle di Liferay che esporta Apache CXF, preferisco però essere indipendente da Liferay per due motivi:
- utilizzare una versione diversa del framework e possibilmente l'ultima, in questo caso la versione 3.1.6, Liferay uilizza la vecchia versione 3.0.3. OSGi consente tutto ciò in modo semplice e agevole.
- Liferay 7 non esporta e non utilizza tutto lo stack offerto da Apache CXF, come per esempio la parte di WS-Security, WS-Policy, etc..
Per maggiorni approfondimenti consiglio la lettura del documento Liferay SOAP e REST Extender pubblicato sulla LDN.
Ricordate che siamo in ambiente OSGi? Bene, installare Apache CXF significa eseguire l'installazione dei bundle all'interno di Apache Felix che ricordo essere il container OSGi scelto dal Liferay.
Per il tipo di client SOAP da realizzare, i bundle di Apache CXF (versione 3.1.6) da installare sono:
- Apache XmlSchema Core (v. 2.2.1)
- Apache CXF Core
- Apache CXF Runtime JAXB DataBinding
- Apache CXF Runtime XML Binding
- Apache CXF Runtime SOAP Binding
- Apache CXF Runtime Core for WSDL
- Apache CXF Runtime Simple Frontend
- Apache CXF Runtime JAX-WS Frontend
- Apache CXF Runtime HTTP Transport
L'installazione dei nove elementi del framework di Apache CXF può essere eseguita connettendosi via telnet alla Apache Felix GoGo Shell. Accertato che il portale Liferay 7 sia in esecuzione, l'installazione del framework Apache CXF può avvenire eseguendo i comandi mostrati a seguire.
$ telnet localhost 11311 g! install https://repository.apache.org/content/repositories/releases/org/apache/ws/xmlschema/xmlschema-core/2.2.1/xmlschema-core-2.2.1.jar g! install https://repository.apache.org/content/repositories/releases/org/apache/cxf/cxf-core/3.1.6/cxf-core-3.1.6.jar g! install https://repository.apache.org/content/repositories/releases/org/apache/cxf/cxf-rt-databinding-jaxb/3.1.6/cxf-rt-databinding-jaxb-3.1.6.jar g! install https://repository.apache.org/content/repositories/releases/org/apache/cxf/cxf-rt-bindings-xml/3.1.6/cxf-rt-bindings-xml-3.1.6.jar g! install https://repository.apache.org/content/repositories/releases/org/apache/cxf/cxf-rt-bindings-soap/3.1.6/cxf-rt-bindings-soap-3.1.6.jar g! install https://repository.apache.org/content/repositories/releases/org/apache/cxf/cxf-rt-wsdl/3.1.6/cxf-rt-wsdl-3.1.6.jar g! install https://repository.apache.org/content/repositories/releases/org/apache/cxf/cxf-rt-frontend-simple/3.1.6/cxf-rt-frontend-simple-3.1.6.jar g! install https://repository.apache.org/content/repositories/releases/org/apache/cxf/cxf-rt-frontend-jaxws/3.1.6/cxf-rt-frontend-jaxws-3.1.6.jar g! install https://repository.apache.org/content/repositories/releases/org/apache/cxf/cxf-rt-transports-http/3.1.6/cxf-rt-transports-http-3.1.6.jar
Il comando install esegue l'installazione dei bundle su Apache Felix. Il comando install accetta come parametro una URI e personalmente preferisco installare i bundle prelevando gli stessi dal repository maven di Apache, ecco perché ho specificato la URL per ogni bundle da installare. E' possibile scaricare prima i bundle e poi eseguire l'installazione specificando come URI file:///$ABSOLUTE_PATH_BUNDLE_FILE
I bundle che sono stati installati sono tutti nello stato Installed e il comando sulla gogo shell mostrato a seguire fa vedere lo stato dei bundle appena installati.
g! lb|grep -e "Xml|Apache CXF" 479|Installed | 1|XmlSchema Core (2.2.1) 480|Installed | 1|Apache CXF Core (3.1.6) 481|Installed | 1|Apache CXF Runtime JAXB DataBinding (3.1.6) 482|Installed | 1|Apache CXF Runtime XML Binding (3.1.6) 483|Installed | 1|Apache CXF Runtime SOAP Binding (3.1.6) 484|Installed | 1|Apache CXF Runtime Core for WSDL (3.1.6) 485|Installed | 1|Apache CXF Runtime Simple Frontend (3.1.6) 486|Installed | 1|Apache CXF Runtime JAX-WS Frontend (3.1.6) 487|Installed | 1|Apache CXF Runtime HTTP Transport (3.1.6)
Con ben in mente il ciclo di vita delle applicazioni in ambiente OSGi mostrato nella presentazione OSGi e Liferay 7 (e che riporto in Figura 3), l'obiettivo è quello di avere tutti i bundle nello stato Active.
Il bundle XmlSchema Core è quello da cui dipende il bundle Apache CXF Core, il primo step è quindi quello di avviare lo starting del bundle XmlSchema Core utilizzando il comando start $idBundle$, così come mostrato a seguire.
g! start 479 g! lb|grep -e "XmlSchema|Apache CXF" 479|Active | 1|XmlSchema Core (2.2.1) 480|Starting | 1|Apache CXF Core (3.1.6) 481|Starting | 1|Apache CXF Runtime JAXB DataBinding (3.1.6) 482|Starting | 1|Apache CXF Runtime XML Binding (3.1.6) 483|Starting | 1|Apache CXF Runtime SOAP Binding (3.1.6) 484|Starting | 1|Apache CXF Runtime Core for WSDL (3.1.6) 485|Starting | 1|Apache CXF Runtime Simple Frontend (3.1.6) 486|Starting | 1|Apache CXF Runtime JAX-WS Frontend (3.1.6) 487|Starting | 1|Apache CXF Runtime HTTP Transport (3.1.6)<em> </em>
Dopo l'esecuzione del comando start per il bundle XmlSchema Core, tutti i bundle Apache CXF sono passati nello stato Starting. Questo stato è dovuto al fatto che i bundle di Apache CXF hanno dichiarato nel proprio Manifest File (MANIFEST.MF) una policy di attivazione del bundle impostata a lazy, questo vuol dire che il passaggio allo stato Active avverrà nel momento in cui qualche altro bundle richiederà i "servigi" del framework Apache CXF.
4. Struttura dell'applicazione CRM Application
Il modulo client SOAP di esempio è stato realizzato rispettando l'OSGi Service Pattern mostrato nella presentazione OSGi e Liferay 7 e con la struttura seguente:
- crmservices-api - Definizione delle API dell'interfaccia per l'accesso al servizio SOAP target
- crmservices-service - Implementazione delle API definite in crmservices-api. Il servizio SOAP del CRM utilizzato è disponibile pubblicamente all'indirizzo http://www.predic8.com:8080/crm/CustomerService. L'implementazione fa uso del framework Apache CXF
- crmservices-commands - Client che mostra come consumare le API
In Figura 4 è mostrato il class diagram dell'intera applicazione e in particolare:
- L'interfaccia CRMService definisce la nostra API pubblica d'interazione con i servizi del CRM e si trova nel modulo crmservices-api
- La classe CRMSOAPService definita come component OSGi implementa l'interfaccia CRMService. Questo è il componete che implementata il colloquio via SOAP con il sistema di CRM e si trova nel modulo crmservices-service
- La classe CRMCustomerServiceCommand definita come component OSGi implementa una serie di comandi OSGi che consentono di eseguire le operazioni definite dall'interfaccia CRMService, insomma, agisce da consumer dei servizi CRM
Ognuno dei moduli rappresenta fisicamente un bundle OSGi, esattamente i bundle sono:
- crmservices-api.jar
- crmservices-service.jar
- crmservices-commands.jar
5. Deploy dei bundle dell'applicazione
Il processo di deploy dei bundle del modulo webservices-client sulla vostra istanza Liferay 7 può avvenire in questo modo:
- Clone del repository liferay-italia-bo-usergroup
- Modifica del file gradle.properties specificando la propria directory d'installazione di Liferay 7, che nel mio caso è /opt/liferay-ce-portal-7.0-ga2-blog. La property da modificare è liferay.workspace.home.dir
A seguire i comandi per il deploy dei bundle del modulo webservices-client.
$ git clone https://github.com/amusarra/liferay-italia-bo-usergroup $ cd liferay-italia-bo-usergroup $ cd modules/webservices-client $ gradle deploy
L'effetto del comando del comando gradle deploy è visibile dai log di Liferay di cui riporto un esempio.
20:34:39,563 INFO [fileinstall-/opt/liferay-ce-portal-7.0-ga2-blog/osgi/modules][BundleStartStopLogger:35] STARTED crmservices-api_1.0.0 [489] 20:34:39,568 INFO [fileinstall-/opt/liferay-ce-portal-7.0-ga2-blog/osgi/modules][BundleStartStopLogger:35] STARTED crmservices.commands_1.0.0 [488] 20:34:49,736 INFO [fileinstall-/opt/liferay-ce-portal-7.0-ga2-blog/osgi/modules][BundleStartStopLogger:35] STARTED crmservices-service_1.0.0 [490] 20:34:49,746 INFO [fileinstall-/opt/liferay-ce-portal-7.0-ga2-blog/osgi/modules][CRMSOAPService:149] Configured SOAP EndPoint : { http://www.predic8.com:8080/crm/CustomerService } 20:34:50,125 INFO [fileinstall-/opt/liferay-ce-portal-7.0-ga2-blog/osgi/modules][BundleStartStopLogger:35] STARTED org.apache.cxf.cxf-core_3.1.6 [480] 20:34:50,778 INFO [fileinstall-/opt/liferay-ce-portal-7.0-ga2-blog/osgi/modules][BundleStartStopLogger:35] STARTED org.apache.cxf.cxf-rt-frontend-simple_3.1.6 [485] 20:34:50,788 INFO [fileinstall-/opt/liferay-ce-portal-7.0-ga2-blog/osgi/modules][BundleStartStopLogger:35] STARTED org.apache.cxf.cxf-rt-frontend-jaxws_3.1.6 [486] 20:34:50,863 INFO [fileinstall-/opt/liferay-ce-portal-7.0-ga2-blog/osgi/modules][BundleStartStopLogger:35] STARTED org.apache.cxf.cxf-rt-bindings-soap_3.1.6 [483] 20:34:50,885 INFO [fileinstall-/opt/liferay-ce-portal-7.0-ga2-blog/osgi/modules][BundleStartStopLogger:35] STARTED org.apache.cxf.cxf-rt-wsdl_3.1.6 [484] 20:34:51,225 INFO [fileinstall-/opt/liferay-ce-portal-7.0-ga2-blog/osgi/modules][BundleStartStopLogger:35] STARTED org.apache.cxf.cxf-rt-transports-http_3.1.6 [487] 20:34:51,237 INFO [fileinstall-/opt/liferay-ce-portal-7.0-ga2-blog/osgi/modules][BundleStartStopLogger:35] STARTED org.apache.cxf.cxf-rt-bindings-xml_3.1.6 [482] 20:34:51,667 INFO [fileinstall-/opt/liferay-ce-portal-7.0-ga2-blog/osgi/modules][BundleStartStopLogger:35] STARTED org.apache.cxf.cxf-rt-databinding-jaxb_3.1.6 [481]
Cosa notate dall'estratto del file di log di Liferay 7? Tutto normale, nulla di strano. Al momento del deploy dei nostri bundle anche i bundle di Apache CXF sono stati avviati e passati nello stato Active. Per evidenziare ancora meglio la nuova situazione eseguire il comando lb dalla gogo shell così come indicato a seguire.
g! lb | grep -e "XmlSchema|Apache CXF|crmservices" 479|Active | 1|XmlSchema Core (2.2.1) 480|Active | 1|Apache CXF Core (3.1.6) 481|Active | 1|Apache CXF Runtime JAXB DataBinding (3.1.6) 482|Active | 1|Apache CXF Runtime XML Binding (3.1.6) 483|Active | 1|Apache CXF Runtime SOAP Binding (3.1.6) 484|Active | 1|Apache CXF Runtime Core for WSDL (3.1.6) 485|Active | 1|Apache CXF Runtime Simple Frontend (3.1.6) 486|Active | 1|Apache CXF Runtime JAX-WS Frontend (3.1.6) 487|Active | 1|Apache CXF Runtime HTTP Transport (3.1.6) 488|Active | 10|crmservices.commands (1.0.0) 489|Active | 10|crmservices-api (1.0.0) 490|Active | 10|crmservices-service (1.0.0)
6. Test del client SOAP
Per il test del client possiamo utilizzare i comandi OSGi definiti in crmservices-commands:
- createDefaultCustomer - Comando per la creazione di un customer
- getCustomer - Comando per il retrieve di un customer specificando l'id del customer
- getCustomers - Comando per il retrieve di tutti i customer
A seguire l'esecuzione in ordine dei comandi OSGi sopra descritti e il relativo output.
g! createDefaultCustomer Customer with id: 4ab5a868-e41e-4c26-867e-2a88af56866e created g! getCustomer 4ab5a868-e41e-4c26-867e-2a88af56866e Customer [person=PersonType [id=4ab5a868-e41e-4c26-867e-2a88af56866e, firstName=Antonio, lastName=Musarra, age=35, address=AddressType [street=Via Guseppe Verdi 90, city=Bronte, zipCode=95034, country=IT]], companyAddressType=CompanyAddressType [companyName=Antonio Musarra's Blog], id=4ab5a868-e41e-4c26-867e-2a88af56866e] g! getCustomers it.dontesta.labs.liferay.lrbo16.webservice.crm.exception.CRMServiceException: The be implement!
7. Risorse
Per approfondimenti su Liferay 7 e OSGi vi lascio queste serie di risorse:
- Liferay Developer Network (LDN)
- EclipseCon Europe 2015 Liferay Modularity Patterns - Liferay portal modern architecting and development
- Liferay 7 OSGi and Modularity
- OSGi Modularity - Tutorial
- OSGi in Action
- OSGi in Depth
8. Conclusioni
In questo articolo abbiamo visto come impostare il vostro ambiente Liferay 7 al fine di realizzare applicazioni che hanno necessità di colloquiare con altri sistemi attraverso il protocollo SOAP. Sicuramente è più interessante vedere com'è strutturata un'applicazione seguendo l'OSGi Service Pattern. Esistono altri modi per utilizzare il framework Apache CXF all'interno delle vostre applicazioni, per esempio, includendo i jar direttamente all'interno dell'applicazione, metodo che personalmente sconsiglio. In genere preferisco l'approccio a bundle quando non ci sono restrizioni particolari, in questo caso ogni applicazione potrà sfruttare il framework Apache CXF dichiarandone solamente l'utilizzo e i bundle delle applicazioni risulteranno più contenuti in termini di dimensioni.