Liferay AUI Auto Complete Ajax Example

Alloy UI AutoComplete Ajax Example


1. Cos’è AlloyUI?

AlloyUI (abbreviato in AUI) è un meta framework Open Source realizzato da Liferay che ingloba una serie di librerie javascript fornendo un set di API per la creazione di applicazioni web robuste e flessibili che toccano i tre livelli del browser:  struttura, stile e comportamento. AUI è costruito su Yahoo User Interface (YUI) e ha il supporto per una vasta gamma di funzioni avanzate studiate appositamente per la tecnologia delle portlet.

2. Obiettivo

Le applicazioni web “moderne” sono sempre più vicine alle comuni applicazioni desktop, framework sempre più completi, complessi e di semplice utilizzo, rendono l’implementazione relativamente semplice, inoltre con l’avvento di HTML 5 la distanza con le applicazioni desktop diventa ancora più breve. In quest’articolo vedremo come sia semplice realizzare una combo completa di funzione auto complete, i cui dati presentati non sono “statici”, bensì, provenienti da una base dati. Sfrutteremo Ajax per il reperimento dei dati da mostrare all’interno della combo. Ovviamente realizzeremo il tutto all’interno di una portlet. In Figura 1 è illustrato il risultato finale del lavoro. Quanto realizzato nel corso dell’articolo è disponibile come progetto Maven Liferay Portlet sul mio repository GitHub all’indirizzo liferay-aui-autocomplete-ajax-example

Alloy UI Autocomplete Ajax Example

Figura 1. Alloy UI Autocomplete Ajax Example

3. Requisiti

Per seguire con profitto il corso dell’articolo, è richiesta una conoscenza minima degli standard e tecnologie che ruotano nell’intorno delle Portlet, oltre che un minimo di dimestichezza con Liferay e il suo ambiente di sviluppo. Gli strumenti a supporto dovrebbero essere i seguenti:

  1. Liferay SDK 6.1
  2. Eclipse + Liferay Plugin o Liferay Studio
  3. Liferay Portal 6.1

L’esempio completo della portlet che troverete sul repository GitHub, è stato realizzato tramite Maven e l’archetype liferay-portlet-archetype versione 6.1.1 Community Edition.

 4. Serving resources

Nella prima versione delle specifiche Java Portlet Specification 1.0 (JSR 168), non era possibile servire risorse generate dinamicamente direttamente dalla portlet, era necessario un ulteriore servlet che serviva le risorse. Questa limitazione ha alcuni svantaggi:

  • Non è disponibile il contesto della portlet, il che significa non avere accesso a render parameters, portlet mode, window state, portlet preferences, portlet session e altro ancora;
  • Le URL generate nella servlet sono al di fuori dello scope del portale, inoltre, lo stato corrente delle pagine del portale viene perso;
  • La servlet non è eseguita nel contesto di sicurezza del portale;

Un vantaggio di servire risorse attraverso una servlet è il meno overhead, dovuto al fatto che la richiesta non deve passare attraverso l’intera struttura del portale, per esempio, quando è necessario servire grandi flussi multimediali.

La seconda versione delle specifiche Java Portlet Specification 2.0 (JSR 286) introduce un nuovo tipo di URL, la resource URL. La resource URL consente di attivare il metodo serveResource, sull’interfaccia ResourceServingPortlet che è possibile sfruttare per creare risorse dinamiche direttamente nel portlet.

package javax.portlet;

/**
 * The <code>ResourceServingPortlet</code> interface allows
 * serving resources through the portlet.
 *
 * The portlet container must call this method for links created by
 * the <code>RenderResponse.createResourceURL()</code> call.
 * If the portlet creates resource URLs with <code>RenderResponse.createResourceURL()</code>
 * it must implement this lifecycle method.
 *
 * @since 2.0
 */
public interface ResourceServingPortlet {

    /**
     * Called by the portlet container to allow the portlet to generate
     * the resource content based on its current state.
     * The portal / portlet container must not render any output in addition
     * to the content returned by the portlet. The portal / portlet container
     * should expect that the portlet may return binary content for a
     * <code>renderResource</code> call.
     *
     * @param   request
     *          the resource request
     * @param   response
     *          the resource response
     *
     * @exception   PortletException
     *              if the portlet has problems fulfilling the
     *              rendering request
     * @exception  UnavailableException
     *                   if the portlet is unavailable to perform render at this time
     * @exception  PortletSecurityException
     *                   if the portlet cannot fullfill this request because of security reasons
     * @exception  java.io.IOException
     *              if the streaming causes an I/O problem
     */

    public void serveResource(ResourceRequest request, ResourceResponse response)
        throws PortletException, java.io.IOException;
}

Noi sfrutteremo questo nuova caratteristica per fornire alla view i dati da mostrare all’interno della combo.

5. Implementazione del serverResource

Partendo dal presupposto che abbiate creato una portlet MVC, vediamo come implementare il metodo serverResource(). Prima di procedere con il come, affrontiamo il cosa, ovvero, che tipo di risorsa e quali dati il metodo deve restituire alla view?. Ipotizziamo che i dati da voler mostrare sulla combo siano l’insieme di ruoli definiti su Liferay e il formato dei dati da restituire deve essere in formato JSON; detto questo, in breve occorre:

  1. Definire una Dynamic Query sull’entità Role;
  2. La Dynamic Query deve esplicitare una where conditions di tipo like sull’attributo name dell’entità Role;
  3. Utilizzare il Local Service Util per recuperare i dati dei ruoli applicando il filtro attraverso la Dynamic Query definita in precedenza;
  4. Preparare l’oggetto JSON contenente i ruoli estratti in precedenza;
  5. Inviare alla view i dati.

La Dynamic Query consente di recuperare la lista dei ruoli il cui nome fa “scopa” con quanto digitato dall’utente all’interno della combo, per esempio, se l’utente digitasse Site* allora sarebbe recuperata la lista di ruoli dove ogni item ha l’attributo name che inizia con Site. Cercando di rispettare l’ordine delle cose da fare (visto in precedenza), cercherò di mostrare brevemente i pezzi di codice del come.

JSONObject json = JSONFactoryUtil.createJSONObject();
JSONArray results = JSONFactoryUtil.createJSONArray();
json.put("response", results);
Source 1 – Inizializzazione oggetti JSON.

Il codice illustrato sopra è una semplice inizializzazione degli oggetti JSON (Object e Array) utilizzati in seguito come contenitori di dati. Invece, a seguire, al Source 2 è mostrata la definizione e creazione della Dynamic Query secondo le regole descritte in precedenza.

DynamicQuery dynamicQuery = DynamicQueryFactoryUtil.forClass(Role.class).
			add(PropertyFactoryUtil.forName("name").like(searchPattern));
Source 2 – Definzione e creazione della Dynamic Query.

Al Source 3, sono invece mostrati il recupero della lista di ruoli e la successiva preparazione dei dati appena restituiti dal Role Local Service  in formato JSON.

List roles = RoleLocalServiceUtil.dynamicQuery(dynamicQuery);
for (Role role : roles) {
	JSONObject listEntry = JSONFactoryUtil.createJSONObject();
	listEntry.put("key", role.getRoleId());
	listEntry.put("name", role.getName());
	listEntry.put("description", role.getDescription());
	listEntry.put("type", role.getType());
	results.put(listEntry);
}
Source 3 – Recupero lista dei ruoli e preparazione dati in JSON.
resourceResponse.setContentType(ContentTypes.APPLICATION_JSON);
PrintWriter writer = resourceResponse.getWriter();
writer.println(json.toString());
Source 4.a – Invio dei dati in formato JSON alla view.

Le ultime righe di codice del Source 4.a inviano la lista di ruoli che soddisfano la ricerca verso la view in formato JSON. La prima riga informa il client che riceve i dati circa il formato degli stessi. Al Source 5 è possibile vedere un esempio di dati inviati alla view. L’esempio completo della classe ViewAUIAutocompleteAjax che implementa l’MVCPortlet è disponibile all’indirizzo ViewAUIAutocompleteAjax.java. In realtà è possibile approfittare del metodo writeJSON() della classe com.liferay.portal.kernel.portlet.LiferayPortlet per ottenere lo stesso risultato del codice precedente (vedi Source 4.b).

writeJSON(resourceRequest, resourceResponse, json);
Source 4.b – Invio dei dati in formato JSON alla view.
{
"response": [
{
"description": "<!--?xml version='1.0' encoding='UTF-8'?-->Site Administrators are super users of their site but cannot make other users into Site Administrators.",
"name": "Site Administrator",
"type": 2,
"key": 10153
},
{
"description": "<!--?xml version='1.0' encoding='UTF-8'?-->All users who belong to a site have this role within that site.",
"name": "Site Member",
"type": 2,
"key": 10154
},
{
"description": "<!--?xml version='1.0' encoding='UTF-8'?-->Site Owners are super users of their site and can assign site roles to users.",
"name": "Site Owner",
"type": 2,
"key": 10155
}
]
}
Source 5 – Dati in formato JSON.

6. Implementazione della view

La view (che dovrebbe poi essere la jsp view.jsp) fondamentalmente si compone di uno script AUI che utilizza i seguenti componenti:

  1. AUI AutoComplete (Alloy UI Modules)
  2. DataSource.IO (YUI Modules)

Il primo elemento è responsabile della visualizzazione e selezione dell’insieme di dati resi disponibili dal secondo componente di datasource, quest’ultimo è invece responsabile del recupero dei dati inviando la richiesta alla resourceURL della portlet. Al Source 6, è mostrato lo script AUI che crea la combo vista precedentemente in Figura 1.


var dataSource = new A.DataSource.IO(
    {
        source: '<%=ajaxResourceURL %>'
    }
);

var autocomplete = new A.AutoComplete(
    {
        dataSource: dataSource,
        delimChar: '',
        contentBox: '#myAutoComplete',
        matchKey: 'name',
        schema: {
            resultListLocator: 'response',
            resultFields: ['key','name','description', 'type']
        },
        uniqueName:'keyword',
        schemaType:'json',
        typeAhead: true,
        cssClass: 'ac_input'
    });

autocomplete.generateRequest = function(query) {
    return {
        request: '&<%=DisplayTerms.KEYWORDS %>=' + query
    };
}

autocomplete.render();
Source 6 – AUI Script per l’AutoComplete Ajax.

Nel codice sorgente mostrato al Source 6, ho voluto evidenziare le righe che ritengo più rilevanti:

  1. L’attributo source del componente DataSource impostato al valore della resourceURL della portlet (vedi Source 7);
  2. L’attributo schema del componente di AutoComplete che informa lo stesso circa lo schema della struttura dati JSON restituita;
  3. Il metodo generateRequest() genera un oggetto che sarà poi passato al metodo sendRequest() del DataSource. In breve, alla resourceURL sarà “appeso” il valore digitato nella combo.
<portlet:resourceURL var="ajaxResourceURL">
	<portlet:param name="<%=Constants.CMD %>" value="<%=ActionKeys.GET_LIFERAY_ROLES %>"/>
</portlet:resourceURL>
Source 7 – Creazione resourceURL della portlet.

Ovviamente è possibile sfruttare il metodo serverResource() per eseguire diverse azioni distinte per la stessa portlet, per questo motivo sulla resourceURL creata (vedi Source 7), è stato impostato un parametro che esplicita l’azione da eseguire. L’esempio completo della view è disponibile all’indirizzo view.jsp

7. Conclusioni

Ancora una volta abbiamo visto come il riutilizzo dei componenti software e il progredire delle tecnologie favoriscono la creazione di qualunque manufatto soprattutto in termini di tempo, quest’ultimo prezioso visto il diminuire del Time to Market. Il progetto AUI è un percorso quasi obbligato per tutti coloro che intraprendono la strada di Liferay e in particolare modo per coloro che sviluppano o avranno intenzione di sviluppare applicazioni che richiedono un livello spinto d’interazione uomo-macchina. Purtroppo la documentazione a corredo del progetto è molto povera e gli esempi presentati non soddisfano mai gli usi reali.

Figura 7 - Vista completa del progetto Hook Mavenizzato

Creare progetti Liferay tramite il plugin m2eclipse (Maven for Eclipse)


Il vostro processo di sviluppo software richiede l’utilizzo di Maven per la gestione del vostro progetto Java? Bene, in questo articolo vedremo come sia possibile creare ogni tipo di progetto (o plugin) Liferay utilizzando Maven, il tutto senza scrivere una riga di comando del tipo mvn archetype:generate. La versione di Liferay cui faremo riferimento è la 6.1 GA1 Community Edition.  I requisiti minimi in termini di software per ottenere il risultato atteso, sono i seguenti:

Supposto che il vostro ambiente di sviluppo sia correttamente installato e configurato e abbiate una buona conoscenza di Eclipse e dello strumento Maven, direi di andare avanti nella trattazione. Nel caso siate completamente a “secco” di Maven, consiglio la lettura di una serie di articoli pubblicati su MokaByte e di cui il primo della serie è Maven: best practices per il processo di build e di rilascio dei progetti in Java

1. Liferay Maven Artifacts

Liferay ha aggiunto il supporto a Maven come ottima alternativa al tool Ant plugin SDK. Gli artefatti sono stati pubblicati sul Central Repository tramite http://oss.sonatype.org, di nostro particolare interesse sono i Maven plugin e gli archetypes per tutti i tipi di plugins Liferay:

  • GroupId: com.liferay.maven.archetypes
  • ArtifactId:
    • liferay-ext-archetype
    • liferay-hook-archetype
    • liferay-layouttpl-archetype
    • liferay-portlet-archetype
    • liferay-servicebuilder-archetype
    • liferay-theme-archetype
    • liferay-web-archetype 

Ogni archetype può essere utilizzato per realizzare la base di ogni plugin Liferay mostrato nel precedente elenco, come per esempio un plugin di tipo Hook che poi andremo effettivamente a creare. L’indirizzo del central repository per il GroupId com.liferay.maven.archetype è:

2. Creazione di un Hook Plugin

La creazione di un Hook Plugin tramite il plugin m2eclipse è davvero un gioco da ragazzi. Gli step da eseguire da Eclipse sono appena quattro che riporto a seguire:

  • Creazione di un nuovo progetto Maven
  • Aggiungere l’archetype liferay-hook-archetype inserendo le seguenti informazioni:
    • Archetype GroupId
    • Archetype ArtifactId
    • Archetype Version
    • Repository URL
  • Selezionare l’archetype aggiunto in precedenza
  • Introdurre le informazioni del progetto Maven per l’Hook
    • GroupId (per esempio: it.dontesta.liferay.hook.sugarcrm)
    • ArtifactId (per esempio: liferay-hook-sugarcrm)
    • Version (per esempio: 0.0.1-SNAPSHOT)
    • Package (per esempio: it.dontesta.liferay.hook.sugarcrm)

Le figure possono essere sempre d’aiuto, quelle a seguire mostrano alcuni degli step di creazione del progetto Maven.

Figura 1 - Creazione nuovo progetto Maven

Figura 1 – Creazione nuovo progetto Maven

Figura 2 - Impostazioni predefinite del progetto

Figura 2 – Impostazioni predefinite del progetto

Lasciare le impostazioni predefinite. In particolare, la non selezione della prima opzione consentirà successivamente l’aggiunta e la selezione dell’archetype liferay-hook-archetype per creare il nostro plugin di tipo Hook.

Figura 3 - Aggiunta dell'Archetype

Figura 3 – Aggiunta dell’Archetype

Figura 4 - Aggiunta dell'Archetype

Figura 4 – Aggiunta dell’Archetype

Aggiunta dell’archetype inserendo i dati specificati in precedenza ricordando d’inserire l’indirizzo del repository.

Figura 5 - Impostazione proprietà del progetto

Figura 5 – Impostazione proprietà del progetto

 

Per il progetto appena creato, in pieno stile Maven, saranno risolte tutte le dipendenze necessarie. L’unica operazione che richiede un minimo di manualità è l’inserimento di una serie di proprietà sul POM che riguardano la propria installazione di Liferay. Il Listato 1 mostra quali sono le proprietà aggiunte sul POM. I valori delle proprietà indicate al Listato 1 sono riferite alla mia installazione di Liferay 6.1.1 CE.

<properties>
<liferay.version>6.1.1</liferay.version>
<liferay.auto.deploy.dir>
  /opt/liferay-portal-6.1.1-ce-ga2/deploy
</liferay.auto.deploy.dir>
<liferay.app.server.portal.dir>
  /opt/liferay-portal-6.1.1-ce-ga2/tomcat-7.0.27/webapps/ROOT
</liferay.app.server.portal.dir>
<liferay.app.server.lib.global.dir>
  /opt/liferay-portal-6.1.1-ce-ga2/tomcat-7.0.27/lib/ext
