Liferay

Assicurarsi che la transazione sia finita

Scritto da il 29 giugno 2015 in Liferay | 0 commenti

Assicurarsi che la transazione sia finita

Come eseguire un’operazione avendo la certezza che una transazione sia terminata? In questo articolo cercheremo di capire che cosa si intende per transazione e come intercettare il completamento di una transazione all’interno di un metodo dei services Cenni sul concetto di transazione Quando parliamo di “transazione” in ambito informatico intendiamo una serie di operazioni, tipicamente che coinvolgono scritture su database, eseguite in sequenza. Eseguire queste operazioni in una transazione significa che, se anche una sola di queste fallisce, allora vengono annullate anche tutte le altre precedentemente eseguite e la transazione si interrompe: in altre parole viene eseguito un rollback della transazione Una caratteristica importante di una transazione è la coerenza dei dati al suo interno: anche se la transazione non è completata e i dati quindi non ancora persistiti su database, eventuali query eseguite all’interno della transazione su questi dati ritornano risultati coerenti con le operazioni compiute. Ad esempio immaginiamo un’operazione di trasferimento di denaro dal conto A al conto B tramite un sistema online: possiamo identificare 2 macro operazioni che vanno a modificare i dati: Prelievo dal conto A Aggiunta sul conto B Immaginiamo che si verifichi un errore nell’esecuzione della fase (2): la transazionalità di questo flusso ci assicura che l’intera operazione verrà annullata e il conto A rimarrà immutato. Se invece le operazioni non fossero state eseguite in modo transazionale la cifra prelevata da A sarebbe andata persa. Inoltre la transazionalità ci assicura che eseguendo una verifica del saldo del conto A tra (1) e (2), la cifra ritornata sarà coerente con il prelievo effettuato, nonostante ancora l’operazione non sia stata effettivamente eseguita sul database. All’interno di Liferay la transazionalità è garantita per tutte le operazioni eseguite all’interno dei service che coinvolgono entità su database: il rollback scatta quando vengono lanciate eccezioni di tipo SystemExcetion e PortalException. Possibili problemi di coerenza di dati tra diverse transazioni Ci  possono essere casi in cui dobbiamo compiere delle operazioni in una transazione differente da quella che sta modificando i dati. Ad esempio se implementiamo un Model Listener e nel metodo afterCreate cerchiamo di fare una findEntity dell’entità appena creata, riceveremo null invece dell’entità. Questo perché il model listener viene eseguito in una transazione separata da quella che ha generato l’entità, che potrebbe non essere ancora completata. Oppure se usiamo il message bus per informare plugin esterni della creazione/modifica di un’entità (vedi http://marcorosce.cluster020.hosting.ovh.net/comunicazione-tra-portlet-con-messagebus/) può succedere che il listener scatti prima che la transazione originaria sia completata, creando disallineamenti e problemi. Intercettare il completamento di una transazione Per intercettare il completamento di una transazione possiamo usare il metodo registerCallback della classe TransactionCommitCallbackRegistryUtil. TransactionCommitCallbackRegistryUtil.registerCallback(new Callable() { @Override public Void call() throws Exception { //Here we are sure that transaction is completed and committed ... doWhateverYouWant(); return null; } }); Questo metodo ci permette di registrare un task (che implementi l’interfaccia Callable) che verrà eseguito solamente al completamento della transazione. Approfondimenti e riferimenti https://en.wikipedia.org/wiki/Database_transaction http://www.liferayaddicts.net/blogs/-/blogs/transaction-management-with-liferay-service...

Leggi

Aggiungere icon font personalizzati

Scritto da il 27 maggio 2015 in Liferay | 0 commenti

Aggiungere icon font personalizzati

Cosa sono le icon font? A cosa servono? Nello sviluppo di applicazioni ci troviamo spesso a dover inserire icone all’interno delle nostre interfacce utente e solitamente utilizziamo immagini bitmap (bmp, jpeg, gif, png, etc.) recuperate in rete o create ad hoc. Questo approccio però porta con se una serie di inconvenienti come ad esempio problemi di scalabilità con risoluzioni differenti (ad esempio su interfacce responsive), aumento del consumo di banda e una certa difficoltà in caso decidessimo, ad esempio, di cambiare l’aspetto dell’immagine in base ad una selezione. Per risolvere questi problemi possiamo utilizzare le icon font: si tratta di set di caratteri, ognuno dei quali rappresenta un’immagine e, come tali, godono di tutti vantaggi dei font tra i quali: Sono vettoriali e quindi scalano senza sgranare Possono essere cambiati di colore tramite css Possono essere ombreggiati tramite css Occupano meno spazio (e quindi utilizzano meno banda) rispetto ad un’immagine A partire dalla versione 6.2 Liferay include al suo interno un pacchetto di icon font (la lista è disponibile qui: http://liferay.github.io/alloy-bootstrap/base-css.html#icons) e possono essere utilizzati out-of-the-box. Esistono in rete molti siti che permettono di creare, anche in modo gratuito, dei set di icon font scegliendo da elenchi interminabili di possibilità quelle che ci interessano. Citiamo ad esempio http://www.fontello.com/, http://www.flaticon.com/ e https://icomoon.io/. In questo articolo vedremo come utilizzare le icon font di un pacchetto custom all’interno della nostra portlet. Creare un pacchetto personalizzato di icon font Prendiamo come esempio il sito Fontello (http://www.fontello.com/).  Possiamo selezionare tutte le icone che vogliamo inserire all’interno del nostro set e scaricarle in un unico archivio zip. Vediamo nel dettaglio cosa contiene l’archivio creato: Cartella CSS – i fogli di stile che tra poco copieremo all’interno del nostro plugin Cartella Font – i file contenenti il font vero e proprio, anche questi dovranno essere copiati nel nostro plugin config.json – un file in formato JSON che contiene le indicazioni su tutte le icone che fanno parte del nostro pacchetto. Caricando questo file sul sito avremo tutte le nostre icone già selezionate e impostate: in questo modo è più semplice modificare il nostro set senza dover tutte le volte ripartire da capo demo.html – file di demo dell’intero set di icone da aprire in qualsiasi browser LICENSE.txt – file di licenza README.txt – istruzioni di installazione. Da leggere sempre!!  🙂 Aggiungere le icon font al proprio plugin Copiare i file dei font all’interno di docroot. Io consiglio di utilizzare la sottocartella fonts ma non è obbligatorio Copiare i file css all’interno di docroot. Anche in questo caso nessun path è obbligatorio ma consiglio di utilizzare la sottocartella css. In realtà per il nostro esempio ci interessa solo il file senza suffisso, nel nostro caso marcorosetti.css Apriamo il file marcorosetti.css e per prima verifichiamo (ed eventualmente correggiamo) i path relativi ai font che troviamo all’interno dell’istruzione @font-face Assicuriamoci che il selettore css e le classi del set non inizino con “icon-” o potremmo ritrovarci con alcune incompatibilità con gli icon font di default di liferay. Possiamo modificare il file css a mano oppure utilizzare le impostazioni avanzate di esportazione di fontello. Il risultato da ottenere dovrà essere simile a questo: Sempre per questioni di compatibilità meglio rimuovere le direttive su width e margin-right: Infine aggiungiamo al file liferay-portlet.xml i riferimenti ai css <header-portlet-css>/css/marcorosetti.css</header-portlet-css> in modo che il css venga caricato automaticamente su ogni nostra pagina Esempi di utilizzo A...

Leggi

Comunicazione tra plugin grazie al Message Bus

Scritto da il 19 aprile 2015 in Liferay | 0 commenti

Comunicazione tra plugin grazie al Message Bus

Come far comunicare tra loro due plugin differenti? Ci sono vari modi per trasferire informazioni tra due plugin differenti. Uno di questi è lo scambio di messaggi tramite Message Bus. Possiamo individuare due ruoli principali in questa comunicazione: Message producer – Il plugin che crea il messaggio Message consumer – Il plugin che riceve il messaggio Vediamo quali sono i passi necessari per implementare questo tipo di comunicazione Message producer – Creare la Destination Per prima cosa occorre creare una destinazione per i nostri messaggi. Questa operazione può essere fatta nel file messaging-spring.xml ma in questo modo ogni volta che il plugin sarà deployato la destination verrà ricreata, perdendo tutti i listener eventualmente associati. Un modo per ovviare a questo problema è creare la destination tramite codice java: private static String DESTINATION_NAME = "marcorosetti/myentity/update" private void createDestinations() { if(!MessageBusUtil.getMessageBus().hasDestination(DESTINATION_NAME)){ BaseDestination destination = new ParallelDestination(); destination.setName(DESTINATION_NAME); destination.open(); MessageBusUtil.addDestination(destination); }else { Destination destination = MessageBusUtil.getMessageBus().getDestination(DESTINATION_NAME); destination.open(); } } Il miglior momento in cui invocare questo metodo è all’interno del metodo di startup del plugin. Per i dettagli vedere QUI Message producer – Inviare il messaggio Per inviare il messaggio possiamo utilizzare in qualsiasi punto del nostro codice alcuni metodi statici messi a disposizione da Liferay. Il messaggio creato può .... Message message = new Message(); message.put("className", MyEntity.class.getName()); message.put("classPK", myEntity.getPrimaryKey()); MessageBusUtil.sendMessage("marcorosetti/myentity/update", message); ... Message consumer – Implementare il listener Per prima cosa dobbiamo implementare la classe che gestirà la ricezione del messaggio. Per farlo dobbiamo estendere la classe com.liferay.portal.kernel.messaging.MessageListener: in particolare la logica di gestione del messaggio deve essere implementata nel metodo void receive(Message message): public class MyListener extends MessageListener{ .... @Override public void receive(Message message) throws MessageListenerException { String className = message.getString("className"); String classPK = message.getString("classPK"); _log.debug("Message received className "+className+" and classPK "+classPK); .... } Message consumer – Agganciare il listener alla destination Una volta implementato il listener va agganciato alla destinazione creata. Ricordiamoci di gestire anche il redeploy del plugin, quindi di controllare se è già presente un listener del tipo implementato prima di aggiungerlo. Per farlo possiamo usare codice di questo tipo: Destination destination = MessageBusUtil.getMessageBus().getDestination(destinationName); if(destination != null) { Set<MessageListener> listeners = destination.getMessageListeners(); for (MessageListener messageListener : listeners) { if(messageListener instanceof MyListener) { _log.debug("Found MyListener registered to destination "+destinationName+" removing it"); MessageBusUtil.unregisterMessageListener(destination.getName(), messageListener); }else if(messageListener instanceof InvokerMessageListener) InvokerMessageListener invoker = (InvokerMessageListener)messageListener; if(invoker.getMessageListener().getClass().getName().equals(MyListener.class.getName())) _log.debug("Found MyListener registered to destination "+destinationName+" removing it"); MessageBusUtil.unregisterMessageListener(destination.getName(), invoker.getMessageListener()); } } } MessageBusUtil.registerMessageListener(destinationName, new MyListener()); Non facciamoci spaventare da un codice all’apparenza più complesso del solito: si tratta di scorrere tutta la lista dei listener agganciati alla destinazione ed eventualmente sganciare il listener della classe MyListener. La complicazione nasce dal fatto che in alcuni casi viene utilizzato il proxy InvokerMessageListener per wrappare la vera classe del listener. Non ci addentriamo nei dettagli di questa scelta ma ci basta sapere come gestirla: invocando il metodo getMessageListener() sul proxy, che ci restituisce la vera istanza del listener e ci permette di verificarne la classe. Anche in questo caso conviene fare questa operazione all’interno del codice di startup del plugin in modo da essere sicuri che venga eseguita sempre quando il plugin è presente Approfondimenti e riferimenti...

Leggi

Indicizzazione entità custom con Lucene

Scritto da il 12 aprile 2015 in Liferay | 0 commenti

Indicizzazione entità custom con Lucene

Come possiamo utilizzare Lucene per la ricerca delle nostre entità custom? Liferay utilizza il motore di indicizzazione Lucene per eseguire le ricerche su molte delle sue entità di portale. In questo articolo vedremo quali sono i passi per implementare ricerche di questo tipo anche sulle entità delle nostre portlet custom. Implementare l’indexer La prima cosa da fare è descrivere come tradurre la nostra entità custom in modo che Lucene possa gestirla: per fare questo dobbiamo implementare un nostro “indexer”. L’indexer sarà una classe che deve estendere la classe astratta com.liferay.portal.kernel.search.BaseIndexer I metodi principali che dobbiamo implementare: String[] getClassNames() –  fornisce un array dei nomi dei modelli che il nostro indexer gestisce String getPortletId() –  fornisce l’identificativo univoco della nostra portlet String getPortletId(SearchContext searchContext) – analogo al metodo precedente void doDelete(Object entity) – le operazioni da eseguire sugli indici Lucene quando viene eliminata un’entità (ad es. eliminare anche le entità correlate) Document doGetDocument(Object entity) – il metodo principale, in cui dobbiamo implementare la logica di mapping tra la nostra entità custom e l’oggetto di tipo Document gestito direttamente da Lucene e salvato sugli indici Summary doGetSummary(Document document, Locale locale, String snippet, PortletURL portletUrl) – restituisce una rappresentazione sommaria di un oggetto Document proveniente da una ricerca su Lucene. Sebbene questo metodo non sia strettamente necessario per l’utilizzo degli indici di lucene, viene utilizzato in molte portlet del portale, quali Asset Publisher o Ricerca, quindi consiglio di implementarlo almeno in bozza void doReindex(Object object) –  invocato dal portale tutte le volte che è necessario il reindex. Il parametro in ingresso generico permette di gestire diversi casi, ad esempio: List<[MyEntity]> – una lista di entità da indicizzare [MyEntity] – un’unica entità da indicizzare long[] – un array di chiavi primarie delle entità da indicizzare etc. void doReindex(String[] companyIds) –  invocato quando si effettua il reindex da pannello di controllo (Vedi “Reindex completo entità della portlet” per dettagli). In ingresso vengono ricevuti gli id di tutte le company presenti nel portale void doReindex(String className, String classPK) – invocato quando è necessario il reindex di una singola entità, conosciuti nome della classe di modello (className) e chiave univoca (classPK) Come spesso accade nel mondo Liferay ci sono ottimi esempi di implementazione all’interno del codice stesso del portale. In questo caso consiglio di studiare la classe com.liferay.portlet.usersadmin.util.UserIndexer che è quella utilizzata dal portale per indicizzare gli utenti e contiene ottimi spunti e punti di riferimento implementativi per tutti i metodi descritti sopra Definizione classe indexer su liferay-portlet.xml Oltre ad implementare l’indexer dobbiamo comunicare a liferay che la nostra portlet utilizzare un indexer. Per farlo dobbiamo inserire nel liferay-portlet.xml del nostro progetto il tag <indexer-class> con l’indicazione del nome completo (package + nome classe) del nostro indexer Annotation su metodi del Service Abbiamo quasi finito, ci manca solo di invocare il processo di reindicizzazione ogni volta che una nostra entità viene creata, modificata o eliminata. Tra i vari modi che ci sono per invocare la reindicizzazione quello che consiglio è l’utilizzo dell’annotation @Indexable. Questa annotation può essere messa sui metodi dei services (tipicamente nella classe [MyEntity]LocalServiceImpl) che hanno come parametro di ritorno l’entità che vogliamo reindicizzare: in questo modo, ogni volta che un metodo annotato ritorna un’entità, Liferay si preoccupa di intercettare l’entità e di eseguirne il reindex sugli indici di Lucene. L’annotation prevede il parametro “type“, obbligatorio, che può avere 2 valori e ne configura il comportamento: IndexableType.REINDEX – L’entità ritornata viene reindicizzata...

Leggi

Lucene: sincronizzarsi con l’indicizzazione

Scritto da il 8 marzo 2015 in Liferay | 0 commenti

Lucene: sincronizzarsi con l’indicizzazione

Come possiamo essere sicuri che l’indicizzazione di Lucene sia terminata? Lucene è un motore di indicizzazione utilizzato da Liferay per la ricerca delle proprie entità e può essere facilmente implementato anche per le entità custom delle proprie portlet. Oltre agli indiscutibili vantaggi in termini di possibilità di ricerca e di velocità possiamo però incorrere in alcuni piccoli problemi o comportamenti inaspettati. Uno di questi deriva dal fatto che il processo di indicizzazione vero e proprio viene eseguito in modo asincrono (cioè su un thread separato) rispetto al thread principale da cui parte. Questa scelta, unita ad un processo di creazione/aggiornamento dell’entità sugli indici che potrebbe richiedere molto tempo, può condurre a risultati inattesi nelle ricerche eseguite nei momenti successivi. La soluzione a questo problema richiede non più di due righe di codice ma è utile avere una visione un po’ più ampia dell’intero meccanismo di reindicizzazione per capirne meglio il funzionamento. Un esempio per chiarire il problema Abbiamo un’entità che, tra le altre, ha una variabile che ne identifica il colore che può assumere differenti valori(giallo, rosso, verde, etc.). Abbiamo una visualizzazione a lista che ci permette di filtrare le diverse entità per singolo colore e per fare questo esegue una query sugli indici Lucene. Supponiamo di avere il filtro impostato su “Giallo” e di modificare una delle entità una cambiandone il colore. Al salvataggio viene avviato da Liferay il processo di indicizzazione Lucene dell’entità ma non si attende che questo abbia effettivamente terminato l’indicizzazione prima di ritornare il controllo ai livelli superiori. In altre parole l’utente che ha fatto il salvataggio può ricevere la notifica di operazione completata prima che l’aggiornamento degli indici sia terminato. Se in questa situazione viene ricaricata la lista con il filtro a “Giallo”, l’entità incriminata continuerà a comparire anche se il salvataggio è andato a buon fine. Il Message Bus per ottenere processi asincroni L’asincronicità dell’indicizzazione è ottenuta da Liferay sfruttando i servizi del Message Bus. Questi servizi permettono, tra le altre cose, di inviare messaggi a destinazioni (chiamate code) senza preoccuparsi né di chi né di quando verranno ricevuti e processati. Nel nostro caso particolare, in seguito al salvataggio, Liferay invia un messaggio sul Message Bus contenente tutti i dati utili alla reindicizzazione su una coda specifica senza attendere una risposta. Da parte di Lucene ci sarà un processo incaricato di verificare la presenza di messaggi di reindicizzazione sulla coda ed eventualmente processarli, ma su un thread separato da quello che li ha generati Forzare l’attesa di risposta ad un messaggio Esiste però un meccanismo per forzare Liferay ad attendere una risposta ogni volta che invia un messaggio sul Message Bus e questo si ottiene inserendo questo codice in un punto precedente all’operazione di indicizzazione ProxyModeThreadLocal.setForceSync(true); Può essere una buona idea (ma va valutata a seconda dei casi specifici) inserire il codice prima di ogni Action della nostra portlet. Per fare questo è sufficiente fare l’override del metodo callActionMethod nella nostra classe che estende MVCPortlet in questo modo  ...

Leggi

Password di accesso al database criptata

Scritto da il 1 marzo 2015 in Liferay | 0 commenti

Password di accesso al database criptata

Come rendere più sicura la password di connessione al database? Le credenziali di accesso al database vengono salvate, di default, in chiaro all’interno di un file di properties (portal-ext.properties o portal-setup-wizard.properties a seconda dei casi). Se vogliamo rendere più sicuro questo meccanismo possiamo fare una semplice modifica al codice sorgente di Liferay per poter gestire anche valori criptati. La classe che dobbiamo modificare è com.liferay.portal.dao.jdb.DataSourceFactoryImpl, in particolare il metodo initDataSource(Properties properties): Vediamo le operazioni importanti del codice che abbiamo inserito Scorriamo tutte le proprietà impostate fino a trovare la proprietà password Se è stato impostato a TRUE il valore di jdbc.default.encrypted.password allora consideriamo il valore della password come criptato e lo decriptiamo prima di sovrascriverlo nelle properties Una volta modificato il codice dobbiamo rigenerare le librerie di liferay utilzzando i task ant messi a disposizione insieme ai sorgenti: possiamo utilizzare compile e poi andare a sostituire la classe generata all’interno del file portal-impl.jar nella cartella tomcat-7.0.42\webapps\ROOT\WEB-INF\lib oppure rigenerare l’intero file con il task jar. Alcune considerazioni Nell’esempio riportato l’algoritmo di cript-decrypt è un semplice Base64 hashing che serve solo come “placeholder”. Possiamo ovviamente complicare come vogliamo l’algoritmo a seconda delle nostre esigenze L’approccio applicato alla proprietà “password” si può applicare a qualsiasi proprietà si intenda criptare Se non facciamo altre modifiche ai sorgenti potrebbero venire stampati nei log dei messaggi a livello WARN del tipo “Property encrypted.password is not a valid…“. Possiamo tranquillamente ignorare questi messaggi L’esempio vale per Liferay versione 6.2 La sicurezza di questo approccio potrebbe essere aumentata andando ad offuscare il codice della classe Un approccio di sicurezza più architetturale consiste nell’utilizzare datasource esterni e iniettati tramite nome JNDI. In questo modo la gestione della sicurezza delle credenziali di accesso è demandata all’application...

Leggi

Restrizioni indirizzo mail utente

Scritto da il 24 febbraio 2015 in Liferay | 0 commenti

Restrizioni indirizzo mail utente

Come impostare delle restrizioni su username e indirizzi mail dei nuovi utenti del portale? Se vogliamo escludere username o indirizzi mail dal poter essere utilizzati dagli utenti del nostro portale dobbiamo accedere, nel Pannello di Controllo, alla sezione Configurazione -> Impostazioni Portale -> Utenti -> Credenziali riservate In questa parte possiamo inserire i nomi e le email riservate, un valore per ogni riga.   Una volta fatto questo (e ovviamente salvato le modifiche), tentando di inserire un utente con uno username o un indirizzo email riservato riceveremo un errore e l’operazione non andrà a buon fine.     Attenzione: esiste un altro indirizzo email riservato che non è possibile utilizzare nella creazioni degli utenti! Si tratta di quello eventualmente specificato come Nome Utente per la ricezione di posta tramite protocollo POP3. Questo valore può essere impostato sia da file di properties (di solito portal-ext.properties) che da interfaccia. Il modo migliore per verificarlo è di accedere alla lista delle proprietà di portale dal Pannello di Controllo, sezione Configurazione -> Gestione Server -> Proprietà -> Proprietà del Portale e verificare la...

Leggi

Liferay mobile SDK parte I

Scritto da il 21 febbraio 2015 in Android, IOS, Liferay | 0 commenti

Liferay mobile SDK parte I

Come accedere da una app Android o IOS alle nostre portlet custom? In questa prima parte vediamo come, grazie all’uso di Liferay Mobile SDK, è possibile generare librerie per accedere da una app mobile nativa (per IOS o Android) alle nostre portlet custom. Nella seconda parte vedremo come poter utilizzare le librerie generate all’interno delle nostre applicazioni mobile native. Requisiti Server con installato Liferay 6.2 Ambiente di sviluppo con Liferay SDK Client Git (per installare Liferay M0bile SDK) Installazione Liferay Mobile SDK Per installare Liferay Mobile SDK è necessario scaricare il progetto dal repository git. Dalla cartella in cui vogliamo installarlo eseguiamo questo comando da terminale git clone https://github.com/liferay/liferay-mobile-sdk.git e attendiamo che tutto il progetto sia scaricato Creare un remote service per le proprie entità Assicuriamoci che per la nostra entità l’attributo remote-service sia impostato a true nel file service.xml della nostra portlet. Ricordiamoci di rigenerare i services per rendere effettive eventuali modifiche Andiamo a modificare il file generato [ENTITY_NAME]ServiceImpl.java implementando i servizi che vogliamo rendere disponibili alla nostra app. Anche in questo caso occorre rigenerare i services Generiamo i file WSSD (Web Service Deployment Descriptor) per la nostra portlet. Liferay Mobile SDK utilizza questi descrittori per poter identificare i servizi remoti messi a disposizione dalla nostra portlet. Per farlo basta utilizzare il comando ant build-wsdd Assicuriamoci che la nostra portlet sia deployata su un ambiente Liferay avviato. Per verificare i servizi remoti messi a disposizione dalla nostra portlet (e dall’intero portale Liferay) possiamo usare la pagina api/jsonws che la nostra installazione Liferay mette a disposizione    Creare un modulo di generazione per la nostra portlet Il prossimo passo è quello di creare, all’interno di Liferay Mobile SDK, un “modulo”. Ogni modulo contiene le informazioni necessarie all’SDK per poter generare le librerie mobile relative alla nostra portlet Dalla cartella principale dove è installato Liferay Mobile SDK eseguite il comando ./gradlew createModule -P=all Si avvierà un wizard che ci permette di impostare le proprietà del modulo. Per i dettagli su ogni singola proprietà possiamo fare riferimento alla documentazione ufficiale. Le proprietà più importanti sono Context: il contesto web della nostra portlet Server URL: l’indirizzo completo di porta del server POM Description: descrizione del file POM (solo per generazione .jar) da non lasciare vuoto Una volta impostate le proprietà Liferay Mobile SDK si connetterà al nostro server, alla ricerca della nostra portlet e genererà il codice che ci serve all’interno della cartella modules\${portlet_context} Aggiornare i servizi mobile generati Se andiamo a modificare i servizi remoti della nostra portlet dobbiamo ricordarci sempre di rigenerare anche i servizi mobile generati da Liferay Mobile SDK. Per fare questo non è necessario ricreare ogni volta un modulo, ma è sufficiente posizionarsi nella cartella del nostro modulo modules/${portlet_context} e lanciare il comando ../../gradlew generate Generare la libreria per Android Per generare un file .jar contenente tutte le classi per Android è sufficiente posizionarsi nella cartella del nostro modulo modules\${portlet_context} e lanciare il comando ../../gradlew jar All’interno della cartella “build/libs” verrà generato il file .jar Generare la libreria per IOS Per generare un file .zip contenente tutte le classi per IOS è sufficiente posizionarsi nella cartella del nostro modulo modules\${portlet_context} e lanciare il comando ../../gradlew zip All’interno della cartella “build” verrà generato il file .zip Generare la libreria per Windows Attualmente sono supportati ufficialmente solamente Android e IOS. Esiste però una estensione per Liferay Mobile SDK per generare...

Leggi