bloggers bloggers

Jader Jed Francia
Messaggi: 52
Stelle: 0
Data: 31/07/18
Ezio Lombardi
Messaggi: 11
Stelle: 0
Data: 10/04/18
Marco Napolitano
Messaggi: 70
Stelle: 0
Data: 07/02/18
Chiara Mambretti
Messaggi: 25
Stelle: 0
Data: 27/02/17
Serena Traversi
Messaggi: 3
Stelle: 0
Data: 21/07/16
Francesco Falanga
Messaggi: 8
Stelle: 0
Data: 14/06/16
Antonio Musarra
Messaggi: 2
Stelle: 0
Data: 18/11/13
Simone Celli Marchi
Messaggi: 6
Stelle: 0
Data: 09/07/13
marcello marangio
Messaggi: 4
Stelle: 0
Data: 05/07/13
Marco Mancini
Messaggi: 1
Stelle: 0
Data: 05/06/13
Indietro

Come integrare il Workflow di Liferay nelle proprie portlet custom?

L'argomento di oggi è relativo all'integrazione del workflow di Liferay -si, sto parlando di Kaleo! :)- all'interno delle nostre portlet custom!

Come tutti voi già saprete, Kaleo, il workflow di Liferay è una portlet a parte rispetto al portale e si può installare direttamente dal marketplace.

Le funzionalità che mette a disposizione, tuttavia, sono molto comode quando si ha la necessità di realizzare un processo approvativo collegato ad un nostro asset custom.

Di fatto, Kaleo funziona in maniera disaccoppiata rispetto agli altri oggetti del sistema; questo quindi ci offre un grandissimo grado di libertà perché buona parte del lavoro -ovvero pilotare la macchina a stati del processo approvativo- viene gestito direttamente dal motore di Kaleo e per noi è del tutto trasparente.

Questo significa che noi, per utilizzare questo importante framework applicativo, dobbiamo solo preoccuparci di notificare all'handler del gestore di processi che vogliamo far partire un workflow su uno dei nostri asset; tutto il resto avverrà poi all'interno di Kaleo e a noi saranno notificati solamente i cambi di stato del processo!

Vediamo ora nel dettaglio come fare, per attivare questa funzionalità sui nostri asset!

Prima cosa: modello dei dati! Dobbiamo aggiungere nel nostro service.xml i field di audit che utilizzeremo quando riceveremo le notifiche dall'handler di Kaleo e il campo per gestire lo stato del nostro record.

Per farlo, quindi, aggiungiamo questi record al nostro modello:

<!-- Workflow fields -->

<column name="status" type="int"/>

<column name="statusByUserId" type="long"/>

<column name="statusByUserName" type="String"/>

<column name="statusDate" type="Date"/>