</liferay.app.server.lib.global.dir>
<app.server.deploy.dir>
  /opt/liferay-portal-6.1.1-ce-ga2/tomcat-7.0.27/webapps
</app.server.deploy.dir>
</properties>

Listato 1 – Proprietà installazione Liferay aggiunte sul POM (link al file completo).

Figura 6 - POM con evidenza delle proprietà di Liferay

Figura 6 – POM con evidenza delle proprietà di Liferay

Figura 7 - Vista completa del progetto Hook Mavenizzato

Figura 7 – Vista completa del progetto Hook Mavenizzato

 3. Package & Deploy

Una volta creato l’Hook di esempio, non resta altro che creare il package (che in questo caso è un war) da installare in seguito sulla propria installazione di Liferay. Quest’ultima operazione può essere anche eseguita tramite un apposito Maven Goal. La creazione del package liferay-hook-sugarcrm-0.0.1-SNAPSHOT.war e l’eventuale deploy su Liferay, può essere eseguito tramite il menù Run Configurations -> Maven Build specificando rispettivamente i goals package liferay:deploy, così come indicato in Figura 8.

Figura 8 - Configurazione Maven Run

Figura 8 – Configurazione Maven Run

Figura 9 - Esecuzione del Goal liferay:deploy

Figura 9 – Esecuzione del Goal liferay:deploy

4. Conclusioni

Abbiamo visto come sia semplice e immediato creare ogni tipo di plugin Liferay utilizzando uno strumento completo e complesso come Maven grazie al supporto fornito dal plugin m2eclipse. Ovviamente è possibile applicare quanto appena descritto a qualunque progetto Java che utilizzi Maven e il plugin m2eclipse è davvero un grande aiuto nella facilitazione di una serie di attività.

Figura 4 Il CRM dentro il CMS.

SugarCRM inside of Liferay


Certainly the title of the article may seem a little odd, but I have not found better title. I could give a title like “Integration between CRM ….” but then I was not very convinced!

The protagonists of this short article are: SugarCRM implementing a Customer Relationship Management (or CRM) and Liferay instead implements a Content Management System (or CMS).

We are going through a phase where it is needed more and more integration between most disparate information systems with different responsibilities, it’s like doing a puzzle, combine sets different pieces so that their collaboration allows to reach the goal, trying to maintain a single interface to interact with the whole or parts of the puzzle.

We will then see how it is possible and easy to put SugarCRM “inside” Liferay. Assuming a scenario where Liferay implements a web portal of a hypothetical company would not be something out of the ordinary, give access to CRM from the web portal without having to be forced to open a new browser window and avoid repeating the authentication .

Achieving the goal is really simple with Liferay, it is only an activity configuration of the iFrame portlet, already available with Liferay. As shown in the course of the discussion is applicable to the Community Edition and Enterprise Edition of Liferay, the version used is a 6.1 CE GA2.

1.  Requirements

To ensure that the proposed solution is applicable, it is essential that the following requirements are met:

  • Access to the portal with an administrative role or a role that allows you to add applications (portlets) and configuration options;
  • Ability to perform administrative tasks, such as operations of start, stop and change configurations;
  • URL of SugarCRM.

2.   Behavior

Each user of the portal, so authenticated, you can access directly from the portal to the application of CRM, without repeating the authentication procedure. As introduced above, this is possible through iframe portlets.

The Iframe portlet makes it possible to embed another HTML page inside the current page. Furthermore the user can navigate through the embedded page without loosing the context of the portal page.

The Iframe portlet uses the HTML iframe tag that is part of HTML 4 and is supported in all major browsers. The iframe portlet will adjust to the size of the HTML page if that page is hosted in the same server. The browser will add scrollbars if the embedded page does not fit within the size of the iframe.

An important feature of this portlet and fundamental in this scenario, the possibility to perform the authentication process for us. Supports two types of authentication: Basic and Form, we will use the second method, however, the choice depends on the type of authentication supported by the web application to integrate.

You may have guessed that a prerequisite in order for the authentication to work properly, you must have your username (usually the attribute screen name) and password of the portal coincide with those of CRM.

3.   Configuration

Once you add the portlets on a your page, you just have to continue with the configuration whose main parameters and values ​​are as follows:

  • URL of SugarCRM to which you want to give access;
  • Authentication type:
    • Type: Form
    • Method: POST
    • Username
      • FieldName: user_name
      • Value: @screen_name@
    • Password:
      • FieldName: user_password
      • Value: @password@
    • Hidden Variable
      • module=Users;action=Authenticate

The values ​​shown as @screen_name@ and @password@, then replaced at runtime with the actual values ​​and then sent to SugarCRM in the process of authentication, that’s why it is necessary that the credentials match, in Otherwise you will be necessarily required to manually perform authentication in the form of SugarCRM. In Figure 1 is shown the configuration of the iFrame portlets. The specified URL refers to an instance of SugarCRM CE 6.5 hosted on the Cloud Open Shift.

Figura 1 Configurazione iFrame Portlet per SugarCRM.

Figure 1 Configuration of the iFrame Portlet for SugarCRM.

There is a security mechanism such that your credentials are not stored (in session, cookies, etc …) by default, you can also make sure that only users belonging to a particular role can send your password to external systems through the iFrame portlet.

Figura 2 Creazione del ruolo per l’autenticazione trasperente.

Figure 2 Create a new Role for iFrame Portlet

Through the configuration properties (see the Listing 2) you can enable the storage of the password (unencrypted) in session, and also specify the role to be assigned to users who need to be able to send your password to the outside through the iFrame portlet.

public static String getPassword(PortletRequest portletRequest, String password)
throws PortalException, SystemException {
if (!isPasswordTokenEnabled(portletRequest)) {
return StringPool.BLANK;
}
if (Validator.isNull(password) || password.equals("@password@")) {
password = PortalUtil.getUserPassword(portletRequest);
if (password == null) {
password = StringPool.BLANK;
}
}
return password;
}

Listing 1 Get clear password from session (Link on Gist ).

Listing 1 shows GetPassword() class IFrameUtil com.liferay.portlet.iframe.util package that retrieves the user’s password from the session, checking the association role/user using the method isPasswordTokenEnabled().

Figura 3 Associazione del ruolo all’utente.

Figure 3 User Roles.

###
# IFrame Portlet
###
# Specify a role name that a user must be associated with in order to
# configure the IFrame portlet to use the @password@ token. This token is
# used to post the password of users who access this portlet in order to
# automatically login to the framed site.
#
# No role is required by default. However, it is recommended that you
# specify a role in high security environments where users who configure
# this portlet may attempt password theft. See LPS-5272 for more
# information.
#
iframe.password.token.role=iFrameUserToken
##
## Session
##
#
# Set this to true to store the user's password in the session.
#
session.store.password=true

Listing 2 Configuration properties file portal-ext.properties (Link su Gist).

The configuration (see Listing 2) shows the role (a name of your choice) to which users must belong and the explicit instruction to store in session, the user’s password. The application of this configuration requires a restart of the portal. The configuration shown in Listing 2 must be specified in the file portal-ext.properties. This file must be created or found within the directory webapps/ROOT/WEB-INF/classes.

After restarting the portal and set the iFrame portlet, you would login with your credentials to get your workspace ready to use CRM.

Figura 4 Il CRM dentro il CMS.

Figure 4 SugarCRM inside of Liferay.

Figure 5 shows instead the passage of the parameters to the target application, in this case SugarCRM. I have highlighted in particular the password attribute, passed in the clear.

Figure 5 - Sending the password to the instance of SugarCRM

Figure 5 – Sending the password to the instance of SugarCRM

4.   Conclusions

In this short article we have seen how easy it is to integrate SugarCRM “inside” Liferay exploiting the potential provision by the iFrame portlet. Is certainly convenient to be able to authenticate in a transparent manner. This solution can be used to integrate any type of web application.

Importazione Certificati SSL sul Java Keystore (JKS)


Reblog di uno degli articoli più letti.

Antonio Musarra's Blog

Il meccanismo solitamente adottato per la protezione dei dati End-To-End sulla rete internet è basato sull’utilizzo del protocollo Transport Layer Security (TLS) e il suo predecessore Secure Sockets Layer (SSL), entrambi sono dei protocolli crittografici che permettono una comunicazione sicura e una integrità dei dati su reti TCP/IP, cifrano la comunicazione dalla sorgente alla destinazione sul livello di trasporto.

