| RARDeployment.java |
/*
* JBoss, the OpenSource J2EE webOS
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*
*/
package org.jboss.resource.connectionmanager;
import java.beans.PropertyEditor;
import java.beans.PropertyEditorManager;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Iterator;
import javax.management.Notification;
import javax.management.ObjectName;
import javax.resource.ResourceException;
import javax.resource.spi.ConnectionManager;
import javax.resource.spi.ConnectionRequestInfo;
import javax.resource.spi.ManagedConnection;
import javax.resource.spi.ManagedConnectionFactory;
import javax.resource.spi.ResourceAdapter;
import javax.resource.spi.ResourceAdapterAssociation;
import org.jboss.deployment.DeploymentException;
import org.jboss.logging.Logger;
import org.jboss.metadata.MetaData;
import org.jboss.resource.metadata.ConfigPropertyMetaData;
import org.jboss.resource.metadata.ConnectionDefinitionMetaData;
import org.jboss.resource.metadata.ConnectorMetaData;
import org.jboss.system.ServiceMBeanSupport;
import org.jboss.util.Classes;
import org.jboss.util.StringPropertyReplacer;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* The RARDeployment mbean manages instantiation and configuration of a
* ManagedConnectionFactory instance. It is intended to be configured
* primarily by xslt transformation of the ra.xml from a jca adapter.
* Until that is implemented, it uses the old RARDeployment and RARDeployer
* mechanism to obtain information from the ra.xml. Properties for the
* ManagedConectionFactory should be supplied with their values in the
* ManagedConnectionFactoryProperties element.
*
* @author <a href="toby.allsopp@peace.com">Toby Allsopp</a>
* @author <a href="mailto:d_jencks@users.sourceforge.net">David Jencks</a>
* @version $Revision: 1.25.6.5 $
* @jmx:mbean name="jboss.jca:service=RARDeployment"
* extends="org.jboss.system.ServiceMBean, javax.resource.spi.ManagedConnectionFactory"
*/
public class RARDeployment extends ServiceMBeanSupport
implements RARDeploymentMBean, ManagedConnectionFactory
{
static final long serialVersionUID = -294341806721616790L;
public final static String MCF_ATTRIBUTE_CHANGED_NOTIFICATION = "jboss.mcfattributechangednotification";
private Logger log = Logger.getLogger(getClass());
//Hack to use previous ra.xml parsing code until xslt deployment is written.
private ObjectName oldRarDeployment;
private String rarName;
private String connectionDefinition;
private String vendorName;
private String specVersion;
private String eisType;
private String version;
private String managedConnectionFactoryClass;
private String connectionFactoryInterface;
private String connectionFactoryImplClass;
private String connectionInterface;
private String connectionImplClass;
private String transactionSupport;
private Element managedConnectionFactoryProperties;
private String authenticationMechanismType;
private String credentialInterface;
private boolean reauthenticationSupport;
private Class mcfClass;
private ManagedConnectionFactory mcf;
/**
* Default managed constructor for RARDeployment mbeans.
*
* @jmx.managed-constructor
*/
public RARDeployment()
{
}
/**
* The OldRarDeployment attribute refers to a previous-generation RARDeployment.
* THIS IS A HACK UNTIL XSLT DEPLOYMENT IS WRITTEN
*
* @return value of OldRarDeployment
*
* @jmx:managed-attribute
* @todo remove this when xslt based deployment is written.
*/
public ObjectName getOldRarDeployment()
{
return oldRarDeployment;
}
/**
* Set the value of OldRarDeployment
* @param oldRarDeployment - Value to assign to OldRarDeployment
*
* @jmx:managed-attribute
* @todo remove this when xslt based deployment is written.
*/
public void setOldRarDeployment(final ObjectName oldRarDeployment)
{
this.oldRarDeployment = oldRarDeployment;
}
/**
* The RARName attribute holds the file name of the rar
*
* @return the rar name value.
* @jmx:managed-attribute
*/
public String getRARName()
{
return rarName;
}
/**
* Set the RARName value.
*
* @param rarName The new DisplayName value.
* @jmx:managed-attribute
*/
public void setRARName(String rarName)
{
this.rarName = rarName;
}
/**
* The connection definition inside the rar,
* it identifies the unique connection factory
*
* @return the rar name value.
* @jmx:managed-attribute
*/
public String getConnectionDefinition()
{
return connectionDefinition;
}
/**
* Set the connection definition.
*
* @param connectionDefinition - the connection definition
* @jmx:managed-attribute
*/
public void setConnectionDefinition(String connectionDefinition)
{
this.connectionDefinition = connectionDefinition;
}
/**
* The VendorName attribute holds the VendorName from the ra.xml
* It should be supplied by xslt from ra.xml
*
* @return the VendorName value.
* @jmx:managed-attribute
*/
public String getVendorName()
{
return vendorName;
}
/**
* Set the VendorName value.
* @param vendorName The new VendorName value.
* @jmx:managed-attribute
*/
public void setVendorName(String vendorName)
{
this.vendorName = vendorName;
}
/**
* The SpecVersion attribute holds the SpecVersion from the ra.xml
* It should be supplied by xslt from ra.xml
*
* @return the SpecVersion value.
* @jmx:managed-attribute
*/
public String getSpecVersion()
{
return specVersion;
}
/**
* Set the SpecVersion value.
* @param specVersion The new SpecVersion value.
* @jmx:managed-attribute
*/
public void setSpecVersion(String specVersion)
{
this.specVersion = specVersion;
}
/**
* The EisType attribute holds the EisType from the ra.xml.
* It should be supplied by xslt from ra.xml
*
* @return the EisType value.
* @jmx:managed-attribute
*/
public String getEisType()
{
return eisType;
}
/**
* Set the EisType value.
* @param eisType The new EisType value.
* @jmx:managed-attribute
*/
public void setEisType(String eisType)
{
this.eisType = eisType;
}
/**
* The Version attribute holds the Version from the ra.xml.
* It should be supplied by xslt from ra.xml
*
* @return the Version value.
* @jmx:managed-attribute
*/
public String getVersion()
{
return version;
}
/**
* Set the Version value.
* @param version The new Version value.
* @jmx:managed-attribute
*/
public void setVersion(String version)
{
this.version = version;
}
/**
* The ManagedConnectionFactoryClass attribute holds the ManagedConnectionFactoryClass from the ra.xml.
* It should be supplied by xslt from ra.xml
*
* @return the ManagedConnectionFactoryClass value.
* @jmx:managed-attribute
*/
public String getManagedConnectionFactoryClass()
{
return managedConnectionFactoryClass;
}
/**
* Set the ManagedConnectionFactoryClass value.
* @param managedConnectionFactoryClass The new ManagedConnectionFactoryClass value.
* @jmx:managed-attribute
*/
public void setManagedConnectionFactoryClass(final String managedConnectionFactoryClass)
{
this.managedConnectionFactoryClass = managedConnectionFactoryClass;
}
/**
* The ConnectionFactoryInterface attribute holds the ConnectionFactoryInterface from the ra.xml.
* It should be supplied by xslt from ra.xml
*
* @return the ConnectionFactoryInterface value.
* @jmx:managed-attribute
*/
public String getConnectionFactoryInterface()
{
return connectionFactoryInterface;
}
/**
* Set the ConnectionFactoryInterface value.
* @param connectionFactoryInterface The ConnectionFactoryInterface value.
* @jmx:managed-attribute
*/
public void setConnectionFactoryInterface(String connectionFactoryInterface)
{
this.connectionFactoryInterface = connectionFactoryInterface;
}
/**
* The ConnectionFactoryImplClass attribute holds the ConnectionFactoryImplClass from the ra.xml.
* It should be supplied by xslt from ra.xml
*
* @return the ConnectionFactoryImplClass value.
* @jmx:managed-attribute
*/
public String getConnectionFactoryImplClass()
{
return connectionFactoryImplClass;
}
/**
* Set the ConnectionFactoryImplClass value.
* @param connectionFactoryImplClass The ConnectionFactoryImplClass value.
* @jmx:managed-attribute
*/
public void setConnectionFactoryImplClass(String connectionFactoryImplClass)
{
this.connectionFactoryImplClass = connectionFactoryImplClass;
}
/**
* The ConnectionInterface attribute holds the ConnectionInterface from the ra.xml.
* It should be supplied by xslt from ra.xml
*
* @return the ConnectionInterface value.
* @jmx:managed-attribute
*/
public String getConnectionInterface()
{
return connectionInterface;
}
/**
* Set the ConnectionInterface value.
* @param connectionInterface The ConnectionInterface value.
* @jmx:managed-attribute
*/
public void setConnectionInterface(String connectionInterface)
{
this.connectionInterface = connectionInterface;
}
/**
* The ConnectionImplClass attribute holds the ConnectionImplClass from the ra.xml.
* It should be supplied by xslt from ra.xml
*
* @return the connectionImplClass value.
* @jmx:managed-attribute
*/
public String getConnectionImplClass()
{
return connectionImplClass;
}
/**
* Set the ConnectionImplClass value.
* @param connectionImplClass The ConnectionImplClass value.
* @jmx:managed-attribute
*/
public void setConnectionImplClass(String connectionImplClass)
{
this.connectionImplClass = connectionImplClass;
}
/**
* The TransactionSupport attribute holds the TransactionSupport from the ra.xml.
* It should be supplied by xslt from ra.xml
* It is ignored, and choice of ConnectionManager implementations determine
* transaction support.
*
* Get the TransactionSupport value.
* @return the TransactionSupport value.
* @jmx:managed-attribute
*/
public String getTransactionSupport()
{
return transactionSupport;
}
/**
* Set the TransactionSupport value.
* @param transactionSupport The TransactionSupport value.
* @jmx:managed-attribute
*/
public void setTransactionSupport(String transactionSupport)
{
this.transactionSupport = transactionSupport;
}
/**
* The ManagedConnectionFactoryProperties attribute holds the
* ManagedConnectionFactoryProperties from the ra.xml, together with
* user supplied values for all or some of these properties. This must be
* supplied as an element in the same format as in ra.xml, wrapped in a
* properties tag.
* It should be supplied by xslt from ra.xml merged with an user
* configuration xml file.
* An alternative format has a config-property element with attributes for
* name and type and the value as content.
*
* @return the ManagedConnectionFactoryProperties value.
* @jmx:managed-attribute
*/
public Element getManagedConnectionFactoryProperties()
{
return managedConnectionFactoryProperties;
}
/**
* Set the ManagedConnectionFactoryProperties value.
* @param managedConnectionFactoryProperties The ManagedConnectionFactoryProperties value.
* @jmx:managed-attribute
*/
public void setManagedConnectionFactoryProperties(Element managedConnectionFactoryProperties)
{
this.managedConnectionFactoryProperties = managedConnectionFactoryProperties;
}
/**
* The AuthenticationMechanismType attribute holds the AuthenticationMechanismType from the ra.xml.
* It should be supplied by xslt from ra.xml
*
* @return the AuthenticationMechanismType value.
* @jmx:managed-attribute
*/
public String getAuthenticationMechanismType()
{
return authenticationMechanismType;
}
/**
* Set the AuthenticationMechanismType value.
* @param authenticationMechanismType The AuthenticationMechanismType value.
* @jmx:managed-attribute
*/
public void setAuthenticationMechanismType(String authenticationMechanismType)
{
this.authenticationMechanismType = authenticationMechanismType;
}
/**
* The CredentialInterface attribute holds the CredentialInterface from the ra.xml.
* It should be supplied by xslt from ra.xml
*
* @return the CredentialInterface value.
* @jmx:managed-attribute
*/
public String getCredentialInterface()
{
return credentialInterface;
}
/**
* Set the CredentialInterface value.
* @param credentialInterface The CredentialInterface value.
* @jmx:managed-attribute
*/
public void setCredentialInterface(String credentialInterface)
{
this.credentialInterface = credentialInterface;
}
/**
* The ReauthenticationSupport attribute holds the ReauthenticationSupport from the ra.xml.
* It should be supplied by xslt from ra.xml
*
* @return the ReauthenticationSupport value.
* @jmx:managed-attribute
*/
public boolean isReauthenticationSupport()
{
return reauthenticationSupport;
}
/**
* Set the ReauthenticationSupport value.
* @param reauthenticationSupport The ReauthenticationSupport value.
* @jmx:managed-attribute
*/
public void setReauthenticationSupport(boolean reauthenticationSupport)
{
this.reauthenticationSupport = reauthenticationSupport;
}
/**
* The <code>getMcfInstance</code> method returns the
* ManagedConnectionFactory instance represented by this mbean.
* It is needed so PasswordCredentials can match up correctly.
* This will probably have to be implemented as an interceptor when
* the mcf is directly deployed as an mbean.
*
* @return a <code>ManagedConnectionFactory</code> value
*
* @jmx.managed-attribute access="read-only" description="Returns ManagedConnectionFactory instance represented by this mbean"
*/
public ManagedConnectionFactory getMcfInstance()
{
return mcf;
}
/**
* Describe <code>startManagedConnectionFactory</code> method here.
* creates managedConnectionFactory, creates ConnectionFactory, and binds it in jndi.
* Returns the ManagedConnectionFactory to the ConnectionManager that called us.
*
* @todo remove use of oldRarDeployment when xslt based deployment is written.
*/
protected void startService() throws Exception
{
if (mcf != null)
throw new DeploymentException("Stop the RARDeployment before restarting it");
ConnectorMetaData cmd = null;
ConnectionDefinitionMetaData cdmd = null;
ResourceAdapter resourceAdapter = null;
if (oldRarDeployment != null)
{
try
{
resourceAdapter = (ResourceAdapter) getServer().getAttribute(oldRarDeployment, "ResourceAdapter");
cmd = (ConnectorMetaData) getServer().getAttribute(oldRarDeployment, "MetaData");
cdmd = cmd.getConnectionDefinition(connectionDefinition);
if (cdmd == null)
throw new DeploymentException("ConnectionDefinition '" + connectionDefinition + "' not found in rar '" + rarName + "'");
setManagedConnectionFactoryClass(cdmd.getManagedConnectionFactoryClass());
setReauthenticationSupport(cmd.getReauthenticationSupport());
}
catch (Exception e)
{
throw new DeploymentException("couldn't get oldRarDeployment! " + oldRarDeployment, e);
}
}
try
{
mcfClass = Thread.currentThread().getContextClassLoader().loadClass(managedConnectionFactoryClass);
}
catch (ClassNotFoundException cnfe)
{
log.error("Could not find ManagedConnectionFactory class: " + managedConnectionFactoryClass, cnfe);
throw new DeploymentException("Could not find ManagedConnectionFactory class: "
+ managedConnectionFactoryClass);
}
try
{
mcf = (ManagedConnectionFactory) mcfClass.newInstance();
}
catch (Exception e)
{
log.error("Could not instantiate ManagedConnectionFactory: " + managedConnectionFactoryClass, e);
throw new DeploymentException("Could not instantiate ManagedConnectionFactory: "
+ managedConnectionFactoryClass);
}
if (cmd != null)
{
// Set the resource adapter properties
setMcfProperties(cmd.getProperties(), false);
// Set the connection definition properties
setMcfProperties(cdmd.getProperties(), true);
}
//set overridden properties;
setMcfProperties(managedConnectionFactoryProperties);
if (resourceAdapter != null && mcf instanceof ResourceAdapterAssociation)
{
ResourceAdapterAssociation raa = (ResourceAdapterAssociation) mcf;
raa.setResourceAdapter(resourceAdapter);
}
}
/**
* The <code>stopManagedConnectionFactory</code> method unbinds the ConnectionFactory
* from jndi, releases the ManagedConnectionFactory instane, and releases the
* ManagedConnectionFactory class.
*
*/
protected void stopService()
{
mcf = null;
mcfClass = null;
}
/**
* The setManagedConnectionFactoryAttribute method can be used to set
* attributes on the ManagedConnectionFactory from code, without using the
* xml configuration.
*
* @param name a <code>String</code> value
* @param clazz a <code>Class</code> value
* @param value an <code>Object</code> value
*
* @jmx:managed-operation
*/
public void setManagedConnectionFactoryAttribute(String name, Class clazz, Object value)
{
setManagedConnectionFactoryAttribute(name, clazz, value, false);
}
protected void setManagedConnectionFactoryAttribute(String name, Class clazz, Object value, boolean mustExist)
{
if (name == null || name.length() == 0)
throw new IllegalArgumentException("Null or empty attribute name " + name);
String setterName = "set" + Character.toUpperCase(name.charAt(0));
if (name.length() > 1)
setterName = setterName.concat(name.substring(1));
Method setter;
try
{
setter = mcfClass.getMethod(setterName, new Class[] {clazz});
}
catch (NoSuchMethodException nsme)
{
String error = "The class '" + mcfClass.toString() + "' has no setter for config property '" + name + "'";
if (mustExist)
throw new IllegalArgumentException(error);
else
{
log.trace(error);
return;
}
}
try
{
setter.invoke(mcf, new Object[] {value});
log.debug("set property " + name + " to value " + value);
}
catch (Exception e)
{
String error = "Unable to invoke setter method '" + setter + "' " + "on object '" + mcf + "'";
if (mustExist)
throw new IllegalArgumentException(error);
else
{
log.trace(error);
return;
}
}
sendNotification(new Notification(MCF_ATTRIBUTE_CHANGED_NOTIFICATION, getServiceName(),
getNextNotificationSequenceNumber()));
}
/**
* The <code>getManagedConnectionFactoryAttribute</code> method can be used
* to examine the managed connection factory properties.
*
* @param name a <code>String</code> value
* @return an <code>Object</code> value
*
* @jmx:managed-operation
*/
public Object getManagedConnectionFactoryAttribute(String name)
{
if (name == null || name.length() == 0)
throw new IllegalArgumentException("Null or empty attribute name " + name);
String getterName = "get" + Character.toUpperCase(name.charAt(0));
if (name.length() > 1)
getterName = getterName.concat(name.substring(1));
Method getter;
try
{
getter = mcfClass.getMethod(getterName, new Class[] {});
}
catch (NoSuchMethodException e)
{
String msg = "The class '" + mcfClass + "' has no getter("
+ getterName + ") for config property '" + name + "'";
log.debug(msg, e);
throw new IllegalArgumentException(msg);
}
try
{
Object value = getter.invoke(mcf, new Object[]{});
log.debug("get property " + name + ": value " + value);
return value;
}
catch (Exception e)
{
String msg = "Unable to invoke getter method '" + getter
+ "' " + "on object '" + mcf + "'";
log.debug(msg, e);
throw new IllegalArgumentException(msg);
}
}
//ObjectFactory implementation
//protected methods
protected void setMcfProperties(Collection properties, boolean mustExist) throws DeploymentException
{
for (Iterator i = properties.iterator(); i.hasNext();)
{
ConfigPropertyMetaData cpmd = (ConfigPropertyMetaData) i.next();
String name = cpmd.getName();
String type = cpmd.getType();
String value = cpmd.getValue();
if (name == null || name.length() == 0 || value == null || value.length() == 0)
{
log.debug("Not setting config property '" + name + "'");
continue;
}
// see if it is a primitive type first
Class clazz = Classes.getPrimitiveTypeForName(type);
if (clazz == null)
{
//not primitive, look for it.
try
{
clazz = Thread.currentThread().getContextClassLoader().loadClass(type);
}
catch (ClassNotFoundException cnfe)
{
log.warn("Unable to find class '" + type + "' for " + "property '" + name + "' - skipping property.");
continue;
}
}
PropertyEditor pe = PropertyEditorManager.findEditor(clazz);
if (pe == null)
{
log.warn("Unable to find a PropertyEditor for class '" + clazz + "' of property '" + name + "' - "
+ "skipping property");
continue;
}
value = StringPropertyReplacer.replaceProperties(value);
log.debug("setting property: " + name + " to value " + value);
try
{
pe.setAsText(value);
}
catch (IllegalArgumentException iae)
{
log.warn("Value '" + value + "' is not valid for property '" + name + "' of class '" + clazz
+ "' - skipping " + "property");
continue;
}
Object v = pe.getValue();
setManagedConnectionFactoryAttribute(name, clazz, v, mustExist);
}
}
protected void setMcfProperties(Element mcfProps) throws DeploymentException
{
if (mcfProps == null)
{
return;
} // end of if ()
// See if the config has disabled property replacement
boolean replace = true;
String replaceAttr = mcfProps.getAttribute("replace");
if (replaceAttr.length() > 0)
replace = Boolean.valueOf(replaceAttr).booleanValue();
// the properties that the deployment descriptor says we need to set
NodeList props = mcfProps.getChildNodes();
for (int i = 0; i < props.getLength(); i++)
{
if (props.item(i).getNodeType() == Node.ELEMENT_NODE)
{
Element prop = (Element) props.item(i);
if (prop.getTagName().equals("config-property"))
{
String name = null;
String type = null;
String value = null;
//Support for more friendly config style
//<config-property name="" type=""></config-property>
if (prop.hasAttribute("name"))
{
name = prop.getAttribute("name");
type = prop.getAttribute("type");
value = MetaData.getElementContent(prop);
} // end of if ()
else
{
name = MetaData.getElementContent(MetaData.getUniqueChild(prop, "config-property-name"));
type = MetaData.getElementContent(MetaData.getUniqueChild(prop, "config-property-type"));
value = MetaData.getElementContent(MetaData.getOptionalChild(prop, "config-property-value"));
} // end of else
if (name == null || name.length() == 0 || value == null || value.length() == 0)
{
log.debug("Not setting config property '" + name + "'");
continue;
}
if (type == null || type.length() == 0)
{
// Default to String for convenience.
type = "java.lang.String";
} // end of if ()
// see if it is a primitive type first
Class clazz = Classes.getPrimitiveTypeForName(type);
if (clazz == null)
{
//not primitive, look for it.
try
{
clazz = Thread.currentThread().getContextClassLoader().loadClass(type);
}
catch (ClassNotFoundException cnfe)
{
log.warn("Unable to find class '" + type + "' for " + "property '" + name
+ "' - skipping property.");
continue;
}
}
PropertyEditor pe = PropertyEditorManager.findEditor(clazz);
if (pe == null)
{
log.warn("Unable to find a PropertyEditor for class '" + clazz + "' of property '" + name + "' - "
+ "skipping property");
continue;
}
if (replace == true)
value = StringPropertyReplacer.replaceProperties(value);
log.debug("setting property: " + name + " to value " + value);
try
{
pe.setAsText(value);
}
catch (IllegalArgumentException iae)
{
log.warn("Value '" + value + "' is not valid for property '" + name + "' of class '" + clazz
+ "' - skipping " + "property");
continue;
}
Object v = pe.getValue();
setManagedConnectionFactoryAttribute(name, clazz, v);
} // end of if ()
} // end of if ()
} //end of for
}
//ManagedConnectionFactory implementation, used to keep backward compatibility
// between configs using this mbean and newer xmbean based configs.
/**
* Creates a connection factory instance.
*/
public Object createConnectionFactory() throws ResourceException
{
return mcf.createConnectionFactory();
}
/**
* Creates a connection factory instance.
*/
public Object createConnectionFactory(ConnectionManager cxManager) throws ResourceException
{
return mcf.createConnectionFactory(cxManager);
}
/**
* Creates a new ManagedConnection
*/
public ManagedConnection createManagedConnection(javax.security.auth.Subject subject,
ConnectionRequestInfo cxRequestInfo) throws ResourceException
{
return mcf.createManagedConnection(subject, cxRequestInfo);
}
/**
* Tests object for equality
*/
public boolean equals(Object other)
{
return mcf.equals(other);
}
/**
* Gets the logwriter for this instance.
*/
public java.io.PrintWriter getLogWriter() throws ResourceException
{
return mcf.getLogWriter();
}
/**
* Override toString() so we don't fall fowl an NPE in hashCode
*/
public String toString()
{
StringBuffer buffer = new StringBuffer();
buffer.append(getClass().getName());
buffer.append('@');
buffer.append(Integer.toHexString(System.identityHashCode(this)));
return buffer.toString();
}
/**
* Generates a hashCode for this object
*/
public int hashCode()
{
return mcf.hashCode();
}
/**
* Returns a matching connection from the set.
*/
public ManagedConnection matchManagedConnections(java.util.Set connectionSet, javax.security.auth.Subject subject,
ConnectionRequestInfo cxRequestInfo) throws ResourceException
{
return mcf.matchManagedConnections(connectionSet, subject, cxRequestInfo);
}
/**
* Sets the logwriter for this instance.
*/
public void setLogWriter(java.io.PrintWriter out) throws ResourceException
{
mcf.setLogWriter(out);
}
}// RARDeployment
| RARDeployment.java |