I cookie ci aiutano a fornire i nostri servizi.

Utilizzando tali servizi, accetti l'utilizzo dei cookie da parte nostra. Per saperne di piu'

Approvo

D'vel Blog

A partire dalla fine del 2010 lavoro come Liferay Expert presso l'azienda D'vel snc, per la quale scrivo spesso articoli tecnici sul blog.

Il blog è davvero molto utile e ricco di preziosi consigli; per chi fosse interessato l'indirizzo è il seguente: blog.d-vel.com.

Ecco un estratto degli ultimi articoli scritti.

blogdvel
  1. Liferay 7 mette a disposizione alcuni task gradle che possono venirci utili per l'inizializzazione del bundle e per crearne una distrubuzione per i vari ambienti.

    Per prima cosa da eclipse creiamo il workspace Liferay.

    Modifichiamo tramite un editor di testo il file gradle.properties andando a modificare la seguente property

    liferay.workspace.bundle.url

    mettendo come valore il link alla versione che vogliamo utilizzare

    Es:

    liferay.workspace.bundle.url=https://cdn.lfrs.sl/releases.liferay.com/portal/7.0.4-ga5/liferay-ce-portal-tomcat-7.0-ga5-20171018150113838.zip

    A questo punto siamo pronti per inizializzare il bundle

    Possiamo notare come all'interno del nostro workspace sia presente una cartella configs, che contiene tutte le configurazioni suddivise per tipologia di ambiente. La configurazione di default impostata nel gradle.properties è local

    liferay.workspace.environment=local

    Lanciamo il seguente comando per inizializzare il bundle

    gradlew initBundle -Pliferay.workspace.environment=local

    Possiamo non espicitare l'ambiente (in questo caso prenderà il default) o cambiarlo. Il task si connetterà al repository specificato e andrà a scaricare e configurare il nostro bundle nelle cartella bundle del nostro workspace (anche questa è modificabile da build.gradle)

    Ora invece vorremmo preparare uno zip/tar contenente tutto il nostro bundle comprensivo di tutti i moduli (che stanno sotto modules) buildati e già deployati

    gradlew distBundle[Zip|Tar] -Pliferay.workspace.environment=[ENVIRONMENT]

    Es:

    gradlew distBundleTar -Pliferay.workspace.environment=local

    Al termine dell'esecuzione troveremo nella cartella build del nostro workspace il tar/zip di tutto il nostro bundle comprensivo di moduli.

     

  2. Ho avuto la necessità di dover recuperare il numero delle notifiche non lette tramite un servizio rest per poterne fare il polling via Javascript. Liferay purtroppo non mette a disposizione un api rest per le notifiche, per cui ho deciso di implementarla utilizzando il template BLADE "rest" messo a disposizione da Liferay DXP.

    Ho creato, da Eclipse, un nuovo progetto utilizzando il template "rest"

    Per prima cosa verifichiamo che nel  build.gradle ci siano le seguenti dipendenze:

     compile group: "javax.ws.rs", name:"javax.ws.rs-api", version:"2.0.1" compileOnly group: "org.apache.cxf", name: "cxf-core", version: "3.0.3" compileOnly group: "org.apache.cxf", name: "cxf-rt-frontend-jaxrs", version: "3.0.0" compileOnly group: "org.apache.cxf", name: "cxf-rt-rs-extension-providers", version: "3.0.3"

    Ora creaimo nella cartella resources una cartella configuration e creiamo questi due files:

    • com.liferay.portal.remote.cxf.common.configuration.CXFEndpointPublisherConfiguration-cxf.properties
    • com.liferay.portal.remote.rest.extender.configuration.RestExtenderConfiguration-rest.properties

    creaimo il CXFEndpointPublisherConfiguration-cxf.properties con queste property

     contextPath=/api extensions= authVerifierProperties=auth.verifier.PortalSessionAuthVerifier.urls.includes\=*

    e il RestExtenderConfiguration-rest con queste property

     contextPaths=/api jaxRsProviderFilterStrings= jaxRsServiceFilterStrings= jaxRsApplicationFilterStrings=

    Inserendo queste configurazioni direttamente da property potremo pubblicare i nostri servizi (in questo esempio risponderranno sul path /api) senza dover configurare nulla in control panel, a patto di aggiungere al bnd.bnd le seguenti informazioni

     Liferay-Configuration-Path: /configuration Include-Resource:configuration=src/main/resources/configuration

    A questo punto passiamo all'implementazione del codice vero e proprio

    Il template blade avrà creato già un OSGI component con all'interno dei metodi di esempio.

    Le annotation di JAX ci permettono di recuperare alcuni parametri direttamente dal contesto, ma purtroppo i parametri recuperabili di default non sono correlati a oggetti Liferay. Nel nostro specifico caso sarebbe utile poter recuperare l'utente direttamente dal contesto, senza che questo debba essere passato come parametro.

    Cercando un pò in rete ho trovato questo articolo che spiega come creare dei custom provider:

    https://web.liferay.com/it/web/user.26526/blog/-/blogs/rest-custom-context-providers

    Di seguito il custom provider che ho creato per recuperare l'utente loggato

     @Component(immediate = true, service = UserContextProvider.class) @Provider public class UserContextProvider implements ContextProvider<User> { @Override public User createContext(Message message) { try { return _portal.getUser( (HttpServletRequest)message.getContextualProperty( "HTTP.REQUEST")); } catch (PortalException pe) { if (_log.isWarnEnabled()) { _log.warn("Unable to get user", pe); } return null; } } private static final Log _log = LogFactoryUtil.getLog( UserContextProvider.class); @Reference private Portal _portal; }

    Implementata la seguente classe basterà referenziarla attraverso il metodo getSingletons()creato in automatico da blade

     @Override public Set<Object> getSingletons() { Set<Object> singletons = new HashSet<>(); singletons.add(_userContextProvider); singletons.add(this); return singletons; }

    Ora non ci rimane che esporre il nostro metodo per effettuare il count delle notifiche

     @GET @Path("/notificationCount") @Produces(MediaType.APPLICATION_JSON) public String countNotifications(@Context User user) { int notificationCount = _userNotificationEventLocalService.getArchivedUserNotificationEventsCount(user.getUserId(), false); JSONObject jsonObject = JSONFactoryUtil.createJSONObject(); jsonObject.put("notificationCount", notificationCount); return jsonObject.toJSONString(); }

    Invochiamo da browser l'url che risponde sul path /o/api/<rest-path>/notificationCount e il gioco è fatto.

     

     

     

  3. Ciao a tutti!

    Questo è un post super rapido che tratta un tema sicuramente sentito tra chi sviluppa applicazioni web, ovvero "come posso trappare il caricamento della mia (pagina|portlet|singola portlet)?".

    La spiegazione è, come al solito, molto semplice e fornita dalle funzionalità standard di Liferay!

    Vediamoli nel dettaglio! ;)

    Come trappare il caricamento del DOM HTML (ad esclusione delle portlet)

    AUI().ready(
         /*
         This function gets loaded when all the HTML, not including the portlets, is
         loaded.
         */
     
         function() {
         }
    );

     

    Come trappare il caricamento di una singola portlet

    Liferay.Portlet.ready(
        /*
        This function gets loaded after each and every portlet on the page.
        portletId: the current portlet's id
        node: the Alloy Node object of the current portlet
        */

        function(portletId, node) {
        }
    );

    Come trappare quando tutte le portlet sono state caricate

    Liferay.on(
        'allPortletsReady',

        /*
        This function gets loaded when everything, including the portlets, is on
        the page.
        */

        function() {
        }
    );

    Grazie a questi frammenti di javascript potete ottenere l'effetto voluto! :)

    Spero d'esservi stato d'aiuto! :)

    Alla prossima, ciao, J.

  4. Torniamo a parlare di Alloy Editor per capire come abilitare una funzionalità molto utile ed, ahimè, molto necessaria: Incolla da Word.

    Già, perchè purtroppo le persone hanno la brutta abitudine di scrivere su Word (mettendo font, grassetti, allineamenti, rientri,...) e poi copiare il testo direttamente all'interno dell'editor del sito web, con il risultato che la resa grafica è terribile ed i metadati nascosti che vengono copiati sono un'inutile infinità.

    Per fortuna i moderni editor HTML (tra cui CKEditor) sono in grado di gestire questa cosa, consentendo di incollare il testo di Word depurandolo da tutto quello che non serve. Anche Alloy Editor è in grado di farlo, ma bisogna configurarlo opportunamente.

    Per i dettagli tecnici (le dipendenze,...) vi rimando alla lettura del mio precedente articolo Allineamento del testo con Alloy Editor, adesso mi limiterò a farvi vedere direttamente il componente OSGi che dovete implementare.

     @Component(property = { "editor.name=alloyeditor", "javax.portlet.name=" + JournalPortletKeys.JOURNAL, "javax.portlet.name=" + PortletKeys.USER_PROFILE, "service.ranking:Integer=100" }, service = EditorConfigContributor.class) public class PasteFromWordEditorConfigContributor extends BaseEditorConfigContributor { @Override public void populateConfigJSONObject( JSONObject jsonObject, Map<String, Object> inputEditorTaglibAttributes, ThemeDisplay themeDisplay, RequestBackedPortletURLFactory requestBackedPortletURLFactory) { String extraPlugins = jsonObject.getString("extraPlugins"); if (Validator.isNotNull(extraPlugins)) extraPlugins += StringPool.COMMA; extraPlugins += "ae_uibridge,ae_buttonbridge,pastefromword,clipboard,dialog,dialogui"; jsonObject.put("extraPlugins", extraPlugins); JSONObject toolbars = jsonObject.getJSONObject("toolbars"); if (toolbars != null) { JSONObject add = toolbars.getJSONObject("add"); if (add != null) { JSONArray buttons = add.getJSONArray("buttons"); buttons.put("PasteFromWord"); } } } }

    In questo caso l'elemento chiave è extraPlugins; infatti prima di poter aggiungere il pulsante, bisogna abilitare alcuni plugin di CKEditor e questo si fa semplicemente aggiungedoli alla lista di quelli già presenti nell'oggetto di configurazione; se siete pignoli potete controllare se ci sono doppioni...

    Una volta fatto questo potete aggiungere il pulsante, che si chiama PasteFromWord, all'interno della toolbar add; questa toolbar, per intenderci, è quella contrassegnata dal grande simbolo + sulla sinistra, la stessa che consente di aggiungere immagini, tabelle,... Infatti, in questo caso, non dobbiamo modificare il testo selezionato ma agire direttamente sul contenuto dell'editor, nel punto in cui si trova il cursore.

    Per maggiori dettagli consultare:

  5. Liferay 7 introduce tante novità tra cui Alloy Editor, il nuovo e potente editor HTML derivato da CKEditor.

    Tutto molto bello ed interessante ma chi di voi ha avuto modo di utilizzarlo si sarà sicuramente chiesto come fare per allineare il testo.

    Perchè mi consente di inserire tabelle, cambiare lo stile ma non allineare il testo? E' impossibile che Alloy Editor non consenta di farlo...

    Infatti è vero, Alloy Editor può farlo ma bisogna scrivere qualche riga di codice per abilitare i pulsanti; innanzitutto aggiungete questa dipendenza nel vostro file build.gradle:

     compileOnly group: "com.liferay", name: "com.liferay.journal.api", version: "2.9.2"

    Dopodichè aggiungete la seguente classe Java al vostro bundle web:

     @Component(property = { "editor.name=alloyeditor", "javax.portlet.name=" + JournalPortletKeys.JOURNAL, "service.ranking:Integer=100" }, service = EditorConfigContributor.class) public class TextAlignmentEditorConfigContributor extends BaseEditorConfigContributor { @Override public void populateConfigJSONObject( JSONObject jsonObject, Map<String, Object> inputEditorTaglibAttributes, ThemeDisplay themeDisplay, RequestBackedPortletURLFactory requestBackedPortletURLFactory) { JSONObject toolbars = jsonObject.getJSONObject("toolbars"); if (toolbars != null) { JSONObject toolbarStyles = toolbars.getJSONObject("styles"); if (toolbarStyles != null) { JSONArray selections = toolbarStyles.getJSONArray("selections"); if (selections != null) { for (int i = 0; i < selections.length(); i++) { JSONObject selection = selections.getJSONObject(i); if (selection.has("name") && selection.getString("name").equals("text")) { JSONArray buttons = selection.getJSONArray("buttons"); if (buttons != null) { buttons.put("paragraphLeft"); buttons.put("paragraphCenter"); buttons.put("paragraphRight"); buttons.put("paragraphJustify"); } break; } } } } } } }

    La classe rappresenta un componente di tipo EditorConfigContributor che è l'elemento adibito a modificare la configurazione dell'editor HTML; il componente possiede alcune proprietà attraverso le quali è possibile fare modifiche molto granulari:

    • editor.config.key, è una proprietà ripetibile che rappresenta lo specifico campo del form in cui modificare la configurazione (contentEditor, summaryEditor,...);
    • editor.name, è una proprietà ripetibile che rappresenta il tipo di editor di cui modificare la configurazione (alloyeditor, ckeditor,...);
    • javax.portlet.name, è una proprietà ripetibile che rappresenta il nome della portlet in cui modificare la configurazione (può essere anche una portlet custom);
    • service.ranking:Integer, rappresenta la priorità del componente (potrebbero essercene più di uno da eseguire).

    La nostra classe estende poi la superclasse BaseEditorConfigContributor che si occupa di tutto il lavoro e ci obbliga ad implementare unicamente il metodo populateConfigJSONObject; questo metodo possiede alcuni parametri tra cui jsonObject che rappresenta la configurazione corrente dell'editor HTML.

    Tutto quello che abbiamo fatto nel codice è stato recuperare la sezione della configurazione che contiene i pulsanti ed aggiungere in fondo quelli adibiti all'allineamento del testo. Ecco quello che otteniamo:

    Attenzione perchè non abbiamo implementato l'allineamento del testo, quello già esisteva in Alloy Editor con tanto di icone; abbiamo solo aggiunto i pulsanti con il loro nome specifico.

    Per maggiori dettagli consultare: