User: allsopp
Date: 01/01/14 21:06:58
Added: src/main/org/jboss/resource ConnectionFactoryConfig.java
ConnectionFactoryLoader.java
ConnectionFactoryLoaderMBean.java
ConnectionManagerImpl.java RARDeployer.java
RARDeployerMBean.java RARMetaData.java
Log:
First cut at the J2EE Connector Architecture.
Revision Changes Path
1.1 jboss/src/main/org/jboss/resource/ConnectionFactoryConfig.java
Index: ConnectionFactoryConfig.java
===================================================================
/*
* JBoss, the OpenSource EJB server
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.resource;
/**
* Provides access to configuration parameters for a JCA connection
* factory.
*
* @author Toby Allsopp ([EMAIL PROTECTED])
* @version $Revision: 1.1 $
*/
public interface ConnectionFactoryConfig
{
// Constants -----------------------------------------------------
// Static --------------------------------------------------------
// Public --------------------------------------------------------
/**
* The name of the class implementing {@link
* org.jboss.resource.security.PrincipalMapping} that is to be used
* for mapping caller principals to resource principals for this
* connection factory.
*/
String getPrincipalMappingClass();
void setPrincipalMappingClass(String className);
/**
* A string in a format parseable by {@link
* java.util.Properties#load} that defines the properties to set on
* the <code>PrincipalMapping</code> for this connection factory
* instance.
*/
String getPrincipalMappingProperties();
void setPrincipalMappingProperties(String properties);
// Connection pooling parameters
/**
* The name of the pool strategy to use - if not set then an
* automagic setting is chosen.
*
* @see org.jboss.resource.pool.PoolStrategyFactory
*/
String getPoolStrategy();
void setPoolStrategy(String strategyName);
void setMinSize(int minSize);
int getMinSize();
void setMaxSize(int maxSize);
int getMaxSize();
void setBlocking(boolean blocking);
boolean getBlocking();
void setGCEnabled(boolean gcEnabled);
boolean getGCEnabled();
void setGCInterval(long interval);
long getGCInterval();
void setGCMinIdleTime(long idleMillis);
long getGCMinIdleTime();
void setIdleTimeoutEnabled(boolean enabled);
boolean getIdleTimeoutEnabled();
void setIdleTimeout(long idleMillis);
long getIdleTimeout();
void setMaxIdleTimeoutPercent(float percent);
float getMaxIdleTimeoutPercent();
void setInvalidateOnError(boolean invalidate);
boolean getInvalidateOnError();
void setTimestampUsed(boolean timestamp);
boolean getTimestampUsed();
}
1.1 jboss/src/main/org/jboss/resource/ConnectionFactoryLoader.java
Index: ConnectionFactoryLoader.java
===================================================================
/*
* JBoss, the OpenSource EJB server
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.resource;
import java.beans.PropertyEditor;
import java.beans.PropertyEditorManager;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.NoSuchMethodException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.Notification;
import javax.management.NotificationFilter;
import javax.management.NotificationListener;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.Name;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.spi.ObjectFactory;
import javax.resource.Referenceable;
import javax.resource.ResourceException;
import javax.resource.spi.ConnectionManager;
import javax.resource.spi.ManagedConnectionFactory;
import javax.transaction.TransactionManager;
import org.jboss.logging.Log;
import org.jboss.logging.LogWriter;
import org.jboss.resource.security.PrincipalMapping;
import org.jboss.util.ServiceMBeanSupport;
/**
* Service that configures an instance of a deployed resource
* adapter and binds the resulting connection factory into JNDI.
*
* <p> This service does nothing until it receives a notification
* from the RAR deployer that the resource adapter has been
* deployed.
*
* @see RARDeployer
* @author Toby Allsopp ([EMAIL PROTECTED])
* @version $Revision: 1.1 $
*/
public class ConnectionFactoryLoader
extends ServiceMBeanSupport
implements ConnectionFactoryLoaderMBean, NotificationListener, ObjectFactory
{
// Constants -----------------------------------------------------
// Attributes ----------------------------------------------------
private MBeanServer server = null;
private String resourceAdapterName = null;
private String factoryName = null;
private String properties = null;
private String rarDeployerName = null;
private String tmName = "java:/TransactionManager";
// Principal mapping parameters
private String princMapClass;
private String princMapProps;
// Pool strategy parameters
private String poolStrategy;
// ObjectPool configuration parameters
private int minSize;
private int maxSize;
private boolean blocking;
private boolean gcEnabled;
private long gcInterval;
private long gcMinIdleTime;
private boolean idleTimeoutEnabled;
private long idleTimeout;
private float maxIdleTimeoutPercent;
private boolean invalidateOnError;
private boolean timestampUsed;
private ObjectName rarDeployerObjectName = null;
/** The JNDI name to which this connection factory is bound */
private String bindName;
private ConnectionManagerImpl cm = null;
/** Maps factory name to <code>ConnectionFactory</code> instance
for JNDI lookups */
private static Map cfs = new HashMap();
// Static --------------------------------------------------------
// Constructors --------------------------------------------------
// Public --------------------------------------------------------
// ConnectionFactoryLoaderMBean implementation -------------------
public String getResourceAdapterName() { return resourceAdapterName; }
public void setResourceAdapterName(String resourceAdapterName) {
this.resourceAdapterName = resourceAdapterName;
}
public String getFactoryName() { return factoryName; }
public void setFactoryName(String name) { this.factoryName = name; }
public String getProperties() { return properties; }
public void setProperties(String p) { this.properties = p; }
public String getRARDeployerName() { return rarDeployerName; }
public void setRARDeployerName(String rarDeployerName)
{
this.rarDeployerName = rarDeployerName;
}
public String getTransactionManagerName() { return tmName; }
public void setTransactionManagerName(String n) { tmName = n; }
// Pincipal mapping settings
public String getPrincipalMappingClass() { return princMapClass; }
public void setPrincipalMappingClass(String c) { princMapClass = c; }
public String getPrincipalMappingProperties() { return princMapProps; }
public void setPrincipalMappingProperties(String p) { princMapProps = p; }
// Object pool settings
public String getPoolStrategy() { return poolStrategy; }
public void setPoolStrategy(String strategy) { poolStrategy = strategy; }
public int getMinSize() { return minSize; }
public void setMinSize(int minSize) { this.minSize = minSize; }
public int getMaxSize() { return maxSize; }
public void setMaxSize(int maxSize) { this.maxSize = maxSize; }
public boolean getBlocking() { return blocking; }
public void setBlocking(boolean blocking) { this.blocking = blocking; }
public boolean getGCEnabled() { return gcEnabled; }
public void setGCEnabled(boolean gcEnabled) { this.gcEnabled = gcEnabled; }
public long getGCInterval() { return gcInterval; }
public void setGCInterval(long interval) { this.gcInterval = interval; }
public long getGCMinIdleTime() { return gcMinIdleTime; }
public void setGCMinIdleTime(long idleMillis) { gcMinIdleTime = idleMillis; }
public boolean getIdleTimeoutEnabled() { return idleTimeoutEnabled; }
public void setIdleTimeoutEnabled(boolean e) { idleTimeoutEnabled = e; }
public long getIdleTimeout() { return idleTimeout; }
public void setIdleTimeout(long idleMillis) { idleTimeout = idleMillis; }
public float getMaxIdleTimeoutPercent() { return maxIdleTimeoutPercent; }
public void setMaxIdleTimeoutPercent(float p) { maxIdleTimeoutPercent = p; }
public boolean getInvalidateOnError() { return invalidateOnError; }
public void setInvalidateOnError(boolean i) { invalidateOnError = i; }
public boolean getTimestampUsed() { return timestampUsed; }
public void setTimestampUsed(boolean tstamp) { timestampUsed = tstamp; }
// ServiceMBeanSupport overrides ---------------------------------
public String getName() { return "ConnectionFactoryLoader"; }
protected ObjectName getObjectName(MBeanServer server, ObjectName name)
{
this.server = server;
if (name == null)
{
String nameStr = OBJECT_NAME + ",name=" + factoryName;
try
{
name = new ObjectName(nameStr);
}
catch (MalformedObjectNameException mone)
{
log.error("The name '" + nameStr + "' is malformed");
log.exception(mone);
}
}
return name;
}
protected void initService() throws Exception
{
rarDeployerObjectName = new ObjectName(rarDeployerName);
server.addNotificationListener(rarDeployerObjectName, this,
new RAFilter(log), null);
log = Log.createLog(factoryName);
}
// NotificationListener implementation ---------------------------
public void handleNotification(Notification n, Object handback)
{
log.debug("Received notification '" + n + "'");
// We know that this is relevent to us because of the filter
String type = n.getType();
try
{
if (type.endsWith(DEPLOY_NOTIFICATION))
loadConnectionFactory((RARMetaData) n.getUserData());
else if (type.endsWith(UNDEPLOY_NOTIFICATION))
unloadConnectionFactory((RARMetaData) n.getUserData());
else
log.error("Unknown notification type: " + type);
}
catch (Exception e)
{
log.exception(e);
}
}
// ObjectFactory implementation ----------------------------------
public Object getObjectInstance(Object obj, Name name, Context nameCtx,
Hashtable environment)
{
// Return the connection factory with the requested name
Log.getLog().debug("ConnectionFactoryLoader.getObjectInstance, name = '" +
name + "'");
synchronized (cfs)
{
return cfs.get(name.toString());
}
}
// Package protected ---------------------------------------------
// Protected -----------------------------------------------------
// Private -------------------------------------------------------
/**
* Does the actual work of configuring a connection factory.
* Because this is invoked from a notification handler, it makes no
* sense to propagate exceptions, so we handle all checked
* exceptions in the body of this method.
*/
private void loadConnectionFactory(RARMetaData metaData)
{
// This context is used in a few places. There is no point
// continuing if JNDI isn't working.
Context ctx;
try
{
ctx = new InitialContext();
}
catch (NamingException ne)
{
log.error("Unable to obtain initial context");
log.exception(ne);
return;
}
// This is the class loader through which we should be able to
// load the resource adapter's classes
ClassLoader cl = metaData.getClassLoader();
// Create the ManagedConnectionFactory instance
Class mcfClass;
ManagedConnectionFactory mcf;
String mcfClassName = metaData.getManagedConnectionFactoryClass();
try
{
mcfClass = cl.loadClass(mcfClassName);
}
catch (ClassNotFoundException cnfe)
{
log.error("Unable to load managed connection factory class '" +
mcfClassName + "'");
log.exception(cnfe);
return;
}
try
{
mcf = (ManagedConnectionFactory) mcfClass.newInstance();
}
catch (Exception e)
{
log.error("Unable to instantiate manageed connection factory class '" +
mcfClass + "'");
log.exception(e);
return;
}
// Set the properties on it
Properties props = new Properties();
try
{
props.load(
new ByteArrayInputStream(properties.getBytes("ISO-8859-1")));
}
catch (IOException ioe)
{
// This shouldn't happen, so we try to carry on as if it didn't
log.error("Problem converting properties string '" + properties +
"' to Properties");
log.exception(ioe);
}
// the properties that the deployment descriptor says we need to
// set
Map ddProps = metaData.getProperties();
for (Iterator i=ddProps.values().iterator(); i.hasNext(); )
{
RARMetaData.Property ddProp = (RARMetaData.Property) i.next();
String value = (String) props.get(ddProp.name);
if (value == null )
{
if (ddProp.value == null)
{
log.warning("Not setting config property '" + ddProp.name + "'");
continue;
}
log.warning("Using default value '" + ddProp.value + "' for " +
"config property '" + ddProp.name + "'");
value = ddProp.value;
}
Class clazz;
Method setter;
try {
clazz = cl.loadClass(ddProp.type);
}
catch (ClassNotFoundException cnfe)
{
log.warning("Unable to find class '" + ddProp.type + "' for " +
"property '" + ddProp.name + "' - skipping property.");
continue;
}
PropertyEditor pe = PropertyEditorManager.findEditor(clazz);
if (pe == null)
{
log.warning("Unable to find a PropertyEditor for class '" +
clazz + "' of property '" + ddProp.name + "' - " +
"skipping property");
continue;
}
try
{
pe.setAsText(value);
}
catch (IllegalArgumentException iae)
{
log.warning("Value '" + value + "' is not valid for property '" +
ddProp.name + "' of class '" + clazz + "' - skipping " +
"property");
continue;
}
Object v = pe.getValue();
try
{
setter = mcfClass.getMethod("set" + ddProp.name,
new Class[] { clazz });
}
catch (NoSuchMethodException nsme)
{
log.warning("The class '" + mcfClass.toString() + "' has no " +
"setter for config property '" + ddProp.name + "'");
continue;
}
try
{
setter.invoke(mcf, new Object[] { v });
}
catch (Exception e)
{
log.warning("Unable to invoke setter method '" + setter + "' " +
"on object '" + mcf + "'");
log.exception(e);
}
}
// Give it somewhere to tell people things
PrintWriter logWriter = new LogWriter(log);
try
{
mcf.setLogWriter(logWriter);
}
catch (ResourceException re)
{
log.warning("Unable to set log writer '" + logWriter + "' on " +
"managed connection factory");
log.exception(re);
log.exception(re.getLinkedException());
}
// Find the transaction manager
TransactionManager tm = null;
try
{
tm = (TransactionManager) ctx.lookup(tmName);
}
catch (NamingException ne)
{
log.error("Unable to locate the transaction manager at '" + tmName +
"'");
log.exception(ne);
}
// Create the principal mapper
PrincipalMapping principalMapping;
try
{
principalMapping =
(PrincipalMapping) Class.forName(princMapClass).newInstance();
}
catch (Exception e)
{
log.error("Unable to instantiate principal mapping class '" +
princMapClass + "'");
log.exception(e);
return;
}
principalMapping.setLog(log);
principalMapping.setManagedConnectionFactory(mcf);
principalMapping.setRARMetaData(metaData);
principalMapping.setProperties(princMapProps);
// Create the connection manager
try
{
cm = new ConnectionManagerImpl(metaData, this, mcf, log, tm,
principalMapping);
}
catch (Exception e)
{
log.error("Unable to create connection manager");
log.exception(e);
return;
}
// Create us a connection factory
Object cf;
try
{
cf = mcf.createConnectionFactory(cm);
}
catch (ResourceException re)
{
log.error("Unable to create connection factory");
log.exception(re);
return;
}
// Bind it into JNDI
bindName = "java:/" + factoryName;
log.debug("Binding object '" + cf + "' into JNDI at '" + bindName + "'");
synchronized (cfs)
{
cfs.put(factoryName, cf);
}
((Referenceable) cf).setReference(new Reference(cf.getClass().getName(),
getClass().getName(),
null));
try
{
ctx.bind(bindName, cf);
log.log("Bound connection factory for resource adapter '" +
resourceAdapterName + "' to JNDI name '" + bindName + "'");
}
catch (NamingException ne)
{
log.error("Unable to bind connection factory to JNDI name '" +
bindName + "'");
log.exception(ne);
}
}
/**
* Does the actual work of tearing down a connection factory.
*/
private void unloadConnectionFactory(RARMetaData metaData)
{
// Destroy any managed connections
cm.shutdown();
cfs.remove(factoryName);
log.log("Connection factory '" + factoryName + "' shut down.");
// Unbind from JNDI
try
{
new InitialContext().unbind(bindName);
}
catch (NamingException ne)
{
log.error("Unable to unbind connection factory at JNDI location '" +
bindName + "'");
log.exception(ne);
}
}
// Inner classes -------------------------------------------------
private class RAFilter implements NotificationFilter
{
private Log log;
private RAFilter(Log log) { this.log = log; }
public boolean isNotificationEnabled(Notification n)
{
log.debug("Evaluating notification type='" + n.getType() + "', " +
"message='" + n.getMessage() + "'");
return
n.getType().startsWith(DEPLOYMENT_NOTIFICATION) &&
n.getMessage().equals(resourceAdapterName);
}
}
}
1.1
jboss/src/main/org/jboss/resource/ConnectionFactoryLoaderMBean.java
Index: ConnectionFactoryLoaderMBean.java
===================================================================
/*
* JBoss, the OpenSource EJB server
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.resource;
import org.jboss.util.ServiceMBean;
/**
* MBean that binds a connection factory for a deployed resource
* adapter using a specific configuration. Note that it is entirely
* possible that the resource adapter this refers to doesn't exist
* until later (i.e. until it is deployed). If so, we wait until the
* resource adapter deployer notifies us of the deployment.
*
* @see RARDeployer
* @author Toby Allsopp ([EMAIL PROTECTED])
* @version $Revision: 1.1 $
*/
public interface ConnectionFactoryLoaderMBean
extends ServiceMBean, ConnectionFactoryConfig
{
String OBJECT_NAME = ":service=ConnectionFactoryLoader";
String DEPLOYMENT_NOTIFICATION = "org.jboss.resource.deployment";
String DEPLOY_NOTIFICATION = ".deploy";
String UNDEPLOY_NOTIFICATION = ".undeploy";
/**
* The name of the resource adapter. This is the value from the
* <code>display-name</code> element in its deployment descriptor
* becase I can't see a better name to use.
*/
String getResourceAdapterName();
void setResourceAdapterName(String resourceAdapterName);
/**
* The name under which to bind this connection factory in
* JNDI. The name will be prepended with "java:/" to ensure that it
* is only visible in the local JVM.
*/
String getFactoryName();
void setFactoryName(String factoryName);
/**
* A string in a format parseable by {@link
* java.util.Properties#load} that defines the properties to set on
* the <code>ManagedConnectionFactory</code> for this connection
* factory instance.
*/
String getProperties();
void setProperties(String properties);
/**
* The name of the MBean responsible for deploying the resource
* adapter. This is so we can listen for notification of the
* resource adapter being deployed.
*/
String getRARDeployerName();
void setRARDeployerName(String rarDeployerName);
/**
* The name under which the transaction manager is bound in
* JNDI. This has a sensible default.
*/
String getTransactionManagerName();
void setTransactionManagerName(String transactionManagerName);
}
1.1 jboss/src/main/org/jboss/resource/ConnectionManagerImpl.java
Index: ConnectionManagerImpl.java
===================================================================
/*
* JBoss, the OpenSource EJB server
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.resource;
import java.security.Principal;
import java.util.HashMap;
import java.util.Map;
import javax.resource.ResourceException;
import javax.resource.spi.ApplicationServerInternalException;
import javax.resource.spi.ConnectionEvent;
import javax.resource.spi.ConnectionEventListener;
import javax.resource.spi.ConnectionManager;
import javax.resource.spi.ConnectionRequestInfo;
import javax.resource.spi.ManagedConnection;
import javax.resource.spi.ManagedConnectionFactory;
import javax.resource.spi.security.PasswordCredential;
import javax.security.auth.Subject;
import javax.transaction.RollbackException;
import javax.transaction.Status;
import javax.transaction.Synchronization;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import javax.transaction.xa.XAResource;
import org.jboss.logging.Log;
import org.jboss.minerva.pools.ObjectPool;
import org.jboss.minerva.pools.PoolObjectFactory;
import org.jboss.resource.pool.PoolStrategy;
import org.jboss.resource.pool.PoolStrategyFactory;
import org.jboss.resource.security.PrincipalMapping;
import org.jboss.security.SecurityAssociation;
/**
* Provides connection factories with a hook into the app server's
* "quality of services". There is one instance of this class for
* each connection factory and therefore for each managed connection
* factory instance.
*
* @see <related>
* @author Toby Allsopp ([EMAIL PROTECTED])
* @version $Revision: 1.1 $
*/
public class ConnectionManagerImpl
implements ConnectionManager, ConnectionEventListener
{
// Constants -----------------------------------------------------
// Attributes ----------------------------------------------------
private Log log;
private TransactionManager tm;
private ManagedConnectionFactory mcf;
private RARMetaData metadata;
private PrincipalMapping principalMapping;
private PoolStrategy poolStrategy;
/** Maps Transaction to ManagedConnection */
private Map tx2mc = new HashMap();
// Static --------------------------------------------------------
// Constructors --------------------------------------------------
ConnectionManagerImpl(RARMetaData metadata, ConnectionFactoryConfig cfConfig,
ManagedConnectionFactory mcf, Log log,
TransactionManager tm,
PrincipalMapping principalMapping)
throws SystemException
{
this.log = log;
this.metadata = metadata;
this.mcf = mcf;
poolStrategy = PoolStrategyFactory.getStrategy(metadata, cfConfig,
mcf, log);
//FIXME communicate pool settings to pool strategy, possibly
//through metadata
poolStrategy.setConnectionEventListener(this);
this.tm = tm;
this.principalMapping = principalMapping;
}
// Public --------------------------------------------------------
// ConnectionManager implementation ------------------------------
public Object allocateConnection(ManagedConnectionFactory mcf,
ConnectionRequestInfo cxRequestInfo)
throws ResourceException
{
if (!mcf.equals(this.mcf))
{
throw new ApplicationServerInternalException(
"allocateConnection called for a managed connection factory that" +
"is not the one this connection manager handles. this = '" + this +
"', this.mcf = '" + this.mcf + "', mcf = '" + mcf + "', " +
"cxRequestInfo = '" + cxRequestInfo + "'");
}
// Obtain a subject that identifies the resource principal and
// its credentials. There are two possibilities for passing the
// security information to the resource adapter:
// 1) Component-managed sign-on - in this case cxRequestInfo
// will contain the information that the resource adapter needs
// to sign onto the EIS and we will leave subject null
// 2) Container-managed sign-on - in this case cxRequestInfo is
// null and we will create a Subject identifying the resource
// principal and its credentials
Subject subject;
if (cxRequestInfo != null)
// component-managed sign-on
subject = null;
else
{
// container-managed sign-on
Principal callerPrincipal = SecurityAssociation.getPrincipal();
subject = principalMapping.createSubject(callerPrincipal);
}
// Find an appropriate managed connection
ManagedConnection mc;
// Figure out if we need to associate this managed connection
// with a transaction
try
{
Transaction tx = tm.getTransaction();
if (tx != null)
{
mc = (ManagedConnection) tx2mc.get(tx);
if (mc != null)
{
log.debug("Using connection '" + mc + "', which is already " +
"associated with transaction '" + tx + "'");
}
else
{
log.debug("Finding an unused managed connection to handle " +
"transaction '" + tx + "'");
mc = poolStrategy.getManagedConnection(subject, cxRequestInfo);
log.debug("Enlisting connection '" + mc + "' with transaction " +
"'" + tx + "'");
try
{
tx.enlistResource(mc.getXAResource());
tx2mc.put(tx, mc);
TransactionSynchronization synch =
new TransactionSynchronization(tx, mc);
tx.registerSynchronization(synch);
}
catch (RollbackException rbe)
{
// Oops! The transaction has been marked for
// rollback. We can't give out a connection not
// enlisted in any transaction, so we must throw an
// exception.
log.debug(rbe);
// Don't forget to put the connection back in the
// pool! The connection must have just come from the
// pool because otherwise we wouldn't be trying to
// enlist it.
log.debug("The current transaction is marked for rollback, " +
"returning connection '" + mc + "' to its pool");
try
{
poolStrategy.releaseManagedConnection(mc);
}
catch (ResourceException re)
{
log.exception(re);
}
ResourceException re =
new ResourceException("Transaction marked for rollback");
re.setLinkedException(rbe);
throw re;
}
}
}
else
{
mc = poolStrategy.getManagedConnection(subject, cxRequestInfo);
log.debug("Not enlisting connection '" + mc + "' with a " +
"transaction");
}
}
catch (SystemException se)
{
log.debug(se);
ApplicationServerInternalException asie =
new ApplicationServerInternalException("Transaction manager FUBAR");
asie.setLinkedException(se);
throw asie;
}
// Return an application-level connection handle
return mc.getConnection(subject, cxRequestInfo);
}
// ConnectionEventListener implementation ------------------------
public void connectionClosed(ConnectionEvent event)
{
ManagedConnection mc = (ManagedConnection) event.getSource();
log.debug("connectionClosed for connection '" + mc + "'");
try
{
Transaction tx = tm.getTransaction();
if (tx != null)
{
// Sanity checks
ManagedConnection txmc = (ManagedConnection) tx2mc.get(tx);
if (txmc == null)
{
log.error("The connection '" + mc + "' has been closed in the " +
"context of transaction '" + tx + "' but I have no " +
"record of a connection being enlisted with that " +
"transaction. Bad");
//FIXME what action to take?
}
else if (!txmc.equals(mc))
{
log.error("Connection '" + mc + "' has been closed in the " +
"context of transaction '" + tx + "' but " +
"connection '" + txmc + "' was enlisted in that " +
"transaction. Bad!");
//FIXME what action to take?
}
// The connection will be returned to the pool when the
// transaction completes. See TransactionSynchronization.
/* delisting will only work right with a full-on
XA-compliant resource adapter. I have none to test
with.
// We delist the connection's resource from the transaction (if
// there is one) and return it to the pool so that it can be
// used for other transactions or further work on this
// transaction
log.debug("delisting connection '" + mc + "' from transaction '" +
tx + "'");
try
{
XAResource res = mc.getXAResource();
tx.delistResource(res, XAResource.TMSUCCESS);
}
catch (ResourceException re)
{
log.warning("Unable to get XAResource from managed connection");
log.exception(re);
}
*/
}
else
{
log.debug("Connection '" + mc + "' not participating in a " +
"transaction, returning it to its pool");
try
{
poolStrategy.releaseManagedConnection(mc);
}
catch (ResourceException re)
{
log.exception(re);
}
}
}
catch (SystemException se)
{
log.error("Transaction manager FUBAR");
log.exception(se);
}
}
public void connectionErrorOccurred(ConnectionEvent event)
{
ManagedConnection mc = (ManagedConnection) event.getSource();
log.debug("connectionErrorOccurred for connection '" + mc + "', " +
"exception is '" + event.getException() + "'");
try
{
Transaction tx = tm.getTransaction();
if (tx != null)
{
// Sanity checks
ManagedConnection txmc = (ManagedConnection) tx2mc.get(tx);
if (txmc == null)
{
log.error("An error has occurred for the connection '" + mc +
"' in the context of transaction '" + tx + "' but " +
"I have no record of a connection being enlisted " +
"with that transaction. Bad!");
//FIXME what action to take?
}
else if (!txmc.equals(mc))
{
log.error("An error has occurred for the connection '" + mc +
"' in the context of transaction '" + tx + "' but " +
"connection '" + txmc + "' was enlisted in that " +
"transaction. Bad!");
//FIXME what action to take?
}
try
{
// The managed connection will be destroyed by the pool
// when it is returned at the completion of the
// transaction.
poolStrategy.condemnManagedConnection(mc);
}
catch (ResourceException re)
{
log.exception(re);
}
/* delisting will only work right with a full-on
XA-compliant resource adapter. I have none to test
with.
// We delist the connection's resource from the transaction (if
// there is one) and tell the transaction manager that the unit
// of work has failed, which should mean that the transaction is
// marked for rollback
log.debug("Delisting connection '" + mc + "' from transaction " +
tx + "'");
try
{
XAResource res = mc.getXAResource();
tx.delistResource(res, XAResource.TMFAIL);
}
catch (ResourceException re)
{
log.warning("Unable to get XAResource from managed connection");
log.exception(re);
}
log.debug("Destroying connection '" + mc + "'");
try
{
poolStrategy.destroyManagedConnection(mc);
}
catch (ResourceException re)
{
log.exception(re);
}
*/
}
else
{
log.debug("Connection '" + mc + "' not participating in a " +
"transaction, destroying immediately");
try
{
poolStrategy.condemnManagedConnection(mc);
poolStrategy.releaseManagedConnection(mc);
}
catch (ResourceException re)
{
log.exception(re);
}
}
}
catch (SystemException se)
{
log.error("Transaction manager FUBAR");
log.exception(se);
}
}
// We don't handle local transactions at the moment.
public void localTransactionStarted(ConnectionEvent event)
{
log.error("Local transaction optimisation not implemented");
log.exception(new Exception());
}
public void localTransactionCommitted(ConnectionEvent event)
{
log.error("Local transaction optimisation not implemented");
log.exception(new Exception());
}
public void localTransactionRolledback(ConnectionEvent event)
{
log.error("Local transaction optimisation not implemented");
log.exception(new Exception());
}
// Package protected ---------------------------------------------
void shutdown()
{
// Empty the pool(s)
poolStrategy.shutdown();
}
// Protected -----------------------------------------------------
// Private -------------------------------------------------------
// Inner classes -------------------------------------------------
/**
* An instance of this class is registered as a synchronisation
* whenever a connection is given out as part of a transaction.
*/
private class TransactionSynchronization
implements Synchronization
{
// Attributes -------------------------------------------------
private Transaction tx;
private ManagedConnection mc;
// Constructors -----------------------------------------------
private TransactionSynchronization(Transaction tx, ManagedConnection mc)
{
this.tx = tx;
this.mc = mc;
}
// Synchronization implementation -----------------------------
public void afterCompletion(int status)
{
log.debug("afterCompletion for connection '" + mc + "', transaction " +
"'" + tx + ", status = " + statusName(status));
// Remove the association between this transaction and
// managed connection
ManagedConnection txmc = (ManagedConnection) tx2mc.remove(tx);
// Sanity check
if (txmc == null || !txmc.equals(mc))
{
log.error("Inconsistent transaction assocation: this.tx = '" + tx +
"', this.mc = '" + mc + "', tx2mc(tx) = '" + txmc + "'");
//FIXME what action to take?
}
log.debug("Returning connection '" + mc + "' to its pool");
try
{
poolStrategy.releaseManagedConnection(mc);
}
catch (ResourceException re)
{
log.exception(re);
}
}
public void beforeCompletion() { }
// Private ----------------------------------------------------
private final String statusName(int s)
{
switch (s) {
case Status.STATUS_ACTIVE: return "STATUS_ACTIVE";
case Status.STATUS_COMMITTED: return "STATUS_COMMITED";
case Status.STATUS_COMMITTING: return "STATUS_COMMITTING";
case Status.STATUS_MARKED_ROLLBACK: return "STATUS_MARKED_ROLLBACK";
case Status.STATUS_NO_TRANSACTION: return "STATUS_NO_TRANSACTION";
case Status.STATUS_PREPARED: return "STATUS_PREPARED";
case Status.STATUS_PREPARING: return "STATUS_PREPARING";
case Status.STATUS_ROLLEDBACK: return "STATUS_ROLLEDBACK";
case Status.STATUS_ROLLING_BACK: return "STATUS_ROLLING_BACK";
case Status.STATUS_UNKNOWN: return "STATUS_UNKNOWN";
}
return "REALLY_UNKNOWN";
}
}
}
1.1 jboss/src/main/org/jboss/resource/RARDeployer.java
Index: RARDeployer.java
===================================================================
/*
* JBoss, the OpenSource EJB server
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.resource;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.JarURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import javax.management.Notification;
import org.jboss.configuration.ConfigurationServiceMBean;
import org.jboss.deployment.DeployerMBeanSupport;
import org.jboss.deployment.DeploymentException;
import org.jboss.logging.Log;
import org.jboss.metadata.XmlFileLoader;
import org.jboss.util.MBeanProxy;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* Service that deploys ".rar" files containing resource
* adapters. Deploying the RAR file is the first step in making the
* resource adapter available to application components; once it is
* deployed, one or more connection factories must be configured and
* bound into JNDI, a task performed by the
* <code>ConnectionFactoryLoader</code> service.
*
* @author Toby Allsopp ([EMAIL PROTECTED])
* @version $Revision: 1.1 $
*
* @see org.jboss.resource.ConnectionFactoryLoader
*/
public class RARDeployer
extends DeployerMBeanSupport
implements RARDeployerMBean
{
// Constants -----------------------------------------------------
// Attributes ----------------------------------------------------
/** The directory that will contain local copies of deployed RARs */
private File rarTmpDir;
/** The next sequence number to be used in notifications about
(un)deployment */
private int nextMessageNum = 0;
// Static --------------------------------------------------------
// Constructors --------------------------------------------------
// Public --------------------------------------------------------
// RARDeployerMBean implementation -------------------------------
// DeployerMBeanSupport overrides ---------------------------------
public String getName() { return "RARDeployer"; }
public void initService() throws Exception
{
// find the temp directory - it contains the file
// "tmp.properties"
URL tmpPropURL = getClass().getResource("/tmp.properties");
File tmpDir = new File(tmpPropURL.getFile()).getParentFile();
// Create our temp directory
File deployTmpDir = new File(tmpDir, "deploy");
rarTmpDir = new File(deployTmpDir, getName());
if (rarTmpDir.exists())
{
log.log("Found a temp directory left over from a previous run - " +
"deleting it.");
// What could it mean?
if (!recursiveDelete(rarTmpDir))
{
log.warning("Unable to recursively delete temp directory '" +
rarTmpDir + "' that appears to be left over from " +
"the previous run. This might cause problems.");
}
}
if (!rarTmpDir.exists() && !rarTmpDir.mkdir())
{
throw new DeploymentException("Can't create temp directory '" +
rarTmpDir + "'");
}
}
public void destroyService()
{
// Remove our temp directory
if (!recursiveDelete(rarTmpDir))
{
log.warning("Unable to recursively delete the temp directory '" +
rarTmpDir + "' - it should be cleaned up when the " +
"server is next restarted.");
}
}
protected Object deploy(URL url) throws IOException, DeploymentException
{
log.log("Attempting to deploy RAR at '" + url + "'");
// We want to take a local copy of the RAR so that we don't run
// into problems if the original is removed/replaced. We also
// need the RAR in unpacked form so that we can get at the
// included JARs for classloading (I don't think URLClassLoader
// deals with JARs within JARs).
File unpackedDir = new File(rarTmpDir, generateUniqueDirName(url));
if (unpackedDir.exists())
{
throw new DeploymentException("The application at URL '" + url + "' " +
"appears to already have been " +
"deployed because the directory '" +
unpackedDir + "' exists");
}
unpackedDir.mkdirs();
if (url.getFile().endsWith("/"))
{
// this is a directory - we can only deal with directories in
// the local filesystem (because we can't get a list of files
// from a general URL)
if (!url.getProtocol().equals("file"))
throw new DeploymentException("Can only deploy directories " +
"specified by 'file:' URLs");
copyDirectory(new File(url.getFile()), unpackedDir);
}
else
{
// this is a .rar file somewhere
inflateJar(url, unpackedDir);
}
// Right, now we can forget about URLs and just use the file
// system.
File ddFile = new File(unpackedDir, "META-INF/ra.xml");
if (!ddFile.exists())
{
throw new DeploymentException("No deployment descriptor " +
"('META-INF/ra.xml') found in alleged " +
"resource adapter at '" + url + "'");
}
Document dd;
try
{
dd = XmlFileLoader.getDocument(ddFile.toURL());
}
catch (org.jboss.ejb.DeploymentException de)
{
throw new DeploymentException(de.getMessage(), de.getCause());
}
Element root = dd.getDocumentElement();
RARMetaData metadata = new RARMetaData();
Log.setLog(log);
try
{
metadata.importXml(root);
}
finally
{
Log.unsetLog();
}
// Create a class loader that can load classes from any JARs
// inside the RAR
// First, we need to find the JARs. The procedure for this
// depends on whether the URL points to a RAR file or a
// directory.
Collection jars = new ArrayList();
FileFilter filter = new FileFilter()
{
public boolean accept(File file)
{
return file.getName().endsWith(".jar");
}
};
Collection jarFiles = recursiveFind(unpackedDir, filter);
for (Iterator i = jarFiles.iterator(); i.hasNext(); )
{
File file = (File) i.next();
jars.add(file.toURL());
}
log.debug("Adding the following URLs to classpath:");
for (Iterator i = jars.iterator(); i.hasNext(); )
log.debug(((URL) i.next()).toString());
// Ok, now we have the URLs of the JARs contained in the RAR we
// can create a classloader that loads classes from them
ClassLoader cl = new URLClassLoader(
(URL[]) jars.toArray(new URL[0]),
Thread.currentThread().getContextClassLoader());
metadata.setClassLoader(cl);
// Look for a META-INF/ra-jboss.xml file that defines connection
// factories. My current idea is that this can define connection
// factory loaders in exactly the same way as jboss.jcml.
/* not quite implemented yet
File jbossDDFile = new File(unpackedDir, "META-INF/ra-jboss.xml");
if (jbossDDFile.exists())
{
log.log("Loading JBoss deployment descriptor at '" + jbossDDFile +
"'");
try
{
Document jbossDD = XmlFileLoader.getDocument(jbossDDFile.toURL());
ConfigurationServiceMBean cs = (ConfigurationServiceMBean)
MBeanProxy.create(ConfigurationServiceMBean.class,
ConfigurationServiceMBean.OBJECT_NAME);
cs.load(jbossDD);
//FIXME need to get reference to newly created MBean so we
//can (a) call init and start on it and (b) destroy it
//when this RAR is undeployed
}
catch (Exception e)
{
log.warning("Problem occurred while loading '" + jbossDDFile + "'");
log.exception(e);
}
}
*/
// Let's tell the waiting hordes (of connection factory loaders)
// that this resource adapter is available
Notification notification = new Notification(
ConnectionFactoryLoaderMBean.DEPLOYMENT_NOTIFICATION +
ConnectionFactoryLoaderMBean.DEPLOY_NOTIFICATION, this,
nextMessageNum++, metadata.getDisplayName());
notification.setUserData(metadata);
sendNotification(notification);
DeploymentInfo info = new DeploymentInfo();
info.metadata = metadata;
info.unpackedDir = unpackedDir;
return info;
}
protected void undeploy(URL url, Object o) throws DeploymentException
{
log.log("Undeploying RAR at '" + url + "'");
DeploymentInfo info = (DeploymentInfo) o;
if (info == null)
{
throw new DeploymentException("There doesn't appear to be a RAR " +
"deployed at '" + url + "'");
}
// Tell the waiting hordes (of connection factory loaders)
// that this resource adapter is no longer available
RARMetaData metadata = info.metadata;
Notification notification = new Notification(
ConnectionFactoryLoaderMBean.DEPLOYMENT_NOTIFICATION +
ConnectionFactoryLoaderMBean.UNDEPLOY_NOTIFICATION, this,
nextMessageNum++, metadata.getDisplayName());
sendNotification(notification);
// Remove the temporary copy
File unpackedDir = info.unpackedDir;
if (!recursiveDelete(unpackedDir))
{
log.warning("Unable to recursively delete temp directory '" +
unpackedDir + "' - this should be cleaned up either " +
"when the server is shut down or when it restarts.");
}
}
// Package protected ---------------------------------------------
// Protected -----------------------------------------------------
// Private -------------------------------------------------------
private static int nextNum = 0;
private static String generateUniqueDirName(URL u)
{
int thisNum = nextNum++;
return "rar." + thisNum;
}
private Collection recursiveFind(File dir, FileFilter filter)
{
Collection files = new ArrayList();
File[] candidates = dir.listFiles();
if (candidates == null) return null;
for (int i = 0; i < candidates.length; ++i)
{
File candidate = candidates[i];
if (candidate.isDirectory())
files.addAll(recursiveFind(candidate, filter));
else if (filter.accept(candidate))
files.add(candidate);
}
return files;
}
private void copyDirectory(File srcDir, File destDir)
throws DeploymentException, IOException
{
File[] files = srcDir.listFiles();
if (files == null) throw new DeploymentException("Not a directory: '" +
srcDir + "'");
destDir.mkdirs();
for (int i = 0; i < files.length; ++i)
{
File file = files[i];
File dest = new File(destDir, file.getName());
if (file.isDirectory())
copyDirectory(file, dest);
else
copyFile(file, dest);
}
}
private void copyFile(File src, File dest)
throws IOException
{
InputStream in = new FileInputStream(src);
try
{
OutputStream out = new FileOutputStream(dest);
try
{
copy(in, out);
}
finally
{
out.close();
}
}
finally
{
in.close();
}
}
private void inflateJar(URL url, File destDir)
throws DeploymentException, IOException
{
URL jarUrl;
try
{
jarUrl = new URL("jar:" + url.toString() + "!/");
}
catch (MalformedURLException mfue)
{
throw new DeploymentException("Oops! Couldn't convert URL to a " +
"jar URL", mfue);
}
JarURLConnection jarConnection =
(JarURLConnection) jarUrl.openConnection();
JarFile jarFile = jarConnection.getJarFile();
for (Enumeration e = jarFile.entries(); e.hasMoreElements(); )
{
JarEntry entry = (JarEntry) e.nextElement();
String name = entry.getName();
File outFile = new File(destDir, name);
if (entry.isDirectory())
{
outFile.mkdirs();
}
else
{
InputStream in = jarFile.getInputStream(entry);
try
{
OutputStream out = new FileOutputStream(outFile);
try
{
copy(in, out);
}
finally
{
out.close();
}
}
finally
{
in.close();
}
}
}
jarFile.close();
}
private void copy(InputStream in, OutputStream out) throws IOException
{
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) > 0)
{
out.write(buffer, 0, read);
}
}
private boolean recursiveDelete(File f)
{
if (f.isDirectory())
{
File[] files = f.listFiles();
for (int i=0; i<files.length; ++i)
{
if (!recursiveDelete(files[i])) return false;
}
}
return f.delete();
}
// Inner classes -------------------------------------------------
private static class DeploymentInfo
{
public RARMetaData metadata;
public File unpackedDir;
}
}
1.1 jboss/src/main/org/jboss/resource/RARDeployerMBean.java
Index: RARDeployerMBean.java
===================================================================
/*
* JBoss, the OpenSource EJB server
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.resource;
import org.jboss.deployment.DeployerMBean;
/**
* <description>
*
* @see <related>
* @author Toby Allsopp ([EMAIL PROTECTED])
* @version $Revision: 1.1 $
*/
public interface RARDeployerMBean
extends DeployerMBean
{
// Constants -----------------------------------------------------
String OBJECT_NAME = ":service=RARDeployer";
// Public --------------------------------------------------------
// public RARMetaData getMetaData(String resourceAdapterName);
}
1.1 jboss/src/main/org/jboss/resource/RARMetaData.java
Index: RARMetaData.java
===================================================================
/*
* JBoss, the OpenSource EJB server
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.resource;
import java.lang.StringBuffer;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import org.jboss.deployment.DeploymentException;
import org.jboss.logging.Log;
import org.jboss.metadata.MetaData;
import org.jboss.metadata.XmlLoadable;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* Represents the metadata present in a resource adapter deployment
* descriptor.
*
* @see RARDeployer
* @author Toby Allsopp ([EMAIL PROTECTED])
* @version $Revision: 1.1 $
*/
public class RARMetaData
// extends Y
implements XmlLoadable
{
// Constants -----------------------------------------------------
// Attributes ----------------------------------------------------
private Log log;
private ClassLoader classLoader;
private String displayName;
private String managedConnectionFactoryClass;
private String connectionFactoryInterface;
private String connectionFactoryImplClass;
private String connectionInterface;
private String connectionImplClass;
private int transactionSupport;
public static final int TX_SUPPORT_NO = 0;
public static final int TX_SUPPORT_LOCAL = 1;
public static final int TX_SUPPORT_XA = 2;
private Map properties = new HashMap();
private String authMechType;
private String credentialInterface;
private boolean reauthenticationSupport;
// Static --------------------------------------------------------
// Constructors --------------------------------------------------
// Public --------------------------------------------------------
/**
* The class loader to use for the resource adapter's classes
*/
public ClassLoader getClassLoader() { return classLoader; }
public void setClassLoader(ClassLoader cl) { classLoader = cl; }
public String getDisplayName() { return displayName; }
public String getManagedConnectionFactoryClass()
{
return managedConnectionFactoryClass;
}
/**
* Gets the type of transactions supported by the resource adapter.
*
* @return one of the <code>TX_SUPPORT_*</code> constants
*/
public int getTransactionSupport() { return transactionSupport; }
public Map getProperties() { return properties; }
public String getPropertyType(String name)
{
Property prop = (Property) properties.get(name);
return (prop==null) ? null : prop.type;
}
public String getAuthMechType() { return authMechType; }
public boolean getReauthenticationSupport()
{
return reauthenticationSupport;
}
// XmlLoadable implementation ------------------------------------
public void importXml(Element root) throws DeploymentException
{
log = Log.getLog();
// First, a quick sanity check to ensure that we're looking at
// the right kind of deployment descriptor
String rootTag = root.getTagName();
if (! rootTag.equals("connector"))
{
throw new DeploymentException("Not a resrouce adapter deployment " +
"descriptor because its root tag, '" +
rootTag + "', is not 'connector'");
}
// Then, we iterate over all the elements seeing if we're
// interested
invokeChildren(root);
}
// Y overrides ---------------------------------------------------
// Package protected ---------------------------------------------
// Protected -----------------------------------------------------
// Private -------------------------------------------------------
private void invokeChildren(Element element) throws DeploymentException
{
NodeList children = element.getChildNodes();
for (int i=0; i<children.getLength(); ++i)
{
Node node = children.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE)
{
Element child = (Element) node;
Method method = elementToMethod(child);
if (method == null)
{
// We don't handle this element. Hope it wasn't
// important.
log.warning("Element '" + child + "' not recognised.");
continue;
}
try
{
method.invoke(this, new Object[] { child });
}
catch (InvocationTargetException ite)
{
Throwable t = ite.getTargetException();
if (t instanceof DeploymentException)
throw (DeploymentException) t;
if (t instanceof Exception)
throw new DeploymentException("Exception handling element",
(Exception) t);
if (t instanceof Error) throw (Error) t;
throw new DeploymentException("WTF?: " + t.toString());
}
catch (Exception e)
{
throw new DeploymentException("Exception handling element", e);
}
}
}
}
private Method elementToMethod(Element element)
{
String tag = element.getTagName();
StringBuffer methodName = new StringBuffer("set");
// We can't be having hyphens in our method names
//FIXME this should weed out illegal characters in general
{
int last_hyphen = -1;
int next_hyphen;
while ((next_hyphen = tag.indexOf('-', last_hyphen+1)) != -1)
{
String thisbit = tag.substring(last_hyphen+1, next_hyphen);
methodName.append(toTitleCase(thisbit));
last_hyphen = next_hyphen;
}
methodName.append(toTitleCase(tag.substring(last_hyphen+1)));
}
log.debug("methodName = '" + methodName + "'");
try
{
return getClass().getDeclaredMethod(methodName.toString(),
new Class[] { Element.class });
}
catch (NoSuchMethodException nsme)
{
return null;
}
}
private String toTitleCase(String s)
{
if (s == null) return null;
if (s.length() == 0) return s.toUpperCase();
return s.substring(0, 1).toUpperCase() + s.substring(1);
}
private String getElementContent(Element element) throws DeploymentException
{
try
{
return MetaData.getElementContent(element);
}
catch (org.jboss.ejb.DeploymentException de)
{
throw new DeploymentException(de.getMessage(), de.getCause());
}
}
// Setter methods for XML elements
private void setDisplayName(Element element)
throws DeploymentException
{
displayName = getElementContent(element);
}
private void setVendorName(Element element) {}
private void setSpecVersion(Element element) {}
private void setVersion(Element element) {}
private void setEisType(Element element) {}
private void setResourceadapter(Element element) throws DeploymentException
{
invokeChildren(element);
}
private void setManagedconnectionfactoryClass(Element element)
throws DeploymentException
{
managedConnectionFactoryClass = getElementContent(element);
}
private void setConnectionfactoryInterface(Element element)
throws DeploymentException
{
connectionFactoryInterface = getElementContent(element);
}
private void setConnectionfactoryImplClass(Element element)
throws DeploymentException
{
connectionFactoryImplClass = getElementContent(element);
}
private void setConnectionInterface(Element element)
throws DeploymentException
{
connectionInterface = getElementContent(element);
}
private void setConnectionImplClass(Element element)
throws DeploymentException
{
connectionImplClass = getElementContent(element);
}
private void setTransactionSupport(Element element)
throws DeploymentException
{
String s = getElementContent(element);
int ts;
if (s.equals("no_transaction" )) ts = TX_SUPPORT_NO;
else if (s.equals("local_transaction")) ts = TX_SUPPORT_LOCAL;
else if (s.equals("xa_transaction" )) ts = TX_SUPPORT_XA;
else
throw new DeploymentException("Invalid transaction support '" +
s + "', it must be one of " +
"'no_transaction', " +
"'local_transaction' or " +
"'xa_transaction'");
transactionSupport = ts;
}
private void setConfigProperty(Element element)
throws DeploymentException
{
try
{
Element nameE= MetaData.getUniqueChild(element,
"config-property-name");
Element typeE= MetaData.getUniqueChild(element,
"config-property-type");
Element valueE= MetaData.getUniqueChild(element,
"config-property-value");
Property p = new Property();
p.name = getElementContent(nameE);
p.type = getElementContent(typeE);
p.value = getElementContent(valueE);
properties.put(p.name, p);
}
catch (org.jboss.ejb.DeploymentException de)
{
throw new DeploymentException(de.getMessage(), de.getCause());
}
}
private void setAuthMechanism(Element element) throws DeploymentException
{
invokeChildren(element);
}
private void setAuthMechType(Element element) throws DeploymentException
{
authMechType = getElementContent(element);
}
private void setCredentialInterface(Element element)
throws DeploymentException
{
credentialInterface = getElementContent(element);
}
private void setReauthenticationSupport(Element element)
throws DeploymentException
{
String value = getElementContent(element);
if (!value.equals("true") && !value.equals("false"))
throw new DeploymentException("reauthentication-support must be one " +
"of 'true' or 'false', not '" + value +
"'");
reauthenticationSupport = Boolean.valueOf(value).booleanValue();
}
// Inner classes -------------------------------------------------
public class Property
{
public String name;
public String type;
public String value;
}
}