Embedding derby into Jboss
In this post I want to show how you can
start jboss with an embedded derby network database.
The aim is, that when jboss starts:
it will start derby
open port 1527 for derby to receive
jdbc callscreate a new database if there is
none existingcreate a datasource inside jboss
You can now use any derby jdbc client
to communicate with the database, and use derby datasource inside
jboss as well.
I had to implement three components:
an mbean to start the derby network
servera datasource to connect to derby
database with option create=truean mbean that will get an initial
connection so that database gets created
Jboss mbean
In Jboss you can deploy mbeans, which
automatically get started on deployment. The implementation of an
Mbean is very simple: you must create an interface that ends with
Mbean and has methods start() and stop(), and implement a class for
this interface that shares the same name without the Mbean part.
Then you create an xml with a reference
to the class implementation, and a name settings. For example:
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
<?xml version="1.0"
encoding="UTF-8"?>
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
<server>
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
<mbean
code="jankester.com.derby.jboss.DerbyDatabase"
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
name="jboss.jdbc:service=DerbyDatabase">
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
</mbean>
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
face="Monospace"></server>
The deployment of an Mbean can be done
in several ways: you can create an xml file, drop it in the deploy
directory and make sure that the java classes are available in the
lib directory, or you can create a .sar file. The latter has the
advantage that you can do hot deployment, so I prefer it.
You must: create a jar file or
directory that ends in .sar (so that jboss recognizes it type on
deployment), and add a jar to this .sar file with the necessary
classes.
The network server Mbean
The interface for this mbean looks
like:
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
package
com.jankester.derby.jboss;
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
public interface
DerbyDatabaseMBean
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
{
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
public void start()
throws Exception;
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
public void stop()
throws Exception;
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
}
The class implementing this interface
has following:
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
package
com.jankester.derby.jboss;
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
import
java.sql.DriverManager;
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
import
java.sql.SQLException;
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
public class
DerbyDatabase implements DerbyDatabaseMBean
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
{
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
public static final
String START_NETWORK_SERVER = "derby.drda.startNetworkServer";
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
public static final
String HOST = "localhost";
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
public static final
String PORT_NUMBER = "1527";
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
public static final
String DRIVER_CLASSNAME = "org.apache.derby.jdbc.EmbeddedDriver";
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
public static final
String SHUTDOWN_URL = "jdbc:derby:;shutdown=true";
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
public static final
String SHUTDOWN_MESSAGE = "Derby system shutdown.";
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
public static final
String MSG_INIT_SUCCESS = "Derby JDBC driver loaded
successfully";
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
public static final
String MSG_INIT_CLASS_NOT_FOUND = "The Derby JDBC driver ("
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
+
DRIVER_CLASSNAME + ") could not be found. Make sure the
appropriate JAR"
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
+ " files
are available.";
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
public static final
String MSG_TERM_SUCCESS = "Derby shutdown was successful.";
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
public static final
String MSG_TERM_FAILURE = "Unexpected Exception was caught from
the Derby shutdown.";
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
public void start()
throws Exception
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
{
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
setSystemProperties();
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
initializeCloudscape();
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
}
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
public void stop()
throws Exception
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
{
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
shutdownCloudscape();
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
}
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
private void
setSystemProperties()
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
{
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
String dataDir =
System.getProperty("jboss.server.data.dir");
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
System.out.println("jboss.server.data.dir="
+ dataDir);
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
System.setProperty(START_NETWORK_SERVER,
"true");
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
System.setProperty("derby.system.home",
dataDir);
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
}
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
private void
initializeCloudscape()
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
{
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
try
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
{
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
Class.forName(DRIVER_CLASSNAME);
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
System.out.println(MSG_INIT_SUCCESS);
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
}
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
catch
(ClassNotFoundException varException)
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
{
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
System.out.println(MSG_INIT_CLASS_NOT_FOUND);
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
varException.printStackTrace();
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
}
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
}
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
private void
shutdownCloudscape()
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
{
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
try
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
{
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
DriverManager.getConnection(SHUTDOWN_URL);
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
}
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
catch
(SQLException varException)
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
{
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
System.out.println("message="
+ varException.getMessage());
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
System.out.println("sqlstate="
+ varException.getSQLState());
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
if
(varException.getMessage().equals(SHUTDOWN_MESSAGE))
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
{
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
System.out.println(MSG_TERM_SUCCESS);
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
}
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
else
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
{
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
System.out.println(MSG_TERM_FAILURE);
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
varException.printStackTrace();
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
}
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
}
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
}
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
}
In initializeCloudscape() it loads the
driver class. Before, in system properties it sets system properties
that will be picked up by the driver class:
network mode is true
the root directory for derby
database storage is the jboss server data dir.
The xml that belong to this mbean is:
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
<?xml version="1.0"
encoding="UTF-8"?>
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
<server>
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
<mbean
code="jankester.com.derby.jboss.DerbyDatabase"
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
name="jboss.jdbc:service=DerbyDatabase">
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
</mbean>
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
face="Monospace"></server>
The xml file must be renamed into
META-INF/jboss-service.xml, the classes added to a jar, and the jar
and META-INF directory together packed into a .sar file. You can now
deploy the file directly in the deploy dir of your server.
The datasource
To create a derby datasource, you can
use the samples that comes with jboss.
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
<?xml version="1.0"
encoding="UTF-8"?>
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
<datasources>
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
<local-tx-datasource>
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
<jndi-name>AuditTrail.DataSource</jndi-name>
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
face="Courier, monospace"><connection-url>jdbc:derby:${jboss.server.data.dir}${/}carnot;create=true</connection-url>
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
<driver-class>org.apache.derby.jdbc.EmbeddedDriver</driver-class>
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
<user-name>carnot</user-name>
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
<password>carnot</password>
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
<min-pool-size>5</min-pool-size>
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
<max-pool-size>20</max-pool-size>
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
<idle-timeout-minutes>5</idle-timeout-minutes>
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
<track-statements/>
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
<depends>jboss.jdbc:service=DerbyDatabase</depends>
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
</local-tx-datasource>
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
</datasources>
Important to note here, is, that the
connection url creates a new database if none is existing and uses
the jboss data directory as its basis for database data.
The datasource has a dependency on the
derbydatabase mbean that we just created. It will not load before
that mbean has been loaded.
The poolfiller MBean
This mbean is necessary as we must make
sure that the database gets created straight away on loading. If we
leave this out, we can have the scenario that an external jdbc client
calls derby, but that the database has not been created yet. The
database only gets created the first time the datasource connection
gets created. So, this mbean will create a connection and close it
again.
Here we an interface PoolFillerMbean:
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
package
jankester.com.derby.jboss;
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
import
javax.management.ObjectName;
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
public interface
PoolFillerMBean
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
{
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
public void start()
throws Exception;
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
public void stop()
throws Exception;
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
public void
setConnectionManager(ObjectName cm);
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
}
and a class PoolFiller:
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
package
jankester.com.derby.jboss;
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
import
java.sql.Connection;
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
import
javax.management.ObjectName;
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
import
javax.naming.InitialContext;
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
import
javax.sql.DataSource;
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
import
org.jboss.system.ServiceMBeanSupport;
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
public class PoolFiller
extends ServiceMBeanSupport implements PoolFillerMBean
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
{
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
public void start()
throws Exception
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
{
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
System.out.println("Starting
PoolFiller");
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
startService();
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
}
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
public void stop()
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
{
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
System.out.println("Stopping
PoolFiller");
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
}
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
private ObjectName
cm;
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
public void
setConnectionManager(ObjectName cm)
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
{
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
this.cm = cm;
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
}
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
protected void
startService() throws Exception
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
{
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
String jndiName =
(String) server.getAttribute(cm, "BindName");
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
DataSource ds =
(DataSource) new InitialContext().lookup(jndiName);
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
System.out.println("Found
datasource for jndiname=" + jndiName);
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
Connection c =
ds.getConnection();
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
c.close();
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
}
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
}
Here we had to add an extra method
setConnectionManager to load an existing mbean object. We have to
implement this method in class and interface, so that Jboss can find
it.
Further we extended ServiceMBeanSupport
so that we have access to the Mbean Server. We
need it to find our Mbean that holds the jndi name of our datasource.
With the jndi name, we can find the datasource, and retrieve a
connection. Now the database gets created.
The method BindName is an attribute of
the Mbean that gets passed into the setConnection method. If you use
a different version of Jboss (tested with 4.0.5), then look into
http://localhost:8080/jmx-console,
and find an Mbean that has an attribute that holds the jndi
reference.
The jboss-service.xml looks like:
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
<?xml version="1.0"
encoding="UTF-8"?>
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
<server>
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
<mbean
code="ag.carnot.derby.jboss.PoolFiller"
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
name="jboss.jdbc:service=PoolFiller">
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
<depends
optional-attribute-name="ConnectionManager">jboss.jca:name=AuditTrail.DataSource,service=DataSourceBinding</depends>
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
<!-- -->
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
</mbean>
style="margin-left: 0.5in; margin-bottom: 0in; page-break-before: auto;">
face="Monospace"></server>
Deployment on jboss
The easiest is to make a copy of the
server/default directory, and create a server/derby directory.
Further you must put the derby.jar and
derbynet.jar files in server/derby/lib.
Copy the two mbeans and datasource.xml
of above in the deploy directory.
Checks
When you have started derby, you should
see that port 1527 got opened, and that the directory carnot has been
created under server/derby/data.
jdbc client
You can use the db2 driver db2jcc.jar,
db2jcc_license_c.jar.
The url looks like:
jdbc:derby:net://localhost/carnot
Comments