Archive for the ‘RS Library’ Category

Eclipse RCP Common Feature launched

Monday, August 11th, 2014

Good news for all Eclipse developers that want to use some of my projects in their own Eclipse/RCP projects. I bundled some modules and projects into a Luna Eclipse Feature Plug-In – called RCP Common Feature.

You will need the Update Site http://download.ralph-schuster.eu/rcp-updates/luna/releases/ to be added in your IDE and install the feature as you would do with every other Eclipse feature plug-in.

These are the modules and projects currently bundled:

Furthermore, there are three more plug-ins available specific to Eclipse/E4 UI and logging. The feature plug-in is released under LGPL V3 license (as all projects bundled in it).

 

Using Pooled Data Connections with RS Libs Data Hibernate Library

Thursday, July 3rd, 2014

The standard way of configuring a data source for RSLib’s Data Hibernate Library is to use the driver’s DataSource implementation as shown here:

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<dbconfig>
   <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
 
   <datasource class="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource">
      <property name="url">jdbc:mysql://db-host:3306/db-name</property>
      <property name="user">db-user</property>
      <property name="password">db-password</property>
   </datasource>
</dbconfig>

However, this setup will result in creating a new connection each time you start a new transaction. This is most likely not what you want in a productive application. Instead you shall use a pooled DataSource, as the c3p0 project provides:

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8"?>
<dbconfig>
   <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
 
   <datasource class="com.mchange.v2.c3p0.ComboPooledDataSource">
      <property name="driverClass">com.mysql.jdbc.Driver</property>
      <property name="jdbcUrl">jdbc:mysql://db-host:3306/db-name?autoReconnect=true</property>
      <property name="user">db-user</property>
      <property name="password">db-password</property>
   </datasource>
</dbconfig>

I stumbled across this problem while implementing a project and receiving a

java.net.SocketException: No buffer space available (maximum connections reached?): connect

exception.

Update July 26nd: You will need the autoReconnect=true parameter with MySQL to avoid problems with connections in the pools not being used for quite a long time.

Update August 18th: This URL parameter doesn’t work correctly. The solution is to add a c3p0.properties file in your classpath:

1
2
3
4
5
6
7
8
9
10
11
c3p0.maxPoolSize=50
c3p0.minPoolSize=5
c3p0.timeout=0
c3p0.maxStatements=0
c3p0.maxStatementsPerConnection=0
c3p0.idleConnectionTestPeriod=300
c3p0.acquireIncrement=1
c3p0.validate=true
c3p0.preferredTestQuery=SELECT 1;
c3p0.testConnectionOnCheckin=false
c3p0.testConnectionOnCheckout=true

(Don’t try to set these properties via your hibernate.cfg file. Some of them cannot be set there!)

RS Library V1.2.5 released

Thursday, May 8th, 2014

I released RS Library V1.2.5 which mainly contains fixes to issues found by static code analysis. A complete list of changes can be found here.

The Maven repositories shall be up-to-date by now. The Maven coordinates are:

   <dependency>
      <groupId>eu.ralph-schuster</groupId>
      <artifactId>baselib</artifactId>
      <version>1.2.5</version>
   </dependency>
 
   <dependency>
      <groupId>eu.ralph-schuster</groupId>
      <artifactId>data</artifactId>
      <version>1.2.5</version>
   </dependency>
 
   <dependency>
      <groupId>eu.ralph-schuster</groupId>
      <artifactId>data-file</artifactId>
      <version>1.2.5</version>
   </dependency>
 
   <dependency>
      <groupId>eu.ralph-schuster</groupId>
      <artifactId>data-hibernate</artifactId>
      <version>1.2.5</version>
   </dependency>
 
   <dependency>
      <groupId>eu.ralph-schuster</groupId>
      <artifactId>templating</artifactId>
      <version>1.2.5</version>
   </dependency>

Multiple Releases

Monday, March 10th, 2014

The last few days I released new versions of three of my projects.

All projects are available through Maven Central.

 

RS Library 1.2.2 released

Wednesday, December 11th, 2013

A new version of the RS Library was released. Version 1.2.2 fixes many bugs found by unit tests. The previous version just had 12 unit tests, the new version got 190 unit tests to ensure quality of the code. A complete list of changes can be found here.

The Maven repositories shall be up-to-date by now. The Maven coordinates are:

   <dependency>
      <groupid>eu.ralph-schuster</groupid>
      <artifactid>baselib</artifactid>
      <version>1.2.2</version>
   </dependency>
 
   <dependency>
      <groupid>eu.ralph-schuster</groupid>
      <artifactid>data</artifactid>
      <version>1.2.2</version>
   </dependency>
 
   <dependency>
      <groupid>eu.ralph-schuster</groupid>
      <artifactid>data-file</artifactid>
      <version>1.2.2</version>
   </dependency>
 
   <dependency>
      <groupid>eu.ralph-schuster</groupid>
      <artifactid>data-hibernate</artifactid>
      <version>1.2.2</version>
   </dependency>
 
   <dependency>
      <groupid>eu.ralph-schuster</groupid>
      <artifactid>templating</artifactid>
      <version>1.2.2</version>
   </dependency>

