/*
* Copyright (c) 2005
* XDoclet Team
* All rights reserved.
*/
package org.xdoclet.plugin.ejb;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;
import org.apache.commons.collections.Transformer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.generama.ConfigurableDocletTagFactory;
import org.xdoclet.plugin.ejb.qtags.EjbActivationConfigPropertyTag;
import org.xdoclet.plugin.ejb.qtags.EjbBeanTag;
import org.xdoclet.plugin.ejb.qtags.EjbEjbExternalRefTag;
import org.xdoclet.plugin.ejb.qtags.EjbEjbRefTag;
import org.xdoclet.plugin.ejb.qtags.EjbEjbServiceRefTag;
import org.xdoclet.plugin.ejb.qtags.EjbFinderTag;
import org.xdoclet.plugin.ejb.qtags.EjbPermissionTag;
import org.xdoclet.plugin.ejb.qtags.EjbPkTag;
import org.xdoclet.plugin.ejb.qtags.EjbRelationTag;
import org.xdoclet.plugin.ejb.qtags.EjbResourceEnvRefTag;
import org.xdoclet.plugin.ejb.qtags.EjbResourceRefTag;
import org.xdoclet.plugin.ejb.qtags.EjbTransactionMethodTag;
import org.xdoclet.plugin.ejb.qtags.EjbTransactionTag;
import org.xdoclet.plugin.ejb.qtags.TagLibrary;
import org.xdoclet.plugin.ejb.qtags.parameter.RoleList;
import org.xdoclet.plugin.ejb.util.DuplicatedJavaMethod;
import com.thoughtworks.qdox.model.AbstractJavaEntity;
import com.thoughtworks.qdox.model.BeanProperty;
import com.thoughtworks.qdox.model.DocletTag;
import com.thoughtworks.qdox.model.JavaClass;
import com.thoughtworks.qdox.model.JavaField;
import com.thoughtworks.qdox.model.JavaMethod;
import com.thoughtworks.qdox.model.JavaParameter;
import com.thoughtworks.qdox.model.Type;
/**
* This class holds common functionality used by all EJB plugin.
* These methods will mostly be called by templates (including
* vendor specific templates). Reusable code should be placed here.
*
* @author Diogo Quintela
* @author Aslak Hellesøy
* @version $Revision: 534 $
*
* TODO: Centralize some logic in findByPrimaryKey / EjbPkTag
* TODO: Refactor this into smaller units
* TODO: Try not to centralize all methods in EjbUtils. Move some into EjbJarXmlPlugin.
*/
public class EjbUtils {
// Bean / Methods / Interfaces flags
public static final int REMOTE = 1 << 0;
public static final int REMOTE_HOME = 1 << 1;
public static final int LOCAL = 1 << 2;
public static final int LOCAL_HOME = 1 << 3;
public static final int SERVICE_END_POINT = 1 << 4;
// Bean flags
public static final int BEAN_EJB = 1 << 0;
public static final int BEAN_ENTITY = 1 << 1;
public static final int BEAN_BMP = 1 << 2;
public static final int BEAN_CMP = 1 << 3;
public static final int BEAN_SESSION = 1 << 4;
public static final int BEAN_STATE_FULL = 1 << 5;
public static final int BEAN_STATE_LESS = 1 << 6;
public static final int BEAN_MESSAGE_DRIVEN = 1 << 7;
// Tag find mechanism flags
public static final int TAG_FIND_CLASS = 1 << 0;
public static final int TAG_FIND_METHOD = 1 << 1;
public static final int TAG_FIND_FIELD = 1 << 2;
public static final int TAG_FIND_RECURSIVE = 1 << 3;
// Methods flags
public static final int IFACE_METHOD_COMPONENT = 1 << 0;
public static final int IFACE_METHOD_CREATE = 1 << 1;
public static final int IFACE_METHOD_HOME = 1 << 2;
public static final int IFACE_METHOD_REMOVE = 1 << 3;
public static final int IFACE_METHOD_FINDER = 1 << 4;
public static final int IFACE_METHOD_SELECT = 1 << 5;
// Extra method flags
public static final int METADATA_METHOD_PERSISTENCE_FIELD = 1 << 6;
public static final int METADATA_METHOD_PRIMARY_KEY_FIELD = 1 << 7;
public static final int METADATA_METHOD_RELATION_FIELD = 1 << 8;
// Interface type auxiliar constants
public static final String REMOTE_INTERFACE = "Remote";
public static final String REMOTE_HOME_INTERFACE = "Home";
public static final String LOCAL_INTERFACE = "Local";
public static final String LOCAL_HOME_INTERFACE = "LocalHome";
public static final String SERVICE_END_POINT_INTERFACE = "ServiceEndpoint";
/** The logging object */
protected static Log log = LogFactory.getLog(EjbUtils.class);
/**
* Maps primitive types to their wrapper classes
*/
private final static Map wrappers;
static {
Map wps = new HashMap();
wps.put("boolean", new Type(Boolean.class.getName()));
wps.put("byte", new Type(Byte.class.getName()));
wps.put("char", new Type(Character.class.getName()));
wps.put("short", new Type(Short.class.getName()));
wps.put("int", new Type(Integer.class.getName()));
wps.put("float", new Type(Float.class.getName()));
wps.put("long", new Type(Long.class.getName()));
wps.put("double", new Type(Double.class.getName()));
wrappers = Collections.unmodifiableMap(wps);
}
// Patterns for method name matching
private static final Pattern methodPattern;
private static final Pattern paramPattern;
private static final Pattern dimensionPattern;
static {
// Defines a small BNF grammar for parsing method signatures
// See @ejb.finder signature
String space = "[ \\t]";
String spaces = "(?:" + space + ")*";
String typeIdentifier = "[a-zA-Z_][a-zA-Z0-9_]+";
String typeDimension = "\\[" + spaces + "\\]";
String typeDimensions = "(?:" + spaces + typeDimension + ")*";
String typeDefination = "(?:" + typeIdentifier + "(?:\\." + typeIdentifier + ")*" + typeDimensions + ")";
String paramWithName = "(" + typeDefination + ")" + space + spaces + "(" + typeIdentifier + ")" + "(" +
typeDimensions + ")";
String paramWithoutName = "(" + typeDefination + ")";
String paramDefinition = "(?:(" + paramWithName + ")|(" + paramWithoutName + "))";
String paramsDefinition = "(?:(?:" + spaces + ")|(?:" + spaces + paramDefinition + spaces + ")|(?:" + spaces +
paramDefinition + spaces + "(?:," + spaces + paramDefinition + spaces + ")+))";
String methodDefination = spaces + "(" + typeDefination + ")" + space + spaces + "(" + typeIdentifier + ")" +
spaces + "\\((" + paramsDefinition + ")\\)" + spaces;
// Let's define the patterns
methodPattern = Pattern.compile(methodDefination);
paramPattern = Pattern.compile(paramDefinition);
dimensionPattern = Pattern.compile(typeDimension);
}
private final EjbConfig config;
// private Map ejbCache = new HashMap();
public EjbUtils() {
this(EjbRuntime.getConfig());
}
public EjbUtils(EjbConfig config) {
this.config = config;
}
public String getEjbName(JavaClass clazz) {
String result = clazz.getNamedParameter(TagLibrary.EJB_BEAN, "name");
if (result == null) {
result = clazz.getName();
result = result.replaceAll(config.getEjbReplaceRegex(), "");
}
return result;
}
public String expandPattern(String pattern, String arg) {
return expandPattern(pattern, new String[] {arg});
}
public String expandPattern(String pattern, String[] args) {
if (pattern == null) {
return null;
}
String formattedName = MessageFormat.format(pattern, args);
if (log.isDebugEnabled()) {
log.debug("Expanded value is '" + formattedName + "'");
}
return formattedName;
}
public String expandPattern(String pattern, JavaClass clazz) {
if (pattern == null) {
return null;
}
String ejbName = getEjbName(clazz);
if (log.isDebugEnabled()) {
log.debug("Expanding pattern '" + pattern + "' with ejb name as argument '" + ejbName + "'");
}
return expandPattern(pattern, ejbName);
}
public int getMethodType(JavaMethod method) {
int retVal = 0;
if (method.getTagByName(TagLibrary.EJB_INTERFACE_METHOD) != null) {
retVal = IFACE_METHOD_COMPONENT;
} else if (method.getName().equals("ejbCreate") && (method.getTagByName(TagLibrary.EJB_CREATE_METHOD) != null)) {
retVal = IFACE_METHOD_CREATE;
} else if (method.getName().startsWith("ejbHome") && (method.getName().length() > "ejbHome".length()) &&
(method.getTagByName(TagLibrary.EJB_HOME_METHOD) != null)) {
retVal = IFACE_METHOD_HOME;
} else if (method.getName().equals("ejbRemove")) {
retVal = IFACE_METHOD_REMOVE;
} else if (method.getName().startsWith("ejbFind") && (method.getName().length() > "ejbFind".length())) {
if ((method.getReturns() != null) && !method.getReturns().isVoid()) {
retVal = IFACE_METHOD_FINDER;
} else {
if (log.isWarnEnabled()) {
log.warn("Inconsistent return type for finder method. Ignoring method. " +
method.getDeclarationSignature(true));
}
}
} else if (method.getName().startsWith("ejbSelect") && (method.getName().length() > "ejbSelect".length())) {
if ((method.getReturns() != null) && !method.getReturns().isVoid()) {
retVal = IFACE_METHOD_SELECT;
} else {
if (log.isWarnEnabled()) {
log.warn("Inconsistent return type for select method. Ignoring method. Return-type=" +
method.getDeclarationSignature(true));
}
}
}
return retVal;
}
/**
* Extension of getMethodType that gathers extra method information using method class
*
* @param method The method to gather info for
*
* @return The metadata bits
*/
public int getMethodMetadata(JavaMethod method) {
return getMethodMetadata(method.getParentClass(), method);
}
/**
* Extension of getMethodType that gathers extra method information
*
* @param javaClass The associated JavaClass
* @param method The method to gather info for
*
* @return The metadata bits
*/
public int getMethodMetadata(JavaClass javaClass, JavaMethod method) {
int retVal = getMethodType(method);
EjbBeanTag beanTag = (EjbBeanTag) javaClass.getTagByName(TagLibrary.EJB_BEAN);
DocletTag tag;
if ((tag = method.getTagByName(TagLibrary.EJB_PERSISTENCE_FIELD)) != null) {
if ((method.isPropertyAccessor() /*|| method.isPropertyMutator()*/)) {
retVal |= METADATA_METHOD_PERSISTENCE_FIELD;
} else {
if (log.isWarnEnabled()) {
log.warn("Ignoring " + TagLibrary.EJB_PERSISTENCE_FIELD + " tag. It should be place on property accessor. " + // or property mutator." +
method.getDeclarationSignature(true) + " - " + EjbUtils.tagToString(tag));
}
}
} else if ((tag = method.getTagByName(TagLibrary.EJB_RELATION)) != null) {
// METADATA_METHOD_RELATION_FIELD isn't compatible with METADATA_METHOD_PERSISTENCE_FIELD ??
if (method.isPropertyAccessor()) {
retVal |= METADATA_METHOD_RELATION_FIELD;
// TODO: Is METADATA_METHOD_RELATION_FIELD compatible with METADATA_METHOD_PERSISTENCE_FIELD ??
} else {
if (log.isWarnEnabled()) {
log.warn("Ignoring " + TagLibrary.EJB_RELATION + " tag. It should be place on property accessor." +
method.getDeclarationSignature(true) + " - " + EjbUtils.tagToString(tag));
}
}
}
if (beanTag != null && beanTag.getPrimkeyField() != null) {
BeanProperty prop = javaClass.getBeanProperty(beanTag.getPrimkeyField());
try {
if (prop == null || prop.getAccessor() == null) {
throw getErrorWithTagLocation(beanTag,
"Could not find getter for prim-key-field: " + beanTag.getPrimkeyField());
}
// Ok, now this must be that accessor for the key
if (method == prop.getAccessor()) {
retVal |= METADATA_METHOD_PRIMARY_KEY_FIELD;
}
} catch (Error e) {
log.error(e.getMessage());
throw e;
}
} else if ((tag = method.getTagByName(TagLibrary.EJB_PK_FIELD)) != null) {
// try {
// method must be a property acessor
if (method.isPropertyAccessor()) {
retVal |= METADATA_METHOD_PRIMARY_KEY_FIELD;
// throw getErrorWithTagLocation(tag, "Tag must be used on a property getter");
} else {
if (log.isWarnEnabled()) {
log.warn("Ignoring " + TagLibrary.EJB_PK_FIELD + " tag. It should be place on property accessor." +
method.getDeclarationSignature(true) + " - " + EjbUtils.tagToString(tag));
}
}
// retVal |= METADATA_METHOD_PRIMARY_KEY_FIELD;
// } catch (Error e) {
// log.error(e.getMessage());
// throw e;
// }
}
return retVal;
}
public Collection getBeans(Collection metadata) {
return getBeans(metadata, BEAN_EJB);
}
public Collection getCMPBeans(Collection metadata) {
return getBeans(metadata, BEAN_CMP);
}
public Collection getBMPBeans(Collection metadata) {
return getBeans(metadata, BEAN_BMP);
}
public Collection getEntityBeans(Collection metadata) {
return getBeans(metadata, BEAN_ENTITY);
}
public Collection getSessionBeans(Collection metadata) {
return getBeans(metadata, BEAN_SESSION);
}
public Collection getMessageDrivenBeans(Collection metadata) {
return getBeans(metadata, BEAN_MESSAGE_DRIVEN);
}
public Collection getStateFullBeans(Collection metadata) {
return getBeans(metadata, BEAN_STATE_FULL);
}
public Collection getStateLessBeans(Collection metadata) {
return getBeans(metadata, BEAN_STATE_LESS);
}
public Collection getBeans(final Collection metadata, final int beanType) {
return CollectionUtils.select(metadata,
new Predicate() {
public boolean evaluate(Object meta) {
JavaClass javaClass = (JavaClass) meta;
return hasFlag(getBeanType(javaClass), beanType);
}
});
}
public Collection getSelectMethods(final JavaClass clazz) {
if (!isCMP(clazz)) {
return null;
}
// Select all public abstract methods started by "ejbSelect" with a non-void
// return type
return CollectionUtils.select(Arrays.asList(clazz.getMethods(true)),
new Predicate() {
public boolean evaluate(Object object) {
JavaMethod method = (JavaMethod) object;
int methodType = getMethodType(method);
boolean retVal = hasFlag(methodType, IFACE_METHOD_SELECT);
retVal = retVal && method.isAbstract();
retVal = retVal && method.isPublic();
return retVal;
}
});
}
public static boolean hasFlag(int fullFlag, int checkFlag) {
return (fullFlag & checkFlag) == checkFlag;
}
public Collection getCMPFields(final JavaClass clazz) {
if (clazz == null) {
throw new Error();
}
if (!isCMP(clazz)) {
return null;
}
return CollectionUtils.select(Arrays.asList(clazz.getMethods(true)),
new Predicate() {
public boolean evaluate(Object object) {
int methodFlags = getMethodMetadata((JavaMethod) object);
return hasFlag(methodFlags, METADATA_METHOD_PERSISTENCE_FIELD);
/*
JavaMethod method = (JavaMethod) object;
EjbPersistenceFieldTag persistenceTag = (EjbPersistenceFieldTag) method.getTagByName(
"ejb.persistence-field");
return (method.isPropertyAccessor() && persistenceTag != null);
*/
}
});
}
public boolean shouldGenerate(Object metadata) {
JavaClass javaClass = (JavaClass) metadata;
boolean isEjb = isEJB(javaClass);
EjbBeanTag beanTag = (EjbBeanTag) javaClass.getTagByName(TagLibrary.EJB_BEAN);
boolean ignore = (beanTag != null) && !beanTag.isGenerate();
return isEjb && !ignore;
}
public String firstSentence(String comment) {
if (comment == null) {
return null;
}
int idx = comment.indexOf('\n');
return idx >= 0 ? comment.substring(0, idx) : comment;
}
public String description(JavaClass javaClass) {
String description = javaClass.getNamedParameter(TagLibrary.EJB_BEAN, "description");
if (description == null) {
description = firstSentence(javaClass.getComment());
}
if (description == null) {
description = "No description";
}
return description;
}
public JavaMethod getFinderMethodBySignature(String finderSignature) {
return getMethodBySignature(finderSignature);
}
public JavaMethod getMethodBySignature(String signature) {
Matcher matcher = methodPattern.matcher(signature);
if (matcher.matches()) {
JavaMethod method = new JavaMethod(new Type(matcher.group(1)), matcher.group(2));
// Now let's find out the arguments
matcher = paramPattern.matcher(matcher.group(3));
int beginIdx = 0;
int count = 0;
String paramType = null;
String paramName = null;
List paramLst = new ArrayList();
while (matcher.find(beginIdx)) {
int paramDim = 0;
if (matcher.group(1) != null) {
paramType = matcher.group(2) + (matcher.group(4) != null ? matcher.group(4) : "");
paramName = matcher.group(3);
} else {
paramType = matcher.group(6);
paramName = "_arg" + (count++);
}
// Now we need to parse paramType for it's dimensions
Matcher dMatcher = dimensionPattern.matcher(paramType);
if (dMatcher.find()) {
paramType = paramType.substring(0, dMatcher.start());
paramDim = 1;
while (dMatcher.find(dMatcher.end())) {
paramDim++;
}
}
paramLst.add(new JavaParameter(new Type(paramType, paramDim), paramName));
beginIdx = matcher.end();
}
method.setParameters((JavaParameter[]) paramLst.toArray(new JavaParameter[0]));
return method;
}
throw new Error("Invalid finder signature '" + signature + "'");
}
/**
* Returns true if the given JavaClass has a Remote Interface
* (independend of whether one is generated or not).
*/
public boolean hasRemoteInterface(JavaClass javaClass) {
return hasFlag(getViewType(javaClass), REMOTE)
&& !isMessageDrivenBean(javaClass);
}
/**
* Returns true if the given JavaClass has a Remote Home Interface
* (independend of whether one is generated or not).
*/
public boolean hasRemoteHomeInterface(JavaClass javaClass) {
return hasFlag(getViewType(javaClass), REMOTE_HOME)
&& !isMessageDrivenBean(javaClass);
}
/**
* Returns true if the given JavaClass has a Local Interface
* (independend of whether one is generated or not).
*/
public boolean hasLocalInterface(JavaClass javaClass) {
return hasFlag(getViewType(javaClass), LOCAL)
&& !isMessageDrivenBean(javaClass);
}
/**
* Returns true if the given JavaClass has a Local Home Interface
* (independend of whether one is generated or not).
*/
public boolean hasLocalHomeInterface(JavaClass javaClass) {
return hasFlag(getViewType(javaClass), LOCAL_HOME)
&& !isMessageDrivenBean(javaClass);
}
/**
* Returns true if the given JavaClass has a Service Endpoint Interface
* (independend of whether one is generated or not).
*/
public boolean hasServiceEndPoint(JavaClass javaClass) {
return hasFlag(getViewType(javaClass), SERVICE_END_POINT);
}
public boolean isViewType(JavaClass javaClass, String viewType) {
return hasFlag(getViewType(javaClass), getViewType(viewType));
}
public int getInterfaceType(String ifaceType) {
EjbVersion version = config.getEjbVersion();
int retVal = 0;
if (REMOTE_INTERFACE.equals(ifaceType)) {
retVal |= REMOTE;
} else if (REMOTE_HOME_INTERFACE.equals(ifaceType)) {
retVal |= REMOTE_HOME;
} else if (LOCAL_INTERFACE.equals(ifaceType)) {
retVal |= LOCAL;
} else if (LOCAL_HOME_INTERFACE.equals(ifaceType)) {
retVal |= LOCAL_HOME;
} else if (version.greaterOrEquals(EjbVersion.EJB_2_1) && SERVICE_END_POINT_INTERFACE.equals(ifaceType)) {
retVal |= SERVICE_END_POINT;
}
return retVal;
}
public int getViewType(String viewType) {
EjbVersion version = config.getEjbVersion();
int retVal = 0;
viewType = viewType.toLowerCase();
if (version.greaterOrEquals(EjbVersion.EJB_2_1)) {
if ("all".equals(viewType)) {
// retVal |= REMOTE | REMOTE_HOME;
// retVal |= LOCAL | LOCAL_HOME;
retVal |= SERVICE_END_POINT;
} else if (viewType.indexOf("service-endpoint") != -1) {
retVal |= SERVICE_END_POINT;
}
}
if ("both".equals(viewType) || "all".equals(viewType)) {
retVal |= REMOTE | REMOTE_HOME;
retVal |= LOCAL | LOCAL_HOME;
}
if (viewType.indexOf("remote") != -1) {
retVal |= REMOTE | REMOTE_HOME;
}
if (viewType.indexOf("local") != -1) {
retVal |= LOCAL | LOCAL_HOME;
}
return retVal;
}
public int getViewType(JavaClass javaClass) {
EjbVersion version = config.getEjbVersion();
String viewType = javaClass.getNamedParameter(TagLibrary.EJB_BEAN, "view-type");
if (!version.greaterOrEquals(EjbVersion.EJB_2_0)) {
viewType = "remote";
}
if (viewType == null) {
viewType = "both";
}
return getViewType(viewType);
}
public int getViewType(JavaMethod method, JavaClass javaClass) {
// We should mask method view type with bean's view type
// ie, A method cannot have a view type not supported by the bean
int beanViewType = getViewType(javaClass);
int retVal = 0;
int filterMask = beanViewType;
String viewType = null;
int methodType = getMethodType(method);
switch (methodType) {
case IFACE_METHOD_COMPONENT:
viewType = method.getNamedParameter(TagLibrary.EJB_INTERFACE_METHOD, "view-type");
retVal = (viewType != null) ? getViewType(viewType) : beanViewType;
// If it's a interface method it can only live in business-interfaces
// Let's remove home interfaces if inherited
filterMask &= ~(REMOTE_HOME | LOCAL_HOME);
break;
case IFACE_METHOD_CREATE:
viewType = method.getNamedParameter(TagLibrary.EJB_CREATE_METHOD, "view-type");
retVal = (viewType != null) ? getViewType(viewType) : beanViewType;
// If it's a create method, it can live only in home-interfaces
// Let's set mask to guarantee only homes
filterMask &= (REMOTE_HOME | LOCAL_HOME);
break;
case IFACE_METHOD_HOME:
viewType = method.getNamedParameter(TagLibrary.EJB_HOME_METHOD, "view-type");
retVal = (viewType != null) ? getViewType(viewType) : beanViewType;
// If it's a home method, it can live only in home-interfaces
// Let's set mask to guarantee only homes
filterMask &= (REMOTE_HOME | LOCAL_HOME);
break;
case IFACE_METHOD_REMOVE:
case IFACE_METHOD_FINDER:
case IFACE_METHOD_SELECT:
// TODO: remove methods are only in home interfaces ? Or can be in business ?
// TODO: finder methods are only in home interfaces ? Or can be in business ?
// TODO: select methods are only in home interfaces ? Or can be in business ?
retVal = (REMOTE_HOME | LOCAL_HOME);
break;
default:
// By default a method will not be included, so will not have a view type
break;
}
// Let's mask by bitwise filter
retVal &= filterMask;
return retVal;
}
public boolean isEJB(JavaClass javaClass) {
return hasFlag(getBeanType(javaClass), BEAN_EJB);
}
public boolean isCMP(JavaClass javaClass) {
return hasFlag(getBeanType(javaClass), BEAN_CMP);
}
public boolean isBMP(JavaClass javaClass) {
return hasFlag(getBeanType(javaClass), BEAN_BMP);
}
public boolean isEntityBean(JavaClass javaClass) {
return hasFlag(getBeanType(javaClass), BEAN_ENTITY);
}
public boolean isSessionBean(JavaClass javaClass) {
return hasFlag(getBeanType(javaClass), BEAN_SESSION);
}
public boolean isMessageDrivenBean(JavaClass javaClass) {
return hasFlag(getBeanType(javaClass), BEAN_MESSAGE_DRIVEN);
}
public boolean isStateFull(JavaClass javaClass) {
return hasFlag(getBeanType(javaClass), BEAN_STATE_FULL);
}
public boolean isStateLess(JavaClass javaClass) {
return hasFlag(getBeanType(javaClass), BEAN_STATE_LESS);
}
public int getBeanType(JavaClass javaClass) {
EjbVersion version = config.getEjbVersion();
String beanType = javaClass.getNamedParameter(TagLibrary.EJB_BEAN, "type");
int retVal = 0;
if (javaClass.isA("javax.ejb.EntityBean")) {
retVal |= BEAN_EJB;
retVal |= BEAN_ENTITY;
if (beanType != null && "bmp".equalsIgnoreCase(beanType)) {
retVal |= BEAN_BMP;
} else {
retVal |= BEAN_CMP;
}
} else if (javaClass.isA("javax.ejb.SessionBean")) {
// TODO: Do session beans need to be concrete (ie, not abstract) ?
retVal |= BEAN_EJB;
retVal |= BEAN_SESSION;
if (beanType != null && "stateful".equalsIgnoreCase(beanType)) {
retVal |= BEAN_STATE_FULL;
} else {
retVal |= BEAN_STATE_LESS;
}
} else if (version.greaterOrEquals(EjbVersion.EJB_2_0) && javaClass.isA("javax.ejb.MessageDrivenBean")) {
retVal |= BEAN_EJB;
retVal |= BEAN_MESSAGE_DRIVEN;
}
return retVal;
}
public String reentrant(JavaClass javaClass) {
EjbVersion version = config.getEjbVersion();
String reentrant = javaClass.getNamedParameter(TagLibrary.EJB_BEAN, "reentrant");
String retVal = Boolean.valueOf(reentrant).toString();
if (!version.greaterOrEquals(EjbVersion.EJB_2_1)) {
// ejb spec 1.1 and 2.0 require that the first character is upper case
// ejb spec 2.1+ requires that all characters are lower case
retVal = retVal.substring(0, 1).toUpperCase() + retVal.substring(1);
}
return retVal;
}
public String persistenceType(JavaClass javaClass) {
int beanType = getBeanType(javaClass);
String retVal = null;
if (hasFlag(beanType, BEAN_CMP)) {
retVal = "Container";
} else if (hasFlag(beanType, BEAN_BMP)) {
retVal = "Bean";
}
return retVal;
}
public String entityType(JavaClass javaClass) {
int beanType = getBeanType(javaClass);
if (hasFlag(beanType, BEAN_ENTITY)) {
return "entity";
} else if (hasFlag(beanType, BEAN_SESSION)) {
return "session";
} else if (hasFlag(beanType, BEAN_MESSAGE_DRIVEN)) {
return "message-driven";
}
// This should not eventually happen
// shouldGenerate should not return true for it
return null;
}
public String beanType(JavaClass javaClass) {
int beanType = getBeanType(javaClass);
if (hasFlag(beanType, BEAN_ENTITY)) {
return "Entity";
} else if (hasFlag(beanType, BEAN_SESSION)) {
return "Session";
} else if (hasFlag(beanType, BEAN_MESSAGE_DRIVEN)) {
return "Message Driven"; // Not used yet !
}
return null;
}
public String sessionType(JavaClass javaClass) {
int beanType = getBeanType(javaClass);
String retVal = null;
if (hasFlag(beanType, BEAN_STATE_FULL)) {
retVal = "Stateful";
} else if (hasFlag(beanType, BEAN_STATE_LESS)) {
retVal = "Stateless";
}
return retVal;
}
public String getNamedParameter(AbstractJavaEntity javaEntity, String tagName, String parameterName, String defValue) {
String value = javaEntity.getNamedParameter(tagName, parameterName);
if (value == null) {
value = defValue;
}
return value;
}
public String getNamedParameter(DocletTag tag, String parameterName, String defValue) {
String value = tag.getNamedParameter(parameterName);
if (value == null) {
value = defValue;
}
return value;
}
public boolean hasActivationConfig(JavaClass javaClass) {
EjbBeanTag beanTag = (EjbBeanTag) javaClass.getTagByName(TagLibrary.EJB_BEAN);
EjbActivationConfigPropertyTag actTag = (EjbActivationConfigPropertyTag) javaClass.getTagByName(
TagLibrary.EJB_ACTIVATION_CONFIG_PROPERTY);
boolean retVal = false;
if (beanTag != null) {
retVal |= (beanTag.getDestinationType() != null);
retVal |= (beanTag.getAcknowledgeMode() != null);
retVal |= (beanTag.getSubscriptionDurability() != null);
retVal |= (beanTag.getMessageSelector() != null);
}
retVal |= (actTag != null);
return retVal;
}
public boolean isUseSoftLocking(JavaClass javaClass) {
EjbBeanTag beanTag = (EjbBeanTag) javaClass.getTagByName(TagLibrary.EJB_BEAN);
return (beanTag != null) && beanTag.isUseSoftLocking();
}
public Collection findTagsByName(JavaClass javaClass, String tagName) {
List list = new ArrayList();
findTagsByNameRecursive(list, javaClass, tagName,
TAG_FIND_RECURSIVE | TAG_FIND_CLASS | TAG_FIND_METHOD | TAG_FIND_FIELD);
return list;
}
private void findTagsByNameRecursive(List list, JavaClass javaClass, String tagName, int findFlags) {
DocletTag[] tags;
if (hasFlag(findFlags, TAG_FIND_CLASS)) {
tags = javaClass.getTagsByName(tagName);
for (int i = 0; i < tags.length; i++) {
list.add(new TagReference(tags[i], javaClass));
}
// list.addAll(Arrays.asList(javaClass.getTagsByName(tagName)));
}
if (hasFlag(findFlags, TAG_FIND_METHOD)) {
JavaMethod[] methods = javaClass.getMethods();
for (int i = 0; i < methods.length; i++) {
tags = methods[i].getTagsByName(tagName);
for (int j = 0; j < tags.length; j++) {
list.add(new TagReference(tags[j], methods[i]));
}
// list.addAll(Arrays.asList(methods[i].getTagsByName(tagName)));
}
}
if (hasFlag(findFlags, TAG_FIND_FIELD)) {
JavaField[] fields = javaClass.getFields();
for (int i = 0; i < fields.length; i++) {
tags = fields[i].getTagsByName(tagName);
for (int j = 0; j < tags.length; j++) {
list.add(new TagReference(tags[j], fields[i]));
}
// list.addAll(Arrays.asList(fields[i].getTagsByName(tagName)));
}
}
if (hasFlag(findFlags, TAG_FIND_RECURSIVE)) {
JavaClass superclass = javaClass.getSuperJavaClass();
// THIS IS A HACK AROUND A BUG THAT MUST BE SOLVED!!!
// SOMETIMES A CLASS RETURNS ITSELF AS SUPER ?!?!?!?!?!
if ((superclass != null) && (superclass != javaClass)) {
findTagsByNameRecursive(list, superclass, tagName, findFlags);
}
JavaClass[] implementz = javaClass.getImplementedInterfaces();
for (int h = 0; h < implementz.length; h++) {
if (implementz[h] != null) {
findTagsByNameRecursive(list, implementz[h], tagName, findFlags);
}
}
}
}
private Type wrapType(Type type) {
Type wrapperType = (Type) wrappers.get(type.toString());
return wrapperType != null ? wrapperType : type;
}
public String refType(TagReference reference) {
DocletTag tag = reference.getTag();
String refType = null;
String paramName = null;
if (tag instanceof EjbEjbServiceRefTag) {
refType = ((EjbEjbServiceRefTag) tag).getInterface();
paramName = "interface";
} else if (tag instanceof EjbResourceRefTag) {
refType = ((EjbResourceRefTag) tag).getResType();
paramName = "res-type";
} else if (tag instanceof EjbResourceEnvRefTag) {
refType = ((EjbResourceEnvRefTag) tag).getType();
paramName = "type";
} else {
throw getErrorWithTagLocation(tag, "Unexpected tag type");
}
if (reference.getClazz() != null) {
// Class level tag
if (refType == null) {
throw getErrorWithTagLocation(tag, "'" + paramName + "' is mandatory for class level tag");
}
} else if (reference.getField() != null) {
// Field level tag
refType = wrapType(reference.getField().getType()).toString();
} else if (reference.getMethod() != null) {
// Method level tag
if (reference.getMethod().getReturns().isVoid()) {
throw getErrorWithTagLocation(tag,
"Cannot set @" + tag.getName() + " on a method with a void return type");
}
refType = wrapType(reference.getMethod().getReturns()).toString();
}
if (refType == null) {
throw getErrorWithTagLocation(tag, "'" + paramName + "' could not be resolved");
}
return refType;
}
public Error getErrorWithTagLocation(DocletTag tag, String message) {
return new Error(tagToString(tag) + ": " + message);
}
public static String getMessageWithTagLocation(DocletTag tag, String message) {
return tagToString(tag) + ": " + message;
}
public static String getMessageWithMethodLocation(JavaMethod method, String message) {
return methodToString(method) + ": " + message;
}
public static String methodToString(JavaMethod method) {
StringBuffer locationBuf = new StringBuffer();
locationBuf.append(method.getParentClass().getFullyQualifiedName());
locationBuf.append(':');
locationBuf.append(method.getDeclarationSignature(false));
return locationBuf.toString();
}
public static String tagToString(DocletTag tag) {
StringBuffer retBuf = new StringBuffer();
retBuf.append("@");
retBuf.append(tag.getName());
retBuf.append(" ");
retBuf.append(tag.getValue());
retBuf.append(" (");
retBuf.append(ConfigurableDocletTagFactory.getLocation(tag));
retBuf.append(":");
retBuf.append(tag.getLineNumber());
retBuf.append(")");
return retBuf.toString();
}
public String refName(TagReference reference) {
DocletTag tag = reference.getTag();
String refName = null;
String paramName = null;
if (tag instanceof EjbEjbServiceRefTag) {
refName = ((EjbEjbServiceRefTag) tag).getName_();
paramName = "name";
} else if (tag instanceof EjbResourceRefTag) {
refName = ((EjbResourceRefTag) tag).getResRefName();
paramName = "res-ref-name";
} else if (tag instanceof EjbResourceEnvRefTag) {
refName = ((EjbResourceEnvRefTag) tag).getName_();
paramName = "name";
} else {
throw getErrorWithTagLocation(tag, "Unexpected tag type");
}
if (refName == null) {
if (reference.getClazz() != null) {
// Class level tag
throw getErrorWithTagLocation(tag, "'" + paramName + "' is mandatory for class level tag");
} else if (reference.getField() != null) {
// Field level tag
refName = reference.getField().getName();
} else if (reference.getMethod() != null) {
// Method level tag
refName = reference.getMethod().getName();
}
}
if (refName == null) {
throw getErrorWithTagLocation(tag, "'" + paramName + "' could not be resolved");
}
return refName;
}
public String ejbRefName(TagReference reference) {
return ejbRefName(reference, null);
}
public String ejbRefName(TagReference reference, JavaClass refClass) {
DocletTag tag = reference.getTag();
String ejbRefName = null;
String viewType = null;
String paramName = null;
if (tag instanceof EjbEjbRefTag) {
ejbRefName = ((EjbEjbRefTag) tag).getRefName();
viewType = ((EjbEjbRefTag) tag).getViewType();
paramName = "ref-name";
} else if (tag instanceof EjbEjbExternalRefTag) {
ejbRefName = ((EjbEjbExternalRefTag) tag).getRefName();
viewType = ((EjbEjbExternalRefTag) tag).getViewType();
paramName = "ref-name";
} else {
throw getErrorWithTagLocation(tag, "Unexpected tag type");
}
if (ejbRefName == null) {
if (reference.getClazz() != null) {
// Class level tag
if (refClass != null) {
ejbRefName = getComponentName(refClass, isRemoteEjbRef(viewType, refClass) ? REMOTE : LOCAL, true);
} else {
throw getErrorWithTagLocation(tag, "'" + paramName + "' is mandatory for class level tag");
}
} else if (reference.getField() != null) {
// Field level tag
ejbRefName = reference.getField().getName();
} else if (reference.getMethod() != null) {
// Method level tag
ejbRefName = reference.getMethod().getName();
}
}
if (ejbRefName == null) {
throw getErrorWithTagLocation(tag, "'" + paramName + "' could not be resolved");
}
return ejbRefName;
}
public String getComponentName(JavaClass clazz, int viewType, boolean prependEjb) {
StringBuffer retName = new StringBuffer();
String ejbName = getEjbName(clazz).replace('.', '/');
if (prependEjb && !ejbName.startsWith("ejb/")) {
retName.append("ejb/");
}
retName.append(ejbName);
if (viewType == LOCAL) {
retName.append("Local");
} else if (viewType == REMOTE) {
retName.append("Remote");
}
return retName.toString();
}
public String getJndiName(JavaClass clazz, int viewType) {
EjbBeanTag beanTag = (EjbBeanTag)clazz.getTagByName(TagLibrary.EJB_BEAN);
String jndiName = null;
if ((beanTag != null) && (viewType == LOCAL)) {
jndiName = beanTag.getLocalJndiName();
} else if ((beanTag != null) && (viewType == REMOTE)) {
jndiName = beanTag.getJndiName();
}
if (jndiName == null) {
jndiName = getComponentName(clazz, viewType, false);
}
return jndiName;
}
public boolean isLocalEjbRef(String viewType, JavaClass refClass) {
return isEjbRefType(viewType, refClass, LOCAL);
}
public boolean isLocalEjbRef(String viewType) {
return isEjbRefType(viewType, LOCAL);
}
public boolean isRemoteEjbRef(String viewType, JavaClass refClass) {
return isEjbRefType(viewType, refClass, REMOTE) && !isEjbRefType(viewType, refClass, LOCAL);
}
public boolean isRemoteEjbRef(String viewType) {
return isEjbRefType(viewType, REMOTE) && !isEjbRefType(viewType, LOCAL);
}
private boolean isEjbRefType(String viewType, JavaClass refClass, int desiredView) {
// int beanType = (viewType != null) ? getViewType(viewType) : getViewType(refClass);
int beanType = (viewType != null) ? getViewType(viewType) & getViewType(refClass) : getViewType(refClass);
return hasFlag(beanType, desiredView);
}
private boolean isEjbRefType(String viewType, int desiredView) {
return hasFlag(getViewType(viewType), desiredView);
}
public JavaClass findEjbRef(String ejbName, EjbBeanResolver beanResolver) {
JavaClass javaClass = beanResolver.findEjbByName(ejbName);
if (javaClass == null) {
throw new Error("Couldn't find named ejb: " + ejbName);
}
int beanType = getBeanType(javaClass);
// We can only reference a session or entity bean
if (!hasFlag(beanType, BEAN_ENTITY) && !hasFlag(beanType, BEAN_SESSION)) {
throw new Error("Referenced bean must be a session bean or entity bean: " + ejbName);
}
return javaClass;
}
public JavaMethod externalizeMethodName(JavaMethod method) {
int methodType = getMethodType(method);
String removeString = null;
switch (methodType) {
case IFACE_METHOD_FINDER:
case IFACE_METHOD_CREATE:
case IFACE_METHOD_SELECT:
removeString = "ejb";
break;
case IFACE_METHOD_HOME:
removeString = "ejbHome";
break;
}
JavaMethod retVal = method;
if (removeString != null) {
retVal = removeFromMethodName(method, removeString);
}
return retVal;
}
private JavaMethod removeFromMethodName(JavaMethod method, String removeString) {
if (!method.getName().startsWith(removeString) || method.getName().length() <= removeString.length()) {
throw new Error("Method name: " + method.getName() + ", must start with " + removeString);
}
StringBuffer methodName = new StringBuffer(method.getName());
methodName.delete(0, removeString.length());
methodName.setCharAt(0, Character.toLowerCase(methodName.charAt(0)));
method = new DuplicatedJavaMethod(method);
method.setName(methodName.toString());
return method;
}
public Collection getSecurityRoles(Collection metadata) {
Collection roleTags = new ArrayList();
Collection ejbBeans = getBeans(metadata);
for (Iterator iter = ejbBeans.iterator(); iter.hasNext();) {
JavaClass javaClass = (JavaClass) iter.next();
roleTags.addAll(Arrays.asList(javaClass.getTagsByName(TagLibrary.EJB_PERMISSION)));
JavaMethod[] methods = javaClass.getMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getTagByName(TagLibrary.EJB_PERMISSION) != null) {
int methodType = getMethodType(methods[i]);
if ((methodType != IFACE_METHOD_CREATE) && (methodType != IFACE_METHOD_COMPONENT)) {
throw getErrorWithTagLocation(methods[i].getTagByName(TagLibrary.EJB_PERMISSION),
"Can't mark a method permission on a non interface or create method");
}
}
roleTags.addAll(Arrays.asList(methods[i].getTagsByName(TagLibrary.EJB_PERMISSION)));
}
if (isEntityBean(javaClass)) {
// get roles from finders
roleTags.addAll(Arrays.asList(javaClass.getTagsByName(TagLibrary.EJB_FINDER)));
// and from pk field ( if any )
roleTags.addAll(Arrays.asList(javaClass.getTagsByName(TagLibrary.EJB_PK)));
}
// and from extra security roles
roleTags.addAll(Arrays.asList(javaClass.getTagsByName(TagLibrary.EJB_SECURITY_ROLES)));
}
Collection roles = new TreeSet();
for (Iterator iter = roleTags.iterator(); iter.hasNext();) {
RoleList roleLst = (RoleList) iter.next();
if (roleLst != null && roleLst.getRoleNames() != null) {
roles.addAll(Arrays.asList(roleLst.getRoleNames()));
}
}
return roles;
}
private static class RelationEntryHolder {
private EjbRelationTag relTag;
private JavaMethod method;
private List beanLst = new ArrayList();
public RelationEntryHolder(EjbRelationTag relTag, JavaMethod method) {
this.relTag = relTag;
this.method = method;
}
public void addSourceBean(JavaClass sourceBean) {
beanLst.add(sourceBean);
}
public int countSourceBeans() {
return beanLst.size();
}
public JavaClass[] getSourceBeans() {
return (JavaClass[]) beanLst.toArray(new JavaClass[0]);
}
public JavaMethod getMethod() {
return this.method;
}
public EjbRelationTag getRelTag() {
return this.relTag;
}
public String toString() {
StringBuffer retBuf = new StringBuffer();
retBuf.append("[relTag]={");
retBuf.append((relTag != null) ? ("@" + relTag.getName() + " " + relTag.getValue()) : null);
retBuf.append("},[method]={");
retBuf.append((method != null) ? method.getCallSignature() : null);
retBuf.append("}");
return retBuf.toString();
}
}
private class RelationImpl implements Relation {
/** The logging object */
protected Log log = LogFactory.getLog(RelationImpl.class);
private String name;
private RelationEntryHolder left;
private JavaClass leftBean;
private RelationEntryHolder right;
private JavaClass rightBean;
public RelationImpl(String name) {
this.name = name;
}
public void addHolder(RelationEntryHolder holder, JavaClass sourceBean) {
if (left == null) {
left = holder;
leftBean = sourceBean;
} else if (right == null) {
right = holder;
rightBean = sourceBean;
} else {
IllegalStateException e = new IllegalStateException();
if (log.isErrorEnabled()) {
log.error("This should not happen", e);
}
// This should not happen
throw e;
}
}
private EjbRelationTag getRightTag() {
return right != null ? right.getRelTag() : null;
}
private EjbRelationTag getLeftTag() {
return left != null ? left.getRelTag() : null;
}
public void swap() {
RelationEntryHolder t1 = left;
JavaClass t2 = leftBean;
left = right;
leftBean = rightBean;
right = t1;
rightBean = t2;
}
public String toString() {
StringBuffer retBuf = new StringBuffer();
retBuf.append("[name]={");
retBuf.append(name);
retBuf.append("},[left]={");
retBuf.append(left);
retBuf.append("},[leftBean]={");
retBuf.append((leftBean != null) ? leftBean.getFullyQualifiedName() : null);
retBuf.append("},[right]={");
retBuf.append(right);
retBuf.append("},[rightBean]={");
retBuf.append((rightBean != null) ? rightBean.getFullyQualifiedName() : null);
retBuf.append("}");
return retBuf.toString();
}
private String getRoleName(EjbRelationTag lTag, EjbRelationTag rTag) {
String roleName = null;
if (lTag != null) {
roleName = lTag.getRoleName();
} else {
roleName = rTag.getTargetRoleName();
}
return roleName;
}
private boolean isCascadeDelete(EjbRelationTag lTag, EjbRelationTag rTag) {
boolean retVal = false;
if (lTag != null) {
retVal = lTag.isCascadeDelete();
} else {
retVal = rTag.isTargetCascadeDelete();
}
return retVal;
}
private String getEJBName(JavaClass clazz, EjbRelationTag tag) {
String ejbName = null;
if (clazz != null) {
ejbName = getEjbName(clazz);
} else {
ejbName = tag.getTargetEjb();
if (ejbName == null) {
if (log.isErrorEnabled()) {
log.error("'target-ejb' is mandatory for tag " + tagToString(tag));
}
throw getErrorWithTagLocation(tag, "'target-ejb' is mandatory for tag");
}
}
return ejbName;
}
// --------------------------------------------------------
// Relation interface
// --------------------------------------------------------
public String getName() {
return name;
}
/**
* Gets relation's left side bean
*/
public JavaClass getLeftBean() {
return leftBean;
}
/**
* Gets relation's right side bean
*/
public JavaClass getRightBean() {
return rightBean;
}
/**
* Gets relation's right side method
*/
public JavaMethod getRightMethod() {
return right != null ? right.getMethod() : null;
}
/**
* Gets relation's left side method
*/
public JavaMethod getLeftMethod() {
return (left != null) ? left.getMethod() : null;
}
public boolean isLeftMany() {
boolean retVal = false;
JavaMethod method = getLeftMethod();
EjbRelationTag tag = getRightTag();
if (method != null) {
retVal |= method.getReturns().isA(new Type(Collection.class.getName()));
retVal |= method.getReturns().isA(new Type(Set.class.getName()));
} else {
retVal = tag.isTargetMultiple();
}
return retVal;
}
public boolean isRightMany() {
boolean retVal = false;
JavaMethod method = getRightMethod();
EjbRelationTag tag = getLeftTag();
if (method != null) {
retVal |= method.getReturns().isA(new Type(Collection.class.getName()));
retVal |= method.getReturns().isA(new Type(Set.class.getName()));
} else {
retVal = tag.isTargetMultiple();
}
return retVal;
}
public boolean isBidirectional() {
return (left != null) && (right != null);
}
public boolean isOne2Many() {
return !isLeftMany() && isRightMany();
}
public String getLeftRoleName() {
return getRoleName(getLeftTag(), getRightTag());
}
public String getRightRoleName() {
return getRoleName(getRightTag(), getLeftTag());
}
public boolean isLeftCascadeDelete() {
return isCascadeDelete(getLeftTag(), getRightTag());
}
public boolean isRightCascadeDelete() {
return isCascadeDelete(getRightTag(), getLeftTag());
}
public String getLeftEJBName() {
return getEJBName(getLeftBean(), getRightTag());
}
public String getRightEJBName() {
return getEJBName(getRightBean(), getLeftTag());
}
public Relation reverse() {
RelationImpl retVal = new RelationImpl(name);
retVal.left = this.right;
retVal.leftBean = this.rightBean;
retVal.right = this.left;
retVal.rightBean = this.leftBean;
return retVal;
}
}
public class RelationManagerImpl implements RelationManager {
/** The logging object */
protected Log log = LogFactory.getLog(RelationManagerImpl.class);
/** The map of name / LinkedHashMap */
private SortedMap relations = new TreeMap(); // Strings are Comparable
/** A cache for all relations */
private Collection allRelations = null;
/**
* Returns a map that maintains list of inserted elements
* method / RelationEntryHolder
* @param relationName The relation to look for
* @return The map
*/
private LinkedHashMap getMapFor(String relationName) {
LinkedHashMap retVal;
retVal = (LinkedHashMap) relations.get(relationName);
if (retVal == null) {
retVal = new LinkedHashMap();
relations.put(relationName, retVal);
}
return retVal;
}
public void manage(EjbRelationTag relTag, JavaMethod method, JavaClass sourceBean) {
LinkedHashMap mapFor = getMapFor(relTag.getName_());
RelationEntryHolder entryHolder;
if (mapFor.containsKey(method)) {
entryHolder = (RelationEntryHolder) mapFor.get(method);
if (log.isDebugEnabled()) {
log.debug("Existing relation entry pair for relation named '" + relTag.getName_() + "' found at " +
tagToString(relTag));
}
} else {
if (log.isDebugEnabled()) {
log.debug("A new relation entry pair for relation named '" + relTag.getName_() +
"' is being created at " + tagToString(relTag));
}
entryHolder = new RelationEntryHolder(relTag, method);
mapFor.put(method, entryHolder);
}
entryHolder.addSourceBean(sourceBean);
}
private Collection validateAndCreateRelations(String relationName, LinkedHashMap mapFor) {
List relationLst = new ArrayList();
List entryList = new ArrayList(mapFor.values());
if (entryList.size() > 2) {
RelationEntryHolder firstHolder = (RelationEntryHolder) entryList.get(0);
RelationEntryHolder secondHolder = (RelationEntryHolder) entryList.get(1);
// RelationEntryHolder erroneousHolder = (RelationEntryHolder) entryList.get(2);
if (log.isErrorEnabled()) {
log.error("The relation named '" + relationName + "' has more entries that it should.");
log.error("The first node is declared at " + tagToString(firstHolder.getRelTag()));
log.error("The second node is declared at " + tagToString(secondHolder.getRelTag()));
for (int i = 2; i < entryList.size(); i++) {
RelationEntryHolder holder = (RelationEntryHolder) entryList.get(i);
log.error("Invalid/duplicated at " + tagToString(holder.getRelTag()));
}
}
// throw new Error("The '" + relationName + "' relation is declared in too many places.\n" +
// "It's declared in " + tagToString(firstHolder.getRelTag()) + ",\n" +
// tagToString(secondHolder.getRelTag()) + " and\n" + tagToString(erroneousHolder.getRelTag()));
} else if (entryList.size() == 1) {
if (log.isDebugEnabled()) {
log.debug("It is a unidirectional relation named '" + relationName + "'");
}
RelationEntryHolder holder = (RelationEntryHolder) entryList.get(0);
JavaClass[] sourceBeans = holder.getSourceBeans();
RelationImpl relation;
if (holder.countSourceBeans() > 1) {
if (log.isDebugEnabled()) {
log.debug("This is an unidirectional relation used in several beans");
for (int i = 0; i < sourceBeans.length; i++) {
if (log.isDebugEnabled()) {
log.debug("Used in " + getEjbName(sourceBeans[i]));
}
}
}
if (log.isWarnEnabled()) {
log.warn(
"To support unidirectional relations used in various beans we are going to extend the relation name");
}
String genRelationName;
for (int i = 0; i < sourceBeans.length; i++) {
genRelationName = relationName + "-" + getEjbName(sourceBeans[i]);
if (log.isWarnEnabled()) {
log.warn("Relation name = '" + relationName + "', extendedName='" + genRelationName + "'");
}
if (log.isTraceEnabled()) {
log.trace("Creating RelationImpl for '" + genRelationName + "'");
}
relationLst.add(relation = new RelationImpl(genRelationName));
relation.addHolder(holder, sourceBeans[i]);
}
} else {
if (log.isTraceEnabled()) {
log.trace("Creating RelationImpl for '" + relationName + "'");
}
relationLst.add(relation = new RelationImpl(relationName));
relation.addHolder(holder, sourceBeans[0]);
}
} else {
// Bi-directional relations
// We can't support entries with more that one bean
RelationEntryHolder holder;
JavaClass[] sourceBeans;
if (log.isTraceEnabled()) {
log.trace("Creating RelationImpl for '" + relationName + "'");
}
RelationImpl relation = new RelationImpl(relationName);
boolean shouldAdd = true;
for (int i = 0; i < entryList.size(); i++) {
holder = (RelationEntryHolder) entryList.get(i);
sourceBeans = holder.getSourceBeans();
if (holder.countSourceBeans() != 1) {
if (log.isErrorEnabled()) {
log.error("The bidirectional relation named '" + relationName +
"' is declared in more than one bean.");
log.error("It is defined in " + tagToString(holder.getRelTag()));
for (int j = 0; j < sourceBeans.length; j++) {
log.error("And therefore used in " + getEjbName(sourceBeans[i]) + " - " +
sourceBeans[i].getFullyQualifiedName());
}
}
shouldAdd = false;
// throw new Error("The bidirectional relation named '" + relationName + "' is declared in more than one bean.\n" +
// "It's declared in " + tagToString(holder.getRelTag()));
} else {
relation.addHolder(holder, sourceBeans[0]);
}
}
if (shouldAdd) {
relationLst.add(relation);
} else if (log.isWarnEnabled()) {
log.warn("The bidirectional relation named '" + relationName +
"' is being discarded because is declared in more than one bean.");
}
}
// Now swap relations so that right is always many (if there is a many side).
// This may result in left being null, in case of a unidirectional relationship
// Possible cases are (left-right):
// 1-->1, 1<--1, 1-->N, 1<--N, M-->N, N<--M
// 1<->1, 1<->N, M<->N
// Impossible cases are (left-right):
// N-->1, N<--1
for (Iterator iter = relationLst.iterator(); iter.hasNext();) {
RelationImpl relation = (RelationImpl) iter.next();
if (log.isDebugEnabled()) {
log.debug("Working on relation " + relation);
}
if (relation.isLeftMany() && !relation.isRightMany()) {
if (log.isDebugEnabled()) {
log.debug("This is N-1 relation. Swapping into 1-N.");
}
relation.swap();
}
if (!relation.isBidirectional() && relation.isOne2Many() && relation.getLeftMethod() == null) {
if (log.isDebugEnabled()) {
log.debug("This is 1-N without a left method. Swapping.");
}
relation.swap();
}
}
return relationLst;
}
private Relation selectByBean(Relation[] relationLst, JavaClass bean) {
Relation retVal = null;
if (relationLst != null) {
for (int i = 0; retVal == null && i < relationLst.length; i++) {
Relation current = relationLst[i];
if ((current.getLeftBean() != null) &&
current.getLeftBean().getFullyQualifiedName().equals(bean.getFullyQualifiedName())) {
retVal = current;
} else if ((current.getRightBean() != null) &&
current.getRightBean().getFullyQualifiedName().equals(bean.getFullyQualifiedName())) {
retVal = current;
}
}
}
return retVal;
}
public String toString() {
StringBuffer retBuf = new StringBuffer();
Relation[] relLst = getRelations();
for (int i = 0; i < relLst.length; i++) {
retBuf.append("[");
retBuf.append(i);
retBuf.append("]={");
retBuf.append(relLst[i]);
retBuf.append("}\n");
}
return retBuf.toString();
}
// --------------------------------------------------------
// RelationManager interface
// --------------------------------------------------------
/**
* Match a relation for a method and a bean
* @param method The method to look the relation for
* @param bean The bean in any side of relation
* @return The found relation or null if not found
*/
public Relation getRelationFor(JavaMethod method, JavaClass bean) {
return selectByBean(getRelationsFor(method), bean);
}
/**
* Match relations for a method
* @param method The method to look the relation for
* @return The list of found relations (empty array if not found)
* @return The found relation or null if not found
*/
public Relation[] getRelationsFor(final JavaMethod method) {
Collection retLst = CollectionUtils.select(Arrays.asList(getRelations()),
new Predicate() {
public boolean evaluate(Object arg0) {
Relation current = (Relation) arg0;
boolean isFound;
isFound = (current.getLeftMethod() != null) && current.getLeftMethod().equals(method);
isFound = isFound ||
(current.getRightMethod() != null) && current.getRightMethod().equals(method);
return isFound;
}
});
return (Relation[]) retLst.toArray(new Relation[0]);
}
/**
* Match relation for a name and a bean
* @param relationName The relation name
* @param bean The bean in any side of relation
* @return The found relation or null if not found
*/
public Relation getRelationByName(String relationName, JavaClass bean) {
return selectByBean(getRelationsByName(relationName), bean);
}
/**
* Match relations for a name
* @param relationName The relation name
* @return The list of found relations (empty array if not found)
*/
public Relation[] getRelationsByName(String relationName) {
Collection retVal = new ArrayList();
LinkedHashMap mapFor = (LinkedHashMap) relations.get(relationName);
if (mapFor != null) {
retVal.addAll(validateAndCreateRelations(relationName, mapFor));
}
return (Relation[]) retVal.toArray(new Relation[0]);
}
/**
* Get all known relations
* @return The list of found relations (empty array if not found)
*/
public Relation[] getRelations() {
if (allRelations == null) {
allRelations = new ArrayList();
for (Iterator iter = relations.entrySet().iterator(); iter.hasNext();) {
Map.Entry entry = (Entry) iter.next();
allRelations.addAll(validateAndCreateRelations((String) entry.getKey(),
(LinkedHashMap) entry.getValue()));
}
}
return (Relation[]) allRelations.toArray(new Relation[0]);
}
}
/**
* Creates a relation manager
* @param metadata The collection of JavaClass
* @return An RelationManager
*/
public RelationManager createRelationManager(Collection metadata) {
// Select concrete CMP Beans
Collection cmpBeans = CollectionUtils.select(getBeans(metadata, BEAN_CMP),
new Predicate() {
public boolean evaluate(Object arg0) {
JavaClass javaClass = (JavaClass) arg0;
boolean retVal = shouldGenerate(javaClass);
if (log.isDebugEnabled()) {
log.debug(javaClass.getFullyQualifiedName() +
(retVal ? " is a concrete bean" : " isn't a concrete bean"));
}
return retVal;
}
});
RelationManagerImpl manager = new RelationManagerImpl();
for (Iterator iter = cmpBeans.iterator(); iter.hasNext();) {
JavaClass javaClass = (JavaClass) iter.next();
// Get hierarchy methods
JavaMethod[] methods = javaClass.getMethods(true);
for (int i = 0; i < methods.length; i++) {
if (hasFlag(getMethodMetadata(javaClass, methods[i]), METADATA_METHOD_RELATION_FIELD)) {
// We support the same relation 'name' repeated when we have a uni-direccional
// relation and for the same method
// NOTE: This is to support an uni-direccional relation to be defined
// in an abstract bean, used in several beans. Imagine PrivateClient and CompanyClient
// having a method getAccounts.
// For now, i am not seeing any problem...
manager.manage((EjbRelationTag) methods[i].getTagByName(TagLibrary.EJB_RELATION), methods[i], javaClass);
}
}
}
// At the end verify fields
return manager;
}
public static class TagReference {
private DocletTag tag;
private JavaClass clazz;
private JavaMethod method;
private JavaField field;
public TagReference(DocletTag tag, JavaClass clazz) {
this.tag = tag;
this.clazz = clazz;
}
public TagReference(DocletTag tag, JavaMethod method) {
this.tag = tag;
this.method = method;
}
public TagReference(DocletTag tag, JavaField field) {
this.tag = tag;
this.field = field;
}
public JavaClass getClazz() {
return this.clazz;
}
public void setClazz(JavaClass clazz) {
this.clazz = clazz;
}
public JavaField getField() {
return this.field;
}
public void setField(JavaField field) {
this.field = field;
}
public JavaMethod getMethod() {
return this.method;
}
public void setMethod(JavaMethod method) {
this.method = method;
}
public DocletTag getTag() {
return this.tag;
}
public void setTag(DocletTag tag) {
this.tag = tag;
}
}
public Collection getMethodPermissions(JavaClass javaClass) {
EjbVersion version = config.getEjbVersion();
Collection retLst = new ArrayList();
DocletTag[] tags;
if (!isEJB(javaClass)) {
throw new Error();
}
// Let dig into class level ejb.permission tags
tags = javaClass.getTagsByName(TagLibrary.EJB_PERMISSION);
for (int i = 0; i < tags.length; i++) {
EjbPermissionTag permTag = (EjbPermissionTag) tags[i];
int permType = getViewType(javaClass);
// -------------------------------------------------------
// Let's "bitwise and" to get only the specied masks
// that are compatible with the bean
// HUMM: Is this valid ?
if (permTag.getViewType() != null) {
permType &= getViewType(permTag.getViewType());
} else if (permTag.getMethodIntf() != null) {
permType &= getInterfaceType(permTag.getMethodIntf());
}
if (permType == 0) {
throw getErrorWithTagLocation(permTag,
"Couldn't resolve a compatible interface type reference. Maybe bean/view-type/version doesn't support it!");
}
// -------------------------------------------------------
// We are generating an method permission if there is at least
// one role or unchecked is true
// NOTE: unchecked is only valid for EJB 2.0+
boolean canContinue = (permTag.getRoleNames() != null && permTag.getRoleNames().length > 0);
if (version.greaterOrEquals(EjbVersion.EJB_2_0)) {
canContinue |= permTag.isUnchecked();
}
if (!canContinue) {
throw getErrorWithTagLocation(permTag,
"Couldn't resolve role-names for method permission" +
(version.greaterOrEquals(EjbVersion.EJB_2_0) ? " or unchecked is false" : ""));
}
// Lets expand by permission for interface type
retLst.addAll(MethodPermission.unroll(permType, permTag.getRoleNames()));
}
// Now let's dig into method level ejb.permission tags
JavaMethod[] methods = javaClass.getMethods();
JavaMethod method;
for (int j = 0; j < methods.length; j++) {
tags = (method = methods[j]).getTagsByName(TagLibrary.EJB_PERMISSION);
for (int k = 0; k < tags.length; k++) {
EjbPermissionTag permTag = (EjbPermissionTag) tags[k];
int methodType = getMethodType(method);
if ((methodType != IFACE_METHOD_CREATE) && (methodType != IFACE_METHOD_COMPONENT)) {
throw getErrorWithTagLocation(permTag,
"Can't mark a method permission on a non interface or create method");
}
int permType = getViewType(method, javaClass);
// -------------------------------------------------------
// Let's "bitwise and" to get only the specied masks
// that are compatible with the bean
// HUMM: Is this valid ?
if (permTag.getViewType() != null) {
permType &= getViewType(permTag.getViewType());
} else if (permTag.getMethodIntf() != null) {
permType &= getInterfaceType(permTag.getMethodIntf());
}
if (permType == 0) {
throw getErrorWithTagLocation(permTag,
"Couldn't resolve a compatible interface type reference. Maybe bean/view-type/version doesn't support it!");
}
// -------------------------------------------------------
// We are generating an method permission if there is at least
// one role or unchecked is true
// NOTE: unchecked is only valid for EJB 2.0+
boolean canContinue = (permTag.getRoleNames() != null && permTag.getRoleNames().length > 0);
if (version.greaterOrEquals(EjbVersion.EJB_2_0)) {
canContinue |= permTag.isUnchecked();
}
if (!canContinue) {
throw getErrorWithTagLocation(permTag,
"Couldn't resolve role-names for method permission" +
(version.greaterOrEquals(EjbVersion.EJB_2_0) ? " or unchecked is false" : ""));
}
// Lets expand by permission for interface type
retLst.addAll(MethodPermission.unroll(permType, externalizeMethodName(method), permTag.getRoleNames()));
}
}
if (isEntityBean(javaClass)) {
tags = javaClass.getTagsByName(TagLibrary.EJB_FINDER);
// Let dig into class level ejb.finder tags
for (int i = 0; i < tags.length; i++) {
EjbFinderTag finderTag = (EjbFinderTag) tags[i];
int permType = getViewType(finderTag.getViewType()) & (REMOTE_HOME | LOCAL_HOME);
// -------------------------------------------------------
// Let's "bitwise and" to get only the specied masks
// that are compatible with the bean
// HUMM: Is this valid ?
if (finderTag.getMethodIntf() != null) {
permType &= getInterfaceType(finderTag.getMethodIntf());
}
if (permType == 0) {
throw getErrorWithTagLocation(finderTag,
"Couldn't resolve a compatible interface type reference. Maybe bean/view-type/version doesn't support it!");
}
// -------------------------------------------------------
// We are generating an method permission if there is at least
// one role or unchecked is true
// NOTE: unchecked is only valid for EJB 2.0+
boolean canContinue = (finderTag.getRoleNames() != null && finderTag.getRoleNames().length > 0);
if (version.greaterOrEquals(EjbVersion.EJB_2_0)) {
canContinue |= finderTag.isUnchecked();
}
if (canContinue) {
// Lets expand by permission for interface type
// Method signature should maybe be unrolled by permType, but it's not really relevant
// the return type, soo..
retLst.addAll(MethodPermission.unroll(permType, getFinderMethodBySignature(finderTag.getSignature()),
finderTag.getRoleNames()));
}
}
EjbPkTag pkTag = (EjbPkTag) javaClass.getTagByName(TagLibrary.EJB_PK);
if (pkTag != null) {
// -------------------------------------------------------
// We are generating an method permission if there is at least
// one role or unchecked is true
// NOTE: unchecked is only valid for EJB 2.0+
boolean canContinue = (pkTag.getRoleNames() != null && pkTag.getRoleNames().length > 0);
if (version.greaterOrEquals(EjbVersion.EJB_2_0)) {
canContinue |= pkTag.isUnchecked();
}
// We'll not continue this if we do not have to check a security method for
// "findByPrimaryKey"
if (canContinue) {
int permType = getViewType(javaClass) & (REMOTE_HOME | LOCAL_HOME);
// -------------------------------------------------------
// Let's "bitwise and" to get only the specied masks
// that are compatible with the bean
// HUMM: Is this valid ?
if (pkTag.getMethodIntf() != null) {
permType &= getInterfaceType(pkTag.getMethodIntf());
}
if (permType == 0) {
throw getErrorWithTagLocation(pkTag,
"Couldn't resolve a compatible interface type reference. Maybe bean/view-type/version doesn't support it!");
}
// Lets expand by permission for interface type
// Method signature should maybe be unrolled by permType, but it's not really relevant
// the return type, soo..
retLst.addAll(MethodPermission.unroll(permType,
getFinderMethodBySignature("void findByPrimaryKey()"), pkTag.getRoleNames()));
}
}
}
return retLst;
}
public Collection getContainerTransactions(JavaClass javaClass) {
Collection retLst = new ArrayList();
DocletTag[] tags;
if (!isEJB(javaClass)) {
throw new Error();
}
// Let dig into class level ejb.transaction tags
tags = javaClass.getTagsByName(TagLibrary.EJB_TRANSACTION);
for (int i = 0; i < tags.length; i++) {
EjbTransactionTag transTag = (EjbTransactionTag) tags[i];
int permType = 0;
//int permType = getViewType(javaClass);
// -------------------------------------------------------
// Let's "bitwise and" to get only the specied masks
// that are compatible with the bean
// HUMM: Is this valid ?
if (transTag.getMethodIntf() != null) {
permType = getViewType(javaClass);
permType &= getInterfaceType(transTag.getMethodIntf());
if (permType == 0) {
throw getErrorWithTagLocation(transTag,
"Couldn't resolve a compatible interface type reference. Maybe bean/view-type/version doesn't support it!");
}
// Lets expand by permission for interface type
// Only one entry should be present
retLst.addAll(ContainerTransaction.unroll(permType, transTag.getType()));
} else {
// No permission was set
retLst.add(new ContainerTransaction(transTag.getType()));
}
// if (permType == 0) {
// throw getErrorWithTagLocation(transTag,
// "Couldn't resolve a compatible interface type reference. Maybe bean/view-type/version doesn't support it!");
// }
// Lets expand by permission for interface type
// retLst.addAll(ContainerTransaction.unroll(permType, transTag.getType()));
}
// Now let's dig into method level ejb.transaction tags
JavaMethod[] methods = javaClass.getMethods();
JavaMethod method;
for (int j = 0; j < methods.length; j++) {
tags = (method = methods[j]).getTagsByName(TagLibrary.EJB_TRANSACTION_METHOD);
for (int k = 0; k < tags.length; k++) {
EjbTransactionMethodTag transTag = (EjbTransactionMethodTag) tags[k];
int methodType = getMethodType(method);
if ((methodType != IFACE_METHOD_CREATE) && (methodType != IFACE_METHOD_COMPONENT)) {
throw getErrorWithTagLocation(transTag,
"Can't mark a method transaction on a non interface or create method");
}
int permType = getViewType(method, javaClass);
// -------------------------------------------------------
// Let's "bitwise and" to get only the specied masks
// that are compatible with the bean
// HUMM: Is this valid ?
if (permType == 0) {
throw getErrorWithTagLocation(transTag,
"Couldn't resolve a compatible interface type reference. Maybe bean/view-type/version doesn't support it!");
}
// Lets expand by permission for interface type
retLst.addAll(ContainerTransaction.unroll(permType, externalizeMethodName(method), transTag.getType()));
}
}
if (isEntityBean(javaClass)) {
tags = javaClass.getTagsByName(TagLibrary.EJB_FINDER);
// Let dig into class level ejb.finder tags
for (int i = 0; i < tags.length; i++) {
EjbFinderTag finderTag = (EjbFinderTag) tags[i];
if (finderTag.getTransactionType() == null) {
// We are processing method transactions.
// So the optional element must be present
continue;
}
int permType = getViewType(finderTag.getViewType()) & (REMOTE_HOME | LOCAL_HOME);
// -------------------------------------------------------
// Let's "bitwise and" to get only the specied masks
// that are compatible with the bean
// HUMM: Is this valid ?
if (finderTag.getMethodIntf() != null) {
permType &= getInterfaceType(finderTag.getMethodIntf());
}
if (permType == 0) {
throw getErrorWithTagLocation(finderTag,
"Couldn't resolve a compatible interface type reference. Maybe bean/view-type/version doesn't support it!");
}
// Lets expand by permission for interface type
// Method signature should maybe be unrolled by permType, but it's not really relevant
// the return type, soo..
retLst.addAll(ContainerTransaction.unroll(permType,
getFinderMethodBySignature(finderTag.getSignature()), finderTag.getTransactionType()));
}
}
return retLst;
}
public Collection injectMethodThrowException(final Collection methods, final Class exceptionClass) {
return CollectionUtils.collect(methods,
new Transformer() {
public Object transform(Object method) {
SignatureDuplicatedJavaMethod retVal = new SignatureDuplicatedJavaMethod((JavaMethod) method);
Type ex = new Type(exceptionClass.getName());
if (!retVal.containsException(ex)) {
retVal.addException(ex);
}
return retVal;
}
});
}
public EjbBeanResolver createEjbBeanResolver(Collection metadata) {
EjbBeanResolver retVal = null;
if (metadata != null) {
retVal = new EjbBeanResolverImpl(metadata);
}
return retVal;
}
public class EjbBeanResolverImpl implements EjbBeanResolver {
private final Log log = LogFactory.getLog(EjbBeanResolverImpl.class);
private Map ejbCache = new HashMap();
public EjbBeanResolverImpl(Collection metadata) {
for (Iterator iter = metadata.iterator(); iter.hasNext();) {
JavaClass javaClass = (JavaClass) iter.next();
if (isEJB(javaClass)) {
String ejbName = getEjbName(javaClass);
if (ejbCache.containsKey(ejbName)) {
JavaClass otherClass = (JavaClass) ejbCache.get(ejbName);
String errorMsg = "We cannot have two diferent ejb with same name: " +
javaClass.getFullyQualifiedName() + " and " + otherClass.getFullyQualifiedName();
log.error(errorMsg);
throw new Error(errorMsg);
} else {
ejbCache.put(ejbName, javaClass);
}
}
}
}
// --------------------------------------------------------
// EjbBeanResolver interface
// --------------------------------------------------------
public JavaClass findEjbByName(String ejbName) {
if (log.isTraceEnabled()) {
log.trace("findEjbByName: " + ejbName);
}
return (JavaClass) ejbCache.get(ejbName);
}
}
public static class SignatureDuplicatedJavaMethod extends DuplicatedJavaMethod {
public SignatureDuplicatedJavaMethod(JavaMethod method) {
super(method);
}
public boolean containsException(Type type) {
return Arrays.asList(getExceptions()).contains(type);
}
public void addException(Type type) {
List exceptions = new ArrayList(Arrays.asList(getExceptions()));
exceptions.add(type);
setExceptions((Type[]) exceptions.toArray(new Type[0]));
}
}
public static class Permission {
private final String ifaceType;
private final JavaMethod method;
// class level - applies to all methods
public Permission(String ifaceType) {
this(ifaceType, null);
}
// method level - applies to given method (null to all methods)
public Permission(String ifaceType, JavaMethod method) {
this.ifaceType = ifaceType;
this.method = method;
}
public String getIfaceType() {
return this.ifaceType;
}
public JavaMethod getMethod() {
return this.method;
}
}
public static class ContainerTransaction extends Permission {
private final String transType;
// class level - applies to all methods
public ContainerTransaction(String transType) {
this(null, null, transType);
}
// class level - applies to all methods
public ContainerTransaction(String ifaceType, String transType) {
this(ifaceType, null, transType);
}
// method level - applies to given method (null to all methods)
public ContainerTransaction(String ifaceType, JavaMethod method, String transType) {
super(ifaceType, method);
this.transType = transType;
}
public String getTransType() {
return this.transType;
}
public static Collection unroll(int permType, String transType) {
return unroll(permType, null, transType);
}
public static Collection unroll(int permType, JavaMethod method, String transType) {
Collection retLst = new ArrayList();
if (hasFlag(permType, REMOTE)) {
retLst.add(new ContainerTransaction(REMOTE_INTERFACE, method, transType));
}
if (hasFlag(permType, REMOTE_HOME)) {
retLst.add(new ContainerTransaction(REMOTE_HOME_INTERFACE, method, transType));
}
if (hasFlag(permType, LOCAL)) {
retLst.add(new ContainerTransaction(LOCAL_INTERFACE, method, transType));
}
if (hasFlag(permType, LOCAL_HOME)) {
retLst.add(new ContainerTransaction(LOCAL_HOME_INTERFACE, method, transType));
}
if (hasFlag(permType, SERVICE_END_POINT)) {
retLst.add(new ContainerTransaction(SERVICE_END_POINT_INTERFACE, method, transType));
}
return retLst;
}
}
public static class MethodPermission extends Permission {
private final String[] roles;
// class level - applies to all methods
public MethodPermission(String ifaceType, String[] roles) {
this(ifaceType, null, roles);
}
// method level - applies to given method (null to all methods)
public MethodPermission(String ifaceType, JavaMethod method, String[] roles) {
super(ifaceType, method);
this.roles = roles;
}
public String[] getRoles() {
return this.roles;
}
public static Collection unroll(int permType, String[] roles) {
return unroll(permType, null, roles);
}
public static Collection unroll(int permType, JavaMethod method, String[] roles) {
Collection retLst = new ArrayList();
if (hasFlag(permType, REMOTE)) {
retLst.add(new MethodPermission(REMOTE_INTERFACE, method, roles));
}
if (hasFlag(permType, REMOTE_HOME)) {
retLst.add(new MethodPermission(REMOTE_HOME_INTERFACE, method, roles));
}
if (hasFlag(permType, LOCAL)) {
retLst.add(new MethodPermission(LOCAL_INTERFACE, method, roles));
}
if (hasFlag(permType, LOCAL_HOME)) {
retLst.add(new MethodPermission(LOCAL_HOME_INTERFACE, method, roles));
}
if (hasFlag(permType, SERVICE_END_POINT)) {
retLst.add(new MethodPermission(SERVICE_END_POINT_INTERFACE, method, roles));
}
return retLst;
}
}
}