Una tipica connessione TLS/SSL (per esempio via browser internet) prevede un tipo di autenticazione denominata unilaterale : solo il server è autenticato (il client conosce l’identità del server), ma non vice-versa (il client rimane anonimo e non autenticato). Il client (browser web, EmailUI, Java Client, etc…) valida il certificato del server controllando la firma digitale dei certificati del server, verificando che questa sia valida e riconosciuta da una Certificate Authority conosciuta utilizzando una cifratura a chiave pubblica.

In Figura 1 è illustrato il caso in cui il browser stabilisce una connessione…

View original post 1.440 altre parole

Il blog si trasferisce ma non chiude


Carissimi lettori, da qualche mese la residenza del mio blog è cambiata ma non temete, i battenti di certo non si chiuderanno. Ho iniziato a pubblicare qualche articolo sul nuovo blog e mi farebbe davvero piacere ricevere un vostro feedback e avervi come nuovi follower o per dirla nella nostra lingua, come “miei seguaci”.

Cercherò di mantenere sempre la stessa linea e non far mancare aggiornamenti frequenti, anche se su questo punto il tempo è sempre tiranno. Vi rinnovo l’invito a suggerimenti per argomenti che vorreste vedere pubblicati. A questo punto non resta altro che puntare il vostro browser (che non sia IE) su Antonio Musarra’s Blog.

Grazie a tutti.

Antonio.

2013 in review


The WordPress.com stats helper monkeys prepared a 2013 annual report for this blog.

Here’s an excerpt:

The concert hall at the Sydney Opera House holds 2,700 people. This blog was viewed about 58,000 times in 2013. If it were a concert at Sydney Opera House, it would take about 21 sold-out performances for that many people to see it.

Click here to see the complete report.

Creare report con KReporter


Reporting su SugarCRM CE? Possibile e semplice. Date una lettura all’articolo di Alessandro Cecconi.

Sugar corner

KR logoEbbene, come potrei continuare a dribblare impunemente uno degli argomenti principe per chi si imbatte sulla edizione Community di Sugar: il reporting sui dati! Va bene che le funzionalità di ricerca avanzata previste su ogni modulo del nostro CRM sono, per l’appunto, molto avanzate, quasi da costituire esse stesse dei report elementari ma…

View original post 691 altre parole

Come configurare Liferay 6.1 per PostgreSQL


Nel precedente articolo Come configurare Eclipse per Liferay Portal in Mac OS X, pubblicato sul mio blog, abbiamo visto come configurare un ambiente di sviluppo completo per Liferay 6.0 analogamente per la versione successiva di Liferay 6.1. La distribuzione Liferay di default prevede l’utilizzo del data base HSQL (Hypersonic) per la persistenza dei dati. L’utilizzo di questo tipo di data base in ambienti di produzione non è però consigliato. Nel corso di quest’articolo vedremo Step-by-Step come configurare il data base PostgreSQL per la persistenza dei dati di Liferay. Non saranno…READMORE

WSO2 ESB SugarCRM Proxy Service


L’articolo nasce e prende spunto da una domanda indirizzata a me qualche giorno addietro. Esattamente il quesito recitava: Come posso configurare un Proxy Service di SugarCRM sull’Enterprise Service Bus (ESB) di WSO2? La risposta al quesito è stata abbastanza semplice e nel corso di quest’articolo vedremo come sia semplice configurare un Proxy Service. 1. Cos’è un Proxy Service Un Proxy Service è un servizio virtuale che riceve i messaggi e opzionalmente li elabora prima di essere inoltrati a un servizio definito da un end point. Quest’approccio consente di…READ MORE

How to use the Liferay Portal Client Example


Welcome dear readers!

A few days ago, I made ​​a simple example of using the Liferay Client Library. The project is based on Maven. Below are shown the steps needed to perform a test. I remember that the operations performed by the sample program are:

  • Performs login on Liferay;
  • Retrieves the CompanyID based on the virtualhost;
  • Retrieve UserId of the user to ScreenName and CompanyID;
  • Retrieves the GroupId of the site Guest;
  • Performs the upload of a document on the Document Library site Guest.
$ git clone git://github.com/amusarra/liferay-portal-client-example.git
$ cd liferay-portal-client-example/
$ mvn package

List 1. Clone repository and build the package

$ cd target/
$ java -jar portal-client-example-0.0.1-SNAPSHOT-jar-with-dependencies.jar

List 2. Run the portal client example

[00:18:15,816 INFO UploadDocumentOnDL]: Try lookup User Service by End Point: http://will:will@localhost:8080/api/secure/axis/Portal_UserService...
[00:18:16,176 INFO UploadDocumentOnDL]: Try lookup Company Service by End Point: http://will:will@localhost:8080/api/secure/axis/Portal_CompanyService...
[00:18:16,343 INFO UploadDocumentOnDL]: Get UserID...
[00:18:16,378 INFO UploadDocumentOnDL]: UserId for user named will is 11801
[00:18:16,378 INFO UploadDocumentOnDL]: Try lookup Group Service by End Point: http://will:will@localhost:8080/api/secure/axis/Portal_GroupService...
[00:18:16,441 INFO UploadDocumentOnDL]: Found the group Guest (GroupId: 19) to publish the document
[00:18:16,441 INFO UploadDocumentOnDL]: Try lookup DL App Service by End Point: http://will:will@localhost:8080/api/secure/axis/Portlet_DL_DLAppService...
[00:18:16,922 INFO UploadDocumentOnDL]: The file BenchmarkingSugarOnSolaris-SugarCon2009.pdf has been correctly added to liferay
[00:18:16,922 INFO UploadDocumentOnDL]: File Id:13101
[00:18:16,922 INFO UploadDocumentOnDL]: File Size: 735142
[00:18:16,922 INFO UploadDocumentOnDL]: File Version: 1.0

List 3. Show the performed tasks.

Figure 1 - List View of the Document Library

Figure 1 – List View of the Document Library

Figure 2 - Detail View of the document inserted by SOAP Services

Figure 2 – Detail View of the document inserted by SOAP Services

Liferay Portal Client Example (EN)


In the past and recently I got to be among two systems, one of which Liferay. The system in the middle, was Mule ESB, the mediator between the two systems. The first of the two systems published a series of messages on a JMS queue, these messages were consumed by ESB Mule and after a series of elaborations shipped to the second system (Liferay).

At that time, Liferay had just SOAP services (services rest, would come later), based on the old framework Apache Axis 1.4 and style rpc / encoded. The SOAP component of Mule ESB based on Apache CXF is not compatible with the model rpc / encoded. The first solution was to create the client (to be done later use in Mule ESB) for services of Liferay, starting from the WSDL of the service with which it was necessary to communicate, many of you will know how boring it can be this activity.

In Liferay someone to “good heart” had decided to make available the Liferay Portal Client, this has made the happiness of myself first and foremost and secundis halved the time development of the flow of Mule ESB. Later I realized that the Liferay Portal Client is known by a handful of insiders around, even Liferay itself does not mention the existence in their own documentation SOAP Web Services, is usually discussed the process of creating the client via the WSDL.

Last week I found myself in a similar situation where the Liferay Portal Client has been useful in an integration, by halving the time of development. I made the decision to publish on my GitHub repository a complete example of use of the Liferay Portal Client. The sample project liferay-portal-client-example, based on Maven that performs the following tasks:

  • Performs login on Liferay;
  • Retrieves the CompanyID based on the virtualhost;
  • Retrieve UserId of the user to ScreenName and CompanyID;
  • Retrieves the GroupId of the site Guest;
  • Performs the upload of a document on the Document Library site Guest.

Following an extract of the logs that show the execution of the main class UploadDocumentOnDL. The services used are:

  • Portal_UserService
  • Portal_CompanyService
  • Portal_GroupService
  • Portlet_DL_DLAppService

WSDL documents of all the services exposed by the portal can be reached at http://${HOST|FQDN|IP}:${TCP/IP PORT}/api/axis

[00:18:15,816 INFO  UploadDocumentOnDL]: Try lookup User Service by End Point: http://will:will@localhost:8080/api/secure/axis/Portal_UserService...
[00:18:16,176 INFO  UploadDocumentOnDL]: Try lookup Company Service by End Point: http://will:will@localhost:8080/api/secure/axis/Portal_CompanyService...
[00:18:16,343 INFO  UploadDocumentOnDL]: Get UserID...
[00:18:16,378 INFO  UploadDocumentOnDL]: UserId for user named will is 11801
[00:18:16,378 INFO  UploadDocumentOnDL]: Try lookup Group Service by End Point: http://will:will@localhost:8080/api/secure/axis/Portal_GroupService...
[00:18:16,441 INFO  UploadDocumentOnDL]: Found the group Guest (GroupId: 19) to publish the document
[00:18:16,441 INFO  UploadDocumentOnDL]: Try lookup DL App Service by End Point: http://will:will@localhost:8080/api/secure/axis/Portlet_DL_DLAppService...
[00:18:16,922 INFO  UploadDocumentOnDL]: The file BenchmarkingSugarOnSolaris-SugarCon2009.pdf has been correctly added to liferay
[00:18:16,922 INFO  UploadDocumentOnDL]: File Id:13101
[00:18:16,922 INFO  UploadDocumentOnDL]: File Size: 735142
[00:18:16,922 INFO  UploadDocumentOnDL]: File Version: 1.0