The Class.forName() problem

Monday, November 4th, 2013

In earlier Java days, it was easy to get a Class object when you had its name only. You simply called:

1
2
3
4
5
   // Without parametrized
   Class c = Class.forName("java.lang.String");
 
   // With parameters
   Class<String> = (Class<String>)Class.forName("java.lang.String");

This worked as long as there have been only one class loader. Long time ago :). The world kept spinning and concepts of separated applications in a single Java engine appeared. And so did OSGI. OSGI specified its container in a way that you can have a class being loaded in multiple versions at the same time. Furthermore, an OSGI bundle (effectively a JAR) can describe what other bundles can see their classes and what not. OSGI containers implement these behaviour through different ClassLoader instances responsible for the respective bundles.

However, this introduces a problem on Class.forName(String) calls. The method uses the ClassLoader of the “caller”. That means that it will be restricted to the bundle’s definition. As long as you use this method within bundle A to find a class in bundle A, everything works fine. It will even find a class in bundle B when B exported correctly and A defined B as a pre-requisite.

However, modular code encapsulates common functions. That’s why it can happen that a Class.forName(String) call is implemented in bundle C and doesn’t know about bundle A at all. When bundle A now calls bundle C which in turn calls Class.forName(String) to load a class from bundle A, then it fails. The reason is that ClassLoader C is not allowed to access classes in bundle A.

Several solutions are possible. The OSGI solution for this problem is the friend. You declare bundle C as friend of bundle A and class loading will succeed. However, this works only as long as you don’t try to load a class from bundle B. Now B would be required to declare C as a friend. If B is a 3rd party bundle then this solution is out of reach.

Another solution is the iteration on all OSGI bundles and trying to find the class via their class loaders. However, this is error-prone. Unless you don’t know exactly what bundle contains your required class you might get in trouble. Several versions of the same class can be present (or just define a class with the same name). You would need some heuristics to identify the correct class.

There is a better and most-likely the best solution. Each thread in Java can have a Context Class Loader. This will allow us to resolve all the dependency problems in OSGI. We will define the method in bundle C as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
	/**
	 * Load a class by first checking the thread's class loader and then the caller's class loader.
	 * @param className name of class to be loaded
	 * @return the class found
	 * @throws ClassNotFoundException when the class cannot be found
	 */
	public static Class<?> forName(String className) throws ClassNotFoundException {
		return forName(className, null);
	}
 
	/**
	 * Load a class by directly specifying a class loader.
	 * @param className name of class to be loaded
	 * @param classLoader the class loader to be used - if null the thread's class loader will be  used first
	 * @return the class found
	 * @throws ClassNotFoundException when the class cannot be found
	 */
	public static Class<?> forName(String className, ClassLoader classLoader) throws ClassNotFoundException {
		if (classLoader == null) try {
			// Check the thread's class loader
			classLoader = Thread.currentThread().getContextClassLoader();
			if (classLoader != null) {
				return Class.forName(className, true, classLoader);
			}
		} catch (ClassNotFoundException e) {
			// not found, use the class' loader
			classLoader = null;
		}
		if (classLoader != null) {
			return Class.forName(className, true, classLoader);
		}
		return Class.forName(className);
	}

The method will (if no specific class loader was given) first test the Context Class Loader (lines 21-24). Only if this fails or is (for whatever reasons) not available, then the original Class.forName(String) method will be asked (line 30).

As the Context Class Loader is defined in the beginning of the executing thread, it is usually the class loader of Bundle A which has access to all other dependent bundles. Therefore we will be able to load classes from bundle A and B with code written in bundle C.

1
2
3
4
5
6
7
8
   // Code in bundle C
   public Class<?> getClass(String name) {
      return BundleC.forName(name);
   }
 
   // Code in bundle A
   Class<?> c1 = BundleC.forName("bundleA.className");
   Class<?> c2 = BundleC.forName("bundleB.className");

I added the helper methods in my RS Base Classes Library class LangUtils where you can use it directly from (V1.2.2 – available very soon) in your OSGI projects.

The Importance of Unit Tests

Wednesday, October 23rd, 2013

I am not a close friend of unit tests. In fact, as a programmer I regard them as annoying. However, when I started to write unit tests for my RS Library classes, I discovered many bugs that I didn’t see before. Those bugs never occurred in production yet mainly because the code was used in a slightly different way and bypassed the buggy parts. Some of the bugs are very stupid so that I wondered how they could ever get into a release.

The experience shows me now that it is important to write unit tests for all classes and their non-trivial methods. This is the only way to write better code. The self-confidence that I have in my own code is not enough. So there will be a lot of unit testing effort within the next weeks. And the next RS library code is most-likely the best-tested code ever.

Nobody is perfect. 😉

RS Library 1.2.1 released

Wednesday, October 23rd, 2013

A major milestone of RS Library version 1.2 is out. I already discovered a critical bug in 1.2.0. That’s why the latest version is 1.2.1 now. The most important changes are:

However, I already discovered a minor bug in V1.2.1: RSLIBS-37 describes an incorrect behaviour of SoftMapCache.containsValue(Object) and WeakMapCache.containsValue(Object) methods which will be fixed in next version. V1.2.1 does not use this methods anywhere, so you would need to work-around this function in case you require it.

I also added more documentation now so you will be able to understand and use the libraries. It can be found either through Javadocs or the appropriate module homepages:

The Maven coordinates are:

   <dependency>
      <groupid>eu.ralph-schuster</groupid>
      <artifactid>baselib</artifactid>
      <version>1.2.1</version>
   </dependency>
 
   <dependency>
      <groupid>eu.ralph-schuster</groupid>
      <artifactid>data</artifactid>
      <version>1.2.1</version>
   </dependency>
 
   <dependency>
      <groupid>eu.ralph-schuster</groupid>
      <artifactid>data-file</artifactid>
      <version>1.2.1</version>
   </dependency>
 
   <dependency>
      <groupid>eu.ralph-schuster</groupid>
      <artifactid>data-hibernate</artifactid>
      <version>1.2.1</version>
   </dependency>
 
   <dependency>
      <groupid>eu.ralph-schuster</groupid>
      <artifactid>templating</artifactid>
      <version>1.2.1</version>
   </dependency>

RS Library V1.1.0 released

Monday, August 5th, 2013

I had to do some rework for the RS Library. The most important changes are:

  • RSLIB-19 – Improved DAO registration in abstract DaoFactory implementation
  • RSLIB-20 – Upgrade to Hibernate 4
  • RSLIB-22 – Provide modules as OSGI packages
  • RSLIB-23 – Cache Control for DAOs

A complete documentation can be found either through Javadocs or the appropriate module homepages:

The Maven coordinates are:

   <dependency>
      <groupid>eu.ralph-schuster</groupid>
      <artifactid>baselib</artifactid>
      <version>1.1.0</version>
   </dependency>
 
   <dependency>
      <groupid>eu.ralph-schuster</groupid>
      <artifactid>data</artifactid>
      <version>1.1.0</version>
   </dependency>
 
   <dependency>
      <groupid>eu.ralph-schuster</groupid>
      <artifactid>data-hibernate</artifactid>
      <version>1.1.0</version>
   </dependency>

Apache ServiceMix, Camel and XSL Transformation

Tuesday, July 9th, 2013

This topic cost me a few hours. It is basically how to achieve XML transformation when your original XML file contains a DTD reference that cannot be resolved from your system.

My DTD reference looked like this:

<!DOCTYPE root-element SYSTEM "../dtd/core.dtd">

and the route was simply:

	<camelContext xmlns="http://camel.apache.org/schema/spring">
		<route>
			<from uri="file:data/inbox"/>
			<to uri="xslt://xslt/transformation.xsl"/>
			<to uri="file:data/outbox"/>
		</route>
	</camelContext>

The Camel transformation was always complaining about the missing DTD because it was looking for it in the filesystem instead of the bundle.

There exist many hints on the net but none of them really helped (e.g. using a CatalogResolver). So I decided to tamper my Camel route and adding a bean inbetween:

	<bean id="dtdTransformer" class="de.example.xslt.DtdTransformer"/>
 
	<camelContext xmlns="http://camel.apache.org/schema/spring">
		<route>
			<from uri="file:data/inbox"/>
			<bean ref="dtdTransformer"/>
			<to uri="xslt://xslt/bundesliga.xsl"/>
			<to uri="file:data/outbox"/>
		</route>
	</camelContext>

This DtdTransformer is a simple class having one method, transform():

	public static final String DOCTYPE_LINE = "<!DOCTYPE root PUBLIC \"-//PRIVATE//RS//EN\" \"###URI###\">";
 
	public String transform(String body) throws Exception {
		URL url = FileFinder.find(getClass(), "dtd/core.dtd");
		if (url != null) {
			body = body.replaceAll("<!DOCTYPE[^>]*>", DOCTYPE_LINE).replaceAll("###URI###", url.toURI().toString());
		}
		return body;
	}

The URI will be replaced by looking up the DTD file at runtime, here by using my FileFinder class. Then it continues with replacing the special marker ###URI### by the real URI from the file found.

Although the solution sounds so simple, it took me quite a while to find out that the DOCTYPE references needs to be a URI and not a file or URL reference.