0001: /*
0002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
0003: */
0004: package com.tc.aspectwerkz.definition;
0005:
0006: //import org.dom4j.Attribute;
0007: //import org.dom4j.Document;
0008: //import org.dom4j.DocumentException;
0009: //import org.dom4j.Element;
0010:
0011: import org.w3c.dom.Attr;
0012: import org.w3c.dom.Document;
0013: import org.w3c.dom.Element;
0014: import org.w3c.dom.NamedNodeMap;
0015: import org.w3c.dom.Node;
0016: import org.w3c.dom.NodeList;
0017: import org.w3c.dom.Text;
0018:
0019: import com.tc.aspectwerkz.DeploymentModel;
0020: import com.tc.aspectwerkz.expression.ExpressionInfo;
0021: import com.tc.aspectwerkz.expression.ExpressionNamespace;
0022: import com.tc.aspectwerkz.annotation.AspectAnnotationParser;
0023: import com.tc.aspectwerkz.annotation.MixinAnnotationParser;
0024: import com.tc.aspectwerkz.aspect.AdviceType;
0025: import com.tc.aspectwerkz.exception.DefinitionException;
0026: import com.tc.aspectwerkz.intercept.AdvisableImpl;
0027: import com.tc.aspectwerkz.reflect.impl.asm.AsmClassInfo;
0028: import com.tc.aspectwerkz.reflect.impl.java.JavaClassInfo;
0029: import com.tc.aspectwerkz.reflect.impl.java.JavaMethodInfo;
0030: import com.tc.aspectwerkz.reflect.ClassInfo;
0031: import com.tc.aspectwerkz.reflect.MethodInfo;
0032: import com.tc.aspectwerkz.transform.inlining.AspectModelManager;
0033: import com.tc.aspectwerkz.util.Strings;
0034:
0035: import java.io.IOException;
0036: import java.util.ArrayList;
0037: import java.util.HashSet;
0038: import java.util.Iterator;
0039: import java.util.List;
0040: import java.util.Set;
0041: import java.util.StringTokenizer;
0042:
0043: /**
0044: * Parses the XML definition using <tt>dom4j</tt>.
0045: *
0046: * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
0047: * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
0048: */
0049: public class DocumentParser {
0050:
0051: /**
0052: * Parses aspect class names.
0053: *
0054: * @param document the defintion as a document
0055: * @return the aspect class names
0056: */
0057: public static List parseAspectClassNames(Document document) {
0058: List aspectClassNames = new ArrayList();
0059:
0060: Element documentElement = document.getDocumentElement();
0061: NodeList systemNodes = documentElement.getChildNodes();
0062: for (int i = 0; i < systemNodes.getLength(); i++) {
0063: Node systemNode = systemNodes.item(i);
0064: String nodeName = systemNode.getNodeName();
0065: if (nodeName.equals("system")) {
0066: String basePackage = getBasePackage((Element) systemNode);
0067:
0068: NodeList childNodes = systemNode.getChildNodes();
0069: for (int j = 0; j < childNodes.getLength(); j++) {
0070: Node childNode = childNodes.item(j);
0071: if (childNode.getNodeName().equals("aspect")) {
0072: addAspectClassName(aspectClassNames, childNode,
0073: basePackage);
0074:
0075: } else if (childNode.getNodeName()
0076: .equals("package")) {
0077: NodeList aspectNodes = childNode
0078: .getChildNodes();
0079: for (int k = 0; k < aspectNodes.getLength(); k++) {
0080: Node aspectNode = aspectNodes.item(k);
0081: if (aspectNode.getNodeName().equals(
0082: "aspect")) {
0083: addAspectClassName(aspectClassNames,
0084: aspectNode, basePackage);
0085: }
0086: }
0087: }
0088: }
0089: }
0090: }
0091:
0092: aspectClassNames.add(Virtual.class.getName());
0093: return aspectClassNames;
0094: }
0095:
0096: private static void addAspectClassName(List aspectClassNames,
0097: Node aspectNode, String basePackage) {
0098: if (aspectNode.getNodeName().equals("aspect")) {
0099: NamedNodeMap attrs = aspectNode.getAttributes();
0100: for (int l = 0; l < attrs.getLength(); l++) {
0101: Node attr = attrs.item(l);
0102: if (attr.getNodeName().equals("class")) {
0103: aspectClassNames.add(basePackage
0104: + ((Attr) attr).getValue().trim());
0105: }
0106: }
0107: }
0108: }
0109:
0110: /**
0111: * Parses the definition DOM document.
0112: *
0113: * @param xmlDef the defintion xml
0114: * @param systemDef the system definition
0115: * @param aspectClass the aspect class
0116: * @return the definition
0117: * @throws DocumentParserException
0118: */
0119: public static AspectDefinition parseAspectDefinition(String xmlDef,
0120: SystemDefinition systemDef, Class aspectClass) {
0121: Document document;
0122: try {
0123: document = XmlParser.createDocument(xmlDef);
0124: } catch (IOException e) {
0125: throw new DefinitionException(
0126: "Unable to parse definition; " + e.toString());
0127: }
0128:
0129: Element aspectElement = document.getDocumentElement();
0130:
0131: if (!"aspect".equals(aspectElement.getNodeName())) {
0132: throw new DefinitionException(
0133: "XML definition for aspect is not well-formed: "
0134: + xmlDef);
0135: }
0136: String specialAspectName = null;
0137: String className = null;
0138: String deploymentModelAsString = null;
0139: String containerClassName = null;
0140: NamedNodeMap aspectAttributes = aspectElement.getAttributes();
0141: for (int i = 0; i < aspectAttributes.getLength(); i++) {
0142: Node attribute = aspectAttributes.item(i);
0143: String name = attribute.getNodeName().trim();
0144: if (name.equalsIgnoreCase("class")) {
0145: className = ((Attr) attribute).getValue().trim();
0146: } else if (name.equalsIgnoreCase("deployment-model")) {
0147: deploymentModelAsString = ((Attr) attribute).getValue()
0148: .trim();
0149: } else if (name.equalsIgnoreCase("name")) {
0150: specialAspectName = ((Attr) attribute).getValue()
0151: .trim();
0152: } else if (name.equalsIgnoreCase("container")) {
0153: containerClassName = ((Attr) attribute).getValue()
0154: .trim();
0155: }
0156: }
0157: if (specialAspectName == null
0158: || specialAspectName.trim().length() == 0) {
0159: specialAspectName = className;
0160: }
0161:
0162: ClassInfo classInfo = JavaClassInfo.getClassInfo(aspectClass);
0163: ClassLoader loader = aspectClass.getClassLoader();
0164:
0165: // create the aspect definition
0166: AspectDefinition aspectDef = new AspectDefinition(
0167: specialAspectName, classInfo, systemDef);
0168: //TODO: if this XML centric deployment is supposed to PRESERVE @Aspect values, then it is broken
0169: aspectDef.setContainerClassName(containerClassName);
0170: aspectDef.setDeploymentModel(DeploymentModel
0171: .getDeploymentModelFor(deploymentModelAsString));
0172:
0173: parsePointcutElements(aspectElement, aspectDef); //needed to support undefined named pointcut in Attributes AW-152
0174:
0175: // load the different aspect model and let them define their aspects
0176: AspectModelManager.defineAspect(classInfo, aspectDef, loader);
0177:
0178: // parse the aspect info
0179: parseParameterElements(aspectElement, aspectDef);
0180: parsePointcutElements(aspectElement, aspectDef); //reparse pc for XML override (AW-152)
0181: parseAdviceElements(aspectElement, aspectDef, JavaClassInfo
0182: .getClassInfo(aspectClass));
0183: parseIntroduceElements(aspectElement, aspectDef, "",
0184: aspectClass.getClassLoader());
0185: return aspectDef;
0186: }
0187:
0188: /**
0189: * Parses the definition DOM document.
0190: *
0191: * @param loader the current class loader
0192: * @param document the defintion as a document
0193: * @return the definitions
0194: */
0195: public static Set parse(ClassLoader loader, Document document) {
0196: // parse the transformation scopes
0197: return parseSystemElements(loader, document
0198: .getDocumentElement());
0199: }
0200:
0201: /**
0202: * Parses the <tt>system</tt> elements.
0203: *
0204: * @param loader the current class loader
0205: * @param root the root element
0206: */
0207: private static Set parseSystemElements(ClassLoader loader,
0208: Element root) {
0209: Set systemDefs = new HashSet();
0210:
0211: NodeList rootNodes = root.getChildNodes();
0212: for (int i = 0; i < rootNodes.getLength(); i++) {
0213: Node childNode = rootNodes.item(i);
0214: if (childNode.getNodeName().equals("system")) {
0215: Element systemElement = (Element) childNode;
0216: SystemDefinition definition = parseSystemElement(
0217: loader, systemElement,
0218: getBasePackage(systemElement));
0219: if (definition != null) {
0220: systemDefs.add(definition);
0221: }
0222: }
0223: }
0224: return systemDefs;
0225: }
0226:
0227: /**
0228: * Parses the <tt>system</tt> elements.
0229: *
0230: * @param loader the current class loader
0231: * @param systemElement the system element
0232: * @param basePackage the base package
0233: * @return the definition for the system
0234: */
0235: private static SystemDefinition parseSystemElement(
0236: ClassLoader loader, Element systemElement,
0237: String basePackage) {
0238: String uuid = systemElement.getAttribute("id");
0239: if (uuid == null || uuid.equals("")) {
0240: throw new DefinitionException(
0241: "system UUID must be specified");
0242: }
0243: SystemDefinition definition = new SystemDefinition(uuid);
0244:
0245: // add the virtual aspect
0246: addVirtualAspect(definition);
0247:
0248: // parse the global pointcuts
0249: List globalPointcuts = parseGlobalPointcutDefs(systemElement);
0250:
0251: //FIXME: systemDef should link a namespace, + remove static hashmap in Namespace (uuid clash in parallel CL)
0252: ExpressionNamespace systemNamespace = ExpressionNamespace
0253: .getNamespace(definition.getUuid());
0254: for (Iterator iterator = globalPointcuts.iterator(); iterator
0255: .hasNext();) {
0256: PointcutInfo pointcutInfo = (PointcutInfo) iterator.next();
0257: systemNamespace.addExpressionInfo(pointcutInfo.name,
0258: new ExpressionInfo(pointcutInfo.expression,
0259: systemNamespace.getName()));
0260: }
0261:
0262: // parse the global deployment scopes definitions
0263: parseDeploymentScopeDefs(systemElement, definition);
0264:
0265: // parse the global advisable definitions
0266: parseAdvisableDefs(systemElement, definition);
0267:
0268: // parse the include, exclude and prepare elements
0269: parseIncludePackageElements(systemElement, definition,
0270: basePackage);
0271: parseExcludePackageElements(systemElement, definition,
0272: basePackage);
0273: parsePrepareElements(systemElement, definition, basePackage);
0274:
0275: // parse without package elements
0276: parseAspectElements(loader, systemElement, definition,
0277: basePackage, globalPointcuts);
0278:
0279: // parse without package elements
0280: parseMixinElements(loader, systemElement, definition,
0281: basePackage);
0282:
0283: // parse with package elements
0284: parsePackageElements(loader, systemElement, definition,
0285: basePackage, globalPointcuts);
0286:
0287: // add all deployment scopes to the virtual advice
0288: DefinitionParserHelper
0289: .attachDeploymentScopeDefsToVirtualAdvice(definition);
0290:
0291: return definition;
0292: }
0293:
0294: /**
0295: * Parses the global pointcuts.
0296: *
0297: * @param systemElement the system element
0298: * @return a list with the pointcuts
0299: */
0300: private static List parseGlobalPointcutDefs(Element systemElement) {
0301: List globalPointcuts = new ArrayList();
0302:
0303: NodeList childNodes = systemElement.getChildNodes();
0304: for (int i = 0; i < childNodes.getLength(); i++) {
0305: Node childNode = childNodes.item(i);
0306: if (childNode.getNodeName().equals("pointcut")) {
0307: Element pointcutElement = (Element) childNode;
0308: PointcutInfo pointcutInfo = new PointcutInfo(
0309: pointcutElement.getAttribute("name"), //
0310: pointcutElement.getAttribute("expression")
0311: .trim());
0312: // pointcut CDATA is expression unless already specified as an attribute
0313: if (pointcutInfo.expression == null
0314: || pointcutInfo.expression.trim().length() == 0) {
0315: pointcutInfo.expression = getText(pointcutElement)
0316: .trim().replace('\n', ' ');
0317: }
0318: globalPointcuts.add(pointcutInfo);
0319: }
0320: }
0321:
0322: return globalPointcuts;
0323: }
0324:
0325: /**
0326: * Parses the global deployment-scope elements.
0327: *
0328: * @param systemElement the system element
0329: * @param definition
0330: */
0331: private static void parseDeploymentScopeDefs(Element systemElement,
0332: SystemDefinition definition) {
0333: NodeList childNodes = systemElement.getChildNodes();
0334: for (int i = 0; i < childNodes.getLength(); i++) {
0335: Node childNode = childNodes.item(i);
0336: if (childNode.getNodeName().equals("deployment-scope")) {
0337: Element deploymentScopeElement = (Element) childNode;
0338: String name = deploymentScopeElement
0339: .getAttribute("name");
0340: String expression = deploymentScopeElement
0341: .getAttribute("expression");
0342: // pointcut CDATA is expression unless already specified as an attribute
0343: if (expression == null
0344: || expression.trim().length() == 0) {
0345: expression = getText(deploymentScopeElement).trim();
0346: }
0347: DefinitionParserHelper.createAndAddDeploymentScopeDef(
0348: name, expression, definition);
0349: }
0350: }
0351: }
0352:
0353: /**
0354: * Parses the global advisable elements.
0355: *
0356: * @param systemElement the system element
0357: * @param definition
0358: */
0359: private static void parseAdvisableDefs(Element systemElement,
0360: SystemDefinition definition) {
0361: NodeList childNodes = systemElement.getChildNodes();
0362: for (int i = 0; i < childNodes.getLength(); i++) {
0363: Node childNode = childNodes.item(i);
0364: if (childNode.getNodeName().equals("advisable")) {
0365: Element advisableElement = (Element) childNode;
0366: String pointcutTypes = advisableElement
0367: .getAttribute("pointcut-type");
0368: if (pointcutTypes == null
0369: || pointcutTypes.trim().length() == 0) {
0370: pointcutTypes = "all";
0371: }
0372: String expression = advisableElement
0373: .getAttribute("expression");
0374: // pointcut CDATA is expression unless already specified as an attribute
0375: if (expression == null
0376: || expression.trim().length() == 0) {
0377: expression = getText(advisableElement).trim();
0378: }
0379: handleAdvisableDefinition(definition, expression,
0380: pointcutTypes);
0381: }
0382: }
0383: }
0384:
0385: /**
0386: * Parses the definition DOM document.
0387: *
0388: * @param loader the current class loader
0389: * @param systemElement the system element
0390: * @param definition the definition
0391: * @param basePackage the base package
0392: * @param globalPointcuts the global pointcuts
0393: */
0394: private static void parsePackageElements(ClassLoader loader,
0395: Element systemElement, SystemDefinition definition,
0396: String basePackage, List globalPointcuts) {
0397: NodeList childNodes = systemElement.getChildNodes();
0398: for (int i = 0; i < childNodes.getLength(); i++) {
0399: Node childNode = childNodes.item(i);
0400: if (childNode.getNodeName().equals("package")) {
0401: Element packageElement = (Element) childNode;
0402: String packageName = basePackage
0403: + getPackage(packageElement);
0404: parseAspectElements(loader, packageElement, definition,
0405: packageName, globalPointcuts);
0406: parseMixinElements(loader, packageElement, definition,
0407: packageName);
0408: parseAdvisableDefs(packageElement, definition);
0409: }
0410: }
0411: }
0412:
0413: /**
0414: * Parses the <tt>aspect</tt> elements.
0415: *
0416: * @param loader the current class loader
0417: * @param systemElement the system element
0418: * @param definition the definition object
0419: * @param packageName the package name
0420: * @param globalPointcuts the global pointcuts
0421: */
0422: private static void parseAspectElements(ClassLoader loader,
0423: Element systemElement, SystemDefinition definition,
0424: String packageName, List globalPointcuts) {
0425: NodeList childNodes = systemElement.getChildNodes();
0426: for (int i = 0; i < childNodes.getLength(); i++) {
0427: Node childNode = childNodes.item(i);
0428: if (childNode.getNodeName().equals("aspect")) {
0429: Element aspectElement = (Element) childNode;
0430:
0431: String aspectName = aspectElement.getAttribute("name");
0432: String className = aspectElement.getAttribute("class");
0433: String deploymentModel = aspectElement
0434: .getAttribute("deployment-model");
0435: String containerClassName = aspectElement
0436: .getAttribute("container");
0437:
0438: // class is mandatory
0439: if (Strings.isNullOrEmpty(className)) {
0440: System.err
0441: .println("Warning: could not load aspect without 'class=..' attribute");
0442: new Exception().printStackTrace();
0443: continue;
0444: }
0445:
0446: String aspectClassName = packageName + className;
0447: if (aspectName == null
0448: || aspectName.trim().length() == 0) {
0449: aspectName = aspectClassName;
0450: }
0451:
0452: // create the aspect definition
0453: ClassInfo aspectClassInfo;
0454: try {
0455: aspectClassInfo = AsmClassInfo.getClassInfo(
0456: aspectClassName, loader);
0457: } catch (Exception e) {
0458: System.err
0459: .println("Warning: could not load aspect "
0460: + aspectClassName + " from "
0461: + loader + "; " + e.toString());
0462: e.printStackTrace();
0463: continue;
0464: }
0465:
0466: AspectDefinition aspectDef = new AspectDefinition(
0467: aspectName, aspectClassInfo, definition);
0468:
0469: // add the global pointcuts to the aspect
0470: for (Iterator it = globalPointcuts.iterator(); it
0471: .hasNext();) {
0472: PointcutInfo pointcutInfo = (PointcutInfo) it
0473: .next();
0474: DefinitionParserHelper
0475: .createAndAddPointcutDefToAspectDef(
0476: pointcutInfo.name,
0477: pointcutInfo.expression, aspectDef);
0478: }
0479: parsePointcutElements(aspectElement, aspectDef); //needed to support undefined named pointcut in Attributes AW-152
0480:
0481: // load the different aspect model and let them define their aspects
0482: AspectModelManager.defineAspect(aspectClassInfo,
0483: aspectDef, loader);
0484:
0485: // parse the class bytecode annotations
0486: AspectAnnotationParser.parse(aspectClassInfo,
0487: aspectDef, loader);
0488:
0489: // XML definition settings always overrides attribute definition settings AW-357
0490: if (!Strings.isNullOrEmpty(deploymentModel)) {
0491: aspectDef.setDeploymentModel(DeploymentModel
0492: .getDeploymentModelFor(deploymentModel));
0493: }
0494: if (!Strings.isNullOrEmpty(aspectName)) {
0495: aspectDef.setName(aspectName);
0496: }
0497: if (!Strings.isNullOrEmpty(containerClassName)) {
0498: aspectDef.setContainerClassName(containerClassName);
0499: }
0500:
0501: // parse the aspect info
0502: parseParameterElements(aspectElement, aspectDef);
0503: parsePointcutElements(aspectElement, aspectDef); // reparse pc for XML override (AW-152)
0504: parseAdviceElements(aspectElement, aspectDef,
0505: aspectClassInfo);
0506: parseIntroduceElements(aspectElement, aspectDef,
0507: packageName, loader);
0508:
0509: definition.addAspect(aspectDef);
0510: }
0511: }
0512: }
0513:
0514: /**
0515: * Parses the <tt>mixin</tt> elements.
0516: *
0517: * @param loader the current class loader
0518: * @param systemElement the system element
0519: * @param systemDefinition the system definition
0520: * @param packageName the package name
0521: */
0522: private static void parseMixinElements(ClassLoader loader,
0523: Element systemElement, SystemDefinition systemDefinition,
0524: String packageName) {
0525: NodeList childNodes = systemElement.getChildNodes();
0526: for (int i = 0; i < childNodes.getLength(); i++) {
0527: Node childNode = childNodes.item(i);
0528: if (childNode.getNodeName().equals("mixin")) {
0529: Element mixinElement = (Element) childNode;
0530:
0531: String className = mixinElement.getAttribute("class");
0532: String deploymentModelAsString = mixinElement
0533: .getAttribute("deployment-model");
0534: boolean isTransient = false;
0535: boolean isTransientSetInXML = false;
0536: String transientValue = mixinElement
0537: .getAttribute("transient");
0538: if (transientValue != null) {
0539: isTransient = transientValue
0540: .equalsIgnoreCase("true");
0541: isTransientSetInXML = true;
0542: }
0543:
0544: String factoryClassName = mixinElement
0545: .getAttribute("factory");
0546: String expression = mixinElement
0547: .getAttribute("bind-to");
0548:
0549: String mixinClassName = packageName + className;
0550:
0551: // create the mixin definition
0552: ClassInfo mixinClassInfo;
0553: try {
0554: mixinClassInfo = AsmClassInfo.getClassInfo(
0555: mixinClassName, loader);
0556: } catch (Exception e) {
0557: System.err.println("Warning: could not load mixin "
0558: + mixinClassName + " from " + loader + "; "
0559: + e.toString());
0560: e.printStackTrace();
0561: continue;
0562: }
0563:
0564: DeploymentModel deploymentModel = deploymentModelAsString == null
0565: || deploymentModelAsString.trim().length() == 0 ? DeploymentModel.PER_INSTANCE
0566: : DeploymentModel
0567: .getDeploymentModelFor(deploymentModelAsString);
0568:
0569: MixinDefinition mixinDefinition = DefinitionParserHelper
0570: .createAndAddMixinDefToSystemDef(
0571: mixinClassInfo, expression,
0572: deploymentModel, isTransient,
0573: systemDefinition);
0574:
0575: // parse the class bytecode annotations
0576: MixinAnnotationParser.parse(mixinClassInfo,
0577: mixinDefinition);
0578:
0579: // XML definition settings always overrides attribute definition settings if present
0580: if (!Strings.isNullOrEmpty(deploymentModelAsString)) {
0581: mixinDefinition
0582: .setDeploymentModel(DeploymentModel
0583: .getDeploymentModelFor(deploymentModelAsString));
0584: }
0585: if (!Strings.isNullOrEmpty(factoryClassName)) {
0586: mixinDefinition
0587: .setFactoryClassName(factoryClassName);
0588: }
0589: if (isTransientSetInXML) {
0590: mixinDefinition.setTransient(isTransient);
0591: }
0592:
0593: parseParameterElements(mixinElement, mixinDefinition);
0594: }
0595: }
0596: }
0597:
0598: /**
0599: * Adds a virtual system aspect to the definition. Needed to do various tricks.
0600: *
0601: * @param definition
0602: */
0603: public static void addVirtualAspect(SystemDefinition definition) {
0604: Class clazz = Virtual.class;
0605: String aspectName = clazz.getName();
0606: ClassInfo aspectClassInfo = JavaClassInfo.getClassInfo(clazz);
0607: AspectDefinition aspectDef = new AspectDefinition(aspectName,
0608: aspectClassInfo, definition);
0609: try {
0610: MethodInfo methodInfo = JavaMethodInfo.getMethodInfo(clazz
0611: .getDeclaredMethod("virtual", new Class[] {}));
0612: aspectDef
0613: .addBeforeAdviceDefinition(new AdviceDefinition(
0614: methodInfo.getName(), AdviceType.BEFORE,
0615: null, aspectName, aspectName, null,
0616: methodInfo, aspectDef));
0617: } catch (NoSuchMethodException e) {
0618: throw new Error("virtual aspect [" + aspectName
0619: + "] does not have expected method: "
0620: + e.toString());
0621: }
0622: definition.addAspect(aspectDef);
0623: }
0624:
0625: /**
0626: * Parses the aspectElement parameters.
0627: *
0628: * @param aspectElement the aspect element
0629: * @param aspectDef the aspect def
0630: */
0631: private static void parseParameterElements(Element aspectElement,
0632: AspectDefinition aspectDef) {
0633: NodeList childNodes = aspectElement.getChildNodes();
0634: for (int i = 0; i < childNodes.getLength(); i++) {
0635: Node childNode = childNodes.item(i);
0636: if (childNode.getNodeName().equals("param")) {
0637: Element paramElement = (Element) childNode;
0638: aspectDef.addParameter(paramElement
0639: .getAttribute("name"), paramElement
0640: .getAttribute("value"));
0641: }
0642: }
0643: }
0644:
0645: /**
0646: * Parses the mixinElement parameters.
0647: *
0648: * @param mixinElement the mixin element
0649: * @param mixinDef the mixin def
0650: */
0651: private static void parseParameterElements(Element mixinElement,
0652: MixinDefinition mixinDef) {
0653: NodeList childNodes = mixinElement.getChildNodes();
0654: for (int i = 0; i < childNodes.getLength(); i++) {
0655: Node childNode = childNodes.item(i);
0656: if (childNode.getNodeName().equals("param")) {
0657: Element paramElement = (Element) childNode;
0658: mixinDef.addParameter(
0659: paramElement.getAttribute("name"), paramElement
0660: .getAttribute("value"));
0661: }
0662: }
0663: }
0664:
0665: /**
0666: * Parses the pointcuts.
0667: *
0668: * @param aspectElement the aspect element
0669: * @param aspectDef the system definition
0670: */
0671: private static void parsePointcutElements(Element aspectElement,
0672: AspectDefinition aspectDef) {
0673: NodeList aspectNodes = aspectElement.getChildNodes();
0674: for (int i = 0; i < aspectNodes.getLength(); i++) {
0675: Node childNode = aspectNodes.item(i);
0676: if (childNode.getNodeType() != Node.ELEMENT_NODE) {
0677: continue;
0678: }
0679: Element childElement = (Element) childNode;
0680: if (childElement.getNodeName().equals("pointcut")) {
0681: String name = childElement.getAttribute("name");
0682: String expression = childElement
0683: .getAttribute("expression");
0684: // pointcut CDATA is expression unless already specified as an attribute
0685: if (expression == null
0686: || expression.trim().length() == 0) {
0687: expression = getText(childElement).trim();
0688: }
0689: DefinitionParserHelper
0690: .createAndAddPointcutDefToAspectDef(name,
0691: expression, aspectDef);
0692: } else if (childElement.getNodeName().equals(
0693: "deployment-scope")) {
0694: String name = childElement.getAttribute("name");
0695: String expression = childElement
0696: .getAttribute("expression");
0697: // pointcut CDATA is expression unless already specified as an attribute
0698: if (expression == null) {
0699: expression = getText(childElement).trim();
0700: }
0701: DefinitionParserHelper.createAndAddDeploymentScopeDef(
0702: name, expression, aspectDef
0703: .getSystemDefinition());
0704: } else if (childElement.getNodeName().equals("advisable")) {
0705: String expression = childElement
0706: .getAttribute("expression");
0707: String pointcutTypes = childElement
0708: .getAttribute("pointcut-type");
0709: if (expression == null
0710: || expression.trim().length() == 0) {
0711: expression = getText(childElement).trim();
0712: }
0713: handleAdvisableDefinition(aspectDef
0714: .getSystemDefinition(), expression,
0715: pointcutTypes);
0716: }
0717: }
0718: }
0719:
0720: public static String getText(Element element) {
0721: NodeList childNodes = element.getChildNodes();
0722: for (int i = 0; i < childNodes.getLength(); i++) {
0723: Node childNode = childNodes.item(i);
0724: if (childNode.getNodeType() == Node.TEXT_NODE) {
0725: return ((Text) childNode).getData();
0726: }
0727: }
0728: return "";
0729: }
0730:
0731: /**
0732: * Parses the advices.
0733: *
0734: * @param aspectElement the aspect element
0735: * @param aspectDef the system definition
0736: * @param aspectClassInfo the aspect class
0737: */
0738: private static void parseAdviceElements(Element aspectElement,
0739: AspectDefinition aspectDef, ClassInfo aspectClassInfo) {
0740: NodeList childNodes = aspectElement.getChildNodes();
0741: for (int i = 0; i < childNodes.getLength(); i++) {
0742: Node childNode = childNodes.item(i);
0743: if (childNode.getNodeName().equals("advice")) {
0744: Element adviceElement = (Element) childNode;
0745:
0746: String name = adviceElement.getAttribute("name");
0747: String type = adviceElement.getAttribute("type");
0748: String bindTo = adviceElement.getAttribute("bind-to");
0749:
0750: MethodInfo method = DefinitionParserHelper
0751: .createMethodInfoForAdviceFQN(name, aspectDef,
0752: aspectClassInfo);
0753: DefinitionParserHelper
0754: .createAndAddAdviceDefsToAspectDef(type,
0755: bindTo, name, method, aspectDef);
0756:
0757: NodeList bindNodes = adviceElement.getChildNodes();
0758: for (int j = 0; j < bindNodes.getLength(); j++) {
0759: Node bindToNode = bindNodes.item(j);
0760: if (bindToNode.getNodeName().equals("bind-to")) {
0761: Element bindToElement = (Element) bindToNode;
0762: String pointcut = bindToElement
0763: .getAttribute("pointcut");
0764: DefinitionParserHelper
0765: .createAndAddAdviceDefsToAspectDef(
0766: type, pointcut, name, method,
0767: aspectDef);
0768: }
0769: }
0770: }
0771: }
0772: }
0773:
0774: /**
0775: * Parses the interface introductions.
0776: *
0777: * @param aspectElement the aspect element
0778: * @param aspectDef the system definition
0779: * @param packageName
0780: * @param loader
0781: */
0782: private static void parseIntroduceElements(Element aspectElement,
0783: AspectDefinition aspectDef, String packageName,
0784: ClassLoader loader) {
0785: NodeList childNodes = aspectElement.getChildNodes();
0786: for (int i = 0; i < childNodes.getLength(); i++) {
0787: Node childNode = childNodes.item(i);
0788: if (childNode.getNodeName().equals("introduce")) {
0789: Element introduceElement = (Element) childNode;
0790:
0791: String klass = introduceElement.getAttribute("class");
0792: String name = introduceElement.getAttribute("name");
0793: String bindTo = introduceElement
0794: .getAttribute("bind-to");
0795:
0796: // default name = FQN
0797: String fullClassName = packageName + klass;
0798: if (name == null || name.length() == 0) {
0799: name = fullClassName;
0800: }
0801:
0802: // load the class info to determine if it is a pure interface introduction
0803: ClassInfo introductionClassInfo;
0804: try {
0805: introductionClassInfo = AsmClassInfo.getClassInfo(
0806: fullClassName, loader);
0807: } catch (Exception e) {
0808: throw new DefinitionException(
0809: "could not find interface introduction: "
0810: + packageName + klass + "; "
0811: + e.getMessage());
0812: }
0813:
0814: // pure interface introduction
0815: if (introductionClassInfo.isInterface()) {
0816: DefinitionParserHelper
0817: .createAndAddInterfaceIntroductionDefToAspectDef(
0818: bindTo, name, fullClassName,
0819: aspectDef);
0820:
0821: // handles nested "bind-to" elements
0822: NodeList bindToNodes = introduceElement
0823: .getChildNodes();
0824: for (int j = 0; j < bindToNodes.getLength(); j++) {
0825: Node bindToNode = bindToNodes.item(j);
0826: if (bindToNode.getNodeName().equals("bindTo")) {
0827: Element bindToElement = (Element) bindToNode;
0828: String pointcut = bindToElement
0829: .getAttribute("pointcut");
0830: DefinitionParserHelper
0831: .createAndAddInterfaceIntroductionDefToAspectDef(
0832: pointcut, name,
0833: fullClassName, aspectDef);
0834: }
0835: }
0836: }
0837: }
0838: }
0839: }
0840:
0841: /**
0842: * Retrieves and returns the package.
0843: *
0844: * @param packageElement the package element
0845: * @return the package as a string ending with DOT, or empty string
0846: */
0847: private static String getPackage(Element packageElement) {
0848: String packageName = packageElement.getAttribute("name");
0849: if (packageName != null) {
0850: if (packageName.endsWith(".*")) {
0851: return packageName.substring(0,
0852: packageName.length() - 1);
0853: } else if (!packageName.endsWith(".")) {
0854: return packageName + ".";
0855: }
0856: }
0857: return "";
0858: }
0859:
0860: /**
0861: * Parses the <tt>include</tt> elements.
0862: *
0863: * @param root the root element
0864: * @param definition the definition object
0865: * @param packageName the package name
0866: */
0867: private static void parseIncludePackageElements(Element root,
0868: SystemDefinition definition, String packageName) {
0869: NodeList childNodes = root.getChildNodes();
0870: for (int i = 0; i < childNodes.getLength(); i++) {
0871: Node includeNode = childNodes.item(i);
0872: if (includeNode.getNodeName().equals("include")) {
0873: Element includeElement = (Element) includeNode;
0874: String packageValue = includeElement
0875: .getAttribute("package");
0876:
0877: String includePackage = "";
0878: // handle base package
0879: if (packageName.endsWith(".*")) {
0880: includePackage = packageName.substring(0,
0881: packageName.length() - 2);
0882: } else if (packageName.endsWith(".")) {
0883: includePackage = packageName.substring(0,
0884: packageName.length() - 1);
0885: }
0886:
0887: // handle exclude package
0888: includePackage = packageName + packageValue.trim();
0889: if (includePackage.endsWith(".*")) {
0890: includePackage = includePackage.substring(0,
0891: includePackage.length() - 2);
0892: } else if (includePackage.endsWith(".")) {
0893: includePackage = includePackage.substring(0,
0894: includePackage.length() - 1);
0895: }
0896: if (includePackage.length() != 0) {
0897: definition.addIncludePackage(includePackage);
0898: }
0899: }
0900: }
0901: }
0902:
0903: /**
0904: * Parses the <tt>exclude</tt> elements.
0905: *
0906: * @param root the root element
0907: * @param definition the definition object
0908: * @param packageName the package name
0909: */
0910: private static void parseExcludePackageElements(Element root,
0911: SystemDefinition definition, String packageName) {
0912: NodeList childNodes = root.getChildNodes();
0913: for (int i = 0; i < childNodes.getLength(); i++) {
0914: Node childNode = childNodes.item(i);
0915: if (childNode.getNodeName().equals("exclude")) {
0916: Element excludeElement = (Element) childNode;
0917:
0918: String excludeValue = excludeElement
0919: .getAttribute("package");
0920:
0921: String excludePackage = "";
0922: // handle base package
0923: if (packageName.endsWith(".*")) {
0924: excludePackage = packageName.substring(0,
0925: packageName.length() - 2);
0926: } else if (packageName.endsWith(".")) {
0927: excludePackage = packageName.substring(0,
0928: packageName.length() - 1);
0929: }
0930:
0931: // handle exclude package
0932: excludePackage = packageName + excludeValue.trim();
0933: if (excludePackage.endsWith(".*")) {
0934: excludePackage = excludePackage.substring(0,
0935: excludePackage.length() - 2);
0936: } else if (excludePackage.endsWith(".")) {
0937: excludePackage = excludePackage.substring(0,
0938: excludePackage.length() - 1);
0939: }
0940: if (excludePackage.length() != 0) {
0941: definition.addExcludePackage(excludePackage);
0942: }
0943: }
0944: }
0945: }
0946:
0947: /**
0948: * Parses the <tt>prepare</tt> elements.
0949: *
0950: * @param root the root element
0951: * @param definition the definition object
0952: * @param packageName the base package name
0953: */
0954: private static void parsePrepareElements(Element root,
0955: SystemDefinition definition, String packageName) {
0956: NodeList childNodes = root.getChildNodes();
0957: for (int i = 0; i < childNodes.getLength(); i++) {
0958: Node childNode = childNodes.item(i);
0959: if (childNode.getNodeName().equals("prepare")) {
0960: Element prepareElement = (Element) childNode;
0961: String packageValue = prepareElement
0962: .getAttribute("package");
0963:
0964: String preparePackage = "";
0965:
0966: // handle base package
0967: if (packageName.endsWith(".*")) {
0968: preparePackage = packageName.substring(0,
0969: packageName.length() - 2);
0970: } else if (packageName.endsWith(".")) {
0971: preparePackage = packageName.substring(0,
0972: packageName.length() - 1);
0973: }
0974:
0975: // handle prepare package
0976: preparePackage = packageName + packageValue.trim();
0977: if (preparePackage.endsWith(".*")) {
0978: preparePackage = preparePackage.substring(0,
0979: preparePackage.length() - 2);
0980: } else if (preparePackage.endsWith(".")) {
0981: preparePackage = preparePackage.substring(0,
0982: preparePackage.length() - 1);
0983: }
0984: if (preparePackage.length() != 0) {
0985: definition.addPreparePackage(preparePackage);
0986: }
0987: }
0988: }
0989: }
0990:
0991: /**
0992: * Retrieves and returns the base package for a system element
0993: *
0994: * @param system a system element
0995: * @return the base package
0996: */
0997: private static String getBasePackage(Element system) {
0998: String basePackage = "";
0999: NamedNodeMap attrs = system.getAttributes();
1000: for (int i = 0; i < attrs.getLength(); i++) {
1001: Node item = attrs.item(i);
1002: if (item.getNodeName().equalsIgnoreCase("base-package")) {
1003: basePackage = ((Attr) item).getValue().trim();
1004: if (basePackage.endsWith(".*")) {
1005: basePackage = basePackage.substring(0, basePackage
1006: .length() - 1);
1007: } else if (!basePackage.endsWith(".")) {
1008: basePackage += ".";
1009: }
1010: break;
1011: }
1012: }
1013:
1014: /*
1015: for (Iterator it2 = system.attributeIterator(); it2.hasNext();) {
1016: Attribute attribute = (Attribute) it2.next();
1017: if (attribute.getName().trim().equalsIgnoreCase("base-package")) {
1018: basePackage = attribute.getValue().trim();
1019: if (basePackage.endsWith(".*")) {
1020: basePackage = basePackage.substring(0, basePackage.length() - 1);
1021: } else if (basePackage.endsWith(".")) {
1022: // skip
1023: } else {
1024: basePackage += ".";
1025: }
1026: break;
1027: } else {
1028: continue;
1029: }
1030: }
1031: */
1032: return basePackage;
1033: }
1034:
1035: /**
1036: * Struct with pointcut info.
1037: */
1038: private static class PointcutInfo {
1039: public String name;
1040: public String expression;
1041:
1042: public PointcutInfo(String name, String expression) {
1043: this .name = name;
1044: this .expression = expression;
1045: }
1046: }
1047:
1048: /**
1049: * Handles the advisable definition.
1050: *
1051: * @param definition
1052: * @param withinPointcut
1053: * @param pointcutTypes
1054: */
1055: private static void handleAdvisableDefinition(
1056: SystemDefinition definition, String withinPointcut,
1057: String pointcutTypes) {
1058: // add the Advisable Mixin with the expression defined to the system definitions
1059: definition.addMixinDefinition(DefinitionParserHelper
1060: .createAndAddMixinDefToSystemDef(
1061: AdvisableImpl.CLASS_INFO, withinPointcut,
1062: DeploymentModel.PER_INSTANCE, false, // advisble mixin is NOT transient
1063: definition));
1064:
1065: boolean hasAllPointcuts = false;
1066: boolean hasExecutionPointcut = false;
1067: boolean hasCallPointcut = false;
1068: boolean hasSetPointcut = false;
1069: boolean hasGetPointcut = false;
1070: boolean hasHandlerPointcut = false;
1071: if (pointcutTypes == null || pointcutTypes.equals("")
1072: || pointcutTypes.equalsIgnoreCase("all")) {
1073: hasAllPointcuts = true;
1074: } else {
1075: StringTokenizer tokenizer = new StringTokenizer(
1076: pointcutTypes, "|");
1077: while (tokenizer.hasMoreTokens()) {
1078: String token = tokenizer.nextToken();
1079: if (token.trim().equalsIgnoreCase("all")) {
1080: hasAllPointcuts = true;
1081: break;
1082: } else if (token.trim().equalsIgnoreCase("execution")) {
1083: hasExecutionPointcut = true;
1084: } else if (token.trim().equalsIgnoreCase("call")) {
1085: hasCallPointcut = true;
1086: } else if (token.trim().equalsIgnoreCase("set")) {
1087: hasSetPointcut = true;
1088: } else if (token.trim().equalsIgnoreCase("getDefault")) {
1089: hasGetPointcut = true;
1090: } else if (token.trim().equalsIgnoreCase("handler")) {
1091: hasHandlerPointcut = true;
1092: }
1093: }
1094: }
1095: if (hasAllPointcuts || hasExecutionPointcut) {
1096: DefinitionParserHelper.createAndAddAdvisableDef(
1097: // TODO add ctor to expression - BUT: problem with mixin and ctor, ordering issue, Jp.invoke() calls field instance that has not been init yet in ctor (since body not invoked)
1098: //"(( execution(!static * *.*(..)) || execution(*.new(..)) ) && " + withinPointcut + ')',
1099: // we exclude static method execution since we need the advisable instance
1100: "(execution(!static * *.*(..)) && "
1101: + withinPointcut + ')', definition);
1102: }
1103: if (hasAllPointcuts || hasCallPointcut) {
1104: DefinitionParserHelper.createAndAddAdvisableDef(
1105: // TODO add ctor to expression - BUT: problem with mixin and ctor, ordering issue, Jp.invoke() calls field instance that has not been init yet in ctor (since body not invoked) //"(call(!static * " + typePattern + ".*(..)) || call(" + typePattern + ".new(..)))",
1106: // we exclude static method withincode since we need the advisable instance
1107: // as a consequence, withincode(staticinitialization(..)) is also excluded
1108: "(call(* *.*(..)) && withincode(!static * *.*(..)) && "
1109: + withinPointcut + ')', definition);
1110: }
1111: if (hasAllPointcuts || hasSetPointcut) {
1112: DefinitionParserHelper.createAndAddAdvisableDef(
1113: // we exclude static method withincode since we need the advisable instance
1114: // as a consequence, withincode(staticinitialization(..)) is also excluded
1115: "(set(* *.*) && withincode(!static * *.*(..)) && "
1116: + withinPointcut + ')', definition);
1117: }
1118: if (hasAllPointcuts || hasGetPointcut) {
1119: DefinitionParserHelper.createAndAddAdvisableDef(
1120: // we exclude static method withincode since we need the advisable instance
1121: // as a consequence, withincode(staticinitialization(..)) is also excluded
1122: "(getDefault(* *.*) && withincode(!static * *.*(..)) && "
1123: + withinPointcut + ')', definition);
1124: }
1125: if (hasAllPointcuts || hasHandlerPointcut) {
1126: DefinitionParserHelper.createAndAddAdvisableDef(
1127: // we exclude static method withincode since we need the advisable instance
1128: // as a consequence, withincode(staticinitialization(..)) is also excluded
1129: "(handler(*..*) && withincode(!static * *.*(..)) && "
1130: + withinPointcut + ')', definition);
1131: }
1132: }
1133: }
|