The advantage of using the Liferay Portal Client is more than obvious and hopefully always someone “good heart” to do the same for RESTful services.

Liferay Portal Client Example


In passato e recentemente ho avuto modo di essere in mezzo a due sistemi, uno dei quali Liferay. Il sistema di mezzo era Mule ESBmediatore tra i due sistemi. Il sistema uno pubblicava una serie di messaggi su di una coda JMS, questi venivano consumati da Mule ESB e dopo una serie di elaborazioni  spediti al sistema due, Liferay per l’appunto.

La versione corrente in quel momento di Liferay disponeva dei soli servizi SOAP (i servizi rest sarebbero venuti in seguito), basati sul vecchio framework Apache Axis 1.4 e in stile rpc/encoded. Il componente SOAP di Mule ESB basato su Apache CXF non è compatibile con il modello rpc/encoded. La soluzione venuta in mente a tutti era quella di realizzare il client (da fare utilizzare in seguito a Mule ESB) per servizi di Liferay partendo dal documento WSDL del servizio con il quale occorreva comunicare, e parecchi di voi sapranno quanto noiosa possa essere quest’attiva.

In Liferay qualcuno di “buon cuore” aveva deciso bene di rendere disponibile il Liferay Portal Client, questo ha fatto la felicità mia in primis e in secundis dimezzato il tempo di sviluppo del flow su Mule ESB. In seguito mi sono reso conto che il Liferay Portal Client è conosciuto da un giro ristretto di addetti ai lavori, anche Liferay stessa non menziona dell’esistenza nella propria documentazione SOAP Web Services, è discusso il solito processo di creazione del client via WSDL.

La scorsa settimana mi son ritrovato in una situazione simile dove il Liferay Portal Client è stato utile in un’attività d’integrazione, dimezzandone il tempo di sviluppo. Ho preso la decisione di pubblicare sul mio repository GitHub un esempio completo d’utilizzo del Liferay Portal Client.  Il progetto d’esempio liferay-portal-client-example, basato su Maven esegue i seguenti task:

  • Esegue la login sul sistema Liferay;
  • Recupera la CompanyId sulla base del virtualhost;
  • Recupera UserId dell’utente su base ScreenNameCompanyId;
  • Recupera il GroupId del site Guest;
  • Esegue l’upload di un documento sulla Document Library del site Guest.

A seguire un estratto dei log che mostrano l’esecuzione del main della classe UploadDocumentOnDL. In ordine d’utilizzo, i servizi consumati del portale Liferay sono:

  • Portal_UserService
  • Portal_CompanyService
  • Portal_GroupService
  • Portlet_DL_DLAppService

I documenti WSDL di tutti i servizi esposti dal portale sono raggiungibili all’indirizzo http://${HOST|FQDN|IP}:${TCP/IP PORT}/api/axis

[00:18:15,816 INFO  UploadDocumentOnDL]: Try lookup User Service by End Point: http://will:will@localhost:8080/api/secure/axis/Portal_UserService...
[00:18:16,176 INFO  UploadDocumentOnDL]: Try lookup Company Service by End Point: http://will:will@localhost:8080/api/secure/axis/Portal_CompanyService...
[00:18:16,343 INFO  UploadDocumentOnDL]: Get UserID...
[00:18:16,378 INFO  UploadDocumentOnDL]: UserId for user named will is 11801
[00:18:16,378 INFO  UploadDocumentOnDL]: Try lookup Group Service by End Point: http://will:will@localhost:8080/api/secure/axis/Portal_GroupService...
[00:18:16,441 INFO  UploadDocumentOnDL]: Found the group Guest (GroupId: 19) to publish the document
[00:18:16,441 INFO  UploadDocumentOnDL]: Try lookup DL App Service by End Point: http://will:will@localhost:8080/api/secure/axis/Portlet_DL_DLAppService...
[00:18:16,922 INFO  UploadDocumentOnDL]: The file BenchmarkingSugarOnSolaris-SugarCon2009.pdf has been correctly added to liferay
[00:18:16,922 INFO  UploadDocumentOnDL]: File Id:13101
[00:18:16,922 INFO  UploadDocumentOnDL]: File Size: 735142
[00:18:16,922 INFO  UploadDocumentOnDL]: File Version: 1.0

Il vantaggio nell’utilizzo del Liferay Portal Client è più che ovvio e speriamo che sempre qualcuno di “buon cuore” faccia lo stesso per i servizi RESTful.

Introduzione a Liferay Hooks: primo episodio


Vi presento il primo articolo scritto da ospite per il Blog di Dvel.

L’articolo intende comunicare le informazioni base che riguardano gli hooks favorendo l’aspetto reale, in altre parole, far capire a cosa servono tramite l’esposizione e realizzazione di un caso di studio quanto più possibile vicino al reale. Sarà quindi presentato un caso d’integrazione che farà uso degli hooks, toccando i vari aspetti di personalizzazione. L’articolo sarà suddiviso in più episodi per evitare una “sbrodolata” d’informazione e rendere più efficace l’assimilazione di quanto esposto.

Continuate la lettura sul blog di Dvel Introduzione agli Hooks: primo episodio

Introduzione al CRM e a SugarCRM


Ho il piacere di presentare il video dell’amico Alessandro Cecconi. Panoramica introduttiva sui software di gestione delle relazioni con la clientela e su SugarCRM, la piattaforma open source commerciale più diffusa al mondo.

Sfidando i leader di mercato


Eccolo, appena sfornato un altro articolo di Alex. Buona lettura.

Sugar corner

MarketLeadersGli analisti concordano: Sugar è un CRM leader. Le analisi Gartner e Forrester del 2012 promuovono Sugar come CRM leader di mercato, caratterizzato, in particolare, dal più alto tasso di crescita. I due report più autorevoli del mercato delle soluzioni CRM ovvero Gartner (1) e Forrester (2), pubblicati quasi contemporaneamente lo scorso anno,

View original post 543 altre parole

How can I view the list of Liferay JSON Web Services?


To overview and verify which service methods are registered and available, user can use following URL to list them all in browser (notice the ‘jsonws’ in the URL, it is relevant for all JSON Web Services calls – more on invocation later:

http://localhost:8080/api/jsonws

The result is a list of all registered and exposed service methods. For each method user can see more details, by clicking the method name. On method details page, user can even invoke the method for testing purposes.

To list registered services on portlet, don’t forget to use portlet contenxt path:

http://localhost:8080/<portlet>/api/jsonws

For more information you can see the follow resources:

The follow figures show a set of the examples.

Liferay JSON WS API List

Figure 1. Liferay JSON WS API List

Figure 2. Execute a test on JSON user API

Figure 2. Execute a test on JSON user API

Figure 3. How to extract the Curl command

Figure 3. How to extract the Curl command

The follow command (curl) for execute a call for the GetUserById service.

curl http://localhost:8080/api/secure/jsonws/user/get-user-by-id \
 -u test@liferay.com:test \
 -d p_auth=Z2wAxRKd \
 -d userId=11801 | python -m json.tool
Figura 4. JSON output for the Get User By Id service

Figura 4. JSON output for the Get User By Id service

 

Introduzione a Liferay Message Bus on SlideShare


Ieri sera su SlideShare ho reso disponibile l’articolo Introduzione a Liferay Message Bus pubblicato sul blog qualche settimana addietro.

Bug #62075 – Export to CSV for fields of type TEXT is not working properly


When you export data to CSV, fields of type “text” that contain, for example, the characters “new line” create problems at the import stage on the Excel worksheet. Below is the patch file to apply to include/export_utils.php.

You could follow the bug by http://www.sugarcrm.com/support/bugs.html#issue_62075

From 3249d7de911089e70929b7630240dc256288ac5f Fri, 29 Mar 2013 00:00:43 +0100
From: Antonio Musarra <antonio.musarra@gmail.com>
Date: Wed, 20 Mar 2013 10:39:32 +0100
Subject: [PATCH] Bug #62075 - Export to CSV for fields of type TEXT is not working properly

diff --git a/include/export_utils.php b/include/export_utils.php
index 1e4f5e3..e2d8fcf 100644
--- a/include/export_utils.php
+++ b/include/export_utils.php
@@ -312,6 +312,10 @@
                             $value = implode(",",$valueArray);
                         }
                         break;
