/*
* Copyright (c) 2001, 2002 The XDoclet team
* All rights reserved.
*/
package xdoclet.modules.ejb.home;
import java.text.MessageFormat;
import java.util.*;
import org.apache.commons.logging.Log;
import xjavadoc.*;
import xdoclet.DocletContext;
import xdoclet.DocletTask;
import xdoclet.XDocletException;
import xdoclet.XDocletMessages;
import xdoclet.modules.ejb.EjbTagsHandler;
import xdoclet.modules.ejb.XDocletModulesEjbMessages;
import xdoclet.modules.ejb.entity.CmpTagsHandler;
import xdoclet.modules.ejb.entity.EntityTagsHandler;
import xdoclet.modules.ejb.entity.PkTagsHandler;
import xdoclet.modules.ejb.home.LocalHomeInterfaceSubTask;
import xdoclet.modules.ejb.intf.InterfaceTagsHandler;
import xdoclet.modules.ejb.session.SessionTagsHandler;
import xdoclet.util.DocletUtil;
import xdoclet.util.LogUtil;
import xdoclet.util.Translator;
import xdoclet.util.TypeConversionUtil;
/**
* @author Ara Abrahamian (ara_e@email.com)
* @created Oct 15, 2001
* @xdoclet.taghandler namespace="EjbHome"
* @version $Revision: 1.37 $
*/
public class HomeTagsHandler extends EjbTagsHandler
{
private String currentSignature;
private String currentExceptions;
private String currentPermission;
/**
* Similar to {@link xdoclet.modules.ejb.intf.InterfaceTagsHandler#getComponentInterface}. Relies on the ejb:home
* tag, which has the following relevant properties:
* <ul>
* <li> remote-class: The fully qualified name of the remote class - overrides all set patterns
* <li> local-class: The fully qualified name of the local class - overrides all set patterns
* <li> remote-pattern: The pattern to be used to determine the unqualified name of the remote class
* <li> local-pattern: The pattern to be used to determine the unqualified name of the local class
* <li> pattern: The pattern to be used in determining the unqualified remote and/or local home interface name -
* used where remote- or local- pattern are not specified.
* <li> remote-package: The package the remote home interface is to be placed in
* <li> local-package: The package the local home interface is to be placed in
* <li> package: The package the remote and/or local home interface is to be placed in - used where remote- or
* local- package are not specified.
* </ul>
*
*
* @param type The type of home interface - can be remote or local.
* @param clazz Description of Parameter
* @return The HomeInterface value
* @exception XDocletException
*/
public static String getHomeInterface(String type, XClass clazz) throws XDocletException
{
Log log = LogUtil.getLog(HomeTagsHandler.class, "getHomeInterface");
// validate type
if (!"remote".equals(type) && !"local".equals(type)) {
throw new XDocletException(Translator.getString(XDocletModulesEjbMessages.class, XDocletModulesEjbMessages.METHOD_ONLY_TAKES_REMOTE_OR_LOCAL, new String[]{"getHomeInterface", type}));
}
String fileName = clazz.getContainingPackage().getName();
String name_pattern = null;
String package_pattern = null;
String home_interface = null;
home_interface = clazz.getDoc().getTagAttributeValue("ejb:home", type + "-class");
if (log.isDebugEnabled()) {
log.debug(type + " home Interface for " + clazz.getQualifiedName() + " = " + home_interface);
}
if (home_interface != null) {
return home_interface;
}
name_pattern = clazz.getDoc().getTagAttributeValue("ejb:home", type + "-pattern");
if (name_pattern == null) {
name_pattern = clazz.getDoc().getTagAttributeValue("ejb:home", "pattern");
if (name_pattern == null) {
name_pattern = "remote".equals(type) ? getHomeClassPattern() : getLocalHomeClassPattern();
}
}
package_pattern = clazz.getDoc().getTagAttributeValue("ejb:home", type + "-package");
if (package_pattern == null) {
package_pattern = clazz.getDoc().getTagAttributeValue("ejb:home", "package");
}
String ejb_name = null;
if (name_pattern.indexOf("{0}") != -1) {
ejb_name = MessageFormat.format(name_pattern, new Object[]{getShortEjbNameFor(clazz)});
}
else {
ejb_name = name_pattern;
}
String subtask_name = null;
if (type.equals("remote")) {
subtask_name = DocletTask.getSubTaskName(HomeInterfaceSubTask.class);
}
else {
subtask_name = DocletTask.getSubTaskName(LocalHomeInterfaceSubTask.class);
}
// Fix package name
StringBuffer sb = new StringBuffer(choosePackage(fileName, package_pattern, subtask_name));
if (sb.length() > 0) {
sb.append('.');
}
sb.append(ejb_name);
return sb.toString();
}
/**
* Returns true if method is an ejbRemove method, false otherwise.
*
* @param method The method to test
* @return true if named ejbRemove
*/
public static boolean isRemoveMethod(XMethod method)
{
return method.getName().equals("ejbRemove");
}
/**
* Returns true if method is a create method marked with a \@ejb.create-method tag, false otherwise.
*
* @param method The method to test
* @return true if ejb.create-method tag found
*/
public static boolean isCreateMethod(XMethod method)
{
return method.getDoc().hasTag("ejb.create-method");
}
/**
* Returns true if method is a home method marked with a \@ejb.home-method tag, false otherwise.
*
* @param method The method to test
* @return true if ejb.home-method tag found
*/
public static boolean isHomeMethod(XMethod method)
{
return method.getDoc().hasTag("ejb.home-method");
}
/**
* Returns a suitable component name (which could be used, for example, in JNDI lookups) for a class.
*
* @param clazz the class
* @param type interface view type, \"local\" or \"remote\"
* @return compname
*/
public static String getCompNameFor(XClass clazz, String type)
{
String compName = getEjbNameFor(clazz).replace('.', '/');
if (type.equals("local")) {
compName = compName + LOCAL_SUFFIX;
}
return compName;
}
/**
* Returns true if method is an ejbFind method, false otherwise.
*
* @param method The method to test
* @return true if name starts with ejbFind
*/
public static boolean isFinderMethod(XMethod method)
{
return method.getName().startsWith("ejbFind");
}
/**
* Gets the HomeDefinition attribute of the HomeTagsHandler class
*
* @param clazz Describe what the parameter does
* @param method Describe what the parameter does
* @param tagType Describe what the parameter does
* @param type Describe what the parameter does
* @return The HomeDefinition value
* @exception XDocletException
*/
public static String getHomeDefinition(XClass clazz, XMethod method, String tagType, String type)
throws XDocletException
{
String methodName = method.getName().substring(3);
StringBuffer homeMethodName = new StringBuffer();
if (tagType.equals("ejb:finder")) {
String ejbReturn = method.getReturnType().getType().getQualifiedName();
if (ejbReturn.equals("java.util.Collection") ||
ejbReturn.equals("java.util.Enumeration") ||
ejbReturn.equals("java.util.Set")) {
homeMethodName.append(ejbReturn);
}
else {
homeMethodName.append(InterfaceTagsHandler.getComponentInterface(type, clazz));
}
}
else if (tagType.equals("ejb:create-method")) {
homeMethodName.append(InterfaceTagsHandler.getComponentInterface(type, clazz));
}
else if (tagType.equals("ejb:home-method")) {
methodName = methodName.substring(4);
homeMethodName.append(method.getReturnType().getType().getQualifiedName());
}
homeMethodName.append(" ");
homeMethodName.append(methodName.substring(0, 1).toLowerCase());
homeMethodName.append(methodName.substring(1));
homeMethodName.append("(");
for (Iterator i = method.getParameters().iterator(); i.hasNext(); ) {
homeMethodName.append(i.next());
if (i.hasNext())
homeMethodName.append(" , ");
}
homeMethodName.append(")");
return fullPackageChange(homeMethodName.toString());
}
public static String getJndiNameOfTypeFor(String type, XClass clazz)
{
XTag bean_tag = clazz.getDoc().getTag("ejb:bean");
String compName = getCompNameFor(clazz, type);
if (bean_tag != null) {
String jndiName = bean_tag.getAttributeValue("jndi-name");
String localJndiName = bean_tag.getAttributeValue("local-jndi-name");
//Return "local" jndi name
if ("local".equals(type)) {
return localJndiName != null ? localJndiName : compName;
}
//Didn't ask for local, assume remote
return jndiName != null ? jndiName : compName;
}
//nothing specified so madeup one
return compName;
}
/**
* Converts ejbHome<em>blabla</em> to home<em>blabla</em> , the one that should appear in home interface.
*
* @param methodName Method name to be converted.
* @return Equivalent home interface method name.
*/
public static String toHomeMethod(String methodName)
{
// Remove "ejbHome" prefix and lower case first char in rest: "ejbHomeFoo"->"foo"
return Character.toLowerCase(methodName.charAt(7)) + methodName.substring(8);
}
/**
* Converts ejbCreate<em>blabla</em> to create<em>blabla</em> , the one that should appear in home interface.
*
* @param methodName Method name to be converted.
* @return Equivalent home interface method name.
*/
public static String toCreateMethod(String methodName)
{
if (methodName.length() > 9) {
// Remove "ejbCreate" prefix and lower case first char in rest: "ejbCreateFoo"->"createFoo", EJB 2 only
return "create" + Character.toUpperCase(methodName.charAt(9)) + methodName.substring(10);
}
else {
return "create";
}
}
/**
* Describe what the method does
*
* @param clazz Describe what the parameter does
* @return Describe the return value
*/
public static XMethod findFirstCreateMethodFor(XClass clazz)
{
Collection methods = clazz.getMethods();
do {
for (Iterator j = methods.iterator(); j.hasNext(); ) {
XMethod method = (XMethod) j.next();
if (HomeTagsHandler.isCreateMethod(method)) {
return method;
}
}
clazz = clazz.getSuperclass();
} while (clazz != null);
return null;
}
/**
* Converts ejbFind<em>blabla</em> to find<em>blabla</em> , the one that should appear in home interface.
*
* @param methodName Method name to be converted.
* @return Equivalent home interface method name.
*/
public static String toFinderMethod(String methodName)
{
// Remove "ejb" prefix and lower case first char in rest: "ejbFindByPrimaryKey"->"findByPrimaryKey"
return Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4);
}
/**
* Convert various collection types within a string to their fully qualified forms.
*
* @param s String to be converted.
* @return String with fully qualified collection types.
*/
public static String fullPackageChange(String s)
{
StringTokenizer st = new StringTokenizer(s, " ");
String sign = st.nextToken();
StringBuffer ret = new StringBuffer();
if (sign.equals("Collection")) {
ret.append("java.util.Collection");
}
else if (sign.equals("Enumeration")) {
ret.append("java.util.Enumeration");
}
else if (sign.equals("Set")) {
ret.append("java.util.Set");
}
else {
ret.append(sign);
}
while (st.hasMoreTokens()) {
ret.append(" ").append(st.nextToken());
}
return ret.toString();
}
/**
* Describe what the method does
*
* @param s Describe what the parameter does
* @param clazz
* @param type
* @return Describe the return value
* @exception XDocletException
*/
public static String finderSignatureFunger(String s, XClass clazz, String type) throws XDocletException
{
StringTokenizer st = new StringTokenizer(s, " ");
String sign = st.nextToken();
StringBuffer ret = new StringBuffer();
if (sign.equals("Collection") || sign.equals("java.util.Collection")) {
ret.append("java.util.Collection");
}
else if (sign.equals("Enumeration") || sign.equals("java.util.Enumeration")) {
ret.append("java.util.Enumeration");
}
else if (sign.equals("Set") || sign.equals("java.util.Set")) {
ret.append("java.util.Set");
}
else {
ret.append(InterfaceTagsHandler.getComponentInterface(type, clazz));
}
while (st.hasMoreTokens()) {
ret.append(" ").append(st.nextToken());
}
return ret.toString();
}
/**
* Gets the LocalHomeClassPattern attribute of the HomeTagsHandler class.
*
* @return The LocalHomeClassPattern value
*/
protected static String getLocalHomeClassPattern()
{
LocalHomeInterfaceSubTask localhomeintf_subtask = ((LocalHomeInterfaceSubTask) DocletContext.getInstance().getSubTaskBy(DocletTask.getSubTaskName(LocalHomeInterfaceSubTask.class)));
if (localhomeintf_subtask != null) {
return localhomeintf_subtask.getLocalHomeClassPattern();
}
else {
return LocalHomeInterfaceSubTask.DEFAULT_LOCALHOMEINTERFACE_CLASS_PATTERN;
}
}
/**
* Gets the HomeClassPattern attribute of the HomeTagsHandler class.
*
* @return The HomeClassPattern value
*/
protected static String getHomeClassPattern()
{
HomeInterfaceSubTask homeintf_subtask = ((HomeInterfaceSubTask) DocletContext.getInstance().getSubTaskBy(DocletTask.getSubTaskName(HomeInterfaceSubTask.class)));
if (homeintf_subtask != null) {
return homeintf_subtask.getHomeClassPattern();
}
else {
return HomeInterfaceSubTask.DEFAULT_HOMEINTERFACE_CLASS_PATTERN;
}
}
public void setCurrentPermission(String permission)
{
currentPermission = permission;
}
/**
* Returns the full qualified local or remote home interface name for the bean, depending on the value of type
* parameter.
*
* @param attributes The attributes of the template tag
* @return Description of the Returned Value
* @exception XDocletException
* @doc.tag type="content"
* @doc.param name="type" optional="false" values="remote,local" description="Specifies the type
* of component home interface."
*/
public String homeInterface(Properties attributes) throws XDocletException
{
String type = attributes.getProperty("type");
type = type != null ? type : "remote";
return getHomeInterface(type, getCurrentClass());
}
/**
* Evaluates the body block if current method is a create method. Create methods should have ejb:create-method
* defined.
*
* @param template The body of the block tag
* @param attributes The attributes of the template tag
* @exception XDocletException
* @see #isCreateMethod(xjavadoc.XMethod)
* @doc.tag type="block"
* @doc.param name="superclasses" optional="true" description="Traverse superclasses too. With
* false value used in remote/local home interface templates. Default is False."
*/
public void ifIsCreateMethod(String template, Properties attributes) throws XDocletException
{
String superclasses_str = attributes.getProperty("superclasses");
boolean superclasses = TypeConversionUtil.stringToBoolean(superclasses_str, true);
if (isCreateMethod(getCurrentMethod())) {
boolean currentMethodDoesntBelongToCurrentClass = !getCurrentMethod().getContainingClass().equals(getCurrentClass());
boolean shouldTraverse = shouldTraverseSuperclassForDependentClass(getCurrentMethod().getContainingClass(), "ejb:home");
if (superclasses == false && currentMethodDoesntBelongToCurrentClass == true && shouldTraverse == false) {
return;
}
generate(template);
}
}
/**
* Evaluates the body block if current create method's ejbPostCreate method does not exist.
*
* @param template The body of the block tag
* @param attributes The attributes of the template tag
* @exception XDocletException
* @doc.tag type="block"
*/
public void ifDoesntHavePostCreateMethod(String template, Properties attributes)
throws XDocletException
{
XMethod currentMethod = getCurrentMethod();
if (!isCreateMethod(currentMethod)) {
String msg = Translator.getString(XDocletModulesEjbMessages.class,
XDocletModulesEjbMessages.CURRENT_METHOD_NOT_CREATE,
new String[]{currentMethod.toString()});
throw new XDocletException(msg);
}
StringBuffer currentMethodName = new StringBuffer(currentMethod.getNameWithSignature(false));
currentMethodName.insert(3, "Post");
XMethod ejbPostCreateMethod = getCurrentClass().getMethod(currentMethodName.toString());
if (ejbPostCreateMethod == null) {
generate(template);
}
}
/**
* Returns the appropriate ejbPostCreate method name for the current ejbCreate method.
*
* @param attributes The attributes of the template tag
* @return Equivalent ejbPostCreate method name
* @doc.tag type="content"
*/
public String ejbPostCreateSignature(Properties attributes)
{
StringBuffer currentMethodName = new StringBuffer(getCurrentMethod().getName());
currentMethodName.insert(3, "Post");
return currentMethodName.toString();
}
/**
* Evaluates the body block if current method is a home method. Home methods should have ejb:home-method defined.
*
* @param template The body of the block tag
* @param attributes The attributes of the template tag
* @exception XDocletException
* @see #isHomeMethod(xjavadoc.XMethod)
* @doc.tag type="block"
* @doc.param name="superclasses" optional="true" description="Traverse superclasses too. With
* false value used in remote/local home interface templates. Default is False."
*/
public void ifIsHomeMethod(String template, Properties attributes) throws XDocletException
{
String superclasses_str = attributes.getProperty("superclasses");
boolean superclasses = TypeConversionUtil.stringToBoolean(superclasses_str, true);
if (isHomeMethod(getCurrentMethod())) {
if (superclasses == false && getCurrentMethod().getContainingClass() != getCurrentClass()
&& shouldTraverseSuperclassForDependentClass(getCurrentMethod().getContainingClass(), "ejb:home") == false) {
return;
}
generate(template);
}
}
/**
* Evaluates the body block if current method is not an ejbRemove method.
*
* @param template The body of the block tag
* @exception XDocletException
* @see #isRemoveMethod(xjavadoc.XMethod)
* @doc.tag type="block"
*/
public void ifNotRemoveMethod(String template) throws XDocletException
{
if (!isRemoveMethod(getCurrentMethod())) {
generate(template);
}
}
/**
* Evaluates the body block if current method is a ejbFind method.
*
* @param template The body of the block tag
* @param attributes The attributes of the template tag
* @exception XDocletException Description of Exception
* @see #isFinderMethod(xjavadoc.XMethod)
* @doc.tag type="block"
* @doc.param name="superclasses" optional="true" description="Traverse superclasses too. With
* false value used in remote/local home interface templates. Default is False."
*/
public void ifIsFinderMethod(String template, Properties attributes) throws XDocletException
{
String superclasses_str = attributes.getProperty("superclasses");
boolean superclasses = TypeConversionUtil.stringToBoolean(superclasses_str, true);
if (isFinderMethod(getCurrentMethod())) {
boolean currentMethodDoesntBelongToCurrentClass = !getCurrentMethod().getContainingClass().equals(getCurrentClass());
boolean shouldTraverse = shouldTraverseSuperclassForDependentClass(getCurrentMethod().getContainingClass(), "ejb:home");
if (superclasses == false && currentMethodDoesntBelongToCurrentClass == true && shouldTraverse == false) {
return;
}
generate(template);
}
}
/**
* @param attributes The attributes of the template tag
* @return Description of the Returned Value
* @exception XDocletException
* @doc.tag type="content"
* @doc.param name="prefixWithEjbSlash" optional="true" values="true,false" description="Specifies
* whether to prefix it with ejb/ or not. False by default."
* @doc.param name="type" optional="false" values="remote,local" description="Specifies if we want
* the jndi name value for local or remote lookup."
*/
public String compName(Properties attributes) throws XDocletException
{
String prefix_with_ejbslash_str = attributes.getProperty("prefixWithEjbSlash");
boolean prefix_with_ejbslash = TypeConversionUtil.stringToBoolean(prefix_with_ejbslash_str, false);
String type = attributes.getProperty("type");
String ejb_name = getCompNameFor(getCurrentClass(), type);
String compName;
if (prefix_with_ejbslash == true) {
compName = prefixWithEjbSlash(ejb_name);
}
else {
compName = ejb_name;
}
return compName;
}
/**
* @param attributes
* @return Description of the Returned Value
* @exception XDocletException
* @doc.tag type="content"
* @doc.param name="type" optional="false" values="remote,local" description="Specifies if we want
* the jndi name value for local or remote lookup."
*/
public String jndiName(Properties attributes) throws XDocletException
{
return getJndiNameOfTypeFor(attributes.getProperty("type"), getCurrentClass());
}
/**
* Returns the name of the class home interface extends.
*
* @param attributes
* @return The name of generated PK class.
* @exception XDocletException
* @doc.tag type="content"
*/
public String extendsFrom(Properties attributes) throws XDocletException
{
String type = attributes.getProperty("type");
type = type != null ? type : "remote";
String extends_param_name = type.equals("remote") ? "extends" : "local-extends";
String def_base_class_name = type.equals("remote") ? "javax.ejb.EJBHome" : "javax.ejb.EJBLocalHome";
return extendsFromFor(getCurrentClass(), "ejb:home", type, extends_param_name, def_base_class_name);
}
/**
* Iterates over all home methods of specified type (finder or create method) defined in a class and super classes.
*
* @param template The body of the block tag
* @param attributes The attributes of the template tag
* @exception XDocletException
* @doc.tag type="block"
* @doc.param name="tagName" optional="false" description="The tag name for the method type to
* iterate over." values="ejb:finder,ejb:create-method"
* @doc.param name="superclasses" values="true,false" description="If true then traverse
* superclasses also, otherwise look up the tag in current concrete class only."
* @doc.param name="tagKey" description="A tag property that will be used as a unique key. This is
* used to avoid duplicate code due to similar tags in superclasses."
*/
public void forAllHomeMethods(String template, Properties attributes) throws XDocletException
{
Log log = LogUtil.getLog(HomeTagsHandler.class, "forAllHomeMethods");
boolean superclasses = TypeConversionUtil.stringToBoolean(attributes.getProperty("superclasses"), false);
String type = attributes.getProperty("type");
String tagType = attributes.getProperty("tagName");
if (type == null) {
throw new XDocletException(Translator.getString(XDocletMessages.class,
XDocletMessages.ATTRIBUTE_NOT_PRESENT_ERROR,
new String[]{"type"}));
}
Set already = new HashSet();
// Exclude definition coming from super classes
XClass currentClass = getCurrentClass().getSuperclass();
while (currentClass != null) {
if (log.isDebugEnabled()) {
log.debug("Looking for super definition in " + currentClass.getName());
}
// 1. METHOD tags
Collection methods = currentClass.getMethods();
for (Iterator j = methods.iterator(); j.hasNext(); ) {
XMethod method = (XMethod) j.next();
// search all this methods tags to ensure that the type of
// Home we are generating matches the view-type (if available)
//
Collection tags =
method.getDoc().getTags(tagType, superclasses);
if (!matchesViewType(tags, type)) {
continue;
}
if (tagType.equals("ejb:finder")) {
if (!isFinderMethod(method)) {
continue;
}
}
else if (tagType.equals("ejb:create-method")) {
if (!isCreateMethod(method)) {
continue;
}
}
else if (tagType.equals("ejb:home-method")) {
if (!isHomeMethod(method)) {
continue;
}
}
String signature = getHomeDefinition(currentClass, method, tagType, type);
if (log.isDebugEnabled()) {
log.debug("Found " + signature);
}
already.add(signature);
}
// 2. CLASS tags
Collection superTags = currentClass.getDoc().getTags(tagType, true);
for (Iterator i = superTags.iterator(); i.hasNext(); ) {
XTag superTag = (XTag) i.next();
// ensure that the type of Home we are generating matches the
// view-type (if available)
//
if (!matchesViewType(superTag, type)) {
continue;
}
String signature = fullPackageChange(superTag.getAttributeValue("signature"));
String typeMapping = superTag.getAttributeValue("result-type-mapping");
if (typeMapping == null || typeMapping.equalsIgnoreCase(type)) {
if (log.isDebugEnabled()) {
log.debug("Found " + signature);
}
already.add(signature);
}
}
currentClass = currentClass.getSuperclass();
}
// 1. Handle METHOD Tag level ejb:finder
Collection methods = getCurrentClass().getMethods();
boolean fbpkFound = false;
for (Iterator j = methods.iterator(); j.hasNext(); ) {
XMethod method = (XMethod) j.next();
// search all this methods tags to ensure that the type of Home
// we are generating matches the view-type (if available)
//
Collection tags =
method.getDoc().getTags(tagType, superclasses);
if (!matchesViewType(tags, type)) {
continue;
}
String signature = null;
if (method.getDoc().getTag("ejb.permission") != null) {
setCurrentPermission("@ejb.permission " + method.getDoc().getTag("ejb.permission").getValue());
}
if (log.isDebugEnabled()) {
log.debug("Finder Method = " + signature);
}
if (tagType.equals("ejb:finder")) {
if (!isFinderMethod(method)) {
continue;
}
signature = getHomeDefinition(getCurrentClass(), method, tagType, type);
if (!already.add(signature)) {
continue;
}
}
else if (tagType.equals("ejb:create-method")) {
if (!isCreateMethod(method)) {
continue;
}
signature = getHomeDefinition(getCurrentClass(), method, tagType, type);
if (!already.add(signature)) {
continue;
}
}
else if (tagType.equals("ejb:home-method")) {
if (!isHomeMethod(method)) {
continue;
}
signature = getHomeDefinition(getCurrentClass(), method, tagType, type);
if (!already.add(signature)) {
continue;
}
}
if (signature != null) {
setCurrentSignature(signature);
Collection exceptions = method.getThrownExceptions();
StringBuffer exc = new StringBuffer();
boolean comma = false;
for (Iterator k = exceptions.iterator(); k.hasNext(); ) {
XClass exception = (XClass) k.next();
// Skip EJBException
if (exception.getQualifiedName().equals("javax.ejb.EJBException"))
continue;
if (comma) {
exc.append(',');
}
exc.append(exception.getQualifiedName());
comma = true;
}
// Add javax.ejb.FinderException to the exception list of finder methods
// if not already done
if (tagType.equals("ejb:finder") && exc.indexOf("javax.ejb.FinderException") < 0) {
if (exc.length() > 0) {
exc.append(",");
}
exc.append("javax.ejb.FinderException");
}
// Add javax.ejb.CreateException to the exception list of create methods
// if not already done
if (tagType.equals("ejb:create-method") && exc.indexOf("javax.ejb.CreateException") < 0) {
if (exc.length() > 0) {
exc.append(",");
}
exc.append("javax.ejb.CreateException");
}
// Add java.rmi.RemoteExceptions to the exception list of remote and remote home
// interfaces
if (type.equalsIgnoreCase("remote")) {
if (exc.length() > 0) {
exc.append(",");
}
exc.append("java.rmi.RemoteException");
}
setCurrentExceptions(exc.toString());
// For javadoc comment only
setCurrentMethod(method);
// If custom findByPrimaryKey exists then we should not add the
// mandatory later
if (method.getName().equals("findByPrimaryKey")) {
fbpkFound = true;
}
generate(template);
}
}
// 2. Handle CLASS Tag level ejb:finder
Collection tags = getCurrentClass().getDoc().getTags(tagType, superclasses);
for (Iterator i = tags.iterator(); i.hasNext(); ) {
XTag tag = (XTag) i.next();
// ensure that the type of Home we are generating matches the
// view-type (if available)
//
if (!matchesViewType(tag, type)) {
continue;
}
String signature = finderSignatureFunger(tag.getAttributeValue("signature"), getCurrentClass(), type);
String typeMapping = tag.getAttributeValue("result-type-mapping");
if (typeMapping == null || typeMapping.equalsIgnoreCase(type)) {
if (!already.add(signature)) {
continue;
}
if (log.isDebugEnabled()) {
log.debug("Finder Method = " + signature);
}
if (signature.indexOf("findByPrimaryKey") != -1) {
fbpkFound = true;
}
setCurrentClassTag(tag);
setCurrentSignature(signature);
if (tag.getAttributeValue("unchecked") != null) {
setCurrentPermission("@ejb.permission unchecked=\"true\"");
}
else if (tag.getAttributeValue("role-name") != null) {
setCurrentPermission("@ejb.permission role-name=\"" + tag.getAttributeValue("role-name") + "\"");
}
else {
// nothing found - nothing set....
setCurrentPermission("");
}
StringBuffer exc = new StringBuffer();
exc.append("javax.ejb.FinderException");
if (type.equalsIgnoreCase("remote")) {
exc.append(",java.rmi.RemoteException");
}
setCurrentExceptions(exc.toString());
generate(template);
}
}
// Add mandatory findByPrimaryKey if not already there
if (!fbpkFound && CmpTagsHandler.isEntityCmp(getCurrentClass()) && tagType.equals("ejb:finder") && EntityTagsHandler.isAConcreteEJBean(getCurrentClass())) {
StringBuffer fbpkSign = new StringBuffer(InterfaceTagsHandler.getComponentInterface(type, getCurrentClass()));
fbpkSign.append(" findByPrimaryKey(");
fbpkSign.append(PkTagsHandler.getPkClassFor(getCurrentClass())).append(" pk").append(")");
if (already.add(fbpkSign)) {
setCurrentSignature(fbpkSign.toString());
StringBuffer exc = new StringBuffer();
exc.append("javax.ejb.FinderException");
if (type.equalsIgnoreCase("remote")) {
exc.append(",java.rmi.RemoteException");
}
setCurrentExceptions(exc.toString());
setCurrentMethod(null);
generate(template);
}
}
// Add mandatory create() method for stateless beans if the bean is not abstract
if (SessionTagsHandler.isSession(getCurrentClass()) && tagType.equals("ejb:create-method")) {
if (already.size() == 0 && SessionTagsHandler.isAConcreteEJBean(getCurrentClass())) {
StringBuffer createSign = new StringBuffer(InterfaceTagsHandler.getComponentInterface(type, getCurrentClass()));
createSign.append(" create()");
setCurrentSignature(createSign.toString());
StringBuffer exc = new StringBuffer();
exc.append("javax.ejb.CreateException");
if (type.equalsIgnoreCase("remote")) {
exc.append(",java.rmi.RemoteException");
}
setCurrentExceptions(exc.toString());
setCurrentMethod(null);
generate(template);
}
}
setCurrentClassTag(null);
setCurrentMethodTag(null);
setCurrentSignature(null);
setCurrentExceptions(null);
setCurrentMethod(null);
}
/**
* Return signature of current home method.
*
* @return Describe the return value
* @exception XDocletException
*/
public String currentSignature() throws XDocletException
{
return currentSignature;
}
/**
* Return permission for current home method.
*
* @return
* @exception XDocletException
* @doc.tag type="content"
*/
public String currentPermission() throws XDocletException
{
return currentPermission;
}
/**
* Return type of current home method.
*
* @return
* @exception XDocletException
* @doc.tag type="content"
* @todo i18n
*/
public String currentType() throws XDocletException
{
String sig = currentSignature();
int index = sig.indexOf(" ");
if (index >= 0) {
return sig.substring(0, index);
}
throw new XDocletException("can not parse signature: " + sig);
}
/**
* generates name for finder utility class backing current finder
*
* @return
* @exception XDocletException
* @doc.tag type="content"
* @todo i18n
*/
public String finderClass() throws XDocletException
{
String sig = currentSignature();
int start = sig.indexOf("find");
int end = sig.indexOf("(");
if (start >= 0 && end > start) {
return sig.substring(start, start + 1).toUpperCase() + sig.substring(start + 1, end);
}
throw new XDocletException("Cannot parse signature: " + sig);
}
/**
* Whether current finder return collection.
*
* @param template
* @param param
* @exception XDocletException
* @doc.tag type="block"
*/
public void ifIsCollectionType(String template, Properties param) throws XDocletException
{
String currentType = currentType();
if ("Collection".equals(currentType) ||
"java.util.Collection".equals(currentType) ||
"Set".equals(currentType) ||
"java.util.Set".equals(currentType)) {
generate(template);
}
}
/**
* Whether current finder return enumeration.
*
* @param template
* @param param
* @exception XDocletException
* @doc.tag type="block"
*/
public void ifIsEnumerationType(String template, Properties param) throws XDocletException
{
String currentType = currentType();
if ("Enumeration".equals(currentType) || "java.util.Enumeration".equals(currentType)) {
generate(template);
}
}
/**
* Whether current finder return interface.
*
* @param template
* @param param
* @exception XDocletException
* @doc.tag type="block"
*/
public void ifIsInterfaceType(String template, Properties param) throws XDocletException
{
String type = currentType();
if (type.equals(InterfaceTagsHandler.getComponentInterface("local", getCurrentClass())) ||
type.equals(InterfaceTagsHandler.getComponentInterface("remote", getCurrentClass()))) {
generate(template);
}
}
/**
* Return name of current home method.
*
* @return method name
* @exception XDocletException
* @doc.tag type="content"
* @todo i18n
*/
public String currentMethod() throws XDocletException
{
String sig = currentSignature();
int start = sig.indexOf(" ");
int stop = sig.indexOf("(");
if (start < 0 || stop < 0) {
throw new XDocletException("Cannot parse signature: " + sig);
}
return sig.substring(start + 1, stop);
}
/**
* Return parameter list definition (types and names) for current home method.
*
* @return comma-separated parameter list
* @exception XDocletException
* @doc.tag type="content"
* @todo i18n
*/
public String parameterListDefinition() throws XDocletException
{
String sig = currentSignature();
int start = sig.indexOf("(");
int stop = sig.indexOf(")");
if (start < 0 || stop < 0) {
throw new XDocletException("Cannot parse signature: " + sig);
}
return sig.substring(start + 1, stop);
}
/**
* Return parameter list (names only) for current home method.
*
* @return comma-separated parameter list
* @exception XDocletException
* @doc.tag type="content"
*/
public String parameterList() throws XDocletException
{
String[] parameters = DocletUtil.tokenizeDelimitedToArray(parameterListDefinition(), " ,");
StringBuffer sb = new StringBuffer();
for (int i = 1; i < parameters.length; i += 2) {
if (i > 1) {
sb.append(", ");
}
sb.append(parameters[i]);
}
return sb.toString();
}
/**
* Return exceptions for current home method.
*
* @return exceptions
* @exception XDocletException
* @doc.tag type="content"
*/
public String currentExceptions() throws XDocletException
{
return currentExceptions;
}
/**
* Gets the DependentClassFor attribute of the HomeTagsHandler object
*
* @param clazz Describe what the parameter does
* @param type Describe what the parameter does
* @return The DependentClassFor value
* @exception XDocletException
*/
protected String getDependentClassFor(XClass clazz, String type) throws XDocletException
{
if ((type.equals("local") && InterfaceTagsHandler.isLocalEjb(clazz)) || (type.equals("remote") && InterfaceTagsHandler.isRemoteEjb(clazz))) {
return getHomeInterface(type, clazz);
}
else {
return null;
}
}
/**
* Sets the CurrentSignature attribute of the HomeTagsHandler object.
*
* @param cs The new CurrentSignature value
*/
protected void setCurrentSignature(String cs)
{
this.currentSignature = cs;
}
/**
* Sets the CurrentExceptions attribute of the HomeTagsHandler object.
*
* @param es The new CurrentExceptions value
*/
protected void setCurrentExceptions(String es)
{
this.currentExceptions = es;
}
/**
* Describe what the method does
*
* @param clazz Describe what the parameter does
* @param tag_name Describe what the parameter does
* @return Describe the return value
* @exception XDocletException
*/
protected boolean shouldTraverseSuperclassForDependentClass(XClass clazz, String tag_name) throws XDocletException
{
if (super.shouldTraverseSuperclassForDependentClass(clazz, tag_name) == false) {
return false;
}
//shouldn't include create methods of parent if parent is itself a concrete ejb
if (isAConcreteEJBean(clazz)) {
return false;
}
return true;
}
/**
* Returns true if an XTag has a view-type compatible with the specified type. A view-type is compatible if it is
* the same as type or \"both\". A missing or empty view-type is assumed to be compatible.
*
* @param tag The XTag to check
* @param type The desired view-type
* @return true if the tag's view-type is compatible
*/
protected boolean matchesViewType(XTag tag, String type)
{
String attr = tag.getAttributeValue("view-type");
return attr == null || attr.length() == 0 || attr.equals(type) || attr.equals("both");
}
/**
* Check every XTag in a collection and return true if they all have a view-type compatible with the specified type.
* A view-type is compatible if it is the same as type or \"both\". A missing or empty view-type is assumed to be
* compatible.
*
* @param tags Collection of XTag to be checked.
* @param type The desired view-type
* @return true if all tags' view-type parameters are compatible
*/
protected boolean matchesViewType(Collection tags, String type)
{
// search all the tags looking for the view-type parameter
//
boolean matches = true;
for (Iterator k = tags.iterator(); k.hasNext() && matches; ) {
matches = matchesViewType((XTag) k.next(), type);
}
return matches;
}
}