Un esempio di integrazione
difficile
Analizzeremo ora un caso particolare di integrazione di codice Python in un'applicazione Java: la creazione di componenti custom in Adobe Livecycle.
LiveCycle è un motore di workflow che permette di creare processi. Questi processi avranno delle variabili di input e di output e saranno formati da componenti legati l'uno all'altro.
LiveCycle esporrà in modo automatico questi processi come EJB, web services (SOAP), watched mail e watched folder.
Insieme al prodotto vengono forniti alcuni componenti (sono venduti in pacchetti).
I componenti che fornisce Adobe gestiscono il rendering di pdf a partire da template, trasformazione e parsing di file xml, spedizione email, interfacciamento con db (via jdbc), interfacciamento con webservices ecc.
I processi sono disegnati con un interfaccia grafica che si chiama WorkBench. In questo programma i componenti sono visualizzati come dei "blocchetti". Per disegnare un processo si collegano i componenti tra di loro determinando così l'ordine di esecuzione, costrutti di selezione, ciclo e programmazione concorrente.
Non mi dilungo di più su questo prodotto la documentazione di LiveCycle si trova sul sito di Adobe.
Per quello che ci interessa è prevista nell'architettura del sistema la creazione di componenti custom da inserire all'interno dei nostri processi. Questi componenti non sono altro che dei semplici jar con dentro una classe java, un file di configurazione xml, e un paio di immagini che saranno utilizzate per visualizzare il componente.
La documentazione completa si trova di nuovo sul sito di Adobe.
Un componente Python di esempio
Per realizzare il nostro componente Python bisogna creare la nostra classe python come abbiamo fatto precedentemente.
Creo quindi un file Convert.py con la mia classe.
import java
from trasformations import make_transform
import com.adobe.idp.Document as doc
import StringIO
class Convert(java.lang.Object):
def convert(self,txt):
"""@sig public java.lang.String convert(com.adobe.idp.Document txt)"""
f_in=open(str(txt.getFile())) # get java file
f_out=StringIO.StringIO() # get fake file
make_transform(f_in,f_out) #convert
f_in.close()
f_out.seek(0)
content=f_out.read() # write content in string
return content
La classe nell'esempio ha un solo metodo pubblico di nome convert che prende in input un file di tipo com.adobe.idp.Document, lo legge, e lo converte con la mia funzione python make_transform (non ci interessa il suo contenuto ai fini dell'esempio). Infine viene restituito in output una stringa (le stringhe jython vengono convertite automaticamente in java.lang.String).
Nella creazione del jar bisogna avere l'accortezza di utilizzare la stessa versione di Java con la quale è stato compilato LiveCycle (nel nostro caso LC 8.2 usa java 1.5). Per ottenere questo si deve modificare lo script che lancia Jython come da esempio sulla pagina precedente della guida.
Una volta ottenuto un jar dobbiamo scompattarlo e aggiungere il file xml e le icone.
Il file xml sarà fatto così:
<component xmlns="http://adobe.com/idp/dsc/component/document"> <!-- Unique id identifying this component --> <component-id>lupo.Form2xml</component-id> <!-- Version --> <version>1.0</version> <class-path></class-path> <!-- Start of the Service definition --> <services> <service name="Convert"> <implementation-class>lupo.Convert</implementation-class> <description>Convert a form file into flat xml</description> <small-icon>icons/jython16.gif</small-icon> <large-icon>icons/jython32.gif</large-icon> <auto-deploy service-id="Convert" /> <operations> <operation name="convert"> <input-parameter name="txt" title="form file" type="com.adobe.idp.Document"> <hint>form file</hint> </input-parameter> <output-parameter name="xml" title="xml file" type="java.lang.String"> <hint>xml file</hint> </output-parameter> <faults> <fault name="Exception" type="java.lang.Exception"/> </faults> <hint>Convert a form file into flat xml</hint> </operation> </operations> </service> </services> </component>
In questo file ho dichiarato il nome della mia classe e del mio componente.
Nella sezione class-path avrei potuto nominare alcuni jar da includere nella class path ma ho preferito aggiungere le classi direttamente nel mio jar. Sotto services vengono elencate le classi utilizzabili dal mio componente e sotto operations vengono elencati i metodi richiamabili per ogni classe. Nel mio caso ho solo una classe Convert che espone un solo metodo convert. Per ogni service è possibile specificare dove trovare le icone per raffigurare il componente su WorkBench (nel mio caso jython16.gif e jython32.gif).
Per ogni metodo esposto vengono elencati gli argomenti in input e quelli in output. Grazie alla descrizione fornita nell'xml LiveCycle esporrà una comoda interfaccia grafica per la configurazione del componente.
La documentazione completa su cosa riportare sull'xml si trova sul sito ufficiale.
Ora dobbiamo ricompattare il jar. Basta usare lo zip senza compressione (LiveCycle non funziona correttamente con i Jar compressi ! ).
Per comodità ho aggiunto anche la classe dove viene definito il tipo com.adobe.idp.Document (l'ho trovata nel developer kit di Livecycle).
Ora abbiamo il nostro componente!
Apriamo WorkBench, importiamo il nostro componente e lo attiviamo (il mio componente l'ho chiamato Form2xml):
Et voilà. Possiamo utilizzarlo all'interno dei nostri processi !