+                    // Bug 62075 - Export to CSV for fields of type TEXT is not working properly
+                    case 'text':
+                    	$value = trim(preg_replace('/\s\s+/', ' ', $value));
+                    	break;
                 }
             }

Introduzione a Liferay Message Bus


Esistono in giro soluzioni Open Source di ogni tipo che implementano Enterprise Service Bus (ESB), Liferay ha preferito non integrare al suo interno una delle soluzioni esistenti (il più delle volte pensanti) in favore di un proprio “piccolo message bus” che fosse in grado di far comunicare in modo semplificato i componenti del portale tramite lo scambio di messaggi. La versione 6.1 di Liferay ha migliorato di molto il Message Bus introducendo un più ricco insieme di service API che facilitano lo scambio dei messaggi tra le portlet e in generale tra i plugins.

1. Utilizzo del Message Bus

I messaggi scambiati all’interno di Liferay tramite il Message Bus, sono esclusivamente di tipo String (in genere il formato adottato è JSON), così facendo l’accoppiamento tra producers e consumers è ancora più ridotto e inoltre sono evitati i problemi di caricamento delle classi. Il Message Bus è situato all’interno del kernel di Liferay, in questo modo sarà possibile accedere ai servizi del Bus da ogni applicazione installata. L’implementazione attuale non consente di inviare messaggi remoti che comunque possono essere inviati attraverso il cluster utilizzando le classi ClusterLink. 

A qualcuno potrebbero venire in mente delle somiglianze con Java Message Service (JMS), il Message Bus di Liferay è molto più semplice e non fornisce tutte le caratteristiche della specifica JMS. Quanto mostrato in Figura 1 è una rappresentazione degli usi comuni del Message Bus.

Figura 1. Usi comuni del Message Bus all'interno di Liferay

Figura 1. Usi comuni del Message Bus all’interno di Liferay

Un esempio tangibile d’uso del Message Bus è appunto la portlet Message Board, questa, invia il messaggio sul bus restituendo la risposta all’utente, che può continuare a interagire con il portale. Chi riceve il messaggio dal bus (il listener), esegue una serie di azioni sul messaggio (nel caso di sottoscrizioni l’azione corrisponde all’invio di un’email a tutti i sottoscritti al messaggio) utilizzando un thread separato.

2. Architettura del Message Bus

Sono quattro i “pezzi” fondamentali che costituisco il Message Bus di Liferay e sono:

  • Message Bus: Gestisce il canale di trasporto dei messaggi garantendo la consegna degli stessi dai senders ai listeners;
  • Destinations: Sono gli indirizzi o destinazioni alle quali i listeners sono registrati affinchè possano ricevere i messaggi;
  • Listeners: Sono i “consumatori” dei messaggi ricevuti nelle destinazioni. Questi ricevono tutti i messaggi inviati alle loro destinazioni registrate;
  • Senders: Chi invia i messaggi sul bus verso una destinazione registrata.

E’ possibile per cui inviare dei messaggi a una o più destinazioni e inoltre possibile configurare listener in ascolto su una o più destinazioni. Tanto per fare un esempio potremmo avere una situazione di questo tipo:

  • Un client invia un messaggio a una destinazione chiamata shirusLabs/HorseGallops;
  • Il Message Bus esegue un’interazione con ogni listener registrato sulla destinazione shirusLabs/HorseGallops;
  • Per ogni listener è chiamato il metodo receive(String message).

Lo schema illustrato in Figura 2 è un possibile scenario d’utilizzo del Message Bus che chiarirà ancor di più le idee sull’architettura. Da notare come un servizio può inviare messaggi a una o più destinazioni e come un listener può essere in ascolto su più destinazioni, oltre al fatto che un servizio può essere sia sender sia listener.

Figura 2. Architettura del Message Bus

Figura 2. Possibile scenario utilizzo del Message Bus

Anche il Message Bus di Liferay come il resto delle altre soluzioni supporta principalmente due tipologie di messaggio:

  • Synchronous messaging: Dopo l’invio di un messaggio, il mittente rimane in attesa di una risposta da parte del destinatario;
  • Asynchronous messaging: Dopo l’invio di un messaggio, il mittente è libero di continuare l’elaborazione. Il mittente può essere configurato per ricevere una call-back o può semplicemente “inviare e dimenticare (Send-and-Forget)”.

    • Call-Back: Il mittente può essere configurato in modo tale che sia richiamato dal destinatario.
    • Send-and-Forget: Il mittente non include nel messaggio informazioni di call-back e continua semplicemente con l’elaborazione.

Tutti gli elementi del Message Bus (destinations, listeners e mapping tra loro) sono magicamente configurabili tramite Spring. La configurazione del Message Bus è realizzata attraverso i seguenti file XML:

  • WEB-INF/src/META-INF/messaging-spring.xml: All’interno di questo file devono essere definite le destinazioni, listeners e il mapping tra di loro;
  • WEB-INF/web.xml : Contiene la lista dei deployment descriptors del plugin, in più occorre aggiungere alla lista anche il file di configurazione messaging-spring.xml di Spring.

Ogni listener definito in configurazione (fare riferimento a WEB-INF/src/META-INF/messaging-spring.xml) deve implementare l’interfaccia base MessageListener (com.liferay.portal.kernel.messaging.MessageListener) sovrascrivendo il metodo (vedi Figura 3):

  • public void receive(Message message) throws MessageListenerException
Figura 3. Class Diagram Message Listener

Figura 3. Class Diagram Message Listener

Liferay fornisce una “facility” class astratta BaseMessageListener che implementa il metodo receive() dell’interfaccia MessageListener fornendo un metodo astratto doReceive(), il vostro listener può quindi estendere direttamente la classe BaseMessageListener implementando il metodo doReceive(). 

Nelle figure a seguire sono mostrati i sequence diagram delle due tipologie di messaggi: sincroni e asincroni.

Figura 3. Messaggio Sincrono

Figura 4. Messaggio Sincrono

Dalla Figura 5 e Figura 6 è possibile notare che ci sono due tipi di destinations per messaggi di tipo asincrono:

  • Parallel Destination:  Utilizzato nei casi in cui i messaggi devono essere inviati in parallelo. Su questo tipo di destinazione è possibile agire sulla configurazione del Thread Pool (Asynchronous “Send and Forget” vedi Figura 6);
  • Serial Destination: Utilizzato nel caso in cui le richieste devono essere inviate in serie. In questo caso la dimensione del Thread Pool è impostata a uno (Asynchronous con callbacks vedi Figura 5). 
Figura 4. Messaggio Asincrono con dispatch seriale

Figura 5. Messaggio Asincrono con invio seriale

Figura 5. Messaggio Asincrono con dispatch parallelo

Figura 6. Messaggio Asincrono con invio parallelo

In Figura 7 è invece indicato il class diagram che mostra le relazioni tra i tipi di destinazione implementati dal Message Bus di Liferay.

Figura 7. Relazioni tra i tipi di destinazione

Figura 7. Relazioni tra i tipi di destinazione

3. Configurazione

Nel precedente paragrafo abbiamo visto quali sono gli elementi che ruotano nell’intorno del Message Bus e qual è il file di configurazione tramite il quale è possibile configurare ogni singolo elemento. Potremmo suddividere la configurazione per sezioni, quali:

  • Listeners: in questa sezione devono essere specificate una o più classi che gestiscono i messaggi che transitano sul Message Bus verso una o più destinazioni;
  • Destinations: in questa sezione devono essere specificate una o più destinazioni dichiarando il tipo e il nome;
  • Configurator: in questa sezione devono essere specificate le relazioni destinazione => listener.

A titolo esemplificativo sono mostrati a seguire le tre sezioni di configurazione di ogni elemento del Message Bus. Come potete notare la configurazione è in puro stile Spring.

<!– Listeners –>
<bean id="messageListener.marketing_listener"
      class="it.dontesta.crm.messaging.impl.MarketingMessagingImpl" />
<bean id="messageListener.sales_listener"
      class="it.dontesta.crm.messaging.impl.SalesMessagingImpl" />
