Cookies help us deliver our services.

By using our services, you agree to our use of cookies. Learn more

I understand

D'vel Blog

By the end of the 2010 I work as Liferay Expert for D'vel snc, for which I often write technical articles on its blog.

This blog is really interesting and full of articles; if you're curious, this is the link: blog.d-vel.com.

Here is a list of the latest articles written.

blogdvel
  1. Buongiorno a tutti e ben ritrovati!

    Questo è proprio un periodo felice: riesco a scrivere un sacco di non-post (come quello di ieri ma anche come quello che sto scrivendo ora.. :D) che affrontano tematiche che.. Interessano praticamente solo me! ;D

    In realtà quello di oggi è un topic che mi da un po' da fare da sempre; ho sempre avuto il pallino di abbandonare Eclipse (o il Liferay Developer Studio) in funzione di una IDE che fosse un po' più robusta, stabile, funzionante, chi-più-ne-ha-più-ne-metta... :D

    Scherzi a parte, senza nulla togliere al Liferay Developer Studio 2.2.2 (che ad oggi l'Ing. Napolitano lista ancora nella sua personale top list delle versioni del LDS -di cui è un attento e preciso catalogatore seriale.. :D-), avevo da un po' cominciato a guardare al tema ma senza successo.

    L'antefatto...

    Poi è successo un fatto.. Nel weekend ho fatto upgrade del sistema operativo senza fare backup (prima volta in 20 anni.. :/).

    Beh, Big Sur (ho un mac..) ha un piccolo glitch per cui non viene più impostata correttamente la JAVA_HOME.

    Poco male, direte voi, mica tu Jader sei uno che sviluppa.. :D

    ... Vero!

    Però, però, però, c'è un però.. :D

    ... Questa settimana stavo proprio tenendo un corso guardacaso sulla 6.2 di LR.

    E il fatto che non mi setti più la JAVA_HOME (anche se a manazza sembra averla correttamente settata..), il Liferay Developer Studio 2.2.2. NON mi parte più! 

    [N.d.J.: Appunto che ho correttamente configurato l'init di Eclipse impostando a manazza l'argomento per la corretta JVM, ma niente. Parte ma si frizza sullo splash screen e sulla selezione del workspace..]

    L'esigenza..

    Quindi quello che fino a sabato mattina era solo un vezzo, ora è diventato una triste necessità! ;)

    Per terminare il corso non ho avuto grossi problemi: ho riesumato il mac che avevo dismesso durante il lockdown in favore del nuovo e quindi il corso è terminato correttamente.

    Però ci sono alcuni progetti sui quali abbiamo della maintenance attiva per i quali, purtroppo o per fortuna :), dobbiamo fare manutenzione.

    [N.d.J.: Dobbiamo.. Devo: perché né l'Inge, né gli altri colleghi ne vogliono sapere.. :D]

    La soluzione

    Quindi questa mattina, di buon'ora (come sono solito fare da quando sono in smart working :)), mi sono messo d'impegno per far funzionare il LRSDK62 su IntelliJ.. 

    Spoiler: la soluzione che segue è ovvia, lo so, talmente ovvia che i più, tra voi, sicuramente la bolleranno come "minchiata" :). La scrivo comunque, però, perché un giorno mi servirà e allora non dovrò rifare tutto il giro che ho fatto questa mattina! :)

    Ragionandoci un po' su ho avuto un'intuizione: il DevStudio non fa altro che gestire dinamicamente il classpath e poi via ANT eseguire dei task.

    Se sistemo a manazza il classpath e faccio in modo che ANT buildi, vinco facile.. :)

    Quindi:

    • ho aperto in IntelliJ LE SINGOLE PORTLET contenute all'interno del SDK;
      • Quindi i progetti contenuti nelle varie folder del SDK (portlets, layouttpl, hooks, etc..);
    • ho configurato il classpath (more on this later...) delle singole portlet impostando:
      • il classpath globale con tutte le dipendenze per far compilare i miei portlet;
      • il classpath dei singoli moduli puntando alla loro WEB-INF/lib interna (quando necessario);
    • ho configurato ANT (la versione corretta) e l'ho fatto funzionare (solo da command line, sorry...)

    Dettagli tecnici

    Questo è lo screenshot di come ho configurato il classpath globale:

    Come sicuramente avrete notato bisogna aggiungere (per praticità / velocità):

    • tutti i JAR contenuti nella lib del Tomcat bundle Liferay;
    • tutti i JAR contenuti nella lib/ext del Tomcat bundle Liferay;
    • questi singoli JAR, presi dalla <tomcat home>/webapps/ROOT/WEB-INF/lib:
      • commons-logging.jar
      • jstl-api.jar
      • jstl-impl.jar
      • log4j.jar
      • util-bridges.jar
      • util-java.jar
      • util-taglib.jar

    Fatto questo gli artefatti vi compileranno già; rimane da sistemare ANT.

    Per farlo funzionare, mi sono scaricato la versione apache-ant-1.9.15 e, a mano, lancio i singoli task da dentro alle folder dei singoli plugin.Questo approccio funziona: compila e fa deploy correttamente!

    Conclusioni

    Sicuramente starete dicendo peste e corna di questo post ;), mi sembra quasi di sentirvi! :)

    Però dovete ammettere che di articoli che spiegano questa cosa non ce ne sono proprio su internet... Forse perché, come dicevo all'inizio, forse è un problema soltanto mio.. :D

    Aggiungo che tutto quanto sopra funziona perché io ho già un SDK che è correttamente configurato: intendo che al suo interno è già presente, parametrizzato correttamente dal Liferay Developer Studio, il file build.jed.properties (che è il file che permette ad ANT di funzionare correttamente).

    Se così non fosse, nel senso che state iniziando un progetto nuovo sulla 6.2, beh, il mio consiglio è FERMARVI e cominciare il vostro nuovo  progetto su LR7.x perché, e sono serio, la vostra vita sarà molto più semplice e divertente! ;)

    In ultima analisi, è ovvio che questo paradigma (LR62 + IntelliJ) è un palliativo: quello che si perde nel non usare il Liferay Developer Studio è tanta roba (snippet, pannellini di configurazione, wizard.. Tanta roba davvero!).

    È vero anche però, per contro, che il tempo che guadagnerete lavorando con questa configurazione sarà mostruosamente più alto del tempo che Eclipse -io parlo per me, magari la vostra esperienza è diversa..- vi fa perdere di solito.. :)

    Detto questo, sperando di avervi aiutato a migliorare un po' la vostra performance lavorativa (o aver risolto il problema che BUG Sur ha introdotto.. :)), vi lascio e vi do appuntamento alla prossima! ;)

    Divertitevi e buon IntelliJ a tutti (anche con LR62)!! ;)

  2. Buongiorno a tutti!

    Quello di oggi non è un "vero" post (come quelli che siete abituati a leggere su questo blog ;)), ma è più un post di servizio..

    Questa mattina, giocando con SourceTree, ho fatto una hotfix su un ramo di produzione per un cliente e, all'atto di chiudere la hotfix mi sono imbattuto nel messaggio che vedete come titolo!

    Scrivo qui la soluzione, così la prossima volta che mi succederà non dovrò cercare su tutto il web il post che ho messo anche nelle risorse! :) 

    La soluzione è semplice: bisogna dire a SourceTree di utilizzare il git di sistema e non il suo interno.

    Come fare? Easy:

    If anybody using SourceTree, similar error was fixed by going to Preferences -> tab Git -> section Git version -> button Use System Git, and select from the dialog 'git'. It appears that after an update it forgot where it's command line tools are

    E, come aggiunge un altro utente nello stesso thread:

    Just remember to restart SourceTree then it works

    Per oggi è tutto; prometto che non appena avrò un minuto vi scriverò un post succoso degno dell'Ing. Napolitano, promesso! ;)

    Alla prossima!

    Source:

  3. Oggi vi parlerò di IFrame e di Javascript per un problema che ho avuto utilizzando Liferay ma che in realtà può essere applicato anche in altri contesti.

    La necessità che avevo era quella di visualizzare una pagina di Liferay 7.2 all'interno di un IFrame di una pagina di Liferay 6.2; inoltre avevo bisogno che l'IFrame si ridimensionasse in altezza automaticamente in modo da evitare il classico problema della doppia barra di scorrimento laterale.

    I più attenti di voi potrebbero dire: "Liferay ha già una portlet IFrame che fa esattamente quello che ti serve". Vero, peccato però che il ridimensionamento dell'IFrame non funzioni perchè vengono messi in atto dei controlli di sicurezza per cui Javascript non è in grado di recuperare dall'IFrame le informazioni necessarie per determinarne l'altezza; e nemmeno l'IFrame è in grado di invocare funzioni Javascript sul container esterno, per lo stesso motivo.

    Inoltre Liferay non consente che le sue pagine siano incluse in un IFrame (la famigerata Same Origin policy), quindi di problemi da risolvere ce ne sono diversi; ma procediamo per passi.

    Il primo problema che risolviamo è fare in modo che le pagine di Liferay 7.2 possano essere incluse in un IFrame; per questo dobbiamo creare il file system-ext.properties e posizionarlo nella cartella <tomcat>/webapps/ROOT/WEB-INF/classes. Il contenuto del file sarà l'elenco numerale di tutte le URL che devono essere incluse nell'IFrame, come ad esempio:

     http.header.secure.x.frame.options.0=/pagina-1 http.header.secure.x.frame.options.1=/web/guest/pagina-1 http.header.secure.x.frame.options.2=/en/page-1 http.header.secure.x.frame.options.3=/en/web/guest/page-2 http.header.secure.x.frame.options.4=... http.header.secure.x.frame.options.5=...

    A questo punto possiamo salvare il file, riavviare il server di Liferay 7.2 e finalmente riusciremo ad includere le specifiche pagine in un IFrame su Liferay 6.2.

    Bene, ma ora come facciamo a ridimensionare automaticamente l'IFrame in altezza? Per ottenere il risultato voluto dobbiamo riuscire a trasferire informazioni dall'IFrame al container. Per fare ciò dobbiamo scomodare Javascript ed in particolare la funzione postMessage che consente di inviare "messaggi" da una finestra ad un'altra del browser (anche non IFrame). Non entro nei dettagli della funzione ma se siete curiosi leggete qui.

    A questo punto, nella JSP della portlet da includere nell'IFrame aggiungiamo questo frammento di codice:

     <aui:script use="aui-base"> var content = A.one('#content'); var height = content.height(); parent.postMessage('{"height": ' + height + '}', '*'); </aui:script>

    Il codice non fa altro che recuperare l'elemento del DOM che rappresenta il contenuto della pagina e calcolarne l'altezza in pixel; dopodichè invia alla finestra parent (ossia il container dell'IFrame) un messaggio. Nel caso specifico il messaggio è una stringa che rappresenta un oggetto JSON con tutte le informazioni necessarie, nel nostro caso l'altezza in pixel; fate attenzione perchè la funzione postMessage consente di inviare anche oggetti ma, se non ricordo male, il buon vecchio IE supporta invece solamente stringhe.

    Ora possiamo spostarci su Liferay 6.2 dove dobbiamo andare ad intercettare il messaggio inviato dall'IFrame; il dove è ovviamente la JSP che visualizza l'IFrame e quindi avete 2 possibilità (nessuna delle quali verrà analizzata in questo post perché immagino siate già in grado di farlo da soli):

    1. fare un hook sulla portlet IFrame di Liferay 6.2
    2. farvi una vostra portlet custom per includere l'IFrame

    Quello che interessa a me adesso è solamente farvi vedere il codice per intercettare il messaggio:

     <aui:script use="aui-base"> var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent"; var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message"; var listener = window[eventMethod]; // Ascolta i messaggi che arrivano dall'altra finestra listener(messageEvent, function(e) { var key = e.message ? "message" : "data"; // Contenuto del messaggio var data = e[key]; try { // Sapendo che il messaggio è in formato JSON, lo convertiamo var json = A.JSON.parse(data);  // Recupero del nodo del DOM che rappresenta l'IFrame var iframe = A.one('#<portlet:namespace />iframe'); // Se il nodo esiste, ne imposto l'altezza if (iframe) iframe.setStyle('height', json.height); } catch(e) { console.error(e); } }, false); </aui:script>

    Forte vero? Chiaramente vi ho fatto vedere solamente come modificare l'altezza ma nel messaggio potete inviare qualunque informazione e farne poi quello che volete.

  4. Eccoci di nuovo qui, con il primo post del 2020 anche se siamo già a marzo...

    Oggi vi voglio parlare di qualcosa di piuttosto semplice ma che ha richiesto il solito tempo di indagine nei sorgenti di Liferay per capire se e come era possibile fare quanto richiesto.

    A partire dalla versione 7, Liferay consente di graficare le checkbox anche in un modo alternativo molto più accattivamente; in pratica anzichè dichiarare il campo booleano nel seguente solito modo (ipotizzando che male sia un campo booleano della nostra entità):

    <aui:input name="male" />

    possiamo definirlo anche così:

    <aui:input checked="<%= user.isMale() %>" name="male" type="toggle-switch" />

    Questo farà sì che a video, al posto della solita noiosa e bruttina checkbox, sia visualizzato un componente grafico molto più gradevole e moderno.

    Il problema di questa soluzione è che il componente grafico visualizza automaticamente l'etichetta SI oppure NO a seconda del valore del campo booleano; apparentemente non è possibile modificare queste etichette perchè il DTD della taglib non lo consente.

    Tuttavia, spulciando tra i sorgenti del portale, ho scoperto che la taglib supporta i dynamic attributes ossia, in parole povere, consente di specificare attributi non definiti nel DTD; guarda caso, tra i vari attributi, ci sono anche quelli per personalizzare le suddette etichette: labelOff e labelOn. Ecco quindi come definire il campo del form:

    <aui:input checked="<%= user.isMale() %>" labelOff="female" labelOn="male" name="male" type="toggle-switch" />

    Vi lascio come esercizio quello di scoprire a cosa servono gli altri attributi dinamici supportati dalla taglib:

    • autoComplete
    • buttonIconOff
    • buttonIconOn
    • dayLight
    • displayStyle
    • format
    • iconOff
    • iconOn
    • nullable
    • timeFormat

    Enjoy!

  5. Ciao a tutti e bentrovati sul nostro blog!

    Oggi pomeriggio, mentre m'annoiavo, ho deciso di risolvere uno dei puzzle più grandi che m'attanagliano da sempre su Liferay: capire dove finiscono (o dove hanno infilato.. :)) le JSP che sono richiamate dalle taglib di portale!

    [NdJ: lo so, non è una di quell cose da non doverci dormir di notte, però sapete che non ho una vita semplice, quindi abbiate pietà di me! ;D]

    Prima di svelarvi il segreto, però, vorrei farvi comprendere il caso d'uso, così che, se dovesse capitare anche a voi, possiate arrivare celermente ad una soluzione!

    Taglib core di prodotto e JSP che ne implementano la view

    Una volta mi sono trovato a dover mettere mano all'output di una taglib e, di conseguenza, mi sono fiondato nella classe java ce ne implementava la logica e sono andato a prendermi il nome della pagina JSP corrispondente per modificarla.

    Ora non ricordo più quale fosse quella volta la taglib, però, per semplicità, prendiamo come esempio la com.liferay.taglib.ui.IconDeleteTag.

    Se aprite questa classe e andate a cercare la JSP, troverete questo statement:

    private static final String _PAGE = "/html/taglib/ui/icon_delete/page.jsp";

     

    Allora, come spesso faccio quando parto per la tangente ;), sono partito a cercare sul FS il file incriminato ma...

    jedd@ne:~/liferay-ce-portal-src-7.1.1-ga2$ find . -type f -name page.jsp | grep -i icon_delete

    jedd@ne:~/liferay-ce-portal-src-7.1.1-ga2$

     

    Niente! Della mia JSP non c'è traccia! :(

    Allora, sconfortato e sempre pronto a reinventar la ruota come se non ci fosse un domani, sarò sicuramente partito a creare la mia versione di taglib per sistemare il problema che avevo (non ricordo, ma conoscendo i tempi che ho a disposizione io quando faccio questo genere di cose, può essere che non mi sbagli poi di tantissimo.. :)).

    E invece, come sempre, bastava leggere! :)

    Se io avessi investito più di 7 secondi per analizzare il codice della taglib, forse (dico forse perché non è detto.. :D) mi sarei accorto che all'inizio del metodogetPage() c'è questaimplementazione:

    if (FileAvailabilityUtil.isAvailable(servletContext, _PAGE)) {
        return _PAGE;
    }

     

    la quale mi avrebbe fornito un indizio molto interessante, ovvero che il concetto "IF IS AVAILABLE"può significare, per logica ;), che il file potrebbe anche non esserci.. Ah, ecco perché non lo trovavo.. :D

    Allora da dove viene preso il codice che genera l'output della taglib?

    Chiaramente il codice è presente nel resto dell'implementazione del metodo getPage(); ora però c'è da capire il perché e, soprattutto, come dovrei fare io se volessi modificarne l'output.

    Perché l'output della taglib è dentro al metodo getPage()?

    Chiaramente, al solito, i nostri amici hanno ottimizzato l'implementazione per far si che l'overhead di rendition delle singole taglib -che, come avrete notato anche voi in LR sono usate parecchio.. :D- sia super ridotto! A tal fine, quindi, hanno semplicemente eliminato le singole page.jsp e portato il codice che esse contenevano all'interno del metodo getPage().

    Come faccio ad affermare che il motivo è questo? :)

    Beh, continuate a leggere.. :D

    Ok ma.. Come faccio a modificare l'output di una taglib di LR?

    Questa cosa l'ho scoperta, invece, navigando sul FS e cianfrusagliando tra i sorgenti del portale..

    Ho trovato dentro le taglib dei file chiamati page.jsp.readme che, stranamente :D, ho aperto per leggerli..

    Guardate che cosa ci ho trovato dentro:

     The content of this JSP file was inlined to improve performance. To use your own content instead, remove the ".readme" extension and add your content to this file.

     

    Eggià: avevo proprio ragione!

    I file sono scomparsi perché hanno integrato la logica nel getPage() e se volessi modificarne l'output mi basterebbe seguire il suggerimento!

    Molto bene! A questo punto, però, ripenso al comando che ho dato prima.. E lo rilancio aggiustandolo:

    jedd@ne:~/liferay-ce-portal-src-7.1.1-ga2$ find . -type f -name page.jsp.readme | grep -i icon_delete

    jedd@ne:~/liferay-ce-portal-src-7.1.1-ga2$

     

    Ma come?? Non c'è il mio file!!

    Quindi?? Come faccio a modificare il mio output?

    Beh, questa volta il gioco è semplice: siccome il mio getPage() s'aspetta che la JSP possa esserci, dovrò solo fare in modo di fargliela trovare nel punto giusto del FS!

    E per farlo, mi basterà fare un fragment host per fargliela trovare! :)

    Anche per oggi è tutto; spero d'aver chiarito anche a tutti voi uno dei misteri più grandi di Liferay che da anni m'attanaglia la vita.. 

    ... E concludo dicendo che la seniority, se proprio vogliamo, sta anche nel saper leggere il codiceCosa che, evidentemente, come dice anche l'Ing. Napolitano :D, io ancora non ho imparato a fare!

    Passate un buon fine settimana e divertitevi (magari non con i sorgenti di LR, se potete! :D), voi che potete!

    Alla prossima!