/*
* JBoss, the OpenSource J2EE webOS
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.metadata;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Set;
import org.jboss.deployment.DeploymentException;
import org.jboss.invocation.InvocationType;
import org.jboss.security.AnybodyPrincipal;
import org.jboss.security.NobodyPrincipal;
import org.jboss.security.SimplePrincipal;
import org.jboss.mx.util.ObjectNameFactory;
import org.w3c.dom.Element;
/**
* A common meta data class for the entity, message-driven and session beans.
*
* @author Sebastien Alborini
* @author Peter Antman
* @author Daniel OConnor
* @author Scott Stark
* @author Ole Husgaard
* @author Bill Burke
* @author Christian Riege
*
* @version $Revision: 1.41.2.8 $
*/
public abstract class BeanMetaData
extends MetaData
{
// Constants -----------------------------------------------------
public static final char SESSION_TYPE = 'S';
public static final char ENTITY_TYPE = 'E';
public static final char MDB_TYPE = 'M';
public static final String LOCAL_INVOKER_PROXY_BINDING = "LOCAL";
// Attributes ----------------------------------------------------
private ApplicationMetaData application;
// from ejb-jar.xml
/** The ejb-name element specifies an enterprise bean's name. This name is
assigned by the ejb-jar file producer to name the enterprise bean in
the ejb-jar file's deployment descriptor. The name must be unique
among the names of the enterprise beans in the same ejb-jar file.
*/
private String ejbName;
/** The home element contains the fully-qualified name of the enterprise
bean's home interface. */
private String homeClass;
/** The remote element contains the fully-qualified name of the enterprise
bean's remote interface. */
private String remoteClass;
/** The local-home element contains the fully-qualified name of the
enterprise bean's local home interface. */
private String localHomeClass;
/** The local element contains the fully-qualified name of the enterprise
bean's local interface */
private String localClass;
/** The ejb-class element contains the fully-qualified name of the
enterprise bean's class. */
private String ejbClass;
/** The type of bean: ENTITY_TYPE, SESSION_TYPE, MDB_TYPE */
protected char beanType;
/** Is this bean's transactions managed by the container? */
protected boolean containerManagedTx = true;
/** The The env-entry element(s) contains the declaration of an enterprise
bean's environment entry */
private ArrayList environmentEntries = new ArrayList();
/** The The ejb-ref element(s) for the declaration of a reference to an
enterprise bean's home */
private HashMap ejbReferences = new HashMap();
/** The ejb-local-ref element(s) info */
private HashMap ejbLocalReferences = new HashMap();
/** The security-role-ref element(s) info */
private ArrayList securityRoleReferences = new ArrayList();
/** The security-idemtity element info */
private SecurityIdentityMetaData securityIdentity = null;
/** The resource-ref element(s) info */
private HashMap resourceReferences = new HashMap();
/** The resource-env-ref element(s) info */
private HashMap resourceEnvReferences = new HashMap();
/** The method attributes */
private ArrayList methodAttributes = new ArrayList();
private HashMap cachedMethodAttributes = new HashMap();
/** The assembly-descriptor/method-permission element(s) info */
private ArrayList permissionMethods = new ArrayList();
/** The assembly-descriptor/container-transaction element(s) info */
private ArrayList transactionMethods = new ArrayList();
/** The assembly-descriptor/exclude-list method(s) */
private ArrayList excludedMethods = new ArrayList();
/** The invoker names to JNDI name mapping */
protected HashMap invokerBindings = null;
/** The cluster-config element info */
private ClusterConfigMetaData clusterConfig = null;
/** The JNDI name under with the home interface should be bound */
private String jndiName;
/** The JNDI name under with the local home interface should be bound */
private String localJndiName;
/** The container configuration name */
protected String configurationName;
/** The container configuration metadata */
private ConfigurationMetaData configuration;
/** The custom security proxy class */
private String securityProxy;
/** Is the bean marked as clustered */
protected boolean clustered = false;
/** Any object names for services the bean depends on */
private Collection depends = new LinkedList();
// Static --------------------------------------------------------
// Constructors --------------------------------------------------
public BeanMetaData(ApplicationMetaData app, char beanType)
{
application = app;
this.beanType = beanType;
}
// Public --------------------------------------------------------
public boolean isSession()
{
return beanType == SESSION_TYPE;
}
public boolean isMessageDriven()
{
return beanType == MDB_TYPE;
}
public boolean isEntity()
{
return beanType == ENTITY_TYPE;
}
public String getHome()
{
return homeClass;
}
public String getRemote()
{
return remoteClass;
}
public String getLocalHome()
{
return localHomeClass;
}
public String getLocal()
{
return localClass;
}
public String getEjbClass()
{
return ejbClass;
}
public String getEjbName()
{
return ejbName;
}
public boolean isContainerManagedTx()
{
return containerManagedTx;
}
public boolean isBeanManagedTx()
{
return !containerManagedTx;
}
public Iterator getEjbReferences()
{
return ejbReferences.values().iterator();
}
public Iterator getEjbLocalReferences()
{
return ejbLocalReferences.values().iterator();
}
protected abstract void defaultInvokerBindings();
public Iterator getInvokerBindings()
{
if( invokerBindings == null )
{
// See if there is a container default invoker name
String defaultName = configuration.getDefaultInvokerName();
if( defaultName != null )
{
invokerBindings = new HashMap();
invokerBindings.put(defaultName, getJndiName());
}
else
{
// Use the hard-coded defaults
defaultInvokerBindings();
}
}
return invokerBindings.keySet().iterator();
}
public String getInvokerBinding(String invokerName)
{
if( invokerBindings == null )
{
defaultInvokerBindings();
}
return (String)invokerBindings.get(invokerName);
}
public EjbRefMetaData getEjbRefByName(String name)
{
return (EjbRefMetaData)ejbReferences.get(name);
}
public EjbLocalRefMetaData getEjbLocalRefByName(String name)
{
return (EjbLocalRefMetaData)ejbLocalReferences.get(name);
}
public Iterator getEnvironmentEntries()
{
return environmentEntries.iterator();
}
public Iterator getSecurityRoleReferences()
{
return securityRoleReferences.iterator();
}
public Iterator getResourceReferences()
{
return resourceReferences.values().iterator();
}
public Iterator getResourceEnvReferences()
{
return resourceEnvReferences.values().iterator();
}
public String getJndiName()
{
// jndiName may be set in jboss.xml
if (jndiName == null)
{
jndiName = ejbName;
}
return jndiName;
}
/**
* Gets the JNDI name under with the local home interface should be bound.
* The default is local/<ejbName>
*/
public String getLocalJndiName()
{
if (localJndiName == null)
{
localJndiName = "local/" + ejbName;
}
return localJndiName;
}
/**
* Gets the container jndi name used in the object name
*/
public String getContainerObjectNameJndiName()
{
return getHome() != null ? getJndiName() : getLocalJndiName();
}
public String getConfigurationName()
{
if (configurationName == null)
{
configurationName = getDefaultConfigurationName();
}
return configurationName;
}
public ConfigurationMetaData getContainerConfiguration()
{
if (configuration == null)
{
String configName = getConfigurationName();
configuration = application.getConfigurationMetaDataByName(configName);
}
return configuration;
}
public String getSecurityProxy()
{
return securityProxy;
}
public SecurityIdentityMetaData getSecurityIdentityMetaData()
{
return securityIdentity;
}
public ApplicationMetaData getApplicationMetaData()
{
return application;
}
public abstract String getDefaultConfigurationName();
public Iterator getTransactionMethods()
{
return transactionMethods.iterator();
}
public Iterator getPermissionMethods()
{
return permissionMethods.iterator();
}
public Iterator getExcludedMethods()
{
return excludedMethods.iterator();
}
public void addTransactionMethod( MethodMetaData method )
{
transactionMethods.add(method);
}
public void addPermissionMethod(MethodMetaData method)
{
// Insert unchecked methods into the front of the list to speed
// up their validation
if( method.isUnchecked() )
{
permissionMethods.add(0, method);
}
else
{
permissionMethods.add(method);
}
}
public void addExcludedMethod(MethodMetaData method)
{
excludedMethods.add(method);
}
public byte getMethodTransactionType(String methodName, Class[] params,
InvocationType iface)
{
// default value
byte result = TX_UNKNOWN;
Iterator iterator = getTransactionMethods();
while( iterator.hasNext() )
{
MethodMetaData m = (MethodMetaData)iterator.next();
if (m.patternMatches(methodName, params, iface))
{
result = m.getTransactionType();
// if it is an exact match, break, if it is the wildcard
// continue to look for a finer match
if ( m.getMethodName().equals("*") == false )
{
break;
}
}
}
return result;
}
public Collection getDepends()
{
Collection allDepends = new LinkedList(depends);
allDepends.addAll(getContainerConfiguration().getDepends());
return allDepends;
}
/**
* Checks meta data to obtain the Method Attributes of a bean's method:
* method attributes are read-only, idempotent and potentially other
* ones as well.
* These jboss-specific method attributes are described in jboss.xml
*/
private MethodAttributes methodAttributesForMethod(String methodName)
{
MethodAttributes ma =
(MethodAttributes)cachedMethodAttributes.get(methodName);
if(ma == null)
{
Iterator iterator = methodAttributes.iterator();
while(iterator.hasNext() && ma == null)
{
ma = (MethodAttributes)iterator.next();
if(!ma.patternMatches(methodName))
{
ma = null;
}
}
if(ma == null)
{
ma = MethodAttributes.kDefaultMethodAttributes;
}
cachedMethodAttributes.put(methodName, ma);
}
return ma;
}
/**
* Is this method a read-only method described in jboss.xml?
*/
public boolean isMethodReadOnly(String methodName)
{
return methodAttributesForMethod(methodName).readOnly;
}
public boolean isMethodReadOnly(Method method)
{
if(method == null)
{
return false;
}
return methodAttributesForMethod(method.getName()).readOnly;
}
/**
* A somewhat tedious method that builds a Set of the roles
* that have been assigned permission to execute the indicated method. The
* work performed is tedious because of the wildcard style of declaring
* method permission allowed in the ejb-jar.xml descriptor. This method is
* called by the Container.getMethodPermissions() when it fails to find the
* prebuilt set of method roles in its cache.
*
* @return The Set for the application domain roles that
* caller principal's are to be validated against.
* @see org.jboss.ejb.Container#getMethodPermissions(Method, boolean)
*/
public Set getMethodPermissions(String methodName, Class[] params,
InvocationType iface)
{
Set result = new HashSet();
// First check the excluded method list as this takes priority over
// all other assignments
Iterator iterator = getExcludedMethods();
while (iterator.hasNext())
{
MethodMetaData m = (MethodMetaData) iterator.next();
if (m.patternMatches(methodName, params, iface))
{
/* No one is allowed to execute this method so add a role that
fails to equate to any Principal or Principal name and return.
We don't return null to differentiate between an explicit
assignment of no access and no assignment information.
*/
result.add(NobodyPrincipal.NOBODY_PRINCIPAL);
return result;
}
}
// Check the permissioned methods list
iterator = getPermissionMethods();
while (iterator.hasNext())
{
MethodMetaData m = (MethodMetaData) iterator.next();
if (m.patternMatches(methodName, params, iface))
{
/* If this is an unchecked method anyone can access it so
set the result set to a role that equates to any Principal or
Principal name and return.
*/
if (m.isUnchecked())
{
result.clear();
result.add(AnybodyPrincipal.ANYBODY_PRINCIPAL);
break;
}
// Else, add all roles
else
{
Iterator rolesIterator = m.getRoles().iterator();
while (rolesIterator.hasNext())
{
String roleName = (String) rolesIterator.next();
result.add(new SimplePrincipal(roleName));
}
}
}
}
// If no permissions were assigned to the method return null to indicate no access
if( result.isEmpty() )
{
result = null;
}
return result;
}
// Cluster configuration methods
public boolean isClustered()
{
return this.clustered;
}
public ClusterConfigMetaData getClusterConfigMetaData()
{
if( clusterConfig == null )
{
clusterConfig = getContainerConfiguration().getClusterConfigMetaData();
if( clusterConfig == null )
{
clusterConfig = new ClusterConfigMetaData();
}
/* All beans associated with a container are the same type
so this can be done more than once without harm */
clusterConfig.init(this);
}
return this.clusterConfig;
}
public void importEjbJarXml(Element element)
throws DeploymentException
{
// set the ejb-name
ejbName = getElementContent( getUniqueChild(element, "ejb-name") );
// set the classes
// Not for MessageDriven
if (isMessageDriven() == false)
{
homeClass = getElementContent(getOptionalChild(element, "home"));
remoteClass = getElementContent(getOptionalChild(element, "remote"));
localHomeClass = getElementContent(getOptionalChild(element,
"local-home"));
localClass = getElementContent(getOptionalChild(element, "local"));
}
ejbClass = getElementContent(getUniqueChild(element, "ejb-class"));
// set the environment entries
Iterator iterator = getChildrenByTagName(element, "env-entry");
while (iterator.hasNext())
{
Element envEntry = (Element)iterator.next();
EnvEntryMetaData envEntryMetaData = new EnvEntryMetaData();
envEntryMetaData.importEjbJarXml(envEntry);
environmentEntries.add(envEntryMetaData);
}
// set the ejb references
iterator = getChildrenByTagName(element, "ejb-ref");
while (iterator.hasNext())
{
Element ejbRef = (Element) iterator.next();
EjbRefMetaData ejbRefMetaData = new EjbRefMetaData();
ejbRefMetaData.importEjbJarXml(ejbRef);
ejbReferences.put(ejbRefMetaData.getName(), ejbRefMetaData);
}
// set the ejb local references
iterator = getChildrenByTagName(element, "ejb-local-ref");
while (iterator.hasNext())
{
Element ejbLocalRef = (Element) iterator.next();
EjbLocalRefMetaData ejbLocalRefMetaData = new EjbLocalRefMetaData();
ejbLocalRefMetaData.importEjbJarXml(ejbLocalRef);
ejbLocalReferences.put(ejbLocalRefMetaData.getName(),
ejbLocalRefMetaData);
}
// set the security roles references
iterator = getChildrenByTagName(element, "security-role-ref");
while (iterator.hasNext())
{
Element secRoleRef = (Element) iterator.next();
SecurityRoleRefMetaData securityRoleRefMetaData =
new SecurityRoleRefMetaData();
securityRoleRefMetaData.importEjbJarXml(secRoleRef);
securityRoleReferences.add(securityRoleRefMetaData);
}
// The security-identity element
Element securityIdentityElement = getOptionalChild(element,
"security-identity");
if (securityIdentityElement != null)
{
securityIdentity = new SecurityIdentityMetaData();
securityIdentity.importEjbJarXml(securityIdentityElement);
}
// set the resource references
iterator = getChildrenByTagName(element, "resource-ref");
while (iterator.hasNext())
{
Element resourceRef = (Element) iterator.next();
ResourceRefMetaData resourceRefMetaData = new ResourceRefMetaData();
resourceRefMetaData.importEjbJarXml(resourceRef);
resourceReferences.put(resourceRefMetaData.getRefName(),
resourceRefMetaData);
}
// Parse the resource-env-ref elements
iterator = getChildrenByTagName(element, "resource-env-ref");
while (iterator.hasNext())
{
Element resourceRef = (Element) iterator.next();
ResourceEnvRefMetaData refMetaData = new ResourceEnvRefMetaData();
refMetaData.importEjbJarXml(resourceRef);
resourceEnvReferences.put(refMetaData.getRefName(), refMetaData);
}
}
public void importJbossXml(Element element) throws DeploymentException
{
// we must not set defaults here, this might never be called
// set the jndi name, (optional)
jndiName = getElementContent(getOptionalChild(element, "jndi-name"));
// set the JNDI name under with the local home interface should be
// bound (optional)
localJndiName = getElementContent(getOptionalChild(element,
"local-jndi-name"));
// set the configuration (optional)
configurationName = getElementContent(getOptionalChild(element,
"configuration-name"));
if( configurationName != null && getApplicationMetaData().getConfigurationMetaDataByName(configurationName) == null)
{
throw new DeploymentException("configuration '" + configurationName
+ "' not found in standardjboss.xml or jboss.xml");
}
// Get the security proxy
securityProxy = getElementContent(getOptionalChild(element,
"security-proxy"), securityProxy);
// update the resource references (optional)
Iterator iterator = getChildrenByTagName(element, "resource-ref");
while (iterator.hasNext()) {
Element resourceRef = (Element)iterator.next();
String resRefName = getElementContent(getUniqueChild(resourceRef,
"res-ref-name"));
ResourceRefMetaData resourceRefMetaData =
(ResourceRefMetaData)resourceReferences.get(resRefName);
if (resourceRefMetaData == null)
{
throw new DeploymentException("resource-ref " + resRefName
+ " found in jboss.xml but not in ejb-jar.xml");
}
resourceRefMetaData.importJbossXml(resourceRef);
}
// Set the resource-env-ref deployed jndi names
iterator = getChildrenByTagName(element, "resource-env-ref");
while (iterator.hasNext())
{
Element resourceRef = (Element) iterator.next();
String resRefName = getElementContent(getUniqueChild(resourceRef,
"resource-env-ref-name"));
ResourceEnvRefMetaData refMetaData =
(ResourceEnvRefMetaData) resourceEnvReferences.get(resRefName);
if (refMetaData == null)
{
throw new DeploymentException("resource-env-ref " + resRefName
+ " found in jboss.xml but not in ejb-jar.xml");
}
refMetaData.importJbossXml(resourceRef);
}
// set the external ejb-references (optional)
iterator = getChildrenByTagName(element, "ejb-ref");
while (iterator.hasNext())
{
Element ejbRef = (Element)iterator.next();
String ejbRefName = getElementContent(getUniqueChild(ejbRef,
"ejb-ref-name"));
EjbRefMetaData ejbRefMetaData = getEjbRefByName(ejbRefName);
if (ejbRefMetaData == null)
{
throw new DeploymentException("ejb-ref " + ejbRefName
+ " found in jboss.xml but not in ejb-jar.xml");
}
ejbRefMetaData.importJbossXml(ejbRef);
}
//handle the ejb-local-ref elements
iterator = getChildrenByTagName(element, "ejb-local-ref");
while (iterator.hasNext())
{
Element ejbLocalRef = (Element)iterator.next();
String ejbLocalRefName = getElementContent(getUniqueChild(ejbLocalRef,
"ejb-ref-name"));
EjbLocalRefMetaData ejbLocalRefMetaData = getEjbLocalRefByName(ejbLocalRefName);
if (ejbLocalRefMetaData == null)
{
throw new DeploymentException("ejb-local-ref " + ejbLocalRefName
+ " found in jboss.xml but not in ejb-jar.xml");
}
ejbLocalRefMetaData.importJbossXml(ejbLocalRef);
}
// Method attributes of the bean
Element mas = getOptionalChild(element, "method-attributes");
if(mas != null)
{
// read in the read-only methods
iterator = getChildrenByTagName(mas, "method");
while (iterator.hasNext())
{
MethodAttributes ma = new MethodAttributes();
Element maNode = (Element)iterator.next();
ma.pattern = getElementContent(getUniqueChild(maNode,
"method-name"));
ma.readOnly = getOptionalChildBooleanContent(maNode,
"read-only");
ma.idempotent = getOptionalChildBooleanContent(maNode,
"idempotent");
methodAttributes.add(ma);
}
}
// Invokers
// If no invoker bindings have been defined they will be defined
// in EntityMetaData, or SessionMetaData
Element inv = getOptionalChild(element, "invoker-bindings");
if(inv != null)
{
// read in the read-only methods
iterator = getChildrenByTagName(inv, "invoker");
invokerBindings = new HashMap();
while (iterator.hasNext())
{
Element node = (Element)iterator.next();
String invokerBindingName = getUniqueChildContent(node,
"invoker-proxy-binding-name");
String jndiBinding = getOptionalChildContent(node, "jndi-name");
if( jndiBinding == null )
{
jndiBinding = getJndiName(); // default to jndiName
}
invokerBindings.put(invokerBindingName, jndiBinding);
// set the external ejb-references (optional)
Iterator ejbrefiterator = getChildrenByTagName(node, "ejb-ref");
while (ejbrefiterator.hasNext())
{
Element ejbRef = (Element)ejbrefiterator.next();
String ejbRefName = getElementContent(getUniqueChild(ejbRef,
"ejb-ref-name"));
EjbRefMetaData ejbRefMetaData = getEjbRefByName(ejbRefName);
if (ejbRefMetaData == null)
{
throw new DeploymentException("ejb-ref " + ejbRefName
+ " found in jboss.xml but not in ejb-jar.xml");
}
ejbRefMetaData.importJbossXml(invokerBindingName, ejbRef);
}
}
}
// Determine if the bean is to be deployed in the cluster (more
// advanced config will be added in the future)
String clusteredElt = getElementContent(getOptionalChild(element,
"clustered"), (clustered? "True" : "False"));
clustered = clusteredElt.equalsIgnoreCase ("True");
Element clusterConfigElement = getOptionalChild(element,
"cluster-config");
if (clusterConfigElement != null)
{
this.clusterConfig = new ClusterConfigMetaData();
clusterConfig.init(this);
clusterConfig.importJbossXml(clusterConfigElement);
}
//Get depends object names
for( Iterator dependsElements = getChildrenByTagName(element, "depends");
dependsElements.hasNext();)
{
Element dependsElement = (Element)dependsElements.next();
String dependsName = getElementContent(dependsElement);
depends.add(ObjectNameFactory.create(dependsName));
} // end of for ()
}
// Package protected ---------------------------------------------
// Protected -----------------------------------------------------
// Private -------------------------------------------------------
// Inner classes -------------------------------------------------
}
/*
vim:ts=3:sw=3:et
*/