<bean id="messageListener.customer_support_listener"
      class="it.dontesta.crm.messaging.impl.CustomerSupportMessagingImpl" />

Source 1. Configurazione listener

La configurazione indicata al Source 1 dichiara tre diversi listener ognuno dei quali è una classe che implementa l’interfaccia MessageListener o estende la classe astratta BaseMessageListener.

<!-- Destinations -->
<bean id="destination.crm.customer.ticket"
    class="com.liferay.portal.kernel.messaging.SynchronousDestination">
    <property name="name" value="crm/customer/support/ticket"/>
</bean>
<bean id="destination.crm.customer.ticket.response"
    class="com.liferay.portal.kernel.messaging.SynchronousDestination">
    <property name="name" value="crm/customer/support/ticket/response"/>
</bean>
<bean id="destination.crm.marketing.lead"
    class="com.liferay.portal.kernel.messaging.SerialDestination">
    <property name="name" value="crm/marketing/lead"/>
</bean>
<bean id="destination.crm.marketing.lead"
    class="com.liferay.portal.kernel.messaging.SynchronousDestination">
    <property name="name" value="crm/marketing/lead/response"/>
</bean>
<bean id="destination.crm.marketing.stream"
    class="com.liferay.portal.kernel.messaging.ParallelDestination">
    <property name="name" value="crm/marketing/stream"/>
</bean>

Source 2. Configurazione destinazioni

La configurazione indicata al Source 2 dichiara le destinazioni specificandone il tipo e il nome della destinazione. Il tipo indica la classe che implementa la Destination (vedi class diagram di Figura 7). Le destination supportate sono implementate dalle seguenti classi:

  • com.liferay.portal.kernel.messaging.SynchronousDestination: per messaggio di tipo sincrono;
  • com.liferay.portal.kernel.messaging.SerialDestination: per messaggio di tipo asincrono con call-back;
  • com.liferay.portal.kernel.messaging.ParallelDestination: per messaggio di tipo asincrono send-and-forget.

Il nome della destinazione (vedi Source 2 riga 4) identifica questa all’interno del Message Bus e deve essere univoco; il nome assegnato deve essere a conosciuto dal consumer del servizio.  

<!-- Configurator -->
<bean id="messagingConfigurator"
    class="com.liferay.portal.kernel.messaging.config.PluginMessagingConfigurator">
    <property name="messageListeners">
        <map key-type="java.lang.String" value-type="java.util.List">
            <entry key="crm/customer/support/ticket">
                <list value-type="com.liferay.portal.kernel.messaging.MessageListener">
                    <ref bean="messageListener.customer_support_listener"/>
                </list>
            </entry>
            <entry key="crm/customer/support/ticket/response">
                <list value-type="com.liferay.portal.kernel.messaging.MessageListener">
                    <ref bean="messageListener.customer_support_listener"/>
                </list>
            </entry>
            <entry key="crm/marketing/lead">
                <list value-type="com.liferay.portal.kernel.messaging.MessageListener">
                    <ref bean="messageListener.marketing_listener"/>
                </list>
            </entry>
        </map>
    </property>
    <property name="destinations">
        <list>
            <ref bean="destination.crm.customer.ticket"/>
            <ref bean="destination.crm.customer.ticket.response"/>
            <ref bean="destination.crm.marketing.lead"/>
            <ref bean="destination.crm.marketing.lead.response"/>
        </list>
    </property>
</bean>

Source 3. Configurazione mapping destinazioni => listener

La configurazione indicata al Source 3 specifica le relazioni tra destinazione e listener. Le relazioni possibili sono quelle indicate in Figura 2. La configurazione core del Message Bus di Liferay è disponibile sul file messaging-core-spring.xml invece il file messaging-misc-spring.xml contiene le configurazioni di destinationlistener dei componenti di “serie” di Liferay, alcune delle destinazioni sono:

  • liferay/subscription_sender
  • liferay/message_boards_mailing_list
  • liferay/document_library_pdf_processor

Nel prossimo paragrafo vedremo un semplice esempio di come spedire delle notifiche via email inviando un messaggio verso la destinazione liferay/subscription_sender.

4. Invio messaggi sul Message Bus

Inviare un messaggio sul Message Bus e verso una specifica destinazione è molto semplice tramite il set di API a disposizione. Supponiamo il caso di voler inviare una o più notifiche via mail da una delle nostre portlet, per questo dovremmo preparare un messaggio con il contenuto della notifica e destinatari, in seguito inviare il messaggio verso la destinazione liferay/subscription_sender. In questo caso la destinazione è di tipo ParallelDestination (fare riferimento alla configurazione definita in messaging-misc-spring.xml), stiamo parlando quindi di un messaggio Asincrono (Send-and-Forget). 

L’estratto di codice mostrato al Source 4 in breve:

  • Prepara l’oggetto di tipo SubscriptionSender contenente il testo dell’email e destinatari;
  • Crea il messaggio da inviare sul Message Bus specificando la destinazione e il contenuto informativo, quest’ultimo rappresentato dall’oggetto subscriptionSender (Serializable);
  • Invia il messaggio appena creato sul Message Bus, questo consegnerà il messaggio alla destinazione indicata. 
SubscriptionSender subscriptionSender = new SubscriptionSender();

subscriptionSender.setSubject("Test invio email via Message Bus");
subscriptionSender.setBody("Ecco la mail via Message Bus");
subscriptionSender.setUserId(user.getUserId());
...
subscriptionSender.addRuntimeSubscribers(
	user.getEmailAddress(),
	user.getFullName());

Message myMessage = new Message();

myMessage.setDestinationName("liferay/subscription_sender");
myMessage.setPayload(subscriptionSender);
MessageBusUtil.sendMessage(myMessage.getDestinationName(),  myMessage);

Source 4. Esempio d’invio email via Message Bus (MessageBusExample.java)

Il messaggio inviato sul Message Bus e destinato a liferay/subscription_sender è elaborato dal listener SubscriptionSenderMessageListener che effettivamente invia la mail. Sul mio repository GitHub l’esempio completo della portlet che interagisce con il Message Bus.

5. Conclusioni

Sono partito con l’intenzione di scrivere una serie d’articoli che trattano il Message Bus di Liferay. Con questo primo articolo della serie ho voluto introdurre le caratteristiche fondamentali di questo strumento evidenziando i principali vantaggi e in particolare la semplicità in termini d’uso e configurazione.  Forse qualcuno potrebbe pensare che ho terminato con un semplice esempio, ho comunque in serbo per il prossimo articolo un caso di studio molto più interessante: Il Message Bus come mezzo d’integrazione verso altri sistemi.

SugarCRM: Customize Web To Lead Capture via Ext Framework


In alcuni casi potrebbe essere necessario eseguire delle personalizzazioni del processo di cattura per il potenziale cliente. Questo processo di cattura è scatenato tramite un determinato entryPoint che prende il nome di WebToLeadCapture. Il metodo che consiglierei per apportare delle modifiche al processo standard di cattura, è sicuramente quello di realizzare un proprio entryPoint e registrarlo tramite l’Ext Framework sul vostro sistema. A seguire un esempio su come creare un proprio entryPoint e definirlo (anche installarlo) tramite l’Ext Framework. A questo punto sarà possibile accedere al proprio entrypoint tramite l’URI index.php?entryPoint=myEntryPointWebToLeadCapture.

Per maggiori informazioni sull’Ext Framework consiglio di consultare la documentazione di SugarCRM ma in particolare questo post What’s new in Sugar 6.3: Ext framework enhancements.

<?php
echo "My Custom WebToLeadCapture";

Source 1. Codice dell’entryPoint

<?php
$entry_point_registry['myEntryPointWebToLeadCapture'] = array('file' => 'custom/myEntryPointWebToLeadCapture.php', 'auth' => false);

Source 2. Definizione nuovo entryPoint su myentrypoint_registry.php

<?php
$manifest = array (
    'acceptable_sugar_versions' => array (
        'regex_matches' => array(
            '6\.[56789]\.\d\w*'
            ),
        ),
    'acceptable_sugar_flavors' => array(
        'PRO',
        'CORP',
        'ENT',
        'ULT',
        ),
    'readme' => '',
    'key' => 'myEntryPointWebToLeadCapture',
    'author' => '',
    'description' => 'My Custom WebToLeadCapture',
    'icon' => '',
    'is_uninstallable' => true,
    'name' => 'My Custom WebToLeadCapture',
    'published_date' => '2013-03-21 23:22:07',
    'type' => 'module',
    'version' => '1.0',
    'remove_tables' => false,
    );