Rigeneriamo i nostri oggetti lanciando il task build-service; facciamo refresh sul progetto e prepariamoci a gestire i nostri oggetti.
Per prima cosa predisponiamo tutto quello che occorre per agganciarci al workflow; prima cosa da fare: mappare sul nostro liferay-portlet.xml l'handler che vorremo utilizzare per i nostri oggetti; questa è la riga da utilizzare:
<workflow-handler>it.dvel.test.liferay.workflow.LibroWorkflowHandler</workflow-handler>
Per i pigri come me: va messa subito prima del tag <instanceable/>; se non volete guardare la dtd.. :)
Poi dobbiamo creare questa classe; per farlo, come sempre, siccome dobbiamo implementare l'interfaccia com.liferay.portal.kernel.workflow.WorkflowHandler utilizzeremo l'implementazione di base fornita da Liferay: com.liferay.portal.kernel.workflow.BaseWorkflowHandler.
La nostra classe, quindi, sarà così composta (come al solito, ometto gli import..):
public class LibroWorkflowHandler extends BaseWorkflowHandler {

@Override
public String getClassName() {
// Mappiamo il nostro asset..
return Libro.class.getName();
}

@Override
public String getType(Locale locale) {
return "libro";
}

@Override
public Object updateStatus(
int status, Map<String, Serializable> workflowContext)
throws PortalException, SystemException {
// Dal contesto leggiamo l'id utente..
long userId = GetterUtil.getLong(
workflowContext.get(WorkflowConstants.CONTEXT_USER_ID));

// Sempre dal contesto leggiamo la primary key del nostro oggetto..
long resourcePrimKey = GetterUtil.getLong(
workflowContext.get(WorkflowConstants.CONTEXT_ENTRY_CLASS_PK));

// Estraiamo il ServiceContext che serve sempre.. :)
ServiceContext serviceContext =
(ServiceContext) workflowContext.get("serviceContext");

// E richiamiamo il nostro metodo che farà update dello status sul nostro asset!
return LibroLocalServiceUtil.updateStatus(
userId, resourcePrimKey, status, serviceContext);
}
}
Come vedete, questo handler non è altro che un proxy banale su un metodo della nostra LocalService; un metodo che non fa altro che fare update dello status sul nostro oggetto.
Ed infatti questo è tutto quello che a noi interessa sapere dal giro perverso del workflow: in quale stato si trova l'asset rispetto alla grammatica approvativa che avremo collegato al workflow!
A questo punto direi che possiamo implementare nella nostra LibroLocalServiceImpl il metodo updateStatus:
public Libro updateStatus(
long userId, long resourcePk, int status, ServiceContext ctx)
throws PortalException, SystemException {
// Estraiamo l'utente che sta aggiornando l'asset
User user = userLocalService.getUser(userId);

// Recuperiamo la nostra entity usando la primary key
Libro libro = getLibro(resourcePk);

// Aggiorniamo i field di audit che abbiamo mappato prima nel service.xml
libro.setStatus(status);
libro.setStatusByUserId(userId);
libro.setStatusByUserName(user.getFullName());
libro.setStatusDate(ctx.getModifiedDate());

if (status == WorkflowConstants.STATUS_APPROVED) {
// Se lo stato è approvato allora rendiamo l'asset visibile, così che anche l'asset
// publisher lo mostrerà
assetEntryLocalService.updateVisible(Libro.class.getName(), resourcePk, true);
} else {
// altriment lo lasciamo invisibile,
//così che non sia nemmeno estratto dall'asset publisher
assetEntryLocalService.updateVisible(Libro.class.getName(), resourcePk, false);
}

// facciamo update sul db del nuovo stato
libroPersistence.update(libro, false);

return libro;
}
E anche questa è fatta! Rigeneriamo con build-service, facciamo refresh del progetto e ora andiamo ad agire sulla insert del nostro oggetto per far funzionare il workflow!
Di questo metodo, tuttavia, ometto i setter della entity, così non devo formattare un tera di codice java.. :)
public Libro addEntry(
String nome, long libreriaId, boolean visibile, int numeroPagine,
Date dataDiPubblicazione, String descrizione, String isbn, ServiceContext ctx)
throws PortalException, SystemException {
Date now = new Date();
User user = userLocalService.getUser(ctx.getUserId());
Libro libro = libroPersistence.create(
counterLocalService.increment(Libro.class.getName()));
// Ometto un sacco di setter.. :)
....
// Questo è importante! Mappo lo status del mio asset come draft!
// So che la cosa potrebbe non essere chiara subito, ma voi fidatevi di me! ;)
libro.setStatus(WorkflowConstants.STATUS_DRAFT);

// Salvo sul db la mia entry
libro = libroPersistence.update(libro, true);

// L'aggiungo alle risorse
resourceLocalService.addResources(
libro.getCompanyId(), libro.getGroupId(),
libro.getUserId(), Libro.class.getName(), libro.getPrimaryKey(),
false, true, true);

// L'aggiungo agli asset
assetEntryLocalService.updateEntry(
libro.getUserId(), libro.getGroupId(),
Libro.class.getName(),
libro.getPrimaryKey(),
ctx.getAssetCategoryIds(),
ctx.getAssetTagNames());

// E ora notifico al workflow che c'è un nuovo asset da gestire! :)
WorkflowHandlerRegistryUtil.startWorkflowInstance(libro.getCompanyId(),
libro.getGroupId(), libro.getUserId(), Libro.class.getName(),
libro.getPrimaryKey(), libro, ctx);

return libro;
}
Se non vi funziona la parte delle risorse e degli asset, leggete come fare ad esporre le vostre entity come asset di portale! :)
Fatto! :)
Ora la vostra entity è collegata a Kaleo; se attivate una grammatica di workflow su di essa potrete approvarla direttamente dalla portlet del workflow!
Un attimo! Non vi ho spiegato la cosa dello status DRAFT di default; come viene gestita questa cosa?
Beh, come vi ho detto all'inizio, Kaleo non è installato di default su Liferay ma è un componente a parte. Questo significa che il registry di workflow che invece è distribuito standard con Liferay,
considera anche il caso in cui non solo Kaleo non è installato ma che potrebbe non essere nemmeno attiva una grammatica sul nostro asset.
E quindi?
Questo significa che quando nella nostra insert facciamo questa chiamata:
WorkflowHandlerRegistryUtil.startWorkflowInstance(...);
di fatto diciamo al Registry che c'è una entity da gestire, ma lui, nel caso in cui Kaleo non sia installato oppure non ci siano workflow attivi, chiama direttamente il nostro handler passandogli lo stato APPROVED: in questo modo il nostro asset sarà approvato di default e tutto funzionerà a dovere!
Precedente
Commenti
Nessun commento. Vuoi essere il primo.