Categories
Java RS Library

Using Pooled Data Connections with RS Libs Data Hibernate Library

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!)

Categories
Bugzilla for Java Java

B4J V2.0.1 releaseed

A new version 2.0.1 of B4J has been released. It fixes issues found by static code analysis. A complete change log is available as well as the mandatory Maven Site.

You can download the new version here or visit the Homepage of the utility where you will find more documentation.

The Maven coordinates are:

<dependency>
      <groupId>eu.ralph-schuster</groupId>
      <artifactId>b4j</artifactId>
      <version>2.0.1</version>
</dependency>
Categories
CSV Java

CSV/Excel Utility Package V2.7.1 released

The new version 2.7.1 fixes issues found by static code analysis. A complete change log is available as well as the mandatory Maven Site.

You can download the new version here or visit the Homepage of the utility where you will find some examples on how to use it.

The Maven coordinates are:

<dependency>
      <groupId>eu.ralph-schuster</groupId>
      <artifactId>csv</artifactId>
      <version>2.7.1</version>
</dependency>
Categories
Java RS Library

RS Library V1.2.5 released

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>
Categories
Bugzilla for Java CSV Java RS Library

Multiple Releases

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

All projects are available through Maven Central.

 

Categories
CSV Java

CSV/Excel Utility improves performance

I recently stumbled across a performance test of Java CSV libraries (can’t remember where). To my surprise, someone tested multiple Open Source products including my own CSV/Excel Utility Package. And even more surprising to me, mine was the worst. By far! It took 4 times as much than others spent in parsing a CSV file. Embarrasing! Why did I never spent effort in measuring performance?

Anyway. I took the time and wrote a comparable JUnit perfromance test for all major CSV libraries and gave them a 150MB file to read. Analyzing the results of my own library with JProfiler, I found a very stupid performance eater (simplified here):

1
2
3
4
5
6
String s = "";
for (char c : anotherString.toCharArray()) {
   ...
   s += c;
   ...
}

The “addition” of line 6 was called 150 million times – for each single character in the file. Replacing this by a StringBuilder construct, the performance rose near the other major CSV libraries:

1
2
3
4
5
6
StringBuilder s = new StringBuilder();
for (char c : anotherString.toCharArray()) {
   ...
   s.append(c);
   ...
}

So two things to learn here: (1) Do not under-estimate performance test before releasing something, (2) Take care when using the “addition” operator for strings. 🙂

PS: CSV/Excel Utility Package 1.7 will contain the fix.
PPS: StringBuilder is preferred against StringBuffer as it is not synchronized and therefore faster. Most use cases allow this simplifications.

Categories
Java RS Library

RS Library 1.2.2 released

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>
Categories
Java RS Library

The Class.forName() problem

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.

Categories
Programming languages RS Library

The Importance of Unit Tests

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. 😉

Categories
Java RS Library

RS Library 1.2.1 released

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>