Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Apache Jackrabbit. Java content repository

Un motore di persistenza unico per diversi contenuti, dal testo ai video
Un motore di persistenza unico per diversi contenuti, dal testo ai video
Link copiato negli appunti

Grazie alla crescita delle applicazioni Web e alla diffusione dei contenuti generati dagli utenti, ci si trova a gestire un insieme di informazioni numeroso e, soprattutto, eterogeneo. Basti pensare ad un portale come Amazon che gestisce una mole consistente di prodotti da vendere con recensioni utenti, video, immagini, votazioni, domande e risposte, PDF e decine di altre informazioni tutte di natura diversa.

Gestire siti di questo tipo affidandoci ad una semplice base di dati è operazione impraticabile e in questo articolo ci occuperemo di definire un possibile modello di sviluppo per la gestione di informazioni di natura complessa attraverso l'uso di un content repository.

Cos'è un Content Repository?

Per definire in maniera semplice un content repository, possiamo pensarlo come una grossa base di dati di oggetti: nessuna struttura predefinita, semplicemente un sistema capace di immagazzinare e recuperare in maniera ottimizzata informazioni, anche relazionate tra loro.

La semplicità di questa definizione non ci inganni, in quanto vedremo che, a fronte di "semplici" funzionalità di lettura e scrittura, la gestione del sistema Content Repository nasconde all'utente finale una architettura astratta per poter dare la flessibilità di archiviare diversi tipi di dati.

In ambiente Java la scelta di trovare una soluzione standard al problema venne presa nel 2002 quando con l'inizio dei lavori della JSR 170 nota anche come JCR, si diede l'avvio alla creazione di uno strato software astratto (il package javax.jcr) che consentisse allo sviluppatore di applicazioni di non preoccuparsi di come il prodotto Content Repository fosse implementato a più basso livello.

Infatti, scopo del lavoro è stato quello di trovare un semplice modello su cui basare le implementazioni dei diversi Content Repository nel mercato. Il problema di fondo era quello di trovare una interfaccia comune che fungesse da wrapper ai diversi modelli di logica e persistenza per i prodotti nuovi o quelli già esistenti.

Figura 1. Gestione astratta e unificata di fonti di dati differenti
Gestione astratta e unificata di fonti di dati differenti

Qui l'immagine ci indica possibili modelli di persistenza, ma il problema è esteso anche nel senso della eterogeneità delle informazioni in gioco.

Apache Jackrabbit

Definita la specifica, serviva sviluppare prodotti per implementarne la logica. Il gruppo Apache decise allora di realizzare una soluzione nota come Apache Jackrabbit, che è il Java Content Repository "per definizione". Si tratta di un servizio che si occupa di gestire la persistenza e le operazioni base di ricerca di informazioni anche molto complesse, non strutturate e, soprattutto, diverse tra loro.

Si pensi al caso di content repository che deve occuparsi della gestione dei video, delle recensioni e dei commenti degli utenti: si tratta di informazioni diverse tra di loro per la diversa natura, alcune testuali, altre binarie.

La flessibilità della soluzione incontrata consiste nel vedere le informazioni come nodi o proprietà, un po' come accade per un documento XML. Un nodo è un oggetto, di natura indefinita, ed una proprietà è un informazione concreta: un testo, una immagine, una formula matematica, etc.

Figura 2. Le informazioni rappresentate come nodi di un albero
Le informazioni rappresentate come nodi di un albero

Come vediamo in figura, la radice ha tre oggetti, a, b e c. A loro volta questi oggetti contengono altri oggetti fino ad arrivare alle informazioni (foglie). Attraverso questa semplice astrazione si può pensare di immagazzinare informazioni strutturate, senza una struttura fissata a priori (tipico problema dei database relazionali).

L'implementazione a basso livello è affidata al motore di persistenza e alla logica del prodotto. Non investigheremo su questo punto in quanto si tratta di soluzioni ad hoc.

Come dicevamo prima, Apache Jackrabbit è l'implementazione di riferimento della JCR. Altri prodotti molto noti sul mercato sono Vignette e citiamo anche Alfresco che si basa su una soluzione di content repository proprietaria integrata nella sua soluzione: anche Alfresco è un prodotto open source.

Un esempio concreto

Passiamo all'implementazione di un content repository con un esempio concreto, basato su Apache Jackrabbit. Per il download e l'installazione del servizio ci riferiamo al sito di riferimento.

Ciò che faremo è creare una API per la manipolazione di articoli Web di programmazione Java. Per non rendere l'esempio eccessivamente tedioso, immaginiamo che un articolo si componga di titolo, descrizione e complessità (dove complessità è un valore numerico da 1 a 5 che definisce quanto sia tecnica la lettura).

Bene, come abbiamo imparato in altri articoli, l'ideale applicare il pattern DAO/DTO: l'implementazione concreta del DAO si occuperà delle logiche di accesso al content repository.

Iniziamo a sviluppare la classe DTO:

package it.html.jcr;
/**
 * @author Pasquale Congiustì
 *
 * Un semplice Data Transfer Object per un articolo
 */
public class ArticoloDTO
{
  private String titolo;
  private String descrizione;
  private int complessita;
  public String getTitolo() { return titolo; }
  public void setTitolo(String titolo) { this.titolo = titolo; }  
  public String getDescrizione() { return descrizione; }
  public void setDescrizione(String descrizione) { this.descrizione = descrizione; }
  public int getComplessita() { return complessita; }
  public void setComplessita(int complessita) { this.complessita = complessita; }
}

Si tratta di un semplice Java Bean che sicuramente riutilizzeremo anche nella logica di rappresentazione come contenitore di informazioni da visualizzare all'utente finale.

Seguiamo definendo i metodi dell'interfaccia DAO:

package it.html.jcr;
import java.util.Collection;
/**
 * @author Pasquale Congiustì
 *
 * Metodi per la lettura/scrittura dell'articolo dal content repository
 */
public interface ArticoloManagerDAO
{
  public void insert(ArticoloDTO articolo);
  public void update(ArticoloDTO articolo);
  public void remove(ArticoloDTO articolo);
  public Collection getAll();
  public ArticoloDTO load(String titolo);
}

Visto lo scopo didattico tralasciamo la gestione di possibili eccezioni. Non ci resta che creare un'implementazione concreta della suddetta interfaccia. Prima di farlo, però, ci dobbiamo preoccupare di avere una maniera per connetterci al servizio Jackrabbit. Per questo creiamo una classe con un metodo statico che utilizzeremo al momento di connetterci.

package it.html.jcr.connection;
/**
 * @author Pasquale Congiustì
 *
 * Una semplice classe per connetterci con il JCR
 */
public class JCRConnection
{
  // User name and password
  private static final String USERNAME = "USER";
  private static final String PASSWORD = "PASS";
  // directory dove fisicamente verranno salvati gli articoli
  private static final String ARTICLE_DIR = "c:/temp/articoli";
  private static Session session;
  //Singleton
  public static Session getSession()
  {
    if (session== null)
    {
      // Setting del repository fisico
      System.setProperty("org.apache.jackrabbit.repository.home",JCRConnection.ARTICLE_DIR);
      Repository repository = new TransientRepository();
      // Connessione
      session = repository.login(
                  new SimpleCredentials(JCRConnection.USERNAME,
                  JCRConnection.PASSWORD.toCharArray()));
    }
    return session;
  }
}

Anche qui non ci siamo occupati di eccezioni ed abbiamo affidato a delle costanti la configurazione del Jackrabbit.

L'idea, per semplicità è che la persistenza sia affidata al disco.

public class ArticoloManagerDAOConcrete implements ArticoloManagerDAO
{
  public void insert(ArticoloDTO articolo)
  {
    // Si connette JCR
    Session session = JCRConnection.getSession();
    // Accede al nodo root
    Node rootNode = session.getRootNode();
    // Crea un nuovo nodo, articolo
    Node articoloNode = rootNode.addNode("articolo");
    // Aggiunge le informazioni sull'articolo
    articoloNode.setProperty("titolo", articolo.getTitolo());
    articoloNode.setProperty("descrizione", articolo.getDescrizione());
    articoloNode.setProperty("complessita", articolo.getComplessita());
    // Aggiunge altre informazioni come la data di inserimento
    articoloNode.setProperty("dataCreazione", new java.util.Date());
    //Salva l'articolo
    session.save();
  }

Il metodo insert si commenta da solo e risulta di semplicissima comprensione. L'idea è creare il nodo ed aggiungervi delle proprietà. Ovviamente avremmo potuto navigare l'albero e cercare una posizione più opportuna (per esempio creare un nodo per ogni autore e aggiungere lì tutti gli articoli dello stesso).

Altro interessante metodo che vediamo assieme è la ricerca di oggetti dello stesso tipo:

public Collection getAll()
  {
    // Connessione al JCR
    Session session = JCRConnection.getSession();
    // Creazione della collection
    ArrayList articoli = new ArrayList();
    // Accesso al nodo root
    Node rootNode = session.getRootNode();
    // Creazione di un iteratore sui nodi figli del root
    NodeIterator blogEntryNodeIterator = rootNode.getNodes();
    // Ricerca ricorsiva sui nodi figli, in profondità
    while (blogEntryNodeIterator.hasNext())
    {
      Node articolo = blogEntryNodeIterator.nextNode();
      // Se siamo in presenza si un oggetto articolo
      if (articolo.getName().equals("articolo") == false) continue;
      // Estraiamo le informazioni associate
      String titolo = articolo.getProperty("titolo").getString();
      String descrizione = articolo.getProperty("descrizione").getString();
      // Si tratta di un oggetto complesso
      Value dataCreazione = (Value) articolo.getProperty("dataCreazione").getValue();
      int difficolta = blogEntry.getProperty("difficolta").getInt();
      // e creaiamo il DTO da restituire
      BlogEntryDTO articoloDTO = new BlogEntryDTO(titolo, descrizione,
      difficolta, dataCreazione.getDate());
      // aggiunge l'articolo alla lista da restituire
      articoli.add(articoloDTO);
    }
    return articoli;
  }

Anche qui, il commento nel codice lo rende auto esplicativo. Quello che abbiamo fatto è stato accedere al JCR e ricorsivamente cercare gli articoli da restituire.

Gli altri metodi seguono la stessa logica, li possiamo completare per esercizio. Una volta creata l'implementazione diventa automatico inserire questo DAO nel flusso di comunicazione di una applicazione web java in quanto si sostituisce al layer di persistenza (essendo un layer di persistenza).

Conclusioni

L'esempio che abbiamo visto è solo un'introduzione ad una tecnologia molto potente e ricca di funzionalità. Non ci siamo soffermati sulle potenzialità della ricerca e sull'efficiente gestione di contenuto binario ne di come poter connetterci dal nostro application server al content repository (per esempio tramite JCA).

L'utilizzo di un content repository rende possibile e più semplice l'organizzazione di documenti ed informazioni attraverso la definizione di una o più tassonomie, con la possibilità di rendere sicuro l'accesso alle informazioni e veloce, grazie a tecniche di indicizzazione che vanno aldilà dell'esempio che abbiamo sviluppato.

Ti consigliamo anche