0001: /*
0002: * Copyright (c) 2001, 2002 The XDoclet team
0003: * All rights reserved.
0004: */
0005: package xdoclet.modules.ejb;
0006:
0007: import java.lang.reflect.Method;
0008: import java.lang.reflect.Modifier;
0009:
0010: import java.util.*;
0011:
0012: import org.apache.commons.logging.Log;
0013:
0014: import xjavadoc.*;
0015:
0016: import xdoclet.DocletContext;
0017: import xdoclet.DocletSupport;
0018: import xdoclet.DocletTask;
0019: import xdoclet.SubTask;
0020: import xdoclet.XDocletException;
0021: import xdoclet.XDocletTagSupport;
0022: import xdoclet.modules.ejb.entity.*;
0023: import xdoclet.modules.ejb.home.HomeInterfaceSubTask;
0024: import xdoclet.modules.ejb.home.HomeTagsHandler;
0025: import xdoclet.modules.ejb.home.LocalHomeInterfaceSubTask;
0026: import xdoclet.modules.ejb.intf.LocalInterfaceSubTask;
0027: import xdoclet.modules.ejb.intf.RemoteInterfaceSubTask;
0028: import xdoclet.modules.ejb.mdb.MdbTagsHandler;
0029: import xdoclet.modules.ejb.session.SessionSubTask;
0030: import xdoclet.modules.ejb.session.SessionTagsHandler;
0031: import xdoclet.tagshandler.PackageTagsHandler;
0032: import xdoclet.util.LogUtil;
0033: import xdoclet.util.Translator;
0034: import xdoclet.util.TypeConversionUtil;
0035:
0036: /**
0037: * @author Ara Abrahamian (ara_e@email.com)
0038: * @author <a href="mailto:adrianprice at users.sf.net">Adrian Price</a>
0039: * @created Oct 15, 2001
0040: * @xdoclet.taghandler namespace="Ejb"
0041: * @version $Revision: 1.1 $
0042: */
0043: public class EjbTagsHandler extends XDocletTagSupport {
0044: protected final static String LOCAL_SUFFIX = "Local";
0045:
0046: /**
0047: * Gets the AConcreteEJBean attribute of the EjbTagsHandler class
0048: *
0049: * @param clazz Describe what the parameter does
0050: * @return The AConcreteEJBean value
0051: * @exception XDocletException
0052: */
0053: public static boolean isAConcreteEJBean(XClass clazz)
0054: throws XDocletException {
0055: XTag beanTag = clazz.getDoc().getTag("ejb:bean");
0056:
0057: if (beanTag != null) {
0058: String generateStr = beanTag.getAttributeValue("generate");
0059:
0060: if (generateStr != null) {
0061: boolean generate = TypeConversionUtil.stringToBoolean(
0062: generateStr, true);
0063:
0064: // generate="true" specifically
0065: if (generate == true) {
0066: return true;
0067: } else {
0068: // generate="false" specifically
0069: return false;
0070: }
0071: }
0072:
0073: // ejb:beam name specified, so it's a concrete ejb
0074: if (beanTag.getAttributeValue("name") != null) {
0075: return true;
0076: }
0077: }
0078:
0079: // now try to guess because it wasn't specifically specified whether
0080: // it should be generated or not
0081: SubTask subtask = getSubTaskClassForClass(clazz);
0082:
0083: if (clazz.isAbstract() == true) {
0084: if (hasANonDocletGeneratedSubClass(clazz) == true) {
0085: return false;
0086: }
0087:
0088: // an abstract mdb/etc?
0089: if (subtask == null) {
0090: return false;
0091: }
0092:
0093: // if <entitycmp/bmp/session/> is on, then do the best to guess correctly
0094: if (DocletContext.getInstance().isSubTaskDefined(
0095: subtask.getSubTaskName()) == true) {
0096: //none of the above guesses worked, assume it's concrete!
0097: return true;
0098: } else {
0099: // if <entitycmp/bmp/session/> is off, so if class is abstract then the bean is abstract except for entity cmp beans in ejb2 cmp2
0100: if (CmpTagsHandler.isEntityCmp(clazz)
0101: && CmpTagsHandler.isUsingCmp2Impl(clazz)) {
0102: return true;
0103: }
0104:
0105: return false;
0106: }
0107: } else {
0108: // if <entitycmp/bmp/> is on, then it's an error or not specify the class abstract, except for <session/> that non-abstract is also legal
0109: if (subtask != null
0110: && DocletContext.getInstance().isSubTaskDefined(
0111: subtask.getSubTaskName())) {
0112: if (subtask
0113: .getSubTaskName()
0114: .equals(
0115: DocletTask
0116: .getSubTaskName(SessionSubTask.class))) {
0117: return true;
0118: }
0119:
0120: String currentClassName = clazz.getQualifiedName();
0121:
0122: throw new XDocletException(
0123: Translator
0124: .getString(
0125: "xdoclet.modules.ejb.Messages",
0126: "class_not_abstract",
0127: new String[] {
0128: currentClassName,
0129: DocletTask
0130: .getSubTaskName(SessionSubTask.class) }));
0131: } else {
0132: return true;
0133: }
0134: }
0135: }
0136:
0137: /**
0138: * Returns the EJB name of the clazz by seaching for ejb:bean's name parameter. If that is not found, it uses the
0139: * class' name minus any suffix from the list in the 'ejbClassNameSuffix' config parameter ("Bean,EJB,Ejb" by
0140: * default).
0141: *
0142: * @param clazz The EJB bean class for which we want the EJB name
0143: * @return The EjbName value
0144: * @see #ejbName(java.util.Properties)
0145: */
0146: public static String getEjbNameFor(XClass clazz) {
0147: XTag beanTag = clazz.getDoc().getTag("ejb:bean");
0148: String paramValue = null;
0149:
0150: if (beanTag != null) {
0151: paramValue = beanTag.getAttributeValue("name");
0152: }
0153:
0154: if (paramValue == null) {
0155: String className = clazz.getName();
0156:
0157: // remove any suffix from ejbClassNameSuffix list
0158: String suffixlist = (String) getDocletContext()
0159: .getConfigParam("ejbClassNameSuffix");
0160: StringTokenizer st = new StringTokenizer(suffixlist, ",");
0161:
0162: while (st.hasMoreTokens()) {
0163: String suffix = st.nextToken();
0164:
0165: if (className.endsWith(suffix)) {
0166: int index = className.lastIndexOf(suffix);
0167:
0168: className = className.substring(0, index);
0169: break;
0170: }
0171: }
0172:
0173: return className;
0174: }
0175:
0176: return paramValue;
0177: }
0178:
0179: /**
0180: * Returns short version of the EJB name of the clazz.
0181: *
0182: * @param clazz the class we want its short EJB name
0183: * @return The shortEjbName value
0184: * @see #shortEjbName()
0185: */
0186: public static String getShortEjbNameFor(XClass clazz) {
0187: Log log = LogUtil.getLog(EjbTagsHandler.class, "shortEjbName");
0188:
0189: // Find the last part of the name
0190: StringTokenizer ejbNameTokens = new StringTokenizer(
0191: getEjbNameFor(clazz), ":./\\-");
0192: String name;
0193:
0194: do {
0195: name = ejbNameTokens.nextToken();
0196: } while (ejbNameTokens.hasMoreTokens());
0197:
0198: if (log.isDebugEnabled()) {
0199: log.debug("Name=" + name);
0200: }
0201:
0202: return name;
0203: }
0204:
0205: /**
0206: * @param clazz Description of Parameter
0207: * @return a unique id for clazz
0208: */
0209: public static String getEjbIdFor(XClass clazz) {
0210: return getEjbNameFor(clazz).replace('/', '_');
0211: }
0212:
0213: /**
0214: * Returns the EJB specification version used. The generated files will be compatible with the version specified.
0215: *
0216: * @return The Ejbspec value
0217: */
0218: public static String getEjbSpec() {
0219: return (String) getDocletContext().getConfigParam("EjbSpec");
0220: }
0221:
0222: public static boolean isLocalEjb(XClass clazz)
0223: throws XDocletException {
0224: return isViewtypeEjb(clazz, "local");
0225: }
0226:
0227: public static boolean isRemoteEjb(XClass clazz)
0228: throws XDocletException {
0229: return isViewtypeEjb(clazz, "remote");
0230: }
0231:
0232: /**
0233: * Returns true if clazz is only a local EJB by looking at ejb:bean's view-type parameter.
0234: *
0235: * @param clazz Description of Parameter
0236: * @return The OnlyLocalEjb value
0237: * @exception XDocletException
0238: */
0239: public static boolean isOnlyLocalEjb(XClass clazz)
0240: throws XDocletException {
0241: return isLocalEjb(clazz) && !isRemoteEjb(clazz);
0242: }
0243:
0244: /**
0245: * Returns true if clazz is only a remote EJB by looking at ejb:bean's view-type parameter.
0246: *
0247: * @param clazz Description of Parameter
0248: * @return The OnlyRemoteEjb value
0249: * @exception XDocletException
0250: */
0251: public static boolean isOnlyRemoteEjb(XClass clazz)
0252: throws XDocletException {
0253: return isRemoteEjb(clazz) && !isLocalEjb(clazz);
0254: }
0255:
0256: /**
0257: * Returns the class with the specified ejb name
0258: *
0259: * @param name
0260: * @return
0261: * @exception XDocletException
0262: */
0263: public static XClass getEjb(String name) throws XDocletException {
0264: Collection classes = getXJavaDoc().getSourceClasses();
0265:
0266: for (Iterator i = classes.iterator(); i.hasNext();) {
0267: XClass clazz = (XClass) i.next();
0268:
0269: if (name.equals(getEjbNameFor(clazz))) {
0270: return clazz;
0271: }
0272: }
0273: return null;
0274: }
0275:
0276: /**
0277: * Returns modified package name for a package name. If package name ends with one of the toReplace Strings, then
0278: * it's substituted by the replaceWith String. If packagePattern not null then it's roughly used.
0279: *
0280: * @param packageName The name of the package name the new package name will be derived from
0281: * @param packagePattern The package pattern to use. Can be null
0282: * @param subtask
0283: * @return Description of the Returned Value
0284: * @todo this method is really an utility method that should be deprecated here and moved to
0285: * PackageTagsHandler or even somewhere else
0286: */
0287: public static String choosePackage(String packageName,
0288: String packagePattern, String subtask) {
0289: Log log = LogUtil.getLog(EjbTagsHandler.class, "choosePackage");
0290:
0291: ArrayList packageSubstitutions = PackageTagsHandler
0292: .getPackageSubstitutions(subtask);
0293:
0294: if (log.isDebugEnabled()) {
0295: log.debug("Package name=" + packageName + " - Pattern="
0296: + packagePattern);
0297: }
0298:
0299: if (packagePattern != null) {
0300: // later we may do some parametric {0} fancy stuff here
0301: return packagePattern;
0302: } else {
0303: for (int i = 0; i < packageSubstitutions.size(); i++) {
0304: PackageTagsHandler.PackageSubstitution ps = (PackageTagsHandler.PackageSubstitution) packageSubstitutions
0305: .get(i);
0306: StringTokenizer st = new StringTokenizer(ps
0307: .getPackages(), ",", false);
0308:
0309: while (st.hasMoreTokens()) {
0310: String packages = st.nextToken();
0311: String suffix = "." + packages;
0312:
0313: if (packageName.endsWith(suffix)) {
0314: packageName = packageName.substring(0,
0315: packageName.length() - suffix.length())
0316: + '.' + ps.getSubstituteWith();
0317: break;
0318: }
0319: }
0320: }
0321: }
0322:
0323: if (log.isDebugEnabled()) {
0324: log.debug("packageName=" + packageName);
0325: }
0326:
0327: return packageName;
0328: }
0329:
0330: /**
0331: * Returns the name of EJB ref.
0332: *
0333: * @return The name of current EJB bean.
0334: * @exception XDocletException
0335: * @doc.tag type="content"
0336: */
0337: public static String ejbRefName() throws XDocletException {
0338: String ejbRefName = null;
0339:
0340: String refName = getCurrentClassTag().getAttributeValue(
0341: "ref-name");
0342:
0343: if (refName != null) {
0344: ejbRefName = refName;
0345: } else {
0346: ejbRefName = prefixWithEjbSlash(getEjbNameFor(getCurrentClass()));
0347:
0348: String type = getCurrentClassTag().getAttributeValue(
0349: "view-type");
0350:
0351: if (type != null && type.equals("local")
0352: && isLocalEjb(getCurrentClass())
0353: && isRemoteEjb(getCurrentClass())) {
0354: ejbRefName = ejbRefName + LOCAL_SUFFIX;
0355: }
0356: }
0357:
0358: return ejbRefName;
0359: }
0360:
0361: /**
0362: * Replace "." by "/" and add "ejb/" to the parameter.
0363: *
0364: * @param ejbName The string to parse
0365: * @return The parsed String
0366: */
0367: protected static String prefixWithEjbSlash(String ejbName) {
0368: ejbName = ejbName.replace('.', '/');
0369: if (ejbName.startsWith("ejb/")) {
0370: return ejbName;
0371: } else {
0372: return "ejb/" + ejbName;
0373: }
0374: }
0375:
0376: private static boolean isViewtypeEjb(XClass clazz, String viewtype)
0377: throws XDocletException {
0378: String value = getTagValue(FOR_CLASS, clazz.getDoc(),
0379: "ejb:bean", "view-type", "remote,local,both", null,
0380: true, false);
0381:
0382: if (value == null) {
0383: //default is both if ejb2, remote if ejb1.1
0384: return true;
0385: } else
0386: return value.indexOf(viewtype) != -1
0387: || value.indexOf("both") != -1;
0388: }
0389:
0390: /**
0391: * Gets the SubTaskClassForClass attribute of the EjbTagsHandler class
0392: *
0393: * @param clazz Describe what the parameter does
0394: * @return The SubTaskClassForClass value
0395: * @exception XDocletException
0396: */
0397: private static SubTask getSubTaskClassForClass(XClass clazz)
0398: throws XDocletException {
0399: if (CmpTagsHandler.isEntityCmp(clazz)) {
0400: return DocletContext.getInstance().getSubTaskBy(
0401: DocletTask.getSubTaskName(EntityCmpSubTask.class));
0402: } else if (BmpTagsHandler.isEntityBmp(clazz)) {
0403: return DocletContext.getInstance().getSubTaskBy(
0404: DocletTask.getSubTaskName(EntityBmpSubTask.class));
0405: } else if (SessionTagsHandler.isSession(clazz)) {
0406: return DocletContext.getInstance().getSubTaskBy(
0407: DocletTask.getSubTaskName(SessionSubTask.class));
0408: } else {
0409: return null;
0410: }
0411: }
0412:
0413: /**
0414: * Describe what the method does
0415: *
0416: * @param currentClass Describe what the parameter does
0417: * @return Describe the return value
0418: */
0419: private static boolean hasANonDocletGeneratedSubClass(
0420: XClass currentClass) {
0421: // check if it's abstract and has a non-xdoclet-generated derived class
0422: String fullClassName = currentClass.getQualifiedName();
0423: Collection classes = getXJavaDoc().getSourceClasses();
0424:
0425: for (Iterator i = classes.iterator(); i.hasNext();) {
0426: XClass clazz = (XClass) i.next();
0427:
0428: if (fullClassName.equals(clazz.getQualifiedName()) == false
0429: && !clazz.getDoc().hasTag("xdoclet-generated")
0430: && clazz.isA(fullClassName)) {
0431: return true;
0432: }
0433: }
0434:
0435: return false;
0436: }
0437:
0438: /**
0439: * Returns the name of current EJB bean.
0440: *
0441: * @param attributes The attributes of the template tag
0442: * @return The name of current EJB bean.
0443: * @exception XDocletException
0444: * @see #getEjbNameFor(xjavadoc.XClass)
0445: * @doc.tag type="content"
0446: * @doc.param name="prefixWithEjbSlash" optional="true" values="true,false" description="Specifies
0447: * whether to prefix it with ejb/ or not. False by default."
0448: */
0449: public String ejbName(Properties attributes)
0450: throws XDocletException {
0451: String prefixWithEjbSlashStr = attributes
0452: .getProperty("prefixWithEjbSlash");
0453: boolean prefixWithEjbSlash = TypeConversionUtil
0454: .stringToBoolean(prefixWithEjbSlashStr, false);
0455: String ejbName = getEjbNameFor(getCurrentClass());
0456:
0457: if (prefixWithEjbSlash == true) {
0458: return prefixWithEjbSlash(ejbName);
0459: } else {
0460: return ejbName;
0461: }
0462: }
0463:
0464: /**
0465: * Returns the name of EJB ref.
0466: *
0467: * @return The name of current EJB bean.
0468: * @exception XDocletException
0469: * @doc.tag type="content"
0470: */
0471: public String ejbExternalRefName() throws XDocletException {
0472: String ejbRefName = null;
0473: String refName = getCurrentClassTag().getAttributeValue(
0474: "ref-name");
0475:
0476: if (refName != null) {
0477: ejbRefName = refName;
0478: } else {
0479: ejbRefName = prefixWithEjbSlash(getCurrentClassTag()
0480: .getAttributeValue("ejb-name"));
0481: }
0482:
0483: return ejbRefName;
0484: }
0485:
0486: /**
0487: * Returns the symbolic name of the current class. For an EJBean it's the value of ejb:bean's name parameter.
0488: *
0489: * @return The symbolic name of the current class
0490: * @exception XDocletException
0491: * @see #shortEjbName()
0492: * @doc.tag type="content"
0493: */
0494: public String symbolicClassName() throws XDocletException {
0495: return shortEjbName();
0496: }
0497:
0498: /**
0499: * Returns short version of ejbName(). Example: "foo.bar.MyBean" ->"MyBean", "foo/bar/MyBean" ->"MyBean"
0500: *
0501: * @return Description of the Returned Value
0502: * @exception XDocletException
0503: * @see #getShortEjbNameFor(xjavadoc.XClass)
0504: * @doc.tag type="content"
0505: */
0506: public String shortEjbName() throws XDocletException {
0507: return getShortEjbNameFor(getCurrentClass());
0508: }
0509:
0510: /**
0511: * Evaluates the body block for each EJBean derived from one of the three EJB types: EntityBean, SessionBean or
0512: * MessageDrivenBean.
0513: *
0514: * @param template The body of the block tag
0515: * @exception XDocletException
0516: * @see xdoclet.modules.ejb.entity.EntityTagsHandler#isEntity(xjavadoc.XClass)
0517: * @see xdoclet.modules.ejb.session.SessionTagsHandler#isSession(xjavadoc.XClass)
0518: * @see xdoclet.modules.ejb.mdb.MdbTagsHandler#isMessageDriven(xjavadoc.XClass)
0519: * @doc.tag type="block"
0520: */
0521: public void forAllBeans(String template) throws XDocletException {
0522: Collection classes = getXJavaDoc().getSourceClasses();
0523:
0524: for (Iterator i = classes.iterator(); i.hasNext();) {
0525: XClass clazz = (XClass) i.next();
0526:
0527: setCurrentClass(clazz);
0528:
0529: if (DocletSupport.isDocletGenerated(getCurrentClass())) {
0530: continue;
0531: }
0532:
0533: if (EntityTagsHandler.isEntity(getCurrentClass())
0534: || SessionTagsHandler.isSession(getCurrentClass())
0535: || MdbTagsHandler
0536: .isMessageDriven(getCurrentClass())) {
0537: generate(template);
0538: }
0539: }
0540: }
0541:
0542: /**
0543: * Evaluates the body block if current bean is a concrete bean meaning the generate parameter of ejb:bean is either
0544: * not specified or equals to "true", otherwise the bean is just an abstract base class bean not meant to be used as
0545: * a EJBean but serve as the base for other EJBeans.
0546: *
0547: * @param template The body of the block tag
0548: * @param attributes The attributes of the template tag
0549: * @exception XDocletException
0550: * @doc.tag type="block"
0551: */
0552: public void ifIsAConcreteEJBean(String template,
0553: Properties attributes) throws XDocletException {
0554: if (isAConcreteEJBean(getCurrentClass()) == true) {
0555: generate(template);
0556: }
0557: }
0558:
0559: /**
0560: * Returns Bean type : "Entity", "Session" or "Message Driven".
0561: *
0562: * @return "Entity", "Session" or "Message Driven".
0563: * @exception XDocletException
0564: * @see xdoclet.modules.ejb.entity.EntityTagsHandler#isEntity(xjavadoc.XClass)
0565: * @see xdoclet.modules.ejb.session.SessionTagsHandler#isSession(xjavadoc.XClass)
0566: * @see xdoclet.modules.ejb.mdb.MdbTagsHandler#isMessageDriven(xjavadoc.XClass)
0567: * @doc.tag type="content"
0568: */
0569: public String beanType() throws XDocletException {
0570: if (EntityTagsHandler.isEntity(getCurrentClass())) {
0571: return "Entity";
0572: } else if (SessionTagsHandler.isSession(getCurrentClass())) {
0573: return "Session";
0574: } else if (MdbTagsHandler.isMessageDriven(getCurrentClass())) {
0575: return "Message Driven";
0576: } else {
0577: return "Unknown";
0578: }
0579: }
0580:
0581: /**
0582: * Returns the full-qualified name of the current class's concrete class. This is the class that is generated and is
0583: * derived from current class.
0584: *
0585: * @return The full-qualified name of the current class's concrete class
0586: * @exception XDocletException
0587: * @see xdoclet.modules.ejb.session.SessionTagsHandler#sessionClass()
0588: * @see xdoclet.modules.ejb.entity.BmpTagsHandler#entityBmpClass()
0589: * @see xdoclet.modules.ejb.entity.CmpTagsHandler#entityCmpClass()
0590: * @see xdoclet.modules.ejb.mdb.MdbTagsHandler#messageDrivenClass()
0591: * @doc.tag type="content"
0592: */
0593: public String concreteFullClassName() throws XDocletException {
0594: if (SessionTagsHandler.isSession(getCurrentClass())) {
0595: if (DocletContext.getInstance().isSubTaskDefined(
0596: DocletTask.getSubTaskName(SessionSubTask.class))) {
0597: return SessionTagsHandler
0598: .getSessionClassFor(getCurrentClass());
0599: } else {
0600: return getCurrentClass().getQualifiedName();
0601: }
0602: } else if (BmpTagsHandler.isEntityBmp(getCurrentClass())) {
0603: if (DocletContext.getInstance().isSubTaskDefined(
0604: DocletTask.getSubTaskName(EntityBmpSubTask.class))) {
0605: return BmpTagsHandler
0606: .getEntityBmpClassFor(getCurrentClass());
0607: } else {
0608: return getCurrentClass().getQualifiedName();
0609: }
0610: } else if (CmpTagsHandler.isEntityCmp(getCurrentClass())) {
0611: if (DocletContext.getInstance().isSubTaskDefined(
0612: DocletTask.getSubTaskName(EntityCmpSubTask.class))) {
0613: return CmpTagsHandler
0614: .getEntityCmpClassFor(getCurrentClass());
0615: } else {
0616: return getCurrentClass().getQualifiedName();
0617: }
0618: } else if (MdbTagsHandler.isMessageDriven(getCurrentClass())) {
0619: return MdbTagsHandler
0620: .getMessageDrivenClassFor(getCurrentClass());
0621: } else {
0622: return null;
0623: }
0624: }
0625:
0626: /**
0627: * Returns unique id for current ejb.
0628: *
0629: * @return Description of the Returned Value
0630: * @exception XDocletException
0631: * @doc.tag type="content"
0632: */
0633: public String id() throws XDocletException {
0634: return getEjbIdFor(getCurrentClass());
0635: }
0636:
0637: /**
0638: * @param template Description of Parameter
0639: * @exception XDocletException
0640: * @doc.tag type="block"
0641: */
0642: public void ifLocalEjb(String template) throws XDocletException {
0643: if (isLocalEjb(getCurrentClass())) {
0644: generate(template);
0645: }
0646: }
0647:
0648: /**
0649: * @param template Description of Parameter
0650: * @exception XDocletException
0651: * @doc.tag type="block"
0652: */
0653: public void ifRemoteEjb(String template) throws XDocletException {
0654: if (isRemoteEjb(getCurrentClass())) {
0655: generate(template);
0656: }
0657: }
0658:
0659: /**
0660: * @param template
0661: * @exception XDocletException
0662: * @doc.tag type="block"
0663: */
0664: public void ifNotLocalEjb(String template) throws XDocletException {
0665: if (!isLocalEjb(getCurrentClass())) {
0666: generate(template);
0667: }
0668: }
0669:
0670: /**
0671: * @param template
0672: * @exception XDocletException
0673: * @doc.tag type="block"
0674: */
0675: public void ifNotRemoteEjb(String template) throws XDocletException {
0676: if (!isRemoteEjb(getCurrentClass())) {
0677: generate(template);
0678: }
0679: }
0680:
0681: protected boolean isIntfMethod(String tagName, String type)
0682: throws XDocletException {
0683: if (!getCurrentMethod().getDoc().hasTag(tagName)) {
0684: return false;
0685: }
0686:
0687: String viewType = getTagValue(FOR_CLASS, getCurrentMethod()
0688: .getDoc(), tagName, "view-type", "local,remote,both",
0689: null, false, false);
0690:
0691: if ("both".equals(viewType)) {
0692: viewType = "local,remote";
0693: }
0694:
0695: if (viewType == null) {
0696: viewType = getTagValue(FOR_CLASS, getCurrentClass()
0697: .getDoc(), "ejb:bean", "view-type",
0698: "local,remote,both", "both", true, false);
0699:
0700: if ("both".equals(viewType)) {
0701: viewType = "local,remote";
0702: }
0703: }
0704:
0705: return viewType.indexOf(type) >= 0;
0706: }
0707:
0708: /**
0709: * Returns the interface method name depending on its type.
0710: *
0711: * @param name Description of Parameter
0712: * @return "create" if ejbCreate, "remote" if ejbRemove, find <blabl>if ejbFind, home <blabla>
0713: * if ejbHome.
0714: * @exception XDocletException
0715: */
0716: protected String getInterfaceMethodName(String name)
0717: throws XDocletException {
0718: if (name.startsWith("ejbCreate")) {
0719: return HomeTagsHandler.toCreateMethod(name);
0720: } else if (name.equals("ejbRemove")) {
0721: return "remove";
0722: } else if (name.startsWith("ejbFind")) {
0723: return HomeTagsHandler.toFinderMethod(name);
0724: } else if (name.startsWith("ejbHome")) {
0725: return HomeTagsHandler.toHomeMethod(name);
0726: } else {
0727: return name;
0728: }
0729: }
0730:
0731: protected boolean isInheritedIntfMethod(XClass clazz,
0732: XMethod method, String tagName, String type,
0733: String extendsParamName, String defaultBaseClassName)
0734: throws XDocletException {
0735: return isInheritedIntfMethod(clazz, method
0736: .getNameWithSignature(false), tagName, type,
0737: extendsParamName, defaultBaseClassName);
0738: }
0739:
0740: /**
0741: * Checks whether the specified interface method is inherited from a super-interface.
0742: *
0743: * @param clazz The class being processed.
0744: * @param methodNameWithSignature The normalized method name with parameters (i.e., comma-separated, no spaces,
0745: * return type or parameter names).
0746: * @param tagName The tag name which indicates whether to check the home interface (ejb:home) or a
0747: * component interface (ejb:interface).
0748: * @param type The interface type, "local" or "remote".
0749: * @param extendsParamName The name of the attribute that indicates the super-interface extended by the home
0750: * or component interface in question.
0751: * @param defaultBaseClassName The name of the default super-interface.
0752: * @return <code>true</code> if the specified method is defined in the super-interface,
0753: * otherwise <code>false</code>.
0754: * @throws XDocletException
0755: */
0756: protected boolean isInheritedIntfMethod(XClass clazz,
0757: String methodNameWithSignature, String tagName,
0758: String type, String extendsParamName,
0759: String defaultBaseClassName) throws XDocletException {
0760: Log log = LogUtil.getLog(EjbTagsHandler.class,
0761: "isInheritedIntfMethod");
0762:
0763: // Convert the implementation method name to the interface method name.
0764: methodNameWithSignature = getInterfaceMethodName(methodNameWithSignature);
0765:
0766: if (log.isDebugEnabled()) {
0767: log.debug("Checking whether " + type + " interface method "
0768: + methodNameWithSignature + " is inherited");
0769: }
0770:
0771: XTag beanTag = clazz.getDoc().getTag(tagName);
0772:
0773: if (beanTag == null)
0774: return false;
0775:
0776: // Iterate through the superclasses/interfaces looking for the method.
0777: beanTag.getAttributeValue(extendsParamName);
0778:
0779: String extendsFrom = extendsFromFor(clazz, tagName, type,
0780: extendsParamName, defaultBaseClassName);
0781: StringTokenizer strtok = new StringTokenizer(extendsFrom, ", ");
0782:
0783: while (strtok.hasMoreTokens()) {
0784: String baseClassName = strtok.nextToken();
0785: XClass baseClass = getXJavaDoc().getXClass(baseClassName);
0786:
0787: if (baseClass == null) {
0788: log.warn("Unable to load base class/interface: "
0789: + baseClassName);
0790: continue;
0791: }
0792:
0793: XMethod inheritedMethod = baseClass.getMethod(
0794: methodNameWithSignature, true);
0795:
0796: if (inheritedMethod != null) {
0797: log.debug(type + " method " + methodNameWithSignature
0798: + " is inherited from " + baseClassName);
0799: return true;
0800: }
0801: }
0802: return false;
0803: }
0804:
0805: /**
0806: * Returns true of clazz is an EJB (derived from an EJB type), false otherwise.
0807: *
0808: * @param clazz Description of Parameter
0809: * @return The Ejb value
0810: * @exception XDocletException
0811: */
0812: protected boolean isEjb(XClass clazz) throws XDocletException {
0813: return clazz.isA("javax.ejb.SessionBean")
0814: || clazz.isA("javax.ejb.EntityBean")
0815: || clazz.isA("javax.ejb.MessageDrivenBean");
0816: }
0817:
0818: /**
0819: * sub-classes which deal with patternized class names return a reasonable value
0820: *
0821: * @param clazz the class
0822: * @param type type value used for view-type of remote/local
0823: * @return dependent class name for the class and type
0824: * @exception XDocletException
0825: */
0826: protected String getDependentClassFor(XClass clazz, String type)
0827: throws XDocletException {
0828: return null;
0829: }
0830:
0831: /**
0832: * Gets the DependentClassTagName attribute of the EjbTagsHandler object
0833: *
0834: * @return The DependentClassTagName value
0835: */
0836: protected String getDependentClassTagName() {
0837: //it's too much dependency, we should find a better way
0838: if (getDocletContext()
0839: .getActiveSubTask()
0840: .getSubTaskName()
0841: .equals(
0842: DocletTask
0843: .getSubTaskName(DataObjectSubTask.class))) {
0844: return "ejb:data-object";
0845: } else if (getDocletContext()
0846: .getActiveSubTask()
0847: .getSubTaskName()
0848: .equals(
0849: DocletTask
0850: .getSubTaskName(EntityBmpSubTask.class))
0851: || getDocletContext()
0852: .getActiveSubTask()
0853: .getSubTaskName()
0854: .equals(
0855: DocletTask
0856: .getSubTaskName(EntityCmpSubTask.class))) {
0857: return "ejb:bean";
0858: } else if (getDocletContext()
0859: .getActiveSubTask()
0860: .getSubTaskName()
0861: .equals(
0862: DocletTask
0863: .getSubTaskName(RemoteInterfaceSubTask.class))
0864: || getDocletContext()
0865: .getActiveSubTask()
0866: .getSubTaskName()
0867: .equals(
0868: DocletTask
0869: .getSubTaskName(LocalInterfaceSubTask.class))) {
0870: return "ejb:interface";
0871: } else if (getDocletContext()
0872: .getActiveSubTask()
0873: .getSubTaskName()
0874: .equals(
0875: DocletTask
0876: .getSubTaskName(HomeInterfaceSubTask.class))
0877: || getDocletContext()
0878: .getActiveSubTask()
0879: .getSubTaskName()
0880: .equals(
0881: DocletTask
0882: .getSubTaskName(LocalHomeInterfaceSubTask.class))) {
0883: return "ejb:interface";
0884: } else if (getDocletContext().getActiveSubTask()
0885: .getSubTaskName().equals(
0886: DocletTask
0887: .getSubTaskName(EntityPkSubTask.class))) {
0888: return "ejb:pk";
0889: } else {
0890: return null;
0891: }
0892: }
0893:
0894: /**
0895: * Strips any return type and parameter names from a method signature.
0896: *
0897: * @param signature Method signature to normalize.
0898: * @return Normalized signature.
0899: */
0900: protected String normalizeSignature(String signature) {
0901: StringBuffer sb = new StringBuffer(signature.length());
0902:
0903: StringTokenizer strtok = new StringTokenizer(signature.trim());
0904: StringTokenizer strtok2 = new StringTokenizer(strtok.nextToken(
0905: "(,)").trim(), " \t");
0906:
0907: String methodName;
0908:
0909: do {
0910: methodName = strtok2.nextToken();
0911: } while (strtok2.hasMoreTokens());
0912: sb.append(methodName).append('(');
0913:
0914: boolean comma = false;
0915:
0916: while (strtok.hasMoreTokens()) {
0917: strtok2 = new StringTokenizer(strtok.nextToken().trim(),
0918: " \t");
0919: if (comma)
0920: sb.append(',');
0921: sb.append(strtok2.nextToken());
0922: comma = true;
0923: }
0924: ;
0925: sb.append(')');
0926:
0927: return sb.toString();
0928: }
0929:
0930: /**
0931: * Returns true if class/method denoted by doc has ejb:transaction tag, false otherwise.
0932: *
0933: * @param doc Description of Parameter
0934: * @return Description of the Returned Value
0935: * @exception XDocletException
0936: */
0937: protected boolean hasTransaction(XDoc doc) throws XDocletException {
0938: return doc.hasTag("ejb:transaction");
0939: }
0940:
0941: /**
0942: * Returns the name of the class pk/etc class extends.
0943: *
0944: * @param clazz the class
0945: * @param tagName name of the tag (ejb:bean for example, used for getting generate parameter)
0946: * @param type type value used for view type of remote/local
0947: * @param extendsParamName extends parameter name (is "extends" for ejb:bean but is "local-extends" for local)
0948: * @param defaultBaseClassName default base class name, returned when not deriving from another base class
0949: * @return correct value for the extends statement of a generated class
0950: * @exception XDocletException
0951: */
0952: protected String extendsFromFor(XClass clazz, String tagName,
0953: String type, String extendsParamName,
0954: String defaultBaseClassName) throws XDocletException {
0955: Log log = LogUtil
0956: .getLog(EjbTagsHandler.class, "extendsFromFor");
0957:
0958: log.debug("Looking " + type + " extendsFrom for class "
0959: + clazz.getName());
0960:
0961: // see ejb:pk/etc generate="?" in superclass
0962: XClass super class = clazz.getSuperclass();
0963:
0964: boolean generateSuper;
0965:
0966: if (super class.getDoc().hasTag(tagName)) {
0967: String generateSuperStr = getTagValue(FOR_CLASS, super class
0968: .getDoc(), tagName, "generate", null, null, false,
0969: false);
0970:
0971: generateSuper = TypeConversionUtil.stringToBoolean(
0972: generateSuperStr, true);
0973: } else {
0974: // Two Cases : PersonBean and BaseEntityBean
0975: generateSuper = false;
0976:
0977: Collection interfaces = clazz.getSuperclass()
0978: .getInterfaces();
0979:
0980: for (Iterator i = interfaces.iterator(); i.hasNext();) {
0981: XClass intf = (XClass) i.next();
0982:
0983: // if superclass is not javax.ejb.EntityBean then we have a superclass which
0984: // is itself deriving from javax.ejb.EntityBean
0985: if (intf.getQualifiedName().equals(
0986: "javax.ejb.EntityBean")
0987: || intf.getQualifiedName().equals(
0988: "javax.ejb.SessionBean")
0989: || intf.getQualifiedName().equals(
0990: "javax.ejb.MessageDrivenBean")) {
0991: //it derives from javax.ejb.*Bean and no superclass for pk/etc class is explicitly defined
0992: generateSuper = true;
0993: }
0994: }
0995: }
0996:
0997: log.debug(clazz.getName() + " superclass is generatable? "
0998: + generateSuper);
0999:
1000: // note: look for ejb:pk/etc extends in superclasses also only if generate="false" in superclass
1001: // so extends attribute is inherited only if superclass's pk/etc is not to be generated
1002: String extendsValue = getTagValue(FOR_CLASS, clazz.getDoc(),
1003: tagName, extendsParamName, null, null, !generateSuper,
1004: false);
1005:
1006: // if explicitly specified
1007: if (extendsValue != null) {
1008: log.debug(clazz.getName()
1009: + " contains an explicit extends. Returning "
1010: + extendsValue);
1011: return extendsValue;
1012: } else {
1013: // now try to guess if we are deriving from another ejb bean, and if so, then derive from
1014: // that bean's pk class too (if generate="true" for superclass's pk/etc class)
1015: log
1016: .debug(clazz.getName()
1017: + " does not contains an explicit extends. Trying to guess it");
1018:
1019: // java.lang.Object (the only that have no superclass)
1020: if (super class.getSuperclass() == null) {
1021: log
1022: .debug("Top of class hierarchy reached. Returning default extends: "
1023: + defaultBaseClassName);
1024: return defaultBaseClassName;
1025: }
1026: // if a superclass with generate="true"
1027: else if (generateSuper == true) {
1028: String className = getDependentClassFor(super class,
1029: type);
1030:
1031: if (className != null) {
1032: log.debug("Superclass " + super class.getName()
1033: + " has a dependent class: " + className);
1034: return className;
1035: } else {
1036: log.debug("No dependent class for "
1037: + super class.getName()
1038: + ". Returning default extends: "
1039: + defaultBaseClassName);
1040: return defaultBaseClassName;
1041: }
1042: } else {
1043: // so we have a superclass with pk-generate="false", look at superclass of that superclass!
1044: log
1045: .debug("Can't guess now. Going deeper into class hierarchy");
1046: return extendsFromFor(super class, tagName, type,
1047: extendsParamName, defaultBaseClassName);
1048: }
1049: }
1050: }
1051:
1052: /**
1053: * Describe what the method does
1054: *
1055: * @param clazz Describe what the parameter does
1056: * @param tagName Describe what the parameter does
1057: * @return Describe the return value
1058: * @exception XDocletException
1059: */
1060: protected boolean shouldTraverseSuperclassForDependentClass(
1061: XClass clazz, String tagName) throws XDocletException {
1062: Log log = LogUtil.getLog(EjbTagsHandler.class,
1063: "shouldTraverseSuperclassForDependentClass");
1064:
1065: if (clazz.getQualifiedName().equals("java.lang.Object")) {
1066: log.debug("clazz = java.lang.Object");
1067:
1068: return true;
1069: }
1070:
1071: if (!clazz.isA("javax.ejb.EntityBean")
1072: && !clazz.isA("javax.ejb.SessionBean")) {
1073: log
1074: .debug(clazz.getQualifiedName()
1075: + " is _not_ of type javax.ejb.EntityBean,javax.ejb.SessionBean");
1076:
1077: return true;
1078: } else {
1079: log
1080: .debug(clazz.getQualifiedName()
1081: + " _is_ of type javax.ejb.EntityBean,javax.ejb.SessionBean");
1082: }
1083:
1084: // see ejb:bean generate="?" in superclass
1085: String generateBeanStr = getTagValue(FOR_CLASS, clazz.getDoc(),
1086: "ejb:bean", "generate", null, "true", false, false);
1087:
1088: boolean generateBean = TypeConversionUtil.stringToBoolean(
1089: generateBeanStr, true);
1090:
1091: if (generateBean == false) {
1092: log.debug("generateBean == false");
1093:
1094: return true;
1095: }
1096:
1097: boolean generate = false;
1098:
1099: if (tagName != null) {
1100: // see ejb:pk/etc generate="?" in superclass
1101: String generateStr = getTagValue(FOR_CLASS, clazz.getDoc(),
1102: tagName, "generate", null, "true", false, false);
1103:
1104: generate = TypeConversionUtil.stringToBoolean(generateStr,
1105: true);
1106: }
1107:
1108: if (generate == false) {
1109: log.debug("generate == false");
1110:
1111: return true;
1112: } else {
1113: log.debug("generate == true");
1114:
1115: return false;
1116: }
1117: }
1118: }
|