$installdefs = array (
    'id' => 'TestEntrypoint',
    'copy' => array (
        array (
            'from' => '<basepath>/myEntryPointWebToLeadCapture.php',
            'to' => 'custom/myEntryPointWebToLeadCapture.php',
            ),
        ),
    'entrypoints' => array (
        array (
            'from' => '<basepath>/myentrypoint_registry.php',
            'to_module' => 'application',
            ),
        ),
    );

Source 3. Manifest file per l’installazione del nuovo entryPoint

Web to Lead Forms come Web Content su Liferay


Nel precedente articolo Marketing Automation: Web to Lead Forms abbiamo visto come creare un Web to Lead Forms, adesso invece vedremo come inserire la Web to Lead Forms sul vostro portale Liferay. Niente di più semplice, basta creare un web content contenente l’HTML della Web to Lead Forms e successivamente utilizzare la portlet Web Content Display per visualizzare la Web to Lead Forms all’interno del vostro portale. Fatto!!!

Figura 1. Web to Lead Forms come Web Content Liferay

Figura 1. Web to Lead Forms come Web Content Liferay

Marketing Automation: Web to Lead Forms


1. Introduzione

I tuoi leads potrebbero provenire da una varietà di fonti – moduli web, elenchi acquistati da terze parti, da collegamenti e cold calling, tanto per citarne alcuni. Come si fa a gestire e sfruttare al meglio i tuoi leads? E come si fa a seguire i leads man mano che diventano opportunità? Per la maggior parte delle aziende, la gestione e il monitoraggio dei leads in modo coerente è una sfida chiave del business.

Esempio di processo MFA

Esempio di processo MFA

L’utilizzo del Web to Lead Forms è uno dei modi per generare leads, questi rappresentano i candidati che nel processo di MFA (Marketing Force Automation) potrebbero diventare prospect e per finire customer. Il Web to Lead Forms non è altro che un modulo web, solitamente collegato a una vostra campagna, pubblicato sul vostro portale web (ma non necessariamente) dove i vostri potenziali clienti inseriscono i loro dati perchè interessati a richiedere informazioni sul vostro prodotto. I dati così acquisiti sono pronti a far innescare il processo di Marketing.

Avete ben inteso che siamo in un contesto di CRM (Customer Relationship Management) dove ogni implementazione software include nativamente la funzionalità di “cattura” dei potenziali clienti attraverso il Web to Lead Forms. In quest’articolo vedremo come SugarCRM consente di creare una Web to Lead Forms.

2.  Creazione di una Web to Lead Forms

SugarCRM ha un modulo per la gestione dei Leads e un modulo per la gestione delle campagne, da quest’ultimo, è possibile creare tramite una procedura guidata un Web to Lead Forms. In genere un Web to Lead Forms è legato a una determinata campagna. Alla fine del processo di creazione del Web to Lead Forms, avrete in mano, del puro codice HTML che andrà inserito da qualche parte sul vostro portale internet. I passi da seguire per ottenere tale codice HTML sono i seguenti:

  • Dal modulo Campagne selezionare la voce Create Lead Forms. Quest’azione mostrerà la pagina del wizard per creare la form;
  • Tramite Drag & Drop selezionare i campi (provenienti dal modulo Lead) che desiderate inserire nella form e proseguite avanti;
  • Inserite le informazioni quali:
    • Form Header: È possibile cancellare e inserire le informazioni di intestazione desiderata.
    • Form Description: Inserire una breve descrizione del modulo.
    • Submit Button Label: È possibile cancellare e immettere l’etichetta desiderata per il pulsante d’invio modulo.
    • Post URL: La posizione predefinita cui le informazioni del lead saranno inviate.
    • Edit post URL: Per cambiare la locazione predefinita della Post URL.
    • Redirect URL: Immettere l’URL della pagina che si desidera visualizzare ai tuoi leads dopo aver inviato le loro informazioni. Se non si specifica una URL, sarà visualizzato un messaggio di ringraziamento.
    • Relate Campaign: Immettere o selezionare il nome della campagna legata a questa Web to Lead Forms.
    • Assigned To: Immettere il nome della persona alla quale assegnare il record oppure fare clic su Seleziona per scegliere dall’elenco degli utenti. Per impostazione predefinita, questo record è assegnato a voi.
    • Form Footer:  Inserisci piè di pagina, se necessario.
  • Cliccare sul pulsante Genera Form. Quest’azione visualizzerà la form nell’editor TinyMCE per lasciarvi liberi di apportare eventuali modifiche (esempio: inserimento di un logo, etc…)
  • Per salvare il modulo, è possibile eseguire una delle seguenti operazioni:
    • Copiare e incollare il codice HTML all’interno di un file di testo sul computer locale. Per i sistemi On-Premise, il modulo sarà salvato all’interno della directory cache/generated_forms del server. È comunque possibile copiarlo dalla cache in una posizione diversa.
    • Per salvare il modulo generato come file html sul computer locale, è possibile fare clic con il pulsante destro del mouse su Web to Lead Forms, aprire la pagina in una nuova scheda, selezionare Salva pagina con nome dal menu File del browser e passare alla posizione in cui si desidera salvare.
  • Per visualizzare il modulo fare clic sul collegamento Web to Lead Forms nella parte superiore della pagina.

Per cercare di rendere più chiari i precedenti passi, sono stati replicati è illustrati nelle figure a seguire.

Figura 1. Creazione Web to Lead Forms

Figura 1. Creazione Web to Lead Forms

Figura 2. Selezione dei campi per la Web to Lead Forms

Figura 2. Selezione dei campi per la Web to Lead Forms

Figura 3. Titolo e parametri d'invio della Web to Lead Forms

Figura 3. Titolo e parametri d’invio della Web to Lead Forms

Figura 4. Editor HTML per la personalizzazione della Web to Lead Forms

Figura 4. Editor HTML per la personalizzazione della Web to Lead Forms

Figura 5. Salvataggio della Web to Lead Forms

Figura 5. Salvataggio della Web to Lead Forms

3. Test del Web to Lead Forms

E’ consigliabile prima della pubblicazione sul vostro portale internet, eseguire un test del Web to Lead Forms, questo, attraverso il link mostrato in precedenza (per esempio: https://sugarcrmpgsql-shiruslabs.rhcloud.com/cache/generated_forms/WebToLeadForm_1363792790.html). Quello di Figura 6 è il Web to Lead Forms generato precedentemente e come potete notare, il codice HTML contiene tutto il javascript necessario per la validazione della form. Al submit della form tutti i dati saranno inviati a SugarCRM e utilizzati per inserire il nuovo lead (vedi Figura 7 e Figura 8). In Figura 9 è invece mostrato l’andamento della vostra campagna che evidenzia i leads catturati.

Figura 6. Esempio del Web to Lead Forms generato da SugarCRM

Figura 6. Esempio del Web to Lead Forms generato da SugarCRM

Figura 7. Submit della Web to Lead Forms verso l'entry point di SugarCRM

Figura 7. Submit della Web to Lead Forms verso l’entry point di SugarCRM

Figura 8. Dettaglio del Leads catturato dalla Web to Lead Forms

Figura 8. Dettaglio del Leads catturato dalla Web to Lead Forms

Figura 9. Dettaglio andamento campagna con evidenza dei leads catturati

Figura 9. Dettaglio andamento campagna con evidenza dei leads catturati

Report SugarCRM con Open Office?


Un post veloce, veloce per stuzzicare il vostro appetito. Chi ha detto che per fare i report su SugarCRM serve assolutamente l’installazione di un qualche modulo o “disturbare” la versione commerciale? La soluzione è più semplice del previsto, ancora più semplice da quando SugarCRM ha pubblicato lo schema relazionale del proprio data base. Con strumenti del tutto Open Source è quindi possibile costruirsi i propri reports, basta una buona conoscenza di Data Base Relazionali e Tabelle Pivot, su quest’ultimo punto lo strumento per eccellenza è Open Office Calc. Le figure a seguire illustrano un esempio di report che indica la lavorazione dei Lead da parte degli operatori del CRM.

Figura 1. Sorgente dati SugarCRM

Figura 1. Sorgente dati SugarCRM

Figura 2. Tabella Pivot generata a partire dalla sorgente dati SugarCRM

Figura 2. Tabella Pivot generata a partire dalla sorgente dati SugarCRM

Figura 3. Grafico generato dalla tabella pivot

Figura 3. Grafico generato dalla tabella pivot

Risorse: