Posts Tagged ‘Spring’

Streaming a stream

Friday, February 27th, 2009

I have another dirty trick for you. Let's imagine that you have a document server with following sophisticated interface.

public interface DocumentServer {
	/**
	 * Stores a document.
	 * @return document id
	 */
	public String storeDocument(InputStream in);

	/**
	 * Loads document with given id.
	 * @param id
	 * @return
	 */
	public InputStream loadDocument(String id);
}

It works well, until you realize, that you want to call the DocumentServer remotely, for example using Spring HttpInvoker.

HttpInvoker is a nice small tool, that lets you make remote method invocations over HTTP without much pain. It creates dynamic proxy, serializes all attributes using Java serialization, calls remote proxy, which deserializes arguments, calls the implementation and sends the result back in the same way. It is nice, simple and it works without any problem. You can configure it in five minutes. The downside is, that you have to have Spring Java application on both ends of the wire and all arguments that you send over the wire have to be Serializable.

And that's exactly the trouble we have with our DocumentServer. There is no standard InputStream implementation that implements serializable. Lets think about it. We need to have a stream that is able to stream itself into an ObjectOutputStream. Sounds strange, but it is quite easy. We can simply write a wrapper, that implements writeObject(ObjectOutputStream) method and that takes all the bytes from the underlying stream and writes them to the ObjectOutputStream. It is simple and it does not consume much memory.

Deserialization is much harder. We have to implement readObject(ObjectInputStream in) method, load the data and store them somewhere for later use. We can store them in the memory or in a temporary file. If the streams are larger, temporary file is better choice but we have to delete them after use and the implementation gets messy.

The good news is, that we do not have to implement it, it's already done by RMIIO library. They provide SerializableInputStream class that does exactly what we need. You just have to ignore Javadoc comment saying:

An additional layer around a RemoteInputStream which makes it Serializable and an InputStream. In general, this extra layer is not necessary and I do not recommend using this class. However, in the odd case where the callee really wants to get something which is already an InputStream, this class can be useful.

The only thing we have to do is to wrap all the streams into SerializableInputStream like this

new SerializableInputStream(new DirectRemoteInputStream(inputStream));

It can be done by hand written proxy, by dynamically generated proxy or by AOP.

Of course there are other alternatives. The easiest one is to create something like ByteArayInputStream that implements Serializable. If the streams are small enough, it's the best solution.

We can also try to use Hessian, but I had some troubles when method signatures were more complicated. And of course there is still a possibility to implement own remoting mechanism. After all, HTTP is meant to transport streams. But it would require lot of boilerplate code and I do not like boilerplate code.

Spring managed Hibernate interceptor in JPA

Saturday, January 24th, 2009

I have been trying to teach Hibernate injecting dependencies into Entities (I know, there is magic @Configurable annotation, I wanted to try it without magic). It is quite easy to do it using Hibernate interceptor (for example like this). But there is one drawback. It is not straightforward to inject interceptor into Hibernate when JPA abstraction is in the way.

It is simple to define interceptor in persistence.xml using hibernate.ejb.interceptor property. But it is only possible to specify class name, you can not inject Spring bean. If you read documentation to Spring LocalContainerEntityManagerFactoryBean there is no possibility to specify the interceptor bean there neither. But there is a way how to achieve it. First of all, you have to redefine Hibernate PersistenceProvider.

public class ConfigurableHibernatePersistence extends HibernatePersistence {
	private Interceptor interceptor;
	public Interceptor getInterceptor() {
		return interceptor;
	}

	public void setInterceptor(Interceptor interceptor) {
		this.interceptor = interceptor;
	}

	@SuppressWarnings("unchecked")
	@Override
	public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info, Map map) {
		Ejb3Configuration cfg = new Ejb3Configuration();
		Ejb3Configuration configured = cfg.configure( info, map );
		postprocessConfiguration(info, map, configured);
		return configured != null ? configured.buildEntityManagerFactory() : null;
	}

	@SuppressWarnings("unchecked")
	protected void postprocessConfiguration(PersistenceUnitInfo info, Map map, Ejb3Configuration configured) {
		if (this.interceptor != null)
		{
			if (configured.getInterceptor()==null || EmptyInterceptor.class.equals(configured.getInterceptor().getClass()))
			{
				configured.setInterceptor(this.interceptor);
			}
			else
			{
				throw new IllegalStateException("Hibernate interceptor already set in persistence.xml ("+configured.getInterceptor()+")");
			}
		}
	}
}

(source)

Here we override method createContainerEntityManagerFactory in order to add postprocessConfiguration method call. In this method, it is possible to change Hibernate configuration as needed. Now the only thing to be done is configuring Spring to use our new PersistenceProvider. It is quite simple.

	<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="persistenceUnitName" value="testPU" />
		<property name="dataSource" ref="dataSource" />
		<property name="persistenceProvider">
			<bean class="net.krecan.javacrumbs.jpa.interceptor.ConfigurableHibernatePersistence">
				<property name="interceptor">
					<bean class="net.krecan.javacrumbs.jpa.interceptor.SpringInjectingInterceptor"/>
				</property>
			</bean>
		</property>
	</bean>

