User: slaboure Date: 01/08/19 11:27:49 Added: src/main/org/jboss/ejb/plugins/jrmp/interfaces GenericProxyHA.java HASLSBTargetsManager.java HomeProxyHA.java StatelessSessionProxyHA.java Log: First import of source for HA support for SLSB Revision Changes Path 1.1 jbossmx/src/main/org/jboss/ejb/plugins/jrmp/interfaces/GenericProxyHA.java Index: GenericProxyHA.java =================================================================== /* * JBoss, the OpenSource J2EE WebOS * * Distributable under LGPL license. * See terms of license at gnu.org. */ package org.jboss.ejb.plugins.jrmp.interfaces; import java.lang.reflect.Method; import java.util.Hashtable; import java.io.IOException; import java.rmi.MarshalledObject; import javax.naming.InitialContext; import javax.naming.Name; import javax.ejb.EJBObject; import javax.ejb.EJBHome; import org.jboss.ejb.plugins.jrmp.server.JRMPContainerInvoker; /** * Branched from GenericProxy for HA behaviour * * @see GenericProxy * @author Rickard Öberg ([EMAIL PROTECTED]) * @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a> * @author <a href="mailto:[EMAIL PROTECTED]">Sacha Labourey</a> * @version $Revision: 1.1 $ * * <p><b>Revisions:</b> * * <p><b>20010819 Sacha Labourey:</b> * <ul> * <li> First import of sources * </ul> */ public class GenericProxyHA extends GenericProxy { public interface TargetsManager extends java.io.Serializable { void setFather (GenericProxyHA father); Hashtable getJndiTarget (); int numberOfRegisteredJndiTargets (); void jndiTargetHasFailed (Hashtable entry); ContainerRemote getRemoteTarget (); int numberOfRegisteredRemoteTargets (); void remoteTargetHasFailed (ContainerRemote target); void tick (); } // Constants ----------------------------------------------------- // Attributes ---------------------------------------------------- // Static -------------------------------------------------------- protected ContainerRemote[] crs; protected Hashtable[] jndiProps; protected String completeHAAppName; protected Object resynchFlag = new Object (); protected TargetsManager manager = null; // Constructors -------------------------------------------------- public GenericProxyHA () { // For externalization to work } public GenericProxyHA (String name,ContainerRemote container,boolean optimize) { super(name, container, optimize); } public GenericProxyHA (String name,ContainerRemote container,boolean optimize, TargetsManager mgr) { super(name, container, optimize); this.manager = mgr; this.manager.setFather (this); } // Public -------------------------------------------------------- /** * Externalize this instance. * */ public void writeExternal (java.io.ObjectOutput out) throws IOException { super.writeExternal (out); out.writeObject (this.crs); out.writeObject (this.jndiProps); out.writeUTF (completeHAAppName); out.writeObject (this.manager); } /** * Un-externalize this instance. * */ public void readExternal (java.io.ObjectInput in) throws IOException, ClassNotFoundException { super.readExternal (in); this.crs = (ContainerRemote[])in.readObject (); this.jndiProps = (Hashtable[])in.readObject (); this.completeHAAppName = in.readUTF (); this.manager = (TargetsManager)in.readObject (); manager.setFather (this); } public void setMultipleContainers (ContainerRemote[] containers, Hashtable[] jndiProps, String appPath) { crs = containers; this.jndiProps = jndiProps; this.completeHAAppName = appPath; } // Package protected --------------------------------------------- // Protected ----------------------------------------------------- // simply delegates our calls to our manager // protected java.util.Hashtable getJndiTarget () { return manager.getJndiTarget (); } protected int numberOfRegisteredJndiTargets () { return manager.numberOfRegisteredJndiTargets (); } protected void jndiTargetHasFailed (Hashtable entry) { manager.jndiTargetHasFailed (entry); } protected ContainerRemote getRemoteTarget () { return manager.getRemoteTarget (); } protected int numberOfRegisteredRemoteTargets () { return manager.numberOfRegisteredRemoteTargets (); } protected void remoteTargetHasFailed (ContainerRemote target) { manager.remoteTargetHasFailed (target); } protected void tick () { manager.tick (); } // Private ------------------------------------------------------- // Inner classes ------------------------------------------------- } 1.1 jbossmx/src/main/org/jboss/ejb/plugins/jrmp/interfaces/HASLSBTargetsManager.java Index: HASLSBTargetsManager.java =================================================================== /* * JBoss, the OpenSource J2EE WebOS * * Distributable under LGPL license. * See terms of license at gnu.org. */ package org.jboss.ejb.plugins.jrmp.interfaces; import java.util.Hashtable; import javax.naming.InitialContext; /** * Test implementation of a TargetsManager * * @see GenericProxyHA.TargetsManager * @author <a href="mailto:[EMAIL PROTECTED]">Sacha Labourey</a> * @version $Revision: 1.1 $ * * <p><b>Revisions:</b> * * <p><b>20010819 Sacha Labourey:</b> * <ul> * <li> First import of sources * </ul> */ public class HASLSBTargetsManager implements GenericProxyHA.TargetsManager { protected transient int cursorRemote = 0; protected transient int cursorJndi = 0; protected volatile long DELAY_FOR_RESYNCH_AFTER_DEAD_CONTAINER = 5000; // 5 seconds protected volatile long DELAY_FOR_RESYNCH_FOR_NORMAL_UPDATE = 30000; // 30 seconds protected transient volatile long nextResynch; protected transient volatile boolean updatingData = false; protected transient Object sync_1 = new Object (); protected transient java.util.Vector validJndiTargets = null; protected transient GenericProxyHA father = null; public HASLSBTargetsManager () { } public HASLSBTargetsManager (long normalResynch, long deathResynch) { DELAY_FOR_RESYNCH_AFTER_DEAD_CONTAINER = deathResynch; DELAY_FOR_RESYNCH_FOR_NORMAL_UPDATE = normalResynch; } public void setFather (GenericProxyHA father) { this.father = father; if (father.jndiProps != null) validJndiTargets = new java.util.Vector (java.util.Arrays.asList (father.jndiProps)); nextResynch = System.currentTimeMillis () + DELAY_FOR_RESYNCH_FOR_NORMAL_UPDATE; updatingData = false; } public java.util.Hashtable getJndiTarget () { if (validJndiTargets.size () == 0) { findTargetsSynchronously (); if (validJndiTargets.size () == 0) return null; } cursorJndi = ( (cursorJndi + 1) % validJndiTargets.size () ); return (Hashtable)(validJndiTargets.elementAt (cursorJndi)); } public int numberOfRegisteredJndiTargets () { return validJndiTargets.size (); } public void jndiTargetHasFailed (Hashtable entry) { validJndiTargets.remove (entry); } public ContainerRemote getRemoteTarget () { if (father.crs.length == 0) { findTargetsSynchronously (); if (father.crs.length == 0) return null; } synchronized (father.crs) { cursorRemote = ( (cursorRemote + 1) % father.crs.length ); return father.crs[cursorRemote]; } } public int numberOfRegisteredRemoteTargets () { return father.crs.length; } public void remoteTargetHasFailed (ContainerRemote target) { removeDeadTarget (target); } protected void removeDeadTarget (ContainerRemote target) { //System.out.println("Size before : " + Integer.toString(father.crs.length)); if (father.crs != null) synchronized (father.crs) { //System.out.println("removeDeadTarget has been called"); int length = father.crs.length; for (int i=0; i<length; ++i) if (father.crs[i] == target) { ContainerRemote[] copy = new ContainerRemote[length - 1]; //Hashtable[] copyProps = new Hashtable[length - 1]; System.arraycopy (father.crs, 0, copy, 0, i); //System.arraycopy(jndiProps, 0, copyProps, 0, i); if ( (i+1) < length) { System.arraycopy (father.crs, i+1, copy, i, length - i - 1); //System.arraycopy(jndiProps, i+1, copyProps, i, length - i - 1); } father.crs = copy; //jndiProps = copyProps; resynchAtLeastAt (System.currentTimeMillis () + DELAY_FOR_RESYNCH_AFTER_DEAD_CONTAINER); //System.out.println("Size before : " + Integer.toString(father.crs.length)); return; } } // nothing found } protected void findTargetsSynchronously () { // if this is called, it is because our target list is empty // //System.out.println("findTargetsSynchronously has been called"); synchronized (this) { if (father.crs.length > 0) return; // the list has been probably refilled during our wait for the monitor updateContainers (); } } protected void findTargetsAsynchronously () { //System.out.println("findTargetsAsynchronously has been called"); updatingData = true; Thread t = new Thread ( new Runnable () { public void run () { try { synchronized(this) { updateContainers (); } } finally { updatingData = false; } } } ); t.start (); } public void tick () { if (!updatingData) // this is done in order to do not have to wait on asynchronous updates { boolean resynch = false; synchronized (this) { long now = System.currentTimeMillis (); resynch = (now >= nextResynch); if (resynch) { //System.out.println("Tick has decided to resynch. Next auto resynh at " + Long.toString(now + DELAY_FOR_RESYNCH_FOR_NORMAL_UPDATE ) + " (now is " + Long.toString (now) + " and old update value was: " + Long.toString(nextResynch) + ")"); nextResynch = ( now + DELAY_FOR_RESYNCH_FOR_NORMAL_UPDATE ) ; } } if (resynch) findTargetsAsynchronously (); } } protected void resynchAtLeastAt (long when) { // only keep more urgent resynch need // if ( (nextResynch == 0) || (when < nextResynch) ) nextResynch = when; } protected void updateContainers () { //nextResynch = 0; //System.out.println("updateContainers has been called"); if (father.jndiProps != null) { org.jboss.ha.HASmallConfigEntries haConfigs = null; for (int i=0; i<father.jndiProps.length; i++) { try { //System.out.println("... Test with i = " + Integer.toString (i)); Object obj = new InitialContext (father.jndiProps[i]).lookup ("/HA/HAConfigServer"); if (obj instanceof org.jboss.ha.HARemoteInfo) { haConfigs = ( (org.jboss.ha.HARemoteInfo)obj).getSmallConfigEntriesForApp (father.completeHAAppName); if (haConfigs != null) if (haConfigs.size () > 0) { ContainerRemote[] tmpCr = haConfigs.getContainers (); Hashtable[] tmpJndi = haConfigs.getJndiProps (); java.util.Vector tmpV = new java.util.Vector (java.util.Arrays.asList (tmpJndi)); // reduce time in synch zone synchronized (father.crs) { father.crs = tmpCr; father.jndiProps = tmpJndi; validJndiTargets = tmpV; } this.DELAY_FOR_RESYNCH_AFTER_DEAD_CONTAINER = haConfigs.delayForResynchAfterDeath; this.DELAY_FOR_RESYNCH_FOR_NORMAL_UPDATE = haConfigs.delayForRefresh; // This will have an impact only if the new value is smaller // resynchAtLeastAt (System.currentTimeMillis () + DELAY_FOR_RESYNCH_FOR_NORMAL_UPDATE); return; } } } catch (Exception e) {/*e.printStackTrace ();*/} // during debug phase only!!! } } } } 1.1 jbossmx/src/main/org/jboss/ejb/plugins/jrmp/interfaces/HomeProxyHA.java Index: HomeProxyHA.java =================================================================== /* * JBoss, the OpenSource J2EE WebOS * * Distributable under LGPL license. * See terms of license at gnu.org. */ package org.jboss.ejb.plugins.jrmp.interfaces; import java.io.IOException; import java.lang.reflect.Method; import java.rmi.MarshalledObject; import javax.naming.Name; import javax.ejb.EJBHome; import javax.ejb.EJBObject; import javax.ejb.Handle; import javax.ejb.HomeHandle; import javax.ejb.EJBMetaData; import org.jboss.ejb.CacheKey; import org.jboss.ejb.plugins.jrmp.server.JRMPContainerInvoker; /** * Branched from HomeProxy for HA behaviour * * @see HomeProxy * @author Rickard Öberg ([EMAIL PROTECTED]) * @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a> * @author <a href="mailto:[EMAIL PROTECTED]">Sacha Labourey</a> * @version $Revision: 1.1 $ * * <p><b>Revisions:</b> * * <p><b>20010819 Sacha Labourey:</b> * <ul> * <li> First import of sources * </ul> */ public class HomeProxyHA extends GenericProxyHA { // Constants ----------------------------------------------------- // Attributes ---------------------------------------------------- EJBMetaData ejbMetaData; // Static -------------------------------------------------------- static Method getEJBMetaData; static Method getHomeHandle; static Method removeByHandle; static Method removeByPrimaryKey; static Method removeObject; static Method toStr; static Method eq; static Method hash; static { try { // EJB methods getEJBMetaData = EJBHome.class.getMethod ("getEJBMetaData", new Class[0]); getHomeHandle = EJBHome.class.getMethod ("getHomeHandle", new Class[0]); removeByHandle = EJBHome.class.getMethod ("remove", new Class[] {Handle.class}); removeByPrimaryKey = EJBHome.class.getMethod ("remove", new Class[] {Object.class}); // Get the "remove" method from the EJBObject removeObject = EJBObject.class.getMethod ("remove", new Class[0]); // Object methods toStr = Object.class.getMethod ("toString", new Class[0]); eq = Object.class.getMethod ("equals", new Class[] { Object.class }); hash = Object.class.getMethod ("hashCode", new Class[0]); } catch (Exception e) { e.printStackTrace (); } } // Constructors -------------------------------------------------- public HomeProxyHA () { // For Externalizable to work } public HomeProxyHA (String name, EJBMetaData ejbMetaData, ContainerRemote container, boolean optimize, TargetsManager mgr) { super (name, container, optimize, mgr); this.ejbMetaData = ejbMetaData; } // Public -------------------------------------------------------- // InvocationHandler implementation ------------------------------ public Object invoke (Object proxy, Method m, Object[] args) throws Throwable { // Normalize args to always be an array // Isn't this a bug in the proxy call?? if (args == null) args = new Object[0]; // Implement local methods if (m.equals (toStr)) { return name+"Home"; } else if (m.equals (eq)) { // equality of the proxy home is based on names... return new Boolean (invoke (proxy,toStr, args).equals (name+"Home")); } else if (m.equals (hash)) { return new Integer (this.hashCode ()); } // Implement local EJB calls else if (m.equals (getHomeHandle)) { return new HomeHandleImpl (name); } else if (m.equals (getEJBMetaData)) { return ejbMetaData; } else if (m.equals (removeByHandle)) { // First get the EJBObject EJBObject object = ((Handle) args[0]).getEJBObject (); // remove the object from here object.remove (); // Return Void return Void.TYPE; } // The trick is simple we trick the container in believe it is a remove() on the instance else if (m.equals (removeByPrimaryKey)) { if (optimize && isLocal ()) { return container.invoke ( // The first argument is the id new CacheKey (args[0]), // Pass the "removeMethod" removeObject, // this is a remove() on the object new Object[0], // Tx stuff getTransaction (), // Security attributes getPrincipal (), getCredential ()); } else { // Build a method invocation that carries the identity of the target object RemoteMethodInvocation rmi = new RemoteMethodInvocation ( // The first argument is the id new CacheKey (args[0]), // Pass the "removeMethod" removeObject, // this is a remove() on the object new Object[0]); // Set the transaction context rmi.setTransactionPropagationContext (getTransactionPropagationContext ()); // Set the security stuff // MF fixme this will need to use "thread local" and therefore same construct as above // rmi.setPrincipal(sm != null? sm.getPrincipal() : null); // rmi.setCredential(sm != null? sm.getCredential() : null); // is the credential thread local? (don't think so... but...) rmi.setPrincipal ( getPrincipal () ); rmi.setCredential ( getCredential () ); // Invoke on the remote server, enforce marshaling if (isLocal ()) { // We need to make sure marshaling of exceptions is done properly try { return container.invoke (new MarshalledObject (rmi)).get (); } catch (Throwable e) { throw (Throwable)new MarshalledObject (e).get (); } } else { // Marshaling is done by RMI return container.invoke (new MarshalledObject (rmi)).get (); } } } // If not taken care of, go on and call the container else { // Delegate to container // Optimize if calling another bean in same EJB-application if (optimize && isLocal ()) { return container.invokeHome ( // The method and arguments for the invocation m, args, // Transaction attributes getTransaction (), // Security attributes getPrincipal (), getCredential ()); } else { // Create a new MethodInvocation for distribution RemoteMethodInvocation rmi = new RemoteMethodInvocation (null, m, args); // Set the transaction propagation context rmi.setTransactionPropagationContext (getTransactionPropagationContext ()); // Set the security stuff // MF fixme this will need to use "thread local" and therefore same construct as above // rmi.setPrincipal(sm != null? sm.getPrincipal() : null); // rmi.setCredential(sm != null? sm.getCredential() : null); // is the credential thread local? (don't think so... but...) rmi.setPrincipal ( getPrincipal () ); rmi.setCredential ( getCredential () ); // Invoke on the remote server, enforce marshaling if (isLocal ()) { // We need to make sure marshaling of exceptions is done properly try { return container.invokeHome (new MarshalledObject (rmi)).get (); } catch (Throwable e) { throw (Throwable)new MarshalledObject (e).get (); } } else { // Marshaling is done by RMI // Marshaling is done by RMI // ContainerRemote aTarget = null; java.rmi.RemoteException lastProblem = null; tick (); // this proxy must support concurrent invocations // while (true) { synchronized (crs) { aTarget = getRemoteTarget (); if (numberOfRegisteredRemoteTargets () == 0) throw ( (lastProblem==null)? new java.rmi.RemoteException ("No more valid HA SLSB home availble") : lastProblem ); } try { return aTarget.invokeHome (new MarshalledObject (rmi)).get (); } catch (java.rmi.RemoteException e) { System.out.println ("A SLSB home target has failed with a RemoteException"); remoteTargetHasFailed (aTarget); lastProblem = e; } } } } } } public void writeExternal (java.io.ObjectOutput out) throws IOException { super.writeExternal (out); out.writeObject (ejbMetaData); } public void readExternal (java.io.ObjectInput in) throws IOException, ClassNotFoundException { super.readExternal (in); ejbMetaData = (EJBMetaData)in.readObject (); } // Package protected --------------------------------------------- // Protected ----------------------------------------------------- // Private ------------------------------------------------------- // Inner classes ------------------------------------------------- } 1.1 jbossmx/src/main/org/jboss/ejb/plugins/jrmp/interfaces/StatelessSessionProxyHA.java Index: StatelessSessionProxyHA.java =================================================================== /* * JBoss, the OpenSource J2EE WebOS * * Distributable under LGPL license. * See terms of license at gnu.org. */ package org.jboss.ejb.plugins.jrmp.interfaces; import java.lang.reflect.Method; import java.util.Hashtable; import java.io.IOException; import java.rmi.MarshalledObject; import javax.naming.InitialContext; import javax.naming.Name; import javax.ejb.EJBObject; import javax.ejb.EJBHome; import org.jboss.ejb.plugins.jrmp.server.JRMPContainerInvoker; import org.jboss.ejb.plugins.jrmp.interfaces.StatelessHandleImpl; /** * Branched from StatelessSessionProxy for HA behaviour * * @see StatelessSessionProxy * @author Rickard Öberg ([EMAIL PROTECTED]) * @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a> * @author <a href="mailto:[EMAIL PROTECTED]">Sacha Labourey</a> * @version $Revision: 1.1 $ * * <p><b>Revisions:</b> * * <p><b>20010819 Sacha Labourey:</b> * <ul> * <li> First import of sources * </ul> */ public class StatelessSessionProxyHA extends GenericProxyHA { // Constants ----------------------------------------------------- // Attributes ---------------------------------------------------- // Static -------------------------------------------------------- static Method getPrimaryKey; static Method getHandle; static Method getEJBHome; static Method isIdentical; static Method toStr; static Method eq; static Method hash; static { try { // EJBObject methods getPrimaryKey = EJBObject.class.getMethod ("getPrimaryKey", new Class[0]); getHandle = EJBObject.class.getMethod ("getHandle", new Class[0]); getEJBHome = EJBObject.class.getMethod ("getEJBHome", new Class[0]); isIdentical = EJBObject.class.getMethod ("isIdentical", new Class[] { EJBObject.class }); // Object methods toStr = Object.class.getMethod ("toString", new Class[0]); eq = Object.class.getMethod ("equals", new Class[] { Object.class }); hash = Object.class.getMethod ("hashCode", new Class[0]); } catch (Exception e) { e.printStackTrace (); } } // Constructors -------------------------------------------------- public StatelessSessionProxyHA () { // For externalization to work } public StatelessSessionProxyHA (String name,ContainerRemote container,boolean optimize, TargetsManager mgr) { super (name, container, optimize, mgr); } // Public -------------------------------------------------------- /** * Externalize this instance. * */ public void writeExternal (java.io.ObjectOutput out) throws IOException { super.writeExternal (out); } /** * Un-externalize this instance. * */ public void readExternal (java.io.ObjectInput in) throws IOException, ClassNotFoundException { super.readExternal (in); } // InvocationHandler implementation ------------------------------ public final Object invoke (Object proxy, Method m, Object[] args) throws Throwable { // Normalize args to always be an array // Isn't this a bug in the proxy call?? if (args == null) args = new Object[0]; // Implement local methods if (m.equals (toStr)) { return name+":Stateless"; } else if (m.equals (eq)) { return invoke (proxy, isIdentical, args); } else if (m.equals (hash)) { // We base the stateless hash on the hash of the proxy... // MF XXX: it could be that we want to return the hash of the name? return new Integer (this.hashCode ()); } // Implement local EJB calls else if (m.equals (getHandle)) { return new StatelessHandleImpl (null, name); } else if (m.equals (getPrimaryKey)) { // MF FIXME // The spec says that SSB PrimaryKeys should not be returned and the call should throw an exception // However we need to expose the field *somehow* so we can check for "isIdentical" // For now we use a non-spec compliant implementation and just return the key as is // See jboss1.0 for the PKHolder and the hack to be spec-compliant and yet solve the problem // This should be the following call //throw new RemoteException("Session Beans do not expose their keys, RTFS"); // This is how it can be solved with a PKHolder (extends RemoteException) // throw new PKHolder("RTFS", name); // This is non-spec compliant but will do for now // We can consider the name of the container to be the primary key, since all stateless beans // are equal within a home return name; } else if (m.equals (getEJBHome)) { Hashtable aServerProps = null; javax.naming.NamingException lastProblem = null; while (true) { synchronized (crs) { aServerProps = getJndiTarget (); if (numberOfRegisteredJndiTargets () == 0) throw ( (lastProblem==null)? new javax.naming.NamingException ("No more valid HA SLSB container availble") : lastProblem ); } try { return (EJBHome) new InitialContext (aServerProps).lookup (name); } catch (javax.naming.NamingException e) { jndiTargetHasFailed (aServerProps); lastProblem = e; } } } else if (m.equals (isIdentical)) { // All stateless beans are identical within a home, if the names are equal we are equal return new Boolean (((EJBObject)args[0]).getPrimaryKey ().equals (name)); } // If not taken care of, go on and call the container else { // Delegate to container // Optimize if calling another bean in same EJB-application if (optimize && isLocal ()) { return container.invoke ( // The entity id, method and arguments for the invocation null, m, args, // Transaction attributes getTransaction (), // Security attributes getPrincipal (), getCredential ()); } else { // Create a new MethodInvocation for distribution RemoteMethodInvocation rmi = new RemoteMethodInvocation (null, m, args); // Set the transaction context rmi.setTransactionPropagationContext (getTransactionPropagationContext ()); // Set the security stuff // MF fixme this will need to use "thread local" and therefore same construct as above // rmi.setPrincipal(sm != null? sm.getPrincipal() : null); // rmi.setCredential(sm != null? sm.getCredential() : null); // is the credential thread local? (don't think so... but...) rmi.setPrincipal ( getPrincipal () ); rmi.setCredential ( getCredential () ); // Invoke on the remote server, enforce marshaling if (isLocal ()) { // We need to make sure marshaling of exceptions is done properly try { return container.invoke (new MarshalledObject (rmi)).get (); } catch (Throwable e) { throw (Throwable)new MarshalledObject (e).get (); } } else { // Marshaling is done by RMI // ContainerRemote aTarget = null; java.rmi.RemoteException lastProblem = null; tick (); // this proxy must support concurrent invocations // while (true) { synchronized (crs) { aTarget = getRemoteTarget (); if (numberOfRegisteredRemoteTargets () == 0) throw ( (lastProblem==null)? new java.rmi.RemoteException ("No more valid HA SLSB container availble") : lastProblem ); } try { return aTarget.invoke (new MarshalledObject (rmi)).get (); } catch (java.rmi.RemoteException e) { remoteTargetHasFailed (aTarget); lastProblem = e; } } } } } } // Package protected --------------------------------------------- // Protected ----------------------------------------------------- // Private ------------------------------------------------------- // Inner classes ------------------------------------------------- } _______________________________________________ Jboss-development mailing list [EMAIL PROTECTED] http://lists.sourceforge.net/lists/listinfo/jboss-development