Mokabyte

Dal 1996, architetture, metodologie, sviluppo software

  • Argomenti
    • Programmazione & Linguaggi
      • Java
      • DataBase & elaborazione dei dati
      • Frameworks & Tools
      • Processi di sviluppo
    • Architetture dei sistemi
      • Sicurezza informatica
      • DevOps
    • Project Management
      • Organizzazione aziendale
      • HR
      • Soft skills
    • Lean/Agile
      • Scrum
      • Teoria della complessità
      • Apprendimento & Serious Gaming
    • Internet & Digital
      • Cultura & Società
      • Conferenze & Reportage
      • Marketing & eCommerce
    • Hardware & Tecnologia
      • Intelligenza artificiale
      • UX design & Grafica
  • Ultimo numero
  • Archivio
    • Archivio dal 2006 ad oggi
    • Il primo sito web – 1996-2005
  • Chi siamo
  • Ventennale
  • Libri
  • Contatti
Menu
  • Argomenti
    • Programmazione & Linguaggi
      • Java
      • DataBase & elaborazione dei dati
      • Frameworks & Tools
      • Processi di sviluppo
    • Architetture dei sistemi
      • Sicurezza informatica
      • DevOps
    • Project Management
      • Organizzazione aziendale
      • HR
      • Soft skills
    • Lean/Agile
      • Scrum
      • Teoria della complessità
      • Apprendimento & Serious Gaming
    • Internet & Digital
      • Cultura & Società
      • Conferenze & Reportage
      • Marketing & eCommerce
    • Hardware & Tecnologia
      • Intelligenza artificiale
      • UX design & Grafica
  • Ultimo numero
  • Archivio
    • Archivio dal 2006 ad oggi
    • Il primo sito web – 1996-2005
  • Chi siamo
  • Ventennale
  • Libri
  • Contatti
Cerca
Chiudi

Nel numero:

186 luglio
, anno 2013

Command Query Responsibility Segregation pattern

VII parte: Un esempio pratico

Guglielmo Iozzia

Guglielmo Iozzia

Guglielmo Iozzia si è Laureato nel 1999 in Ingegneria Elettronica (indirizzo Biomedico) presso l‘Università di Bologna. Ha progettato e realizzato un software diagnostico per la predizione dell‘andamento della pressione intracranica in pazienti in terapia intensiva neurochirurgica. Frequenta il mondo Java dall‘inizio del 2000. Dopo numerose esperienze presso un‘azienda di Bologna del settore IT (fino all‘aprile del 2006), e per qualche mese in una analoga società di Roma, ha scelto la libera professione, lavorando per RAI Net fino ai primi mesi del 2008. In seguito è diventato Senior IT Consultant per la FAO (Food and Agriculture Organization of the United Nations). In ambito FAO ha dedicato quasi tutto il 2012 al progetto GRMS (Global Resources Management System) in qualità di "Web Services and cross-environmental integration specialist". Da luglio 2013 si è trasferito a Dublino, dove ricopre il ruolo di SVT Automation Engineer per IBM Ireland.

MokaByte

Command Query Responsibility Segregation pattern

VII parte: Un esempio pratico

Guglielmo Iozzia

Guglielmo Iozzia

  • Questo articolo parla di: Architetture dei sistemi, Frameworks & Tools

Questo mese concludiamo la serie sul pattern architetturale Command Query Responsibility Segregation (CQRS) mostrando un esempio pratico in cui vengono applicati i concetti teorici del framework Axon illustrati nei precedenti articoli della serie.

Nei mesi scorsi siamo andati alla scoperta dei concetti base di CQRS e del framework Axon [1], implementazione Java di tale pattern. In quest’ultimo articolo della serie vedremo un esempio completo di applicazione basata sul framework in esame. Come accennato nelle conclusioni del precedente articolo, la release di riferimento stavolta sarà la 2.0.3 (ultima stabile) e non più la 1.4, con la quale avevamo cominciato. Per la migrazione di progetti che usano la release 1.4 alla release 2.0 si può consultare l’utile guida riportata al link [2]. Per una migliore comprensione del codice, si consiglia la lettura preliminare degli articoli precedenti di questa serie: la trattazione di quello corrente presuppone la conoscenza dei concetti base e dei blocchi logici di Axon.

Creazione del progetto

