Quartz Scheduler 2.x e JdbcJobStore con MySQL 5
Quando si configura Quartz e’ possibile scegliere fra diversi meccanismi di persistenza per le entity dello scheduler (triggers, calendars, jobs, etc…).
Nel caso in cui si voglia utilizzare un database relazionale come meccanismo di persistenza (implementato dalle classi org.quartz.impl.jdbcjobstore.JobStoreTX e org.quartz.impl.jdbcjobstore.JobStoreCMT) e’ necessario creare il database e le relative tabelle.
Lo script SQL in versione ‘innodb’ (tables_mysql_innodb.sql) per la creazione delle tabelle per MySQL fornite con la distribuzione di Quartz 2.1 non e’ compatibile con la release 5 di MySQL (almeno dalla 5.1 in su) in quanto contiene una keyword deprecata con MySQL 4.1 ed in seguito rimossa: TYPE.
Tale keyword e’ stata sostituita con ‘ENGINE’.
Se quindi si desidera utilizzare InnoDB come engine di MySQL per la persistenza dei dati di Quartz, e’ necessario modificare lo script, o, se stiamo utilizzando MySQL 5.5 o superiore, utilizzare lo script di default (tables_mysql.sql), nel quale non viene specificato l’engine: infatti da questa versione del database l’engine di default non e’ piu’ MyISAM ma InnoDB.
Eclipse e sviluppo JSF: content assist
A meno che non si voglia rinnegare un decennio di sviluppo intelligente con Eclipse e tornare a vi (e che sia vi, non vim!) e’ assolutamente indispensabile che l’IDE autocompleti i bean e le property dei bean mentre scrivo le mie belle pagine JSF (rigorosamente con PrimeFaces).
Ma, Eclipse, questo, ‘out of the box’, non lo fa.
Una buona idea sarebbe prendersi una bella vacanza e partire per la California per un paio di mesi; al ritorno si puo’ passare a Eclipse 4.2 (che, in questo momento, e’ previsto per fine giugno) e godersi finalmente la nuova e fiammante feature ‘code assist sulle pagine JSF’.
Per chi come me, invece, non ha molti giorni di ferie da spendere, l’alternativa momentanea e’ provare subito ad utilizzare la milestone 6 di Eclipse 4.2, aka Juno, e verificare, con immensa soddisfazione, che funziona proprio bene.
Usare i profili e il filtering di Maven
In questo tutorial spiegherò come customizzare il build di Maven con configurazione specifiche dell’ambiente di destinazione.
Questo è reso semplice grazie all’uso dei profili e del filtering di Maven.
Per prima cosa, aggiungiamo i profili e la proprietà ‘env’* al pom.xml:
<properties> <env>local</env> </properties> <profiles> <profile> <!-- per lo sviluppo in locale --> <id>local</id> <!-- lasciare vuoto: è il profilo di default! --> </profile> <profile> <!-- per il continuous integration server --> <id>ci-server</id> <properties> <env>ci-server</env> </properties> </profile> <profile> <!-- per il server di collaudo --> <id>collaudo</id> <properties> <env>collaudo</env> </properties> </profile> </profiles>
* L’uso del proprietà ${env} è del tutto una scelta personale.;
Abilitiamo il filtering sulla directory delle risorse o/e sulla dir delle risorse di test.
<resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> </resource> </resources> ..... <testResources> <testResource> <directory>src/test/resources</directory> <filtering>true</filtering> </testResource> </testResources>
Aggiungiamo il path del file di properties del filtro.
<project ...
<build>
<filters>
<filter>src/test/filters/filter-${env}.properties</filter>
</filters>
...
Creiamo i file di properties per i nostri ambienti:
src/test/filters/filter-local.properties
jdbc.pool=local_database ...
src/test/filters/filter-ci-server.properties
jdbc.pool=ci-server_database ...
src/test/filters/filter-collaudo.properties
jdbc.pool=collaudo_database ...
Apriamo la definizione dei connection-pool e sostituiamo il pool-name con la chiave ${jdbc.pool}
<resources>
<jdbc-resource jndi-name="jdbc/test-ds" pool-name="${jdbc.pool}" />
<jdbc-connection-pool name="local_database"
datasource-classname="org.apache.derby.jdbc.EmbeddedDataSource"
res-type="javax.sql.DataSource" ping="true">
<property name="DatabaseName" value="memory:testdb"/>
<property name="ConnectionAttributes" value="create=true" />
<property name="DatabaseName" value="memory_derby" />
<property name="Password" value="" />
<property name="User" value="" />
</jdbc-connection-pool>
<jdbc-connection-pool name="ci-server_database"
is-isolation-level-guaranteed="false"
datasource-classname="org.apache.derby.jdbc.ClientDataSource"
res-type="javax.sql.DataSource">
<property name="PortNumber" value="1527"></property>
<property name="Password" value=""></property>
<property name="User" value=""></property>
<property name="serverName" value="localhost"></property>
<property name="DatabaseName" value="sun-appserv-samples"></property>
<property name="connectionAttributes" value=";create=true"></property>
</jdbc-connection-pool>
<jdbc-connection-pool name="collaudo_database"
datasource-classname="org.postgresql.ds.PGConnectionPoolDataSource"
res-type="javax.sql.ConnectionPoolDataSource" description="javax.sql.XADataSource javax.sql.ConnectionPoolDataSource">
<property name="User" value=""></property>
<property name="DatabaseName" value="coll-db"></property>
<property name="Password" value=""></property>
<property name="ServerName" value="localhost"></property>
<property name="PortNumber" value="5432"></property>
</jdbc-connection-pool>
</resources>
Non resta che buildare, abilitando il profilo
mvn groupId:artifactId:goal -P local
Risorse:
- A Maven2 multi-environment filter setup
- Maven Profile Best Practices
- Maven Filtering
- Introduction to Build Profiles
ActiveMQ e le virtual Topics
Le virtual Topics sono destinazioni logiche mappate su una o più destinzioni fisiche.
Utilizzando una virtual Topic, il producer invia una topic, utilizzando la semantica standard del specifiche JMS per le Topic, e i consumers consumeranno da una physical queue .
L’utilizzo delle Virtual Topic è di default abilitato in ActiveMQ, per poter utilizzare questa feature basta seguire una naming convention:
- la Topic del producer deve avere il prefisso VirtualTopic.<nometopic>
- le Queue dei consumers devono essere denominate Consumer.<nomequeue>.VirtualTopic.<nometopic>
(In ogni caso la naming convention può essere personalizzata.)
I vantaggi dell’uso delle Virtual Topics di ActiveMQ sono:
- failover of the subscriber if that one process running that one consumer thread dies;
- load balancing of messages.
oltre agli stessi vantaggi dell’uso delle durable topics:
- one producer, more consumers
- producers/consumers decoupling
- PERSISTENT delivery mode
- route messages to target destinations based on message headers
E.g.,
abbiamo una topic chiamata VirtualTopic.User.delete, questo messaggio dovrà essere recapitato al sistema blog,forum e chat.
Quindi definiremo una queue per ogni sistema:
- Consumer.Blog.VirtualTopic.User.delete
- Consumer.Forum.VirtualTopic.User.delete
- Consumer.Chat.VirtualTopic.User.delete
EJBRemote standalone client
Ho bisogno di scrivere una piccola classe di test, senza troppe complicazioni, che verifichi il corretto funzionamento di una facade esposta come remote EJB da Glassfish 3.
La strada piu’ veloce e’ quella di creare una classe Java, fare una lookup sull’albero JNDI, ottenere il riferimento all’EJB remote e chiamare il metodo di business.
Quando il servizio remoto e’ esposto dalla stessa macchina sulla quale viene eseguito il client, per ottenere il riferimento e chiamare l’EJB bastano poche righe di codice:
final String globalJndiName = “java:global/a2props-service-ear/a2props-service-ejb/UserProfileCrudServiceBean!it.xxx.yyy.a2.profile.services.user.UserProfileCrudServiceRemote”;
// get ejb remote reference
final javax.naming.InitialContext context = new javax.naming.InitialContext();
final UserProfileCrudServiceRemote service = (UserProfileCrudServiceRemote) context.lookup(globalJndiName);// call ejb business method
final UserProfile userProfile = new UserProfile(“diuis”);
service.create(userProfile);
Nel momento in cui ho invece la necessita’ di eseguire il client da una macchina differente, mi basta utilizzare il costruttore della classe InitialContext che accetta in input un’istanza di java.util.Properties (anche se dovrei dire java.util.Hashtable…) per poter settare l’hostname e la porta dell’ORB listener.
final String globalJndiName = “java:global/a2props-service-ear/a2props-service-ejb/UserProfileCrudServiceBean!it.xxx.yyy.a2.profile.services.user.UserProfileCrudServiceRemote”;
// get ejb remote reference
final Properties properties = new Properties();
properties.setProperty(“org.omg.CORBA.ORBInitialHost”,”codesharing.wordpress.com”);
properties.setProperty(“org.omg.CORBA.ORBInitialPort”, “4837″);
final InitialContext context = new InitialContext(properties);
final UserProfileCrudServiceRemote service = (UserProfileCrudServiceRemote) context.lookup(globalJndiName);// call ejb business method
final UserProfile userProfile = new UserProfile(“diuis”);
service.create(userProfile);
Per eseguire correttamente la chiamata all’EJB e’ necessario aggiungere al classpath del client standalone uno dei JAR forniti da Glassfish, ovvero gf-client.jar, che potete trovare nella lib dell’application server; infatti, nel caso in cui non venga trovato il JAR nel classpath, verra’ lanciata una bellissima java.lang.RuntimeException (Orb initialization erorr).
Buon test a tutti.
ldap for dummies
Chiunque sviluppa software ad un certo punto della propria carriera professionale non può far a meno di “inciampare” nella sigla LDAP. Oppure ha dovuto iniziare ad usarlo.
Ad ogni modo, ti tocca approfondire e magari fai come me: apri il tuo browser (firefox, chrome, ie, quel che è) e parti con una bella googlata su LDAP… et voila, primo della lista trovi LDAP di wikipedia.
Appassionante lettura certo… Comunque dopo una sventagliata di “semplici” acronimi e di riferimenti, wikipedia ti dice che lo hanno creato apposta perché lo standard X500 era troppo complicato, tutto sommato quindi LDAP è una cosa semplice.
Sarà. Ma a me non è che suoni molto familiare:
"cn=vincenzo d'amore,ou=developers,dc=google,dc=com"
Bisogna approfondire e così ho dovuto darmi da fare. Gira gira gira, leggi leggi leggi.
Poi ti guardi indietro e unisci tutti i puntini. Succede sempre così, ce lo insegnano i migliori (la citazione era dovuta :).
Bon, visto che per me è diventato tutto un po’ più semplice, ho pensato bene di scrivere queste poche righe a beneficio di chi ha desiderio capire (e si accontenta di quello che ho capito io).
Iniziamo quindi a sciogliere l’acronimo LDAP.
LDAP sta per Lightweight Directory Access Protocol, ovvero protocollo “leggero” per l’accesso alle directory.
Quindi:
- protocollo – Se siete degli informatici non sto a spiegarvi cos’è un protocollo, altrimenti vi basti sapere che è un insieme di regole.
- leggero – Perché appunto il famoso X500 (a cui si è ispirato LDAP) era troppo complicato da usare.
- directory – Parola che nel linguaggio informatico in genere si riferisce ad un database particolarmente ottimizzato per le operazioni lettura. Partendo dal presupposto che le operazioni di inserimento e aggiornamento saranno piuttosto rare se comparate alle operazioni di lettura. Nello specifico dell’acronimo LDAP per directory si intendono i servizi di directory.
Le directory nascono per permettere alle persone di trovare la propria strada. Ad esempio, tutti siamo entrati in palazzo e abbiamo provato per qualche secondo quel senso di smarrimento e confusione prima di accorgerci che c’era un cartello con le indicazioni o l’elenco delle società. Ecco quel cartello con le indicazioni potrebbe essere considerato l’archetipo di una directory.
Un altro esempio di directory, forse più a buon mercato, potrebbe essere una rubrica telefonica. Per semplicità possiamo definire una rubrica come un insieme ordinato di persone. E per ogni persona ci sono anche informazioni di dettaglio: telefono, indirizzo, email, etc. Proprio come nell’altro caso ci spiega come trovare qualcuno o qualcosa.
A questo punto un servizio di directory è presto detto: è il software che ti permette di interrogare, sfogliare, aggiornare la rubrica.
Fatti questi doverosi approfondimenti, possiamo ritornare su LDAP.
LDAP ci permette di comunicare in modo corretto con un servizio di directory.
Esattamente come il protocollo HTTP permette al browser di comunicare con un server web.
Resta il fatto che una stringa come:
"cn=vincenzo d'amore,ou=developers,dc=google,dc=com"
rimane di difficile comprensione.
In estrema sintesi, questa stringa spiega nel protocollo LDAP dove trovare una persona. Quindi si legge “il signor Vincenzo D’Amore, del gruppo developers, del dominio google, com“. Il servizio di directory leggendo questa stringa sarà in grado di capire dove reperire le informazioni collegate.
L’acronimo cn sta per Common Name, ou indica l’Organization Unit e dc per Domain Component.
Bisogna ricordarsi che LDAP è nato ad un tempo in cui la leggibilità veniva messa in secondo piano rispetto alle performance e trasformare “Common Name” in cn faceva risparmiare un bel po’ di byte.
Per finire gli acronimi più comuni su LDAP descritti in dettaglio:
- uid – User id
- cn – Common Name
- sn – Surname
- l – Location
- ou – Organisational Unit
- o – Organisation
- dc – Domain Component
- st – State
- c – Country