And that all folks, we have Spring configured interceptor even when using JPA abstraction. It would be better if similar classes were in Spring or Hibernate, but it's just few lines of code so feel free to copy them if you need to. If you know easier way how to do it, please mention it in the comments below.

Skrytý drahokam Springu

Thursday, January 22nd, 2009

Dnes jsem koukal na rozhovor s Rodem Johnsonem, v kterém mluvil o novinkách ve Springu 3.0. Mezi řečí se zmínil o anotaci @Configurable, která je už ve Springu 2.5 a označil ji za skrytý drahokam. Protože jsem o něčem takovém slyšel poprvé, tak jsem se podíval do dokumentace a docela mě to zaujalo. (Teda, teď koukám, že jsem se o něčem podobném zmiňoval už před půl rokem zde, ach ta paměť). V zásadě jde o to, že obvykle funguje dependency injection jen u bean, které spravuje Spring. Takže například nejde použít u JPA entit a podobně. Což je docela škoda, protože pak musíme dělat umělou servisní vrstvu a objektový model tím docela trpí. Máme na jednu stranu třídy, které drží stav (entity) a na druhou stranu servisní třídy, v kterých je jen kód a stavu mají pomálu. Ale ve správném objektovém programování bychom měli mít třídy, které kombinují oboje. Takže například objekt User by měl mít metodu remove(), která by ho smazala z databáze. Jenže to by znamenalo, že by každá instance této třídy musela mít v sobě odkaz na EntityManager nebo ještě lépe DAO, což neumíme injektnout.

Možná si říkáte, že jsem se zbláznil, že to je ošklivé. Musím se přiznat, že mi je tento přístup taky cizí, ale asi je to jen otázka zvyku. Nejspíš jsem jen zvyklý na to procedurální programování, kde mám servisní procedury v singletonu a jim předhazuji hloupé datové objekty, které se o sebe neumějí postarat samy.

Anotace @Configurable je tu právě od toho, aby nám usnadnila injektování i do bean, které nejsou spravovány Springem. Předvedu na příkladu. Mám třídu Bean, které se dá podstrčit nějaký text.

@Configurable
public class Bean {
	private String text;
	public String getText() {
		return text;
	}
	public void setText(String text) {
		this.text = text;
	}
}

Mým cílem je zprovoznit tento test.

	public void testIt()
	{
		Bean bean = new Bean();
		assertEquals("Hallo",bean.getText());
	}

Všimněte si, že vytvářím novou instanci a koukám se, co je v ní nastaveno za text. Podle všeho by tam mělo být null. Ale pokud správně poladím Spring, tak tam může být cokoliv.

Prvním krokem je samozřejmě anotace @Configurable, která označí beanu jako kandidáta na injektování. V druhém kroku musím nastavit, co chci injektnout. Mohu například zvolit klasickou XML konfiguraci.

	<bean class="net.krecan.configurable.Bean" scope="prototype">
		<property name="text" value="Hallo"/>
	</bean>

	<context:spring-configured/>

	<context:load-time-weaver/

Zde si všimněme několika věcí. Například toho, že Spring pozná to kam má co injektnout automaticky, podle jména třídy. Nicméně dají se použít i vlastní jména. Pak si všimněme použití rozsahu „protoype“. To dává smysl, já mohu new zavolat kolikrát chci (i když tam to protoype nedáte, tak se to chová stejně, takhle je to jen hezčí). No a pak už nám zbývá jen magie. Pomocí prvního kouzelného slůvka <context:spring-configured/> zařídíme, aby se použil AspectJ aspekt, který to všechno zařídí. Ano, musí se použít AspectJ, zázraky ani Spring nedovede. Zatím.

Druhé kouzelné slůvko <context:load-time-weaver/> nastaví AspectJ, tak aby si podle potřeby při startu aplikace upravil třídy. Aby to totiž všechno fungovalo, tak je potřeba upravit bytecode. A to buď při kompilaci nebo při startu aplikace. Já jsem zvolil druhou variantu, která bohužel také vyžaduje, abyste to celé spouštěli s atributem virtuálního stroje -javaagent:spring-agent-2.5.6.jar. Pokud si kód budete zkoušet sami, tak na to prosím nezapomeňte.

A to je vše, testy projdou bez problému. Vidíme, že Spring umí injektovat i do tříd, nad kterými na první pohled nemá kontrolu. A to aniž bychom nějak zvlášť museli študovat AspectJ. Všechno už máme pěkně připraveno. Samozřejmě, uvedený příklad je umělý, ale pokud bychom našli dost odvahy, tak můžeme bez problémů injektnout EntityManager přímo do entit. A to může být docela užitečné.

Zdrojový kód je ke stažení zde, obzvláště doporučuji extra zvrhlou třídu MagicBean. No a pokud chcete umět Spring tak skvěle jako já, tak se mi ozvěte, můžu vás to naučit :-) .