Sunday, December 2, 2007

Installating JBoss with the Tanuki wrapper

We use Windows 2003 servers in our architecture so we make extensive use of the Tanuki wrapper. However, with all the options involved and with the all the quirk in running JBoss, it is always a challenge to configure the wrapper correctly.

Here are the steps we took to get JBoss running as a service in our Windows 2003 server:

  1. Create environment variable JBOSS_HOME and point this to the installation directory of JBoss
  2. Copy wrapper.exe from {wrapper_installer}\bin to {JBoss}\bin directory
  3. Copy wrapper.dll and wrapper.jar fro {wrapper_installer}\lib to {JBoss}\lib
  4. Copy App.bat.in, InstallApp-NT.bat.in and UninstallApp-NT.bat.in from {wrapper_installer}\src\bin to {JBOSS}\bin directory and remove the .in extensions
  5. Create directory {JBoss}\conf and copy wrapper.conf.in from {wrapper_installer}\src\conf to {JBoss}\conf; remove the .in extension.
  6. Make the wrapper.conf file look like this:

wrapper.java.command=%JAVA_HOME%/bin/java

wrapper.java.mainclass=org.tanukisoftware.wrapper.WrapperSimpleApp

wrapper.java.classpath.1=%JBOSS_HOME%/lib/wrapper.jar

wrapper.java.classpath.2=%JAVA_HOME%/lib/tools.jar

wrapper.java.classpath.3=./run.jar

wrapper.java.library.path.1=%JBOSS_HOME%/lib

wrapper.java.additional.1=-server

#parameters to start Jboss

wrapper.app.parameter.1=org.jboss.Main

#parameter to start default server

wrapper.app.parameter.2=-c default

# Initial Java Heap Size (in MB)

wrapper.java.initmemory=256

# Maximum Java Heap Size (in MB)

wrapper.java.maxmemory=1024

wrapper.logfile=%JBOSS_HOME%/logs/wrapper.log

# name of service as in net startstop JBoss

wrapper.ntservice.name=JBoss

# Name of server as it is displayed

wrapper.ntservice.displayname=JBoss Server

# Description of the service

wrapper.ntservice.description=JBoss 4.0.3 Server

# Mode in which the service is installed. AUTO_START or DEMAND_START

wrapper.ntservice.starttype=DEMAND_START

# Priority at which the service is run. NORMAL, LOW, HIGH, or REALTIME

wrapper.ntservice.process_priority=HIGH

# Allow the service to interact with the desktop.

wrapper.ntservice.interactive=false

Default the wrapper starts the default server in Jboss; we need to the the all server, because we are depending on the extra services from the all server. The wrapper.app.parameter.2 and ..3 accomplish this. This is equivalent to starting jboss with run –c all

  1. Install and start the server using wrapper.exe -i ../conf/wrapper.conf and wrapper.exe -t../conf/wrapper.conf

Monday, November 12, 2007

Apache James Mailet with JDBC Database connection

James is a wonderful mailserver. It works very well for what we are doing. But as with all open source java applications, it is not always very well documented. We needed some mailets which all use the JDBC connection pool as configured in the SAR-INF/config.xml.

I had to use the James source code to figure out how to use the connection pool as I am not very familiar with the Avalon framework. As always, it turned out to be not too difficult, but how to get there took some time.


import javax.mail.MessagingException;
import java.sql.*;
import org.apache.mailet.*;
import org.apache.avalon.cornerstone.services.datasources.DataSourceSelector;
import org.apache.avalon.excalibur.datasource.DataSourceComponent;
import org.apache.avalon.framework.service.ServiceManager;
import org.apache.james.Constants;
import org.apache.james.util.JDBCUtil;

public class ourMailet extends GenericMailet {
private static final String DATASOURCE = "maildb";
protected DataSourceComponent datasource = null;

protected final JDBCUtil jdbcUtil = new JDBCUtil() {
protected void delegateLog(String logString) {
log("JDBCourMailet: " + logString);
}
};

public ourMailet() { }
public String getMailetInfo() {
return "OurMailet version 1.0";
}

public void init() throws MessagingException {
if (datasource != null) return;

try {
ServiceManager componentManager =
(ServiceManager) getMailetContext()
.getAttribute(Constants.AVALON_COMPONENT_MANAGER);

DataSourceSelector datasources =
(DataSourceSelector) componentManager.lookup(DataSourceSelector.ROLE);

datasource = (DataSourceComponent) datasources.select(DATASOURCE);
}
catch (Exception e) {
throw new MessagingException("Error initializing OurMailet", e);
}
}
public void service(Mail mail) throws MessagingException {

Connection conn = null;
try {

conn = datasource.getConnection();
// do processing
}
catch (Exception e){
throw new MessagingException("Error initializing OurMailet", e);
}
finally {
jdbcUtil.closeJDBCConnection(conn);
}
}

}

Tuesday, September 11, 2007

Finally able to set up Solaris 10

I have been struggling a lot installing Solaris 10 lately on my home server. Especially, since all my other computers run Windows. I used Linux before on my home server and getting Samba installed was always a problem. Better still, it never worked.

Thanks to Random Garbage Generator blog entry, getting Samba to work was a breeze. I just made sure that my /etc/sfw/smb.conf file included the workgroup MSHOME and the user as root
and it ran immediately after i started the deamon /etc/init.d/samba start
See here the very simple smb.conf file, where [sambashare] is the name of the share on my server:

[global]
workgroup = SAMBAFS
server string = Samba Server
log file = /var/adm/samba_log.%m
security = SHARE

[sambashare]
comment = sambashare
path = /
user = root
read only = No
guest ok = Yes


Kudos guys. You made it really simple! Using windows explorer I can get to the share using \\myserver\sambashare on my development machines

Monday, May 7, 2007

Serializing and deserializing objects with FDS

I was running into a problem with synchronizing objects which include child objects. The log files in the java classes returned fully filled object including child objects. However, when the sames objects came over to the Actionscript client side, the child object were in there initial state as shallow objects.

Several tries later and with the help of John Zhao from Abode, it turned out that the java classes need to be implemented as Serializable.


package com.grendel.java.data;
import java.io.Serializable

public class Person inplements Serializable
{
public int personId;
public Contact contact;

public Person () { super();}
}
package com.grendel.java.data;
import java.io.Serializable;

public class Contact inplements Serializable
{
public int contactId;
public String contact;
public Contact () { super();}
}

If you instantiate the Person class in the PersonAssembler or on the client the Contact child class will be serialized and deserialized during synchronization.

Friday, May 4, 2007

A wrapper class for DataService methods

Having multiple DataServices, each with their own getItem method (and createItem, deleteItem, fill and updateItem) means handling each event with an ItemReference. Since really the only things changing are the identity object, initial Object and the result handler, it is a perfect candidate for a wrapper class.

public class Services{
private var _personDS:DataService;
private var _workDS:DataService;
private var _instance:Services;

public static function getInstance(){
if (_instance == null) new Services();
return _instance;
}
public function Services(){
if (_instance == null) {
_instance = this;
_personDS = new DataService("my.person");
_workDS = new DataService("my.work");
}
else {
throw new Error("singleton class Services cannot accept multiple instances");
}
}
public function dsPerson():DataService{
return _personDS;
}
public function dsWork():DataService{
return _workDS;
}
public function getItem(ds:DataService,
identity:Object,
initObject:Object,
resFunction:Function) {
var token:ItemReference = ds.getItem(identity, initObject);
token.addResponder(new ItemResponder(resFunction, faultHandler));
}
private function faultHandler(fe:FaultHandler, token:Object=null):void{
Alert.show(fe.fault.faultString(), "Error in DataService");
}
}
You call the wrapped getItem method as follows. I really like it that in Flex 2 you do not need the Delegates anymore if you parameterize a function in a wrapper method, so calling these methods will be even easier:

private function getPerson(personId:int):void{
Services.getInstance().getItem(
Services.getInstance().dsPerson(),
{personId:personId},
new Person(),
personResHandler);
}
public function personResHandler(res:ResultEvent, token:Object=null):void{
var person:Person = Person(res.result);
Alert.show("Person retrieved is " + person.name);
}