Per prima cosa creiamo un nuovo progetto Java in Eclipse. Quindi importiamo nel build path il core di Axon (la libreria axon-core-2.0.3.jar). Per semplicità, in questo esempio supporremo di avere un unico aggregate, ToDoItem (nel mondo reale il domain model ovviamente sarà più complesso, ma a scopo didattico è meglio semplificare per chiarire immediatamente i concetti). Aggiungiamo ad esso un unico attributo, id, di tipo String. Facciamo estendere a ToDoItem la classe   org.axonframework.eventsourcing.AbstractEventSourcedAggregateRoot, l’implementazione di base fornita da Axon per gli aggregate. Implementiamo quindi i metodi getIdentifier() e handle() di tale classe astratta. 

Il codice di ToDoItem

Il codice di ToDoItem al momento risulta quindi essere il seguente:

public class ToDoItem extends AbstractEventSourcedAggregateRoot {
private String id;
 
public ToDoItem() {
}
 
@Override
public Object getIdentifier() {
return id;
}
 
@Override
protected Iterable getChildEntities() {
// TODO Auto-generated method stub
return null;
}
 
@Override
protected void handle(DomainEventMessage arg0) {
if (eventMessage.getPayloadType().equals(ToDoItemCreatedEvent.class)) {
ToDoItemCreatedEvent event =
(ToDoItemCreatedEvent) eventMessage.getPayload();
this.id = event.getTodoId();
}
}
}

getIdentifier() restituisce semplicemente l’identificatore della classe ToDoItem. Nel metodo handle() mettiamo il codice necessario per l’Event specifico. Prima di completare l’implementazione della classe dobbiamo implementare un Command ed un Event per ToDoItem. Chiamiamo il Command CreateToDoItemCommand: esso è relativo alla creazione di un nuovo ToDoItem:

public class CreateToDoItemCommand {

@TargetAggregateIdentifier
private final String todoId;
private final String description;

public CreateToDoItemCommand(String todoId, String description) {
this.todoId = todoId;
this.description = description;
}

public String getTodoId() {
return todoId;
}

public String getDescription() {
return description;
}
}

L’annotation @TargetAggregateIdentifier serve ad indicare qual’è l’attributo target del Command. L’implementazione dell’Event generato dall’esecuzione di tale Command è:

public class ToDoItemCreatedEvent {

private final String todoId;
private final String description;

public ToDoItemCreatedEvent(String todoId, String description) {
this.todoId = todoId;
this.description = description;
}

public String getTodoId() {
return todoId;
}

public String getDescription() {
return description;
}

@Override
public String toString() {
return "ToDoItemCreatedEvent(" + todoId + ", ‘" + description + "‘)";
}
}

Queste ultime due implementazioni sembrano simili. In realtà lo sono, ma solo perchè stiamo esaminando un contesto molto semplice avente un solo aggregate. Man mano che il domain model si complica, le implementazioni di un Command e dell’Event relativo differiscono sempre di più.

Completiamo ToDoItem

A questo punto possiamo completare la classe ToDoItem, partendo dalla creazione di un CommandHandler. A tale scopo aggiungiamo un nuovo costruttore annotato con @CommandHandler:

@CommandHandler
public ToDoItem(CreateToDoItemCommand command) {
apply(new ToDoItemCreatedEvent(command.getTodoId(),
command.getDescription()));
}

In questo modo abbiamo un CommandHandler per il command CreateToDoItemCommand. L’invocazione del metodo apply() della classe AbstractEventSourcedAggregateRoot  fa capire ad Axon che si vuole applicare l’evento ToDoItemCreateEvent all’aggregate. Infine bisogna annotare con l’annotazione @AggregateIdentifier l’attributo che funge da identificatore per l’aggregate:

@AggregateIdentifier
private String id;

e implementare (sempre tramite annotation) l’EventHandler per l’evento ToDoItemCreateEvent

@EventHandler
public void on(ToDoItemCreatedEvent event) {
this.id = event.getTodoId();
}

Esso imposta il valore dell’id dell’aggregate al momento della sua creazione.

Infrastruttura ed esecuzione

A questo punto non ci resta che costruire l’infrastruttura per poter eseguire l’applicazione. In questo paragrafo descriveremo come impostarla e configurarla senza fare rifermento ad alcun tipo di user interface: le considerazioni presentate sono indipendenti da essa: quindi valgono per qualsiasi tipo di applicazione (standalone da riga di comando, standalone con intefaccia grafica, web, etc.).

L’infrastruttura deve provvedere a fornire i seguenti blocchi:

  • Command Bus
  • Command Gateway
  • Event Sourcing Repository
  • Event Store
  • Event Bus

Il tutto può essere fatto in Java puro: 

// Init the Command Bus
CommandBus commandBus = new SimpleCommandBus();
// Init the CommandGateway: it provides a friendlier API
CommandGateway commandGateway = new DefaultCommandGateway(commandBus);
 
// Store Events on the FileSystem, in the "events/" folder
EventStore eventStore = new FileSystemEventStore(
    new SimpleEventFileResolver(new File("./events")));
 
// Init a Simple Event Bus
EventBus eventBus = new SimpleEventBus();
 
// Configure the Event Sourcing Repository
EventSourcingRepository repository =
  new EventSourcingRepository(ToDoItem.class);
repository.setEventStore(eventStore);
repository.setEventBus(eventBus);

// Tell Axon that our ToDoItem Aggregate can handle commands
AggregateAnnotationCommandHandler.subscribe(ToDoItem.class, repository, commandBus);
 
// Send some Commands on the CommandBus.
final String itemId = UUID.randomUUID().toString();
commandGateway.send(new CreateToDoItemCommand(itemId, "Need to do this"));
commandGateway.send(new MarkCompletedCommand(itemId));

Oltre alla soluzione Java puro, si può ricorrere anche a Spring [3]. In questo caso bisogna aggiungere al progetto anche le dipendenze di tale framework: Axon richiede la release 3.0.0 o successiva. Tutti i blocchi vengono definiti in un context file, chiamato, per esempio, axonContext.xml:

    xmlns_xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns_axon="http://www.axonframework.org/schema/core"
xsi_schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.axonframework.org/schema/core http://www.axonframework.org/schema/axon-core-2.0.xsd">
 


 
aggregate-type="org.axonframework.test.sample.ToDoItem"/>
 
aggregate-type="org.axonframework.test.sample.ToDoItem"
repository="toDoRepository"
command-bus="commandBus"/>
 

 



 

Il bootstrap

Infine bisogna implementare il bootstrap file, in questo modo:

private CommandGateway commandGateway;
 
public ToDoItemRunner(CommandGateway commandGateway) {
this.commandGateway = commandGateway;
}

public static void main(String[] args) {
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("axonContext.xml");
ToDoItemRunner runner =
new ToDoItemRunner(applicationContext.getBean(CommandGateway.class));
runner.run();
}

private void run() {
final String itemId = UUID.randomUUID().toString();
commandGateway.send(new CreateToDoItemCommand(itemId, "Need to do this"));
commandGateway.send(new MarkCompletedCommand(itemId));
}

Implementare l’Event Listener

Eseguendo lo startup dell’applicazione, il Command Handling è “up and running” e quindi non resta che implementare solo un Event Listener per poter fare operazioni in base agli eventi da esso prodotti:

public class ToDoEventHandler {
 
@EventHandler
public void handle(ToDoItemCreatedEvent event) {
System.out.println("We've got something to do: " +
event.getDescription() + " (" + event.getTodoId() + ")");
}  
}

L’annotation @EventHandler fa capire ad Axon che il metodo è un Event Handler. Il parametro in ingresso al metodo definisce il tipo di evento di cui è in ascolto. Il wire di tale Event Handler all’infrastruttura applicativa va fatto aggiungendo la seguente riga

AnnotationEventListenerAdapter.subscribe(new ToDoEventHandler(), eventBus);

nel codice di configurazione, prima che i comandi vengano inviati al gateway. Oppure, nel caso di applicazione Spring based, aggiungendo le seguenti due righe al context file:


La prima riga va aggiunta una sola volta, anche se si implementano e si registrano ulteriori Event Handlers.

Conclusioni

Il codice di esempio presentato in questo articolo è molto semplice, ma illustra tutti i passi necessari per implementare l’architettura di una applicazione Axon based. Infatti, a prescindere dalla complessità della business logic applicativa, la implementazione di nuovi Command, Event ed Event Listener è un processo puramente meccanico e ripetitivo.

Riferimenti

[1] Sito ufficiale di Axon framework

http://www.axonframework.org/

 

[2] Guida alla migrazione da Axon 1.4 ad Axon 2.0

http://www.axonframework.org/axon-2-migration-guide/

 

[3] Sito ufficiale di Spring framework

http://www.springsource.org/spring-framework

 

Facebook
Twitter
LinkedIn
Guglielmo Iozzia

Guglielmo Iozzia

Guglielmo Iozzia si è Laureato nel 1999 in Ingegneria Elettronica (indirizzo Biomedico) presso l‘Università di Bologna. Ha progettato e realizzato un software diagnostico per la predizione dell‘andamento della pressione intracranica in pazienti in terapia intensiva neurochirurgica. Frequenta il mondo Java dall‘inizio del 2000. Dopo numerose esperienze presso un‘azienda di Bologna del settore IT (fino all‘aprile del 2006), e per qualche mese in una analoga società di Roma, ha scelto la libera professione, lavorando per RAI Net fino ai primi mesi del 2008. In seguito è diventato Senior IT Consultant per la FAO (Food and Agriculture Organization of the United Nations). In ambito FAO ha dedicato quasi tutto il 2012 al progetto GRMS (Global Resources Management System) in qualità di "Web Services and cross-environmental integration specialist". Da luglio 2013 si è trasferito a Dublino, dove ricopre il ruolo di SVT Automation Engineer per IBM Ireland.

Guglielmo Iozzia

Guglielmo Iozzia

Guglielmo Iozzia si è Laureato nel 1999 in Ingegneria Elettronica (indirizzo Biomedico) presso l‘Università di Bologna. Ha progettato e realizzato un software diagnostico per la predizione dell‘andamento della pressione intracranica in pazienti in terapia intensiva neurochirurgica. Frequenta il mondo Java dall‘inizio del 2000. Dopo numerose esperienze presso un‘azienda di Bologna del settore IT (fino all‘aprile del 2006), e per qualche mese in una analoga società di Roma, ha scelto la libera professione, lavorando per RAI Net fino ai primi mesi del 2008. In seguito è diventato Senior IT Consultant per la FAO (Food and Agriculture Organization of the United Nations). In ambito FAO ha dedicato quasi tutto il 2012 al progetto GRMS (Global Resources Management System) in qualità di "Web Services and cross-environmental integration specialist". Da luglio 2013 si è trasferito a Dublino, dove ricopre il ruolo di SVT Automation Engineer per IBM Ireland.
Tutti gli articoli
Nello stesso numero
Loading...

Il teorema CAP… in Brewer

I parte: Il teorema CAP (Consistency, Availability, Partition tolerance)

Un’applicazione di realtà aumentata con GWT

IV parte: Utilizziamo NyARToolKit

Modularizzare Java con JBoss V parte: Esempi con OSGi

V parte: Esempi con OSGi

Agile Coach Camp 2013

Reportage da Trento

Agile Gamification: apprendere le metodologie giocando

IV parte: Agile. The board game reloaded

Aspetti psicologici nella gestione di progetto

VII parte: La gestione del tempo di lavoro

Nella stessa serie
Loading...

Command Query Responsibility Segregation pattern

VI parte: Event Processing in Axon framework

Command Query Responsibility Segregation pattern

V parte: Repositories ed Event Stores in Axon

Command Query Responsibility Segregation pattern

IV parte: Domain Modeling in Axon framework

Command Query Responsibility Segregation pattern

III parte: Introduzione ad Axon framework

Command Query Responsibility Segregation pattern

II parte: Quando utilizzarlo?

Command Query Responsibility Segregation pattern

I parte: Breve panoramica su CQRS

Mokabyte

MokaByte è una rivista online nata nel 1996, dedicata alla comunità degli sviluppatori java.
La rivista tratta di vari argomenti, tra cui architetture enterprise e integrazione, metodologie di sviluppo lean/agile e aspetti sociali e culturali del web.

Imola Informatica

MokaByte è un marchio registrato da:
Imola Informatica S.P.A.
Via Selice 66/a 40026 Imola (BO)
C.F. e Iscriz. Registro imprese BO 03351570373
P.I. 00614381200
Cap. Soc. euro 100.000,00 i.v.

Privacy | Cookie Policy

Contatti

Contattaci tramite la nostra pagina contatti, oppure scrivendo a redazione@mokabyte.it

Seguici sui social

Facebook Linkedin Rss
Imola Informatica
Mokabyte