Monday, November 23, 2009

JBoss setup for Solaris

Old style, before SMF

/etc/init.d/jboss
====================================
#!/sbin/sh
JBOSS_HOME=/u05/app/jboss-5.0.1.GA
JAVA_HOME=/u05/app/java6/jre1.6.0_02
case "$1" in
start)
cd $JBOSS_HOME/bin
echo "Staring jboss daemon: "
nohup $JBOSS_HOME/bin/run.sh &
;;
stop)
cd $JBOSS_HOME/bin
echo "Stopping jboss daemon: "
$JBOSS_HOME/bin/shutdown.sh -S
;;
restart)
cd $JBOSS_HOME/bin
echo "Restarting jboss daemon: "
$0 stop
sleep 2
$0 start
;;
*)
echo "Usage $0 {startstoprestart}"
exit 1
;;
esac
exit 0
===================================
/etc/rc3.d/S99jboss -> /etc/init.d/jboss
/etc/rcS.d/K07jboss -> /etc/init.d/jboss

With Solaris 10 SMF

The Solaris 10 OS uses the Service Management Facility (SMF) to handle services.

Create a service manifest file:/var/svc/manifest/network/jboss4.xml




name='network/jboss'
type='service'
version='1'>




name='fs'
grouping='require_all'
restart_on='none'
type='service'>
value='svc:/system/filesystem/local' />




grouping='require_all'
restart_on='none'
type='service'>
value='svc:/network/loopback' />


name='ssh_multi-user-server'
grouping='optional_all'
restart_on='none'>
value='svc:/milestone/multi-user-server' />


type='method'
name='start'
exec='/lib/svc/method/svc-jboss4 start'
timeout_seconds='-1'>




type='method'
name='stop'
exec=':kill'
timeout_seconds='-1'>


type='method'
name='restart'
exec='/lib/svc/method/svc-jboss4 restart'
timeout_seconds='-1'>









Now create your "Service Method File" in /lib/svc/method called svc-jboss4:

#!/usr/bin/sh
# William Pool (Puddle) 01/05
# SMF Method file for JBoss
# E-mail: puddle@flipmotion.com
#
# NOTE: If you start JBoss with su -c 'cmds' instead
# You "will" be able to start and stop it via root using the method file
# itself. However, it "does" confuse SMF. It's best to have the straight
# commands and let the actual SMF service do the user rights and permissions
# of execution. You've been WARNED! Use su -c 'cmds' at your own risk!
#
. /lib/svc/share/smf_include.sh
case $1 in
'start')
echo "starting jboss.."
/opt/software/jboss-4.0.1/bin/run.sh & >/dev/null 2> /dev/null
;;
'stop')
echo "stopping jboss.."
/opt/software/jboss-4.0.1/bin/shutdown.sh -S &
pkill java
;;
'restart')
stop
# give stuff some time to stop before we restart
sleep 35
# protect against any services that can't stop before we restart (warning
this kills all Java instances running as 'jboss' user)
pkill java
start
;;
*)
echo "Usage: $0 { start stop restart }"
exit 1
;;
esac
#---EOF

Now fix the permissions for the two files created:

chown root:bin /lib/svc/method/svc-jboss4
chmod 555 /lib/svc/method/svc-jboss4
chown root:sys /var/svc/manifest/network/jboss4.xml
chmod 444 /var/svc/manifest/network/jboss4.xml

Import the service into the service repository:
# svccfg import /var/svc/manifest/network/jboss4.xml
Enable the service:
# svcadm -v enable jboss

Friday, June 26, 2009

Dynamically add jar for JDBC

Java Almanac (exampledepot.com) has example of loading class not in the classpath. For example, if I want to load driver class from the Oracle JDBC Driver jar:
File file = new File("C:\\oracle\\ora92\\jdbc\\lib\\ojdbc14.jar");
// file.toURL() directly is unsafe - does not escape characters illegal in URLs
URL url = file.toURI().toURL();
URL[] urls = new URL[]{url};
ClassLoader cl = new URLClassLoader(urls);
Class cls = cl.loadClass("oracle.jdbc.driver.OracleDriver");

However, if you then call
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection con = DriverManager.getConnection(…);
The calls will fail.

How do tools such as DBVisualizer dynamically add jar files to the classpath and then work with JDBC? DBVisualizer even figures out there are 2 driver classes in ojdbc14.jar and allows you to select which one to load.
This part is easy. It was looking for files like %Driver.class:
JarFile jar = new JarFile(file);
Enumeration allFiles = jar.entries();
while (allFiles.hasMoreElements()) {
JarEntry jarEntry = allFiles.nextElement();
String name = jarEntry.getName();
if (name.endsWith("Driver.class")) {
System.out.println(jarEntry.getName());
}
}

But how to add the jar to classpath so that Class.forName(..) will work?

The important thing to note is that Class.forName() is using the SystemClassLoader.
The groovy Sql class implements loadDriver with:
Class.forName(driverClassname);
and then the thread context class loader ...
Thread.currentThread().getContextClassLoader().loadClass(driverClassName);
and then the class loader that loaded the Sql class itself ...
Sql.class.getClassLoader().loadClass(driverClassName);

So the trick is really to modify the System Class Loader.
http://forums.sun.com/thread.jspa?threadID=300557&start=0&tstart=0 provides a good solution.

---------------------------------------------------------------------------------------
import java.net.URL;
import java.net.URLClassLoader;
import java.io.IOException;
import java.io.File;
import java.lang.reflect.Method;

/**
* The System Class Loader (ClassLoader.getSystemClassLoader()) is a subclass of URLClassLoader.
* It can therefore be casted into a URLClassLoader and used as one.
*
* URLClassLoader has a protected method addURL(URL url),
* which you can use to add files, jars, web addresses - any valid URL in fact.
*
* Since the method is protected you need to use reflection to invoke it.
*/
public class ClasspathAppender {

private static final Class[] parameters = new Class[]{URL.class};

public static void addFile(String s) throws IOException {
File f = new File(s);
addFile(f);
}//end method

public static void addFile(File f) throws IOException {
//addURL(f.toURL());
addURL(f.toURI().toURL());
}//end method


public static void addURL(URL u) throws IOException {

URLClassLoader sysloader = (URLClassLoader)ClassLoader.getSystemClassLoader();
Class sysclass = URLClassLoader.class;

try {
Method method = sysclass.getDeclaredMethod("addURL",parameters);
method.setAccessible(true);
method.invoke(sysloader,new Object[]{ u });
} catch (Throwable t) {
t.printStackTrace();
throw new IOException("Error, could not add URL to system classloader");
}//end try catch

}//end method

}//end class