Ejb 3 con SpringBeanAutowiringInterceptor
Integrare spring in un ejb 3 è possibile usando la classe SpringBeanAutowiringInterceptor. La documentazione di spring ne riporta un esempio sufficientemente esplicativo. Tuttavia se ad esempio il nostro ejb si trova in un ear con classloader condiviso (questo è il default su jboss 4.2 se non esplicitamente configurato nel jboss-app.xml come specificato nella documentazione di jboss), l’interceptor di spring potrebbe trovare nel classpath un file beanRefContext.xml di un’altra applicazione, con conseguenze inattese.
Per fare in modo che l’interceptor di spring trovi il file giusto, è necessario definire un file xml di configurazione di spring con un nome univoco all’interno dell’application server ed usare una classe custom che estenda l’interceptor di spring:
public class MySpringBeanAutowiringInterceptor
extends SpringBeanAutowiringInterceptor {
private static final String CONTEXT_FILE = "my-ejb-context.xml";
@Override
protected BeanFactory getBeanFactory(Object o) {
return SpringBeanFactoryManager.getBeanFactory();
}
private static class SpringBeanFactoryManager {
private static final SpringBeanFactoryManager instance =
new SpringBeanFactoryManager();
private final ClassPathXmlApplicationContext context;
private SpringBeanFactoryManager() {
// singleton
context = new ClassPathXmlApplicationContext(CONTEXT_FILE);
}
public static BeanFactory getBeanFactory() {
return instance.context.getBeanFactory();
}
}
}
In questo modo l’ApplicationContext configurato nel file my-ejb-context.xml verrà caricato una sola volta su ogni singolo nodo del cluster e sarà possibile iniettare i bean di spring nel nostro ejb 3 semplicemente usando l’annotazione @Autowired, come nell’esempio:
@Stateless
@Interceptors(MySpringBeanAutowiringInterceptor.class)
public class MyEjb {
@Autowired
// my spring component defined in my-ejb-context.xml
private MySpringBean mySpringBean;
}
Scrivi messaggi di log decenti, altrimenti Gesù piange
Vorrei proporre alcune considerazioni sulla apparentemente oscura arte dello scrivere messaggi di log. Dico apparentemente oscura perché si tratta di un argomento apparentemente banale ma che in realtà si rivela complesso. Trattandosi di osservazioni generali, queste andrebbero prese con una dose di buon senso e sotto stretta osservazione del proctologo di fiducia; ciò non toglie che con ogni probabilità troverai le seguenti note ragionevolmente utili poiché basate sull’esperienza personale (a.k.a. sangue versato sul campo).
Niente guerre di religione, altrimenti Feuerbach piange
Nel mondo java, log4j è considerato lo standard de facto quando si parla di framework di logging. Tuttavia, il mio consiglio è di usare un framework più moderno, come slf4j o logback. Logback è basato sull’api di slf4j ed è sufficiente dare un’occhiata agli esempi nella documentazione per essere produttivi nel giro di un quarto d’ora. Vorrei evitare di spiegare i vantaggi di questi framework rispetto (ad esempio) a log4j o java.util.logging perché credo l’argomento sia non solo abbondantemente trattato in letteratura ma anche facilmente foriero di guerre di religione. Le guerre di religione sono per definizione irrazionali nonché mortalmente tediose. Sei abbastanza intelligente da documentarti e decidere da solo.
Al di là di un eventuale framework e del linguaggio di programmazione usato, i messaggi di log sono essenziali sia in fase di test/debug che in fase di monitoring in produzione. Il log è spesso sottovalutato e trattato come una seccatura che va espletata più per dovere che per una reale necessità. Tuttavia, ti posso assicurare che non c’è nulla di peggio che essere chiamati a risolvere un problema urgente in produzione e trovarsi davanti ad un log incasinato. In particolare, nel momento in cui qualche migliaio di utenti è in procinto di spendere un mucchio di soldi sul sito del tuo cliente e l’applicazione è scritta da te e per qualche oscuro motivo la possibilità di tale ingente esborso dovesse essere negata agli utenti del suddetto sito, vorrai essere sicuro di avere la possibilità di capire velocemente cosa sta succedendo dietro le quinte. In casi simili, dire che a scrivere male nel log Gesù piange è al massimo un eufemismo neanche troppo colorito.
Garbage in, garbage out
Uno dei concetti elementari del software è quello di input/output. Conoscendo l’input e lo stato di tutte le variabili coinvolte nel processo di elaborazione, sai che puoi aspettarti un certo output. Se l’output non è coerente con le aspettative, vorrà dire che analizzando il contesto, l’input, il codice e lo stato delle variabili locali e globali coinvolte, dovresti riuscire a capire cosa non quadra. Non è necessario tracciare nel log ogni cambiamento di stato di ogni variabile, specie se la funzione o il metodo sono sufficientemente complessi.
Esempio di log inutile:
public BuyResponse buyItem(BuyRequest request) {
log.debug(" ----- buyItem ------ start -----");
// ...
log.debug(" ----- buyItem ------ stop -----");
return response;
}
Esempio di log più utile:
public BuyResponse buyItem(BuyRequest request) {
log.debug("buyItem(): request={}", request);
// ...
log.debug("buyItem(): request={}, response={}", new Object[]{request, response});
return response;
}
In questo modo posso controllare l’input e l’output del metodo. Ripetendo l’input anche all’uscita del metodo, sarà più facile correlare i messaggi in fase di analisi del log. Tuttavia non sempre è utile questo tipo di verbosità. Come al solito, il buon senso dovrebbe guidarti nella scelta. Ad ogni modo, input, output e cambiamenti di stato di variabili importanti andrebbero tracciati almeno a livello di debug.
Loggare a un certo livello
Tutti i framework di logging hanno un meccanismo di livelli per cui è possibile filtrare l’output in modo da ottenere solo i messaggi che davvero ci interessano. Spesso capita di fare copia e incolla di statement di log per cui un messaggio che dovrebbe essere a livello di errore invece finisce a livello di debug. Occhio al copia e incolla!
Formattazione coerente e senza fronzoli
Cerca di mantenere uno stile coerente e senza troppi fronzoli nei messaggi di log. Disattiva il “blocco maiuscole”, abbi pietà. Questo ti aiuterà nella fase di analisi ed eviterà che le tue applicazioni abbiano l’aspetto di una roba scritta da uno sbarbatello in visual basic.
Metti i messaggi in riga
Per quanto possibile, evita di introdurre caratteri di a capo nei messaggi di log. Quando userai grep per andare alla ricerca dei messaggi che ti interessano, è importante che ad una riga di output corrisponda un messaggio coerente. All’inizio, andare a capo sembra dare un aspetto migliore all’output ma col tempo ti renderai conto che avresti fatto meglio a non farlo.
Occhio al copia e incolla
Come già accennato, può capitare di fare copia e incolla di statement di log. Ogni volta che faccio copia e incolla, si accende una speciale lampadina nella mia testa che serve a ricordarmi: “controlla ciò che hai copiato almeno due volte perché sicuramente hai dimenticato di modificare qualcosa che avresti dovuto modificare”. Questo vale più in generale e non solo per i messaggi di log. Se avessi avuto un euro per ogni frammento di codice sbagliato (non escluso il mio) per via di un copia e incolla frettoloso, in questo momento sarei sulla spiaggia di un’isola tropicale a sorseggiare un cocktail attorniato da compiacenti signorine.
Eccezioni
Il log di un errore dovrebbe portarsi dietro l’istanza di eccezione catturata e, se possibile ed utile, un minimo di contesto. Spesso mi capita di vedere codice del tipo:
catch (ConnectionException e) {
log.error("Error: " + e);
}
Sarebbe decisamente meglio una cosa del genere:
catch (ConnectionException e) {
log.error("connection error: user=" + user, e);
}
In questo modo non perdo lo stack trace dell’eccezione scatenata e posso ricondurla ad una specifica istanza di utente.
Conosci il tuo framework
Altrettanto importante è conoscere i meccanismi di deployment e configurazione del framework che stai usando. Potrebbe tornarti utile ad esempio impostare un filtro specifico su un certo logger. Impara inoltre a conoscere i meccanismi di formattazione dei messaggi. Configurando opportunamente un formatter, i framework moderni permettono di tracciare ad esempio timestamp al millisecondo, nomi di classi e metodi e nome del thread. Il nome del thread è essenziale in un’applicazione concorrente per seguire il flusso di esecuzione del software. Non c’è nulla di più frustrante di dover analizzare un log in cui non è presente il nome del thread.
Apache hangs on digest secret generation
This solved the issue. However, I couldn’t recompile apache with the urandom use flag, so I went for the randomness gathering daemon solution. On a gentoo box:
# cat /proc/sys/kernel/random/entropy_avail
16
# emerge -av rng-tools
# rc-update add rngd default
# /etc/init.d/rngd start
# cat /proc/sys/kernel/random/entropy_avail
6854
How to extract a filesystem from a disk image
You need to backup an entire hard disk to a single file. Supposing your disk is at /dev/hda and the backup file is image-file, you’d do:
# cat /dev/hda > image-file
or
# dd if=/dev/hda of=image-file
The file backup you get will hold a copy of every single bit from the hard disk. This means that you also have a copy of the MBR in the first 512 bytes of the file.
Because of this, you can see the partition table on the backup file:
# sfdisk -l -uS image-file
Disk image-file: 0 cylinders, 0 heads, 0 sectors/track
Warning: The partition table looks like it was made
for C/H/S=*/255/32 (instead of 0/0/0).
For this listing I'll assume that geometry.
Units = sectors of 512 bytes, counting from 0
Device Boot Start End #sectors Id System
image-filep1 32 261119 261088 83 Linux
image-filep2 261120 4267679 4006560 82 Linux swap / Solaris
image-filep3 4267680 142253279 137985600 83 Linux
image-filep4 0 - 0 0 Empty
Now, suppose you want to extract partition number 3. You can see that it starts at block 4267680 and is 137985600 blocks long. This translates into:
# dd if=image-file of=partition3-file skip=4267680 count=137985600
Now, peeking into the contents of the partition is as easy as:
# mount -t ext3 -o loop partition3-file /mnt/hack
Basic transactions in Spring using TransactionProxyFactoryBean
UPDATE – Jan 21, 2009: I see that quite a few sites link to this notes. While they should still be valid, at the time of writing, the Spring documentation provides a beautiful, clear and in-depth explanation of transaction management, including the declarative approach which is described here. I strongly encourage you to read the Spring documentation for the most up-to-date details.
Scenario: you have a simple stand-alone java application which accesses a single database using spring DAOs and you want to make your application’s interface transaction aware.
Now, while there’s plenty of ways to achieve this, the fool-proof, working approach is to make use of Spring’s declarative transactions and the TransactionProxyFactoryBean.
Here is an example BeanFactory configuration file:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"
>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost/foobardb"/>
<property name="username" value="dbuser"/>
<property name="password" value="dbpass"/>
</bean>
<bean id="fooDao"
class="com.acme.backend.dao.FooDAOJdbc">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="fooBarServiceImpl"
class="com.acme.backend.FooBarServiceImpl"/>
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="foorBarService"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="txManager"/>
<property name="target" ref="fooBarServiceImpl"/>
<property name="transactionAttributes">
<props>
<prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
</beans>
Okay, this was a lot of configuration data but, don’t worry, we’ll get into each little bit, one at a time and, by the end of this article, you’ll have all figured out.
In the first part, you basically have a boilerplate xml declaration of the required schemas. Those are needed so that your xml editor knows how to do auto completion and so that, when the xml configuration file gets parsed, the parser knows what is syntactically and semantically correct and what’s not.
Then you have a datasource bean declaration:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost/foobardb"/>
<property name="username" value="dbuser"/>
<property name="password" value="dbpass"/>
</bean>
This simply declares a configuration object with the datasource properties, which are the usual driver class name, connection URL and login credentials to the database. If you look closely, you’ll see that I’m using a commons-dbcp BasicDataSource. This means two things:
- the connections you’re going to get from this datasource are going to be pooled by the commons-dbcp driver
- you’ll have to put the commons-dbcp and commons-pool jars in the classpath
The next piece is quite simple:
<bean id="fooDao"
class="com.acme.backend.dao.FooDAOJdbc">
<property name="dataSource" ref="dataSource"/>
</bean>
This declares a DAO, plugs in a jdbc implementation class for it and injects the datasource as a property of the DAO.
<bean id="fooBarServiceImpl"
class="com.acme.backend.FooBarServiceImpl"/>
This declares the service implementation. In other words, this is the bean that implements the interface to our application. It is here merely because we need to declare a placeholder we’ll use in the transactional proxy declaration later.
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
Here we have declared a transaction manager using Spring’s default DataSourceTransactionManager. Then, we inject the datasource property into the transaction manager bean so that it becomes aware of what it should operate upon.
<bean id="foorBarService"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="txManager"/>
<property name="target" ref="fooBarServiceImpl"/>
<property name="transactionAttributes">
<props>
<prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
This is a bit more complicated and needs some careful explanation. The bean we’re declaring here is a transaction proxy, a class provided by Spring which takes care of wrapping the service implementation with a transactional behavior.
The transaction proxy needs a few properties set. Let’s see what they are:
- a transaction manager (remember we had declared that earlier, hadn’t we?)
- a target class; this is the class that the proxy wraps and adds transactional behavior to
- the transaction attributes
The transaction attributes are a set of properties. They describe what the transactional behavior should be. In this very simple but effective example, we are declaring that all methods of our service interface beginning with the name get are to be considered read-only and that they support transaction propagation. The other methods are considered as write methods in terms of transaction behavior and they require transaction propagation.
Now you’re gonna ask me: “And all of this is for what?”. Well, what you achieve with this kind of configuration is a fully transactional service. That means, if something goes wrong within your service operation, all you have to do is throw an exception and the Spring framework (and your database) will take care of rolling back all work.
For a simple, standalone application, this is just great. With a few lines of xml configuration data, you’ve got a fully transactional service. Ain’t that great? If you think it’s not, then you must take a long walk with an Oracle architect.
Backing up a vmware virtual machine
I’ve learnt quite a number of new things today. One of these things is that an ISO9660 filesystem doesn’t allow files bigger than a couple of gigabytes. Another thing is that bzip2 kicks ass, even if it actually doesn’t implement the best compression algorithm available today (your milage may vary).
Another interesting thing is that the good old cdrtools package on Gentoo sucks. In my understanding that’s mainly because of licencing issues which came out during the software development. But, no worries, the new cdrkit ebuild has a modern cdrtools implementation with a compatible interface. That is, the good old mkisofs and cdrecord command lines you (and your GUIs) had learnt how to use are just the same. Different software, same interface. Great, uh? So, first of all, if you want the latest tools on a Gentoo box, you’ll need to:
# emerge -C cdrtools
# emerge -av cdrkit
Anyway, my job today was to backup on DVD-R media a large vmware virtual machine in order to regain free storage space on a server with serious shortage troubles. To begin with, we have a directory which holds the VM (virtual machine) files:
# du -sh my-very-cool-vm
21G my-very-cool-vm
Now, 21 gigabytes of data is a lot because this VM hosts a few extra virtual disks. But, if you’re lucky enough like me, some bzip2 goodness might help:
# tar cvf - my-very-cool-vm | \
bzip2 --compress --verbose --best --stdout > \
my-very-cool-vm.tar.bz2
# ls -lh my-very-cool-vm.tar.bz2
total 4.3G
-rw-r--r-- 1 root root 4.3G Mar 8 15:32 my-very-cool-vm.tar.bz2
Depending on your iron, the time between tar and ls might be enough for you to gain a few extra golds in World of Warcraft. Anyway, now that might actually fit on a DVD-R. But, since there’s a 2GBytes file size limit on ISO9660 filesystems, we still need to do a little something before we can fire up mkisofs. Our old unix friend split comes to the rescue:
# split -b 1024m -d my-very-cool-vm.tar.bz2 \
my-very-cool-vm.tar.bz2-part-
# rm my-very-cool-vm.tar.bz2
# ls -lh
total 4.3G
-rw-r--r-- 1 root root 1.0G Mar 8 16:04 my-very-cool-vm.tar.bz2-part-00
-rw-r--r-- 1 root root 1.0G Mar 8 16:05 my-very-cool-vm.tar.bz2-part-01
-rw-r--r-- 1 root root 1.0G Mar 8 16:05 my-very-cool-vm.tar.bz2-part-02
-rw-r--r-- 1 root root 1.0G Mar 8 16:06 my-very-cool-vm.tar.bz2-part-03
-rw-r--r-- 1 root root 295M Mar 8 16:06 my-very-cool-vm.tar.bz2-part-04
This is just perfect. Assuming the above files are in a directory called mydir, I can now run mkisofs like this:
# mkisofs -o dvd.iso -r mydir
This creates a file which holds the ISO9660 filesystem that we can later feed to cdrecord. My peculiar incantation for cdrecord is as follows:
cdrecord -v dev=/dev/hdc driver=mmc_mdvd -sao dvd.iso
Windows shares in /etc/fstab
Ok, this is pretty much an easy one, but I keep forgetting what the heck you need to specify in your /etc/fstab in order to mount an smb share (at least on a Linux system). Here is an handy example:
//host.lan/sharename /mnt/host/sharename smbfs defaults,rw,noauto,username=scott,password=tiger,uid=myuid,gid=mygid 0 0
All of the above needs to be on one line. Of course you need to replace a few things:
- host.lan
- hostname or ip address of the host you’re connecting to
- sharename
- the windows share name (pretty easy, uh?)
- /mnt/host/sharename
- a local directory where the share is to be mounted (this must exist before mounting so “mkdir -p” it)
- username
- the windows share username
- password
- the windows share password
- uid
- the user id the filesystem needs to be mounted as; this can be either numeric or symbolic and is usually your day-to-day user account
- gid
- the group id the filesystem needs to be mounted as; this can be either numeric or symbolic and is usually your day-to-day user account’s primary group
Once you’ve added that line into /etc/fstab, you can simply:
# mount /mnt/host/sharename
Struttin’ from the CLI
Suppose you want to write a shell script that calls every action in your struts-config.xml in order to, say, stress test every callable url in your application.
Assume you have the following struts-config.xml:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
<struts-config>
<action-mappings>
<action
path="/page1"
forward="/WEB-INF/page/page1.jsp"/>
<action
path="/page2"
forward="/WEB-INF/page/page2.jsp"/>
</action-mappings>
</struts-config>
The point here is that you want to extract the path attribute value for each action and complete it with a full blown URI. You could do that with a lot of grep and/or awk or you could just use xmlstarlet. So, go now, download a copy and install it, or fire up your favourite package manager (be it apt-get, synaptic, portage or whatever) and let it do the job for you.
Once you have xmlstarlet installed, just do:
$ xmlstarlet sel -t -m "/struts-config/action-mappings/action" \
-o http://localhost/ctx -v "@path" -o .do -n struts-config.xml
and you should get the following output:
http://localhost/ctx/page1.do
http://localhost/ctx/page2.do
This basically means that you can, for instance, use wget to grab all those URIs:
$ xmlstarlet sel -t \
-m "/struts-config/action-mappings/action" \
-o "wget http://localhost/ctx" \
-v "@path" \
-o .do -n \
struts-config.xml | sh
This will fire up wget for each action path in the struts-config.xml. Neat, uh?
Under the hood, xmlstarlet is simply using some xslt transformation on the xpath expressions given in the above template to do its work. So, in case you want to sharpen your xml tools, you’ll need to get a better understanding of xpath at least, since it has to be used in the select templates.
UNIX time to human readable
The current issue of the Gentoo Weekly Newsletter has a good clue on how to easily convert a date from the standard UNIX time format (which basically is a number which represents the number of seconds elapsed since January 1, 1970 at midnight, UTC) to a human readable form. The best solution is using date -d on Linux systems such as in:
$ date -d @1161911504
Fri Oct 27 03:11:44 CEST 2006
However, on BSD derived systems, such as Mac OS X (and maybe Solaris), date -d won’t work so you have to used instead:
$ date -r 1161911504
Fri Oct 27 03:11:44 CEST 2006
gpasswd and less +F
Before I knew about gpasswd, I used to add and remove users from groups using a combination of “usermod -G” and some cut and paste in the terminal window. I was even using sed to automate the command. That is now a thing of the past.
Most modern linux distributions have a gpasswd command (at least Gentoo and Ubuntu do have it). Adding a user to a group is as easy as:
# gpasswd -a username groupname
Removing is just a matter of changing the -a switch (add) into -d (delete):
# gpasswd -d username groupname
Another useful thing I discovered recently is the “follow mode” of less, which works like a tail -f. If you want to launch less in “follow mode”, you just have to add the +F switch, as in:
# less +F /var/log/messages
If you want, at any time, to scroll back through the backlog, you just have to interrupt the follow mode typing C-c (that is: control+c). Also, you don’t need to start less in follow mode to use the follow mode: you can just press F at any time within less to turn the follow mode on.