Quartz Scheduler 2.x e JdbcJobStore con MySQL 5

maggio 29, 2012 Lascia un commento

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.

Categories: Uncategorized Etichette: , ,

Eclipse e sviluppo JSF: content assist

aprile 25, 2012 Lascia un commento

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.

Image

Categories: JSF Etichette: ,

Usare i profili e il filtering di Maven

marzo 27, 2012 Lascia un commento

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 

Categories: Maven

ActiveMQ e le virtual Topics

febbraio 6, 2012 Lascia un commento

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

Categories: ActiveMQ

EJBRemote standalone client

gennaio 5, 2012 Lascia un commento

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.

Categories: Glassfish, Java Etichette: , ,

ldap for dummies

settembre 28, 2011 Lascia un commento

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 protocolloleggero” 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
Categories: LDAP

Adding HttpOnly to RESTful response (Jee6)

Consider the following classes:

As you might see RESTful version lacks in HTTPOnly attribute (introduced with RFC 6265) because it only supports the first old RFC 2109. I don’t know which is the rational behind Jersey’s choice (latest version on RFC not implemented) but I need to solve the problem anyhow!

So, as “plain-old-jee-developer” :-D , the first solution I found was to write a servlet Filter and it worked great! Using new servlet 3.0 @WebFilter is not bad but…. googling around, I realized a more neat approach: injecting my own com.sun.jersey.spi.HeaderDelegateProvider implementation.

You only have to add a text file named

META-INF/services/com.sun.jersey.spi.HeaderDelegateProvider

containing the fully qualified name of your implementation. Your implementation must be  marked as Jersey @Provider.
Here my own implementation:

@Provider
public class NewCookie2HeaderDelegateProvider implements
HeaderDelegateProvider<NewCookie2> {

private NewCookieProvider newCookieProvider = null;

public NewCookie2HeaderDelegateProvider(){
super();
newCookieProvider = new NewCookieProvider();
}

@Override
public NewCookie2 fromString(String header) throws IllegalArgumentException {
if (header == null)
throw new IllegalArgumentException(“header must not be null!”);
return NewCookie2Parser.parseNewCookie2(header);
}

@Override
public String toString(NewCookie2 newCookie2) {
StringBuilder b = new StringBuilder();
b.append(newCookieProvider.toString(newCookie2));
if (newCookie2.isHttpOnly()){
b.append(“;HTTPOnly”);
}
return b.toString();
}

@Override
public boolean supports(Class<?> type) {
return type == NewCookie2.class;
}

where my “NewCookie2″ extends Jersey “NewCookie”:

public class NewCookie2 extends NewCookie {

private boolean httpOnly = false;

public NewCookie2(Cookie cookie) {
super(cookie);
}

}

and a new parser takes care ok HTTPOnly attribute also:

public class NewCookie2Parser {

private static class MutableNewCookie2 {
String name = null;
String value = null;
String path = null;
String domain = null;
int version = Cookie.DEFAULT_VERSION;
String comment = null;
int maxAge = NewCookie.DEFAULT_MAX_AGE;
boolean secure = false;
boolean httpOnly = false;

public MutableNewCookie2(String name, String value) {
this.name = name;
this.value = value;
}

public NewCookie2 getImmutableNewCookie2() {
return new NewCookie2(name, value, path, domain, version, comment, maxAge, secure, httpOnly);
}
}

public static NewCookie2 parseNewCookie2(String header) {
String bites[] = header.split(“[;,]“);

MutableNewCookie2 cookie = null;
for (String bite: bites) {
String crumbs[] = bite.split(“=”, 2);
String name = crumbs.length>0 ? crumbs[0].trim() : “”;
String value = crumbs.length>1 ? crumbs[1].trim() : “”;
if (value.startsWith(“\”") && value.endsWith(“\”") && value.length()>1)
value = value.substring(1,value.length()-1);

if (cookie == null)
cookie = new MutableNewCookie2(name, value);
else if (name.startsWith(“Comment”))
cookie.comment = value;
else if (name.startsWith(“Domain”))
cookie.domain = value;
else if (name.startsWith(“Max-Age”))
cookie.maxAge = Integer.parseInt(value);
else if (name.startsWith(“Path”))
cookie.path = value;
else if (name.startsWith(“Secure”))
cookie.secure = true;
else if (name.startsWith(“Version”))
cookie.version = Integer.parseInt(value);
else if (name.startsWith(“Domain”))
cookie.domain = value;
else if (name.startsWith(“HTTPOnly”))
cookie.httpOnly = true;
}

return cookie.getImmutableNewCookie2();
}
}

Obviously this is not meant to be a complete RFC 6265 implementation but it fits my needs.
As an example of a usage inside your own jersey resource, here is a snippet:

@POST
public javax.ws.rs.core.Response loginRedirect(@FormParam(“user”) String userName,
@FormParam(“password”) String password){
Response.ResponseBuilder responseBuilder = null;

//check username and password and if correct:

responseBuilder = addCookie(Response.created(uriOK).status(Status.MOVED_PERMANENTLY));

return responseBuilder.build();

}

where addCookie is:

protected static Response.ResponseBuilder addCookie(Response.ResponseBuilder responseToAddTo){
Cookie authCookie = new Cookie(“AUTH”, “134142134″, “/”, “.mydomain.it”);
NewCookie2 newCookie = new NewCookie2(authCookie, true);
responseToAddTo.cookie(newCookie);
CacheControl cc=new CacheControl();
cc.setMaxAge(7200);
responseToAddTo.cacheControl(cc);
return responseToAddTo;
}

Hope this helps.
Let me know!

Categories: Java Etichette: , , , ,
Iscriviti

Get every new post delivered to your Inbox.