...

Recycle Bin per entità gerarchiche

by user

on
Category: Documents
10

views

Report

Comments

Transcript

Recycle Bin per entità gerarchiche
Recycle Bin per entità gerarchiche
Claudio Umana
Application Architect at I3Solevo srl (Gruppo i3)
“Sommario"
In evidenza:
• Il Recycle Bin in Liferay 6.2
• Strutture gerarchiche: Web Content e Folder
• Caso d’uso: Product e ProductRelease
• Cenni sulla soluzione
• Conclusioni e considerazioni finali
Liferay Symposium Italy, Rome 2014
“Introduzione al Recycle Bin“ - 1
Introduzione
La nuova funzionalità è stata introdotta nella versione di Liferay 6.2.
Il concetto di “Recycle Bin” è famigliare a
tutti gli utenti Windows e non.
Le funzionalità note:
• la cancellazione di un oggetto funzionale determina il suo
"posizionamento" nel cestino;
• dal cestino è possibile cancellare completamente l'oggetto o
ripristinarlo.
Queste funzionalità sono rese fruibili dal "Recycle Bin Framework" di
Liferay.
Liferay Symposium Italy, Rome 2014
"Introduzione al Recycle Bin" - 2
Nel nuovo Liferay 6.2, visivamente:
• Per spostare nel cestino
• Per ripristinare:
Liferay Symposium Italy, Rome 2014
"Introduzione al Recycle Bin" - 3
Caso dei ‘WebContent’ e delle ‘Folder’ standard
Alcuni WebContent in una cartella di nome ‘Archivio news’.
Se spostiamo nel cestino i contenuti editoriali, più la cartella che li
contiene…
Liferay Symposium Italy, Rome 2014
"Introduzione al Recycle Bin" - 4
Se ripristiniamo ‘solo’ i WebContent…
Dal ‘Pannello di controllo’:
Mentre nel cestino…
Liferay Symposium Italy, Rome 2014
"Introduzione al Recycle Bin" - 5
In definitiva la soluzione proposta da Liferay non permette di mantenere
in maniera trasparente la struttura funzionale.
Quindi lo scenario richiesto vorrebbe che:
• chi ripristina un contenuto ‘annidato’ in una folder anch’essa nel
«Recycle Bin» non dovrebbe conoscere la struttura originaria.
Liferay Symposium Italy, Rome 2014
"Recycle Bin Framework"
Il ‘cestino’ per Liferay
Gli elementi su cui focalizzarsi per il "Recycle Bin Framework":
• Abilitare il Trash per i singoli Service Entity;
• Implementare il "Trash Handler" per le entità abilitate al Trash;
• Creare il servizio che sposti l'entità nel "Recycle Bin ";
• Creare un Portlet Action per rendere operativo la ‘move to Recycle
Bin’;
• Implementare il Trash Renderer per le entità abilitate al Trash;
• Implementare il ripristino della entità.
Vediamo alcuni dettagli.
Liferay Symposium Italy, Rome 2014
"Recycle Bin Framework“ - Abilitare il Trash per i singoli Service Entity e il Trash Handler - 1
Nel solito e necessario service.xml definire per ogni "entity" interessata
al gestione del trash:
• <entity name="Entita" … trash-enabled="true">
Eseguire il "Service Builder" per generare le classi di back-end di
gestione del trash per le entità interessate.
Per ogni entità interessata alla gestione del cestino è necessario
implementare l'interfaccia del "TrashHandler" fornita dal framework e
concentrarsi sui metodi principali:
• deleteTrashEntry()
• isInTrash()
• restoreTrashEntry()
Liferay Symposium Italy, Rome 2014
"Recycle Bin Framework“ - Abilitare il Trash per i singoli Service Entity e il Trash Handler - 2
Nel liferay-portlet.xml è necessario referenziare l'handler in
questione:
•
<trash-handler>it.simposio.roma.Entita</trash-handler>
Liferay Symposium Italy, Rome 2014
"Recycle Bin Framework“ - Creare il servizio che sposti l'entità nel "Recycle Bin" - 1
Livello servizi moveToTrash…
Nel nostro EntitaLocalServiceImpl è necessario prestare attenzione il
seguente:
@Indexable(type = IndexableType.REINDEX)
public Entita moveEntitaToTrash(long userId, Entita obj) throws PortalException,
SystemException
{
ServiceContext serviceContext = new ServiceContext();
// Entry - si imposta lo status dell'oggetto
obj.setStatus(WorkflowConstants.STATUS_IN_TRASH);
...
// Asset
//si imposta la visibilità dell'asset
...
// Trash
//si "sposta" l'oggetto nel cestino
...
TrashEntry trashEntry = trashEntryLocalService.addTrashEntry(...);
...
}
Liferay Symposium Italy, Rome 2014
"Recycle Bin Framework“ - Creare il servizio che sposti l'entità nel "Recycle Bin" - 2
Si evidenziano:
•
•
•
@Indexable(type = IndexableType.REINDEX): per aggiornare la
"Liferay reindexes" affinché sia ricercabile nel cestino e non fuori di
esso;
obj.setStatus(WorkflowConstants.STATUS_IN_TRASH): per
indicare al motore di workflow dove l'oggetto si "trova";
trashEntryLocalService.addTrashEntry(...): che aggiunge
l'entità al cestino.
Quest'ultima istruzione aggiorna la tabella specifica nel DB di Liferay.
Liferay Symposium Italy, Rome 2014
"Recycle Bin Framework“ - Creare un Portlet Action per rendere operativo la "move to Recycle Bin"
A livello di ‘MVC Portlet’ si implementa l'action specifico:
public void deleteEntita(ActionRequest request, ActionResponse response) throws
Exception
{
...
EntitaServiceUtil.deleteEntita(entryId, serviceContext);
...
}
Il frammento lato jsp:
<portlet:actionURL name="deleteEntita" var="deleteEntitaURL">
<portlet:param name="entryId" value="<%=obj.getEntryId() %>" />
…
<portlet:param name="redirect" value="<%= redirect %>" />
</portlet:actionURL>
Liferay Symposium Italy, Rome 2014
"Recycle Bin Framework“ - Implementare il Trash Renderer per le entità abilitate al Trash
Come nel caso dell'Trash Handler è necessario implementare i metodi
della: TrashRenderer.
In particolare la getTrashRenderer:
@Override
public TrashRenderer getTrashRenderer(long classPK) throws PortalException,
SystemException {
DLFileShortcut fileShortcut = getDLFileShortcut(classPK);
return new DLFileShortcutTrashRenderer(fileShortcut);
}
Che restituisce, in questo caso, la classe di renderer per il trash della ‘Document
Library’.
Liferay Symposium Italy, Rome 2014
"Recycle Bin Framework“ - Implementare il ripristino della entità - 1
Livello servizi per la restore…
Abbiamo bisogno:
• di creare un metodo per il Service per il ripristino;
• di invocare il metodo del Service dal Trash Handler.
In breve si implementa una restoreEntitaFromTrash() della
EntitaLocalServiceImpl
@Indexable(type = IndexableType.REINDEX)
@Override
public Entita restoreEntitaFromTrash(long userId, long entityId) throws
PortalException, SystemException {
...
obj.setStatus(trashEntry.getStatus());
...
assetEntryLocalService.updateVisible(Entita.class.getName(), obj.getSongId(),
true);
...
trashEntryLocalService.deleteEntry(Entita.class.getName(), entityId);
...
}
Liferay Symposium Italy, Rome 2014
"Recycle Bin Framework“ - Implementare il ripristino della entità - 2
Aggiornare con service.xml !
Per finire… nel "Trash Handler":
@Override
public void restoreTrashEntry(long userId, long classPK) throws
PortalException, SystemException
{
EntitaLocalServiceUtil.restoreEntitaFromTrash(userId, classPK);
}
Liferay Symposium Italy, Rome 2014
“Product e ProductRelease” – Scenario 1
Caso d’uso.
Abbiamo:
• entità Product
• entità ProductRelease
Il prodotto può avere più release di prodotto, ma a un release di
prodotto può essere associato solo a un Product.
Liferay Symposium Italy, Rome 2014
“Product e ProductRelease” - Scenario 2
Tenendo conto dello schema indicato le operazioni da considerare sono
le seguenti:
• Spostare un Product nel cestino: devono essere spostati anche i
rispettivi ProductRelease.
• Cancellare un Product nel cestino: vengono cancellati tutti i
rispettivi ProductRelease.
• Spostare un ProductRelease nel cestino: non ha impatto sul
Product a cui appartiene.
• Cancellare un ProductRelease: non ha impatto sul Product a cui
appartiene.
• Ripristino di un ProductRelease: si ripristina il Product di
appartenenza e poi l’oggetto di riferimento.
• Ripristinare un Product: si ripristinano tutti i ProductRelease
rispettivi.
Liferay Symposium Italy, Rome 2014
“Product e ProductRelease” – Soluzione 1
Da quanto indicato, si conclude che le azioni funzionali sui Product
devono aver effetto sui ProductRelease, ma non vale il contrario.
Questo ha ovviamente impatto sulla soluzione tecnica.
I punti di analisi e di intervento per la soluzione:
• Intervento sul service.xml: le entità Product e ProductRelease da
abilitare per il cestino e la ProductRelease deve avere come ‘padre’ il
Product.
• Implementare il "Trash Handler ": valido sia per Product che per
ProductRelease;
• Implementare il servizio MoveToTrash e RestoreFromTrash: per
Product e per ProductRelease;
• Creare un Portlet Action: MVCPortlet che intercetti le azioni lato
presentation;
• Implementare il Trash Renderer: per le entità abilitate al Trash.
Liferay Symposium Italy, Rome 2014
“Product e ProductRelease” - Soluzione 2
Primo passo – definire le entità con relazione gerarchiche.
Sul ‘solito’ service.xml, gli elementi funzionalmente rilevanti:
<entity name="HDProduct" ... trash-enabled="true">
<column name="productId" type="long" primary="true" />
<!-- For Trash Handler -->
<column name="status" type="int" />
<column name="statusByUserId" type="long" />
<column name="statusByUserName" type="String" />
<column name="statusDate" type="Date" />
...
<!-- References -->
<reference package-path="com.liferay.portal" entity="WorkflowInstanceLink" />
<reference package-path="com.liferay.portlet.asset" entity="AssetEntry" />
<reference package-path="com.liferay.portlet.asset" entity="AssetLink" />
<reference package-path="com.liferay.portlet.trash" entity="TrashEntry" />
</entity>
<entity name="HDProductRelease" ... trash-enabled="true">
<column name="productReleaseId" type="long" primary="true" />
<column name="productId" type="long" />
<!-- For Trash Handler -->
<column name="status" type="int" />
<column name="statusByUserId" type="long" />
<column name="statusByUserName" type="String" />
<column name="statusDate" type="Date" />
...
<reference package-path="com.liferay.portal" entity="WorkflowInstanceLink" />
<reference package-path="com.liferay.portlet.asset" entity="AssetEntry" />
<reference package-path="com.liferay.portlet.asset" entity="AssetLink" />
<reference package-path="com.liferay.portlet.trash" entity="TrashEntry" />
</entity>
Liferay Symposium Italy, Rome 2014
“Product e ProductRelease” - Soluzione 3
In sostanza:
• Il HDProductRelease possiede un riferimento al suo HDProduct;
• Le 2 entità sono Asset a cui si agganciano le funzionalità del Trash;
• Devono essere presenti i campi di gestione dello stato dell’oggetto.
Adesso è necessario «informare» Liferay delle classi adibite alla
gestione del cestino. Ovvero nel liferay-portlet.xml si estrapola:
<liferay-portlet-app>
<portlet>
...
<!-- Trash handler -->
<trash-handler>it. ... .trash.HDProductTrashHandler</trash-handler>
<trash-handler>it. ... .trash.HDProductReleaseTrashHandler</trash-handler>
...
</portlet>
...
</liferay-portlet-app>
Liferay Symposium Italy, Rome 2014
“Product e ProductRelease” - Soluzione 4
In sostanza nel <Entity>TrashHandler (del BaseTrashHandler del
framework), ci si deve soffermare sui metodi (di valenza funzionale):
•
•
public void deleteTrashEntry(long classPK);
public void restoreTrashEntry(long userId, long classPK).
Nel nostro caso (un estratto):
public class HDProductTrashHandler extends BaseTrashHandler {
...
public void deleteTrashEntry(long classPK) throws ... {
HDProductLocalServiceUtil.deleteProduct(classPK); }
...
public void restoreTrashEntry(long userId, long classPK) throws ... {
HDProductLocalServiceUtil.restoreProductFromTrash(userId, classPK);
}
...
}
public class HDProductReleaseTrashHandler extends BaseTrashHandler {
...
public void deleteTrashEntry(long classPK) throws ... {
HDProductReleaseLocalServiceUtil.deleteProductRelease(classPK); }
....
public void restoreTrashEntry(long userId, long classPK) throws ... {
HDProductReleaseLocalServiceUtil.restoreProductReleaseFromTrash(userId, classPK);
}
...
}
Liferay Symposium Italy, Rome 2014
“Product e ProductRelease” - Soluzione 5
Analogamente, lato servizi…
<Entity>ServiceImpl e <Entity>LocalServiceImpl si fanno carico
dell’onere ‘esecutivo’.
public class HDProductLocalServiceImpl extends HDProductLocalServiceBaseImpl {
public HDProduct deleteProduct(HDProduct hdProduct) throws ... {
/**
* 1.si prendono i HDProductReleases del HDProduct: WorkflowConstants.STATUS_ANY
* 2.si cancellano i HDProductReleases ottenuti
* 3.si cancella HDProduct
* 4.gestione eventuale eccezione */
}
public HDProduct moveProductToTrash(long userId, HDProduct hdProduct) throws ... {
...
updateStatus(userId, hdProduct.getProductId(), WorkflowConstants.STATUS_IN_TRASH, new
ServiceContext());
...
}
public void restoreProductFromTrash(long userId, long productId) throws ... {
...
/**
* 1.si prendono i HDProductReleases del HDProduct: WorkflowConstants.STATUS_IN_TRASH
* 2.si ripristano dal cestino gli HDProductReleases
* 3.si ripristina il HDProduct
* 4.gestione eventuale eccezione*/
...
}
}
Liferay Symposium Italy, Rome 2014
“Product e ProductRelease” - Soluzione 6
Dove si evidenziano:
• WorkflowConstants.STATUS_ANY: ovvero nella cancellazione, tutti
i HDProductRelease vengono coivolti.
• WorkflowConstants.STATUS_IN_TRASH: ovvero nel ripristino sono
interessati sono quelli nel ‘Trash’.
Un discorso a parte merita il metodo evidenziato updateStatus.
Questo si occupa o si dovrebbe occupare, sempre considerando il
nostro contesto funzionale, di:
• aggiornare lo stato dell'entità interessata;
• aggiornare a visibilità dell'asset;
• aggiornare lo stato per il workflow;
• aggiornare la tabella TrashEntry: ovvero aggiungere o togliere
l'oggetto dalla tabella del "Trash" sul db di Liferay.
Liferay Symposium Italy, Rome 2014
“Product e ProductRelease” - Soluzione 7
Analogamente per il HDProductReleaseLocalServiceImpl:
public class HDProductReleaseLocalServiceImpl extends HDProductReleaseLocalServiceBaseImpl {
public HDProductRelease moveProductReleaseToTrash(long userId, HDProductRelease hdProductRelease)
throws ... {
...
updateStatus(userId, hdProductRelease.getProductReleaseId(), WorkflowConstants.STATUS_IN_TRASH,
new ServiceContext());
...
}
...
public void restoreProductReleaseFromTrash(long userId, long productReleaseId) throws ... {
/**
* 1. ripristinare il HDProduct dell'HDProductRelease
* 2. ripristinare solo l'HDProductRelease interessato all'azione. Quello in
WorkflowConstants.STATUS_IN_TRASH
* 3. gestione dell'eccezione */
...
}
}
Le osservazioni sono le stesse della HDProductLocalServiceImpl, con la
differenza che in questo caso non sono rilevanti la ‘delete’ poiché rimane
invariata rispetto a una delete ‘standard’.
Non solo, il ripristino di un elemento ‘figlio’ non interessa eventuali altri
oggetti ‘fratelli’.
Liferay Symposium Italy, Rome 2014
“Product e ProductRelease” - Soluzione 8
Ovviamente i ‘servizi’ devono poter essere invocati da azioni utente
effettuate su una interfaccia web.
Per la soluzione presentata è sufficiente una MVCPortlet nella quale
vengono implementati i seguenti:
public void deleteHDProduct(ActionRequest anRequest, ActionResponse aResponse) throws Exception {
...
if (cmd.equals(Constants.MOVE_TO_TRASH)) {
/**
* 1. si recuperano i HDProductReleases
* 2. si spostano i HDProductReleases nel cestino
* 3. si sposta nel cestino il HDProduct
* 4. si gestisce l'eccezione */
}
else { //delete standard …
}
}
public void deleteHDProductRelease(ActionRequest aRequest, ActionResponse aResponse) throws
Exception {
...
if (cmd.equals(Constants.MOVE_TO_TRASH)) {
HDProductReleaseServiceUtil.moveProductReleaseToTrash(themeDisplay.getUserId(),
productReleaseId);
}
else if (cmd.equals(Constants.DELETE)) {
HDProductReleaseServiceUtil.deleteProductRelease(productReleaseId);
...
}
}
Liferay Symposium Italy, Rome 2014
“Product e ProductRelease” - Soluzione 9
Si osserva che nel caso della ‘move_to_trash’ parte della logica
funzionale è demandata all’action dello strato MVC. Ovviamente altre
soluzioni possono essere applicate!
Visivamente la maschera principale:
Dove sono in evidenza le azioni possibili su un singolo prodotto.
Liferay Symposium Italy, Rome 2014
“Product e ProductRelease” - Soluzione 10
Nel caso di più release di prodotto:
Si possono notare due entry ‘associate’ a ‘Windows OS’.
Liferay Symposium Italy, Rome 2014
“Product e ProductRelease” - Soluzione 11
Nel caso si volesse spostare nel cestino ‘windows Me’, l’interfaccia
sarebbe la seguente:
Dove non è permessa nessuna azione per l’oggetto nel cestino.
Liferay Symposium Italy, Rome 2014
“Product e ProductRelease” - Soluzione 12
Invece dall’interfaccia di amministrazione del ‘Recycle Bin’:
È possibile ripristinare o cancellare definitivamente l’oggetto.
Liferay Symposium Italy, Rome 2014
“Considerazioni aggiuntive” - 1
Quanto riportato non ha sufficientemente discusso i seguenti contesti:
• Workflow;
• Indicizzazione;
• Staging.
Workflow
I metodi ai quali bisogna prestare attenzione particolare sono anche
quelli ‘funzionali’:
• add<Entita>
• delete<Entita>
• move<Entita>toTrash
• restore<Entita>fromTrash
In particolare significativi:
• WorkflowHandlerRegistryUtil: per avviare l’istanza di processo.
• WorkflowInstanceLinkLocalServiceUtil: per distruggere l’istanza di
processo.
Liferay Symposium Italy, Rome 2014
“Considerazioni aggiuntive” - 2
Indicizzazione
Anche in questo caso le situazioni più critiche:
• delete<Entita>
• update<Entita>
Con i quali si deve far un uso oculato delle:
• indexer.delete(obj): nel caso di distruzione dell’oggetto;
• indexer.reindex(obj): ogni volta che si aggiorna.
Tale attenzione dovrebbe garantire il corretto funzionamento degli
oggetti che transitano nel cestino.
Staging
In questo caso, il motore di Liferay risolve la maggior parte delle
situazioni.
Liferay Symposium Italy, Rome 2014
“Considerazioni aggiuntive” - 3
E’ noto che:
• quando lo staging è abilitato, Liferay crea un altro e aggiuntivo
"Recycle-Bin" in modalità staging.
• passare da stage a NON stage, implica spostare gli oggetti dal
cestino in stage a quello in NON-stage.
Liferay Symposium Italy, Rome 2014
“Considerazioni aggiuntive” - 4
In sostanza l’attenzione si sposta nel:
Inibire i tasti azione in modalità staging
Nel caso di:
• delete<Entita>
• move<Entita>FromTrash
È prestare attenzione all’id di appartenenza del gruppo/sito che deve
essere quello in modalità staging.
Liferay Symposium Italy, Rome 2014
“Possibili evoluzioni future”
La ‘visione’ padre-figlio di Product e ProductRelease, suggerisce le
seguenti evoluzioni:
• ProductRelease con la possibilità di avere proprie sottostrutture.
• Un criterio più restrittivo per gestire i conflitti tra oggetti diversi.
• Una gestione avanzata delle eccezioni nel caso di cancellazioni
‘definitive’: la delete è distruttiva nel DB.
• In che misura la logica funzionale deve essere demandata a livello di
MVCPortlet e quale a livello di servizio?
• Versionare i Product.
• Ecc…
Liferay Symposium Italy, Rome 2014
Grazie per l’attenzione.
Claudio Umana
[email protected]
Application Architect at I3Solevo srl (Gruppo i3)
Fly UP