Package org.codehaus.aspectwerkz.metadata

Source Code of org.codehaus.aspectwerkz.metadata.AttributeC

/**************************************************************************************
* Copyright (c) The AspectWerkz Team. All rights reserved.                           *
* http://aspectwerkz.codehaus.org                                                    *
* ---------------------------------------------------------------------------------- *
* The software in this package is published under the terms of the BSD style license *
* a copy of which has been included with this distribution in the license.txt file.  *
**************************************************************************************/
package org.codehaus.aspectwerkz.metadata;

import java.util.Iterator;
import java.util.Map;
import java.util.List;
import java.io.FileWriter;
import java.io.IOException;
import java.io.File;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.DocumentHelper;
import org.dom4j.io.XMLWriter;
import org.dom4j.io.OutputFormat;

import com.thoughtworks.qdox.model.JavaMethod;
import com.thoughtworks.qdox.model.JavaParameter;
import com.thoughtworks.qdox.model.JavaField;
import com.thoughtworks.qdox.model.DocletTag;
import com.thoughtworks.qdox.model.JavaClass;

import org.codehaus.aspectwerkz.definition.AspectWerkzDefinition;
import org.codehaus.aspectwerkz.definition.PointcutDefinition;
import org.codehaus.aspectwerkz.definition.AdviceDefinition;
import org.codehaus.aspectwerkz.definition.IntroductionDefinition;
import org.codehaus.aspectwerkz.definition.AttributeTag;
import org.codehaus.aspectwerkz.definition.AspectDefinition;
import org.codehaus.aspectwerkz.definition.IntroductionWeavingRule;
import org.codehaus.aspectwerkz.definition.AdviceWeavingRule;
import org.codehaus.aspectwerkz.definition.ControllerDefinition;
import org.codehaus.aspectwerkz.definition.DefinitionValidator;
import org.codehaus.aspectwerkz.exception.DefinitionException;
import org.codehaus.aspectwerkz.exception.WrappedRuntimeException;
import org.codehaus.aspectwerkz.advice.CFlowPreAdvice;
import org.codehaus.aspectwerkz.advice.CFlowPostAdvice;
import org.codehaus.aspectwerkz.util.UuidGenerator;
import org.codehaus.aspectwerkz.util.Strings;

/**
* Parses a given source tree and compiles "runtime attributes" (set as JavaDoc tags throughout
* the code) into an XML definition.
* <p/>
* Can be called from the command line.
* <p/>
* Validation is turned off by default. To turn it on feed the JVM with:
* <code>-Daspectwerkz.definition.validate=true</code>
*
* @author <a href="mailto:jboner@codehaus.org">Jonas Bon�r</a>
*/
public class AttributeC {

    public static final String METHOD_POINTCUT_NAME = "__aw_method_pointcut_";
    public static final String SETFIELD_POINTCUT_NAME = "__aw_setfield_pointcut_";
    public static final String GETFIELD_POINTCUT_NAME = "__aw_getfield_pointcut_";
    public static final String THROWS_POINTCUT_NAME = "__aw_throws_pointcut_";
    public static final String CALLERSIDE_POINTCUT_NAME = "__aw_callerside_pointcut_";
    public static final String CFLOW_POINTCUT_NAME = "__aw_cflow_pointcut_";
    public static final String CONTROLLER_POINTCUT_NAME = "__aw_controller_pointcut_";

    /**
     * Parses a given source tree, retrieves the runtime attributes defined in the code
     * and creates an XML definition based on these attributes.
     *
     * @param sourcePath the path to the sources to compile attributes for
     * @param fileName the full name of the file name to compile the attributes to
     */
    public static void compile(final String sourcePath, final String fileName) {
        compile(sourcePath, fileName, null, null);
    }

    /**
     * Parses a given source tree, retrieves the runtime attributes defined in the code
     * and creates an XML definition based on these attributes.
     *
     * @param sourcePath the path to the sources to compile attributes for
     * @param fileName the full name of the file to compile the attributes to
     * @param definitionFileToMerge the full name of the file to merge the compiled definition with
     * @param uuid the UUID for the definition
     */
    public static void compile(final String sourcePath,
                               final String fileName,
                               final String definitionFileToMerge,
                               String uuid) {
        if (sourcePath == null) throw new IllegalArgumentException("source path can not be null");
        if (fileName == null) throw new IllegalArgumentException("file name can not be null");

        AspectWerkzDefinition definition = getDefinition(definitionFileToMerge);

        parseRuntimeAttributes(definition, sourcePath);

        validate(definition);

        if (uuid == null) {
            uuid = UuidGenerator.generate(definition);
        }

        Document document = createDocument(definition, uuid);
        writeDocumentToFile(document, fileName);
    }

    /**
     * Parses the attributes and creates definitions for the matching attributes.
     *
     * @param definition the definition
     * @param sourcePath the path to the source dir
     */
    public static void parseRuntimeAttributes(final AspectWerkzDefinition definition,
                                              final String sourcePath) {

        QDoxParser qdoxParser = new QDoxParser(sourcePath);
        String[] allClasses = qdoxParser.getAllClassesNames();

        // add the cflow advice to the system
        definition.addAdvice(CFlowPreAdvice.getDefinition());

        // handle the definition attributes
        for (int i = 0; i < allClasses.length; i++) {
            String className = allClasses[i];
            if (!qdoxParser.parse(className)) {
                continue;
            }
            weaveIntroductionDefinitionAttributes(qdoxParser, definition);
            weaveAdviceDefinitionAttributes(qdoxParser, definition);
        }

        // handle the definition references
        for (int i = 0; i < allClasses.length; i++) {
            String className = allClasses[i];
            if (!qdoxParser.parse(className)) {
                continue;
            }
            parseCFlowPointcutAttributes(definition, className, qdoxParser);
            parseIntroductionAttributes(definition, className, qdoxParser);
            parseJoinPointControllerAttributes(definition, className, qdoxParser);
            parseMethodPointcutAttributes(definition, className, qdoxParser);
            parseSetFieldPointcutAttributes(definition, className, qdoxParser);
            parseGetFieldPointcutAttributes(definition, className, qdoxParser);
            parseThrowsPointcutAttributes(definition, className, qdoxParser);
            parseCallerSidePointcutAttributes(definition, className, qdoxParser);
        }
    }

    /**
     * Creates a DOM documents out of the definition.
     *
     * @param definition the AspectWerkz definition
     * @param uuid the UUID for the definition
     * @return the DOM document
     */
    public static Document createDocument(final AspectWerkzDefinition definition,
                                          final String uuid) {
        if (definition == null) throw new IllegalArgumentException("definition can not be null");

        Document document = DocumentHelper.createDocument();

        Element root = document.addElement("aspectwerkz");
        root.addAttribute("id", uuid);

        handleIntroductionDefinitions(root, definition);
        handleAdviceDefinitions(root, definition);
        handleAspectDefinitions(root, definition);

        return document;
    }

    /**
     * Writes a DOM document to file.
     *
     * @param document the document
     * @param fileName the name of the file (full path)
     */
    public static void writeDocumentToFile(final Document document, final String fileName) {
        try {
            // write the document to file
            OutputFormat format = OutputFormat.createPrettyPrint();
            XMLWriter writer = new XMLWriter(new FileWriter(fileName), format);
            writer.write(document);
            writer.close();

            // print the document to System.out
//            writer = new XMLWriter(System.out, format);
//            writer.write(document);
        }
        catch (IOException e) {
            throw new WrappedRuntimeException(e);
        }
    }

    /**
     * Handles the introduction definitions.
     *
     * @param root the document root
     * @param definition the AspectWerkz definition
     */
    private static void handleIntroductionDefinitions(final Element root,
                                                      final AspectWerkzDefinition definition) {
        for (Iterator it = definition.getIntroductionDefinitions().iterator(); it.hasNext();) {
            IntroductionDefinition def = (IntroductionDefinition)it.next();
            addIntroductionDefElement(root, def);
        }
    }

    /**
     * Returns the definition.
     * If append is set to true then it loads the definition file from disk otherwise
     * it just creates a new blank one.
     *
     * @param fileName the name of the definition file
     * @param append the append flag
     * @return the aspectwerkz definition
     */
    private static AspectWerkzDefinition getDefinition(final String fileName) {
        AspectWerkzDefinition definition;
        if (fileName != null) {
            File definitionFile = new File(fileName);
            if (definitionFile.exists()) {
                definition = AspectWerkzDefinition.loadDefinitionAsFile(fileName);
            }
            else {
                definition = new AspectWerkzDefinition();
            }
        }
        else {
            definition = new AspectWerkzDefinition();
        }
        return definition;
    }

    /**
     * Handles the advice definitions.
     *
     * @param root the document root
     * @param definition the AspectWerkz definition
     */
    private static void handleAdviceDefinitions(final Element root,
                                                final AspectWerkzDefinition definition) {
        // create the cflow pre and post advice definitions
        addAdviceDefElement(root, CFlowPreAdvice.getDefinition());
        addAdviceDefElement(root, CFlowPostAdvice.getDefinition());

        for (Iterator it = definition.getAdviceDefinitions().iterator(); it.hasNext();) {
            AdviceDefinition def = (AdviceDefinition)it.next();
            addAdviceDefElement(root, def);
        }
    }

    /**
     * Handles the introduction definition element.
     *
     * @param root the document root
     * @param introDef the introduction definition
     */
    private static Element addIntroductionDefElement(final Element root,
                                                     final IntroductionDefinition introDef) {
        if (root == null) throw new IllegalArgumentException("root element can not be null");
        if (introDef == null) throw new IllegalArgumentException("introduction definition can not be null");
        Element introDefElement = root.addElement("introduction-def");
        introDefElement.addAttribute("name", introDef.getName());
        introDefElement.addAttribute("interface", introDef.getInterface());
        String implementation = introDef.getImplementation();
        if (implementation != null) {
            introDefElement.addAttribute("implementation", implementation);
        }
        String deploymentModel = introDef.getDeploymentModel();
        if (deploymentModel != null && deploymentModel.length() != 0) {
            introDefElement.addAttribute("deployment-model", deploymentModel);
        }
        else {
            introDefElement.addAttribute("deployment-model", "perJVM");
        }
        String attribute = introDef.getAttribute();
        if (attribute != null && attribute.length() != 0) {
            introDefElement.addAttribute("attribute", attribute);
        }
        return introDefElement;
    }

    /**
     * Handles the advice definition element.
     *
     * @param root the document root
     * @param adviceDef the advice definition
     */
    private static Element addAdviceDefElement(final Element root,
                                               final AdviceDefinition adviceDef) {
        if (root == null) throw new IllegalArgumentException("root element can not be null");
        if (adviceDef == null) throw new IllegalArgumentException("advice definition can not be null");
        Element adviceDefElement = root.addElement("advice-def");
        adviceDefElement.addAttribute("name", adviceDef.getName());
        adviceDefElement.addAttribute("class", adviceDef.getAdviceClassName());
        String deploymentModel = adviceDef.getDeploymentModel();
        if (deploymentModel != null && deploymentModel.length() != 0) {
            adviceDefElement.addAttribute("deployment-model", deploymentModel);
        }
        else {
            adviceDefElement.addAttribute("deployment-model", "perJVM");
        }
        String attribute = adviceDef.getAttribute();
        if (attribute != null && attribute.length() != 0) {
            adviceDefElement.addAttribute("attribute", attribute);
        }

        addAdviceParamElements(adviceDefElement, adviceDef);

        return adviceDefElement;
    }

    /**
     * Handles the advice parameter elements.
     *
     * @param root the document root
     * @param adviceDef the advice definition
     */
    private static void addAdviceParamElements(final Element adviceElement,
                                               final AdviceDefinition adviceDef) {
        if (adviceElement == null) throw new IllegalArgumentException("advice element can not be null");
        if (adviceDef == null) throw new IllegalArgumentException("advice definition can not be null");
        for (Iterator it = adviceDef.getParameters().entrySet().iterator(); it.hasNext();) {
            Map.Entry entry = (Map.Entry)it.next();

            Element adviceParamElement = adviceElement.addElement("param");
            adviceParamElement.addAttribute("name", (String)entry.getKey());
            adviceParamElement.addAttribute("value", (String)entry.getValue());
        }
    }

    /**
     * Handles the aspect defintions.
     *
     * @param root the document root
     * @param definition the AspectWerkz definition
     */
    private static void handleAspectDefinitions(final Element root,
                                                final AspectWerkzDefinition definition) {
        for (Iterator it = definition.getAspectDefinitions().iterator(); it.hasNext();) {
            AspectDefinition aspectDef = (AspectDefinition)it.next();

            Element aspectElement = root.addElement("aspect");
            aspectElement.addAttribute("name", aspectDef.getName());

            handlePointcutDefinitions(aspectElement, aspectDef);
            handleControllerDefinitions(aspectElement, aspectDef);
            handleIntroductionWeavingRules(aspectElement, aspectDef);
            handleAdviceWeavingRules(aspectElement, aspectDef);
        }
    }

    /**
     * Handles the pointcut defintions.
     *
     * @param aspectElement the aspect element
     * @param aspectDef the aspect definition
     */
    private static void handlePointcutDefinitions(final Element aspectElement,
                                                  final AspectDefinition aspectDef) {
        for (Iterator it2 = aspectDef.getPointcutDefs().iterator(); it2.hasNext();) {
            PointcutDefinition pointcutDef = (PointcutDefinition)it2.next();

            Element pointcutDefElement = aspectElement.addElement("pointcut-def");
            pointcutDefElement.addAttribute("name", pointcutDef.getName());
            pointcutDefElement.addAttribute("type", pointcutDef.getType());
            pointcutDefElement.addAttribute("non-reentrant", pointcutDef.getNonReentrant());

            StringBuffer fullPattern = new StringBuffer();
            String type = pointcutDef.getType();
            if (type.equalsIgnoreCase(PointcutDefinition.METHOD) ||
                    type.equalsIgnoreCase(PointcutDefinition.GET_FIELD) ||
                    type.equalsIgnoreCase(PointcutDefinition.SET_FIELD)) {
                String classPattern = pointcutDef.getClassPattern();
                String pattern = pointcutDef.getPattern();
                int space = pattern.indexOf(' ');
                String returnType = pattern.substring(0, space + 1);
                String methodName = pattern.substring(space + 1);
                fullPattern.append(returnType);
                fullPattern.append(classPattern);
                fullPattern.append('.');
                fullPattern.append(methodName);
            }
            else if (type.equalsIgnoreCase(PointcutDefinition.THROWS)) {
                String classPattern = pointcutDef.getClassPattern();
                String pattern = pointcutDef.getPattern();
                int delimiter = pattern.indexOf('#');
                String methodPattern = pattern.substring(0, delimiter);
                String exception = pattern.substring(delimiter + 1);
                int space = methodPattern.indexOf(' ');
                String returnType = methodPattern.substring(0, space + 1);
                String methodName = methodPattern.substring(space + 1);
                fullPattern.append(returnType);
                fullPattern.append(classPattern);
                fullPattern.append('.');
                fullPattern.append(methodName);
                fullPattern.append('#');
                fullPattern.append(exception);
            }
            else if (type.equalsIgnoreCase(PointcutDefinition.CALLER_SIDE)) {
                String callerClassPattern = pointcutDef.getClassPattern();
                String pattern = pointcutDef.getPattern();
                int delimiter = pattern.indexOf('#');
                String calleeClassPattern = pattern.substring(0, delimiter);
                String methodPattern = pattern.substring(delimiter + 1);
                int space = methodPattern.indexOf(' ');
                String returnType = methodPattern.substring(0, space + 1);
                String methodName = methodPattern.substring(space + 1);
                fullPattern.append(callerClassPattern);
                fullPattern.append("->");
                fullPattern.append(returnType);
                fullPattern.append(calleeClassPattern);
                fullPattern.append(".");
                fullPattern.append(methodName);
                ;
            }
            else if (type.equals(PointcutDefinition.CFLOW)) {
                String pattern = pointcutDef.getPattern();
                int delimiter = pattern.indexOf('#');
                String classPattern = pattern.substring(0, delimiter);
                String methodPattern = pattern.substring(delimiter + 1);
                int space = methodPattern.indexOf(' ');
                String returnType = methodPattern.substring(0, space + 1);
                String methodName = methodPattern.substring(space + 1);
                fullPattern.append(returnType);
                fullPattern.append(classPattern);
                fullPattern.append(".");
                fullPattern.append(methodName);
            }
            else {
                throw new RuntimeException("invalid pointcut type: " + pointcutDef.getType());
            }

            pointcutDefElement.addAttribute("pattern", fullPattern.toString());
        }
    }

    /**
     * Handles the join point controllers.
     *
     * @param aspectElement the aspect element
     * @param aspectDef the aspect definition
     */
    private static void handleControllerDefinitions(final Element aspectElement,
                                                    final AspectDefinition aspectDef) {
        for (Iterator it = aspectDef.getControllerDefs().iterator(); it.hasNext();) {
            ControllerDefinition controllerDef = (ControllerDefinition)it.next();

            Element weavingRuleElement = aspectElement.addElement("controller-def");
            weavingRuleElement.addAttribute("pointcut", controllerDef.getExpression());
            weavingRuleElement.addAttribute("class", controllerDef.getClassName());
        }
    }

    /**
     * Handles the introduction weaving rules.
     *
     * @param aspectElement the aspect element
     * @param aspectDef the aspect definition
     */
    private static void handleIntroductionWeavingRules(final Element aspectElement,
                                                       final AspectDefinition aspectDef) {
        for (Iterator it = aspectDef.getIntroductionWeavingRules().iterator(); it.hasNext();) {
            IntroductionWeavingRule weavingRule = (IntroductionWeavingRule)it.next();

            Element weavingRuleElement = aspectElement.addElement("bind-introduction");
            weavingRuleElement.addAttribute("class", weavingRule.getClassPattern());

            for (Iterator it2 = weavingRule.getIntroductionRefs().iterator(); it2.hasNext();) {
                String introductionRef = (String)it2.next();

                Element introductionRefElement = weavingRuleElement.addElement("introduction-ref");
                introductionRefElement.addAttribute("name", introductionRef);
            }
        }
    }

    /**
     * Handles the advice weaving rules.
     *
     * @param aspectElement the aspect element
     * @param aspectDef the aspect definition
     */
    private static void handleAdviceWeavingRules(final Element aspectElement,
                                                 final AspectDefinition aspectDef) {
        for (Iterator it = aspectDef.getAdviceWeavingRules().iterator(); it.hasNext();) {
            AdviceWeavingRule weavingRule = (AdviceWeavingRule)it.next();

            Element weavingRuleElement = aspectElement.addElement("bind-advice");
            weavingRuleElement.addAttribute("pointcut", weavingRule.getExpression());

            String cflowExpression = weavingRule.getCFlowExpression();
            if (cflowExpression != null) {
                weavingRuleElement.addAttribute("cflow", cflowExpression);
            }

            for (Iterator it2 = weavingRule.getAdviceRefs().iterator(); it2.hasNext();) {
                String adviceRef = (String)it2.next();

                Element adviceRefElement = weavingRuleElement.addElement("advice-ref");
                adviceRefElement.addAttribute("name", adviceRef);
            }
        }
    }

    /**
     * Weaves the introduction definition attributes.
     *
     * @param qdoxParser the QDox parser
     * @param definition the definition
     */
    private static void weaveIntroductionDefinitionAttributes(
            final QDoxParser qdoxParser,
            final AspectWerkzDefinition definition) {

        JavaClass javaClass = qdoxParser.getJavaClass();
        DocletTag[] introductionDefTags = javaClass.getTagsByName(AttributeTag.INTRODUCTION_DEF);

        for (int i = 0; i < introductionDefTags.length; i++) {
            if (introductionDefTags[i] == null) {
                continue;
            }

            IntroductionDefinition introDef = new IntroductionDefinition();
            introDef.setName(introductionDefTags[i].getNamedParameter("name"));
            introDef.setInterface(javaClass.getFullyQualifiedName());
            introDef.setImplementation(introductionDefTags[i].getNamedParameter("implementation"));
            introDef.setDeploymentModel(introductionDefTags[i].getNamedParameter("deployment-model"));
            introDef.setIsPersistent(introductionDefTags[i].getNamedParameter("persistent"));
            introDef.setAttribute(introductionDefTags[i].getNamedParameter("attribute"));

            definition.addIntroduction(introDef);
        }
    }

    /**
     * Weaves the advice definition attributes.
     *
     * @param qdoxParser the QDox parser
     * @param definition the definition
     */
    private static void weaveAdviceDefinitionAttributes(
            final QDoxParser qdoxParser,
            final AspectWerkzDefinition definition) {

        JavaClass javaClass = qdoxParser.getJavaClass();
        DocletTag[] adviceDefTags = javaClass.getTagsByName(AttributeTag.ADVICE_DEF);

        for (int i = 0; i < adviceDefTags.length; i++) {
            if (adviceDefTags[i] == null) {
                continue;
            }

            AdviceDefinition adviceDef = new AdviceDefinition();
            adviceDef.setName(adviceDefTags[i].getNamedParameter("name"));
            adviceDef.setAdviceClassName(javaClass.getFullyQualifiedName());
            adviceDef.setDeploymentModel(adviceDefTags[i].getNamedParameter("deployment-model"));
            adviceDef.setIsPersistent(adviceDefTags[i].getNamedParameter("persistent"));
            adviceDef.setAttribute(adviceDefTags[i].getNamedParameter("attribute"));

            weaveAdviceParamAttributes(javaClass, adviceDef);

            definition.addAdvice(adviceDef);
        }
    }

    /**
     * Weaves the advice param attributes.
     *
     * @param qdoxParser the QDox parser
     * @param definition the definition
     */
    private static void weaveAdviceParamAttributes(
            final JavaClass javaClass,
            final AdviceDefinition adviceDefinition) {

        DocletTag[] adviceDefTags = javaClass.getTagsByName(AttributeTag.ADVICE_PARAM);

        for (int i = 0; i < adviceDefTags.length; i++) {
            if (adviceDefTags[i] == null) {
                continue;
            }

            String adviceRef = adviceDefTags[i].getNamedParameter("advice-ref");
            if (adviceRef.equals(adviceDefinition.getName())) {
                adviceDefinition.addParameter(
                        adviceDefTags[i].getNamedParameter("name"),
                        adviceDefTags[i].getNamedParameter("value"));
            }
        }
    }

    /**
     * Weaves the introduction attributes.
     *
     * @param definition the definition
     * @param className the name of the parsed class
     * @param qdoxParser the QDox parser
     */
    private static void parseIntroductionAttributes(
            final AspectWerkzDefinition definition,
            final String className,
            final QDoxParser qdoxParser) {

        AspectDefinition aspectDefinition = definition.getAspectDefinition(
                AspectWerkzDefinition.SYSTEM_ASPECT);

        JavaClass javaClass = qdoxParser.getJavaClass();
        DocletTag[] introductionTags = javaClass.getTagsByName(AttributeTag.INTRODUCTION);

        IntroductionWeavingRule weavingRule = new IntroductionWeavingRule();
        weavingRule.setClassPattern(className);

        for (int i = 0; i < introductionTags.length; i++) {
            if (introductionTags[i] == null) {
                continue;
            }
            String[] attributes = introductionTags[i].getParameters();
            for (int j = 0; j < attributes.length; j++) {
                final String introductionRef = definition.
                        getIntroductionNameByAttribute(attributes[j]);
                if (introductionRef == null) {
                    continue;
                }
                weavingRule.addIntroductionRef(introductionRef);
            }
            aspectDefinition.addIntroductionWeavingRule(weavingRule);
        }
    }

    /**
     * Weaves the pointcut controller attributes.
     *
     * @param definition the definition
     * @param className the name of the parsed class
     * @param qdoxParser the QDox parser
     */
    private static void parseJoinPointControllerAttributes(
            final AspectWerkzDefinition definition,
            final String className,
            final QDoxParser qdoxParser) {
        String pointcutName = CONTROLLER_POINTCUT_NAME + Strings.replaceSubString(className, ".", "_");

        int counter = 0;
        final JavaMethod[] javaMethods = qdoxParser.getJavaMethods();
        for (int i = 0; i < javaMethods.length; i++) {

            DocletTag[] methodTags = javaMethods[i].getTagsByName(AttributeTag.CONTROLLER);
            for (int j = 0; j < methodTags.length; j++) {
                if (methodTags[j] == null) {
                    continue;
                }

                String[] attributes = methodTags[j].getParameters();
                for (int k = 0; k < attributes.length; k++) {
                    String attribute = attributes[k];

                    String expression = pointcutName + counter;

                    // create and add a new pointcut definition
                    PointcutDefinition pointcutDef = new PointcutDefinition();
                    pointcutDef.setName(expression);
                    pointcutDef.setClassPattern(className);
                    pointcutDef.setPattern(createMethodPattern(javaMethods[i]));
                    pointcutDef.setType(PointcutDefinition.METHOD);
                    definition.getAspectDefinition(AspectWerkzDefinition.SYSTEM_ASPECT).
                            addPointcutDef(pointcutDef);

                    // create a new controller definition
                    ControllerDefinition controllerDef = new ControllerDefinition();
                    controllerDef.setClassName(attribute);
                    controllerDef.setExpression(expression);

                    definition.getAspectDefinition(AspectWerkzDefinition.SYSTEM_ASPECT).
                            addControllerDef(controllerDef);

                    // add the pointcut pattern
                    controllerDef.addMethodPointcutPattern(pointcutDef);

                    counter++;
                    break;
                }
            }
        }
    }

    /**
     * Weaves the method attributes.
     *
     * @param definition the definition
     * @param className the name of the parsed class
     * @param qdoxParser the QDox parser
     */
    private static void parseMethodPointcutAttributes(
            final AspectWerkzDefinition definition,
            final String className,
            final QDoxParser qdoxParser) {
        String pointcutName = METHOD_POINTCUT_NAME + Strings.replaceSubString(className, ".", "_");

        int counter = 0;
        final JavaMethod[] javaMethods = qdoxParser.getJavaMethods();
        for (int i = 0; i < javaMethods.length; i++) {

            DocletTag[] methodTags = javaMethods[i].getTagsByName(AttributeTag.METHOD);
            for (int j = 0; j < methodTags.length; j++) {
                if (methodTags[j] == null) {
                    continue;
                }

                String cflowRef = methodTags[j].getNamedParameter("cflow");
                String isNonReentrant = methodTags[j].getNamedParameter("non-reentrant");

                String[] attributes = methodTags[j].getParameters();
                for (int k = 0; k < attributes.length; k++) {
                    String attribute = attributes[k];
                    if (attribute.startsWith("cflow=") ||
                            attribute.startsWith("non-reentrant=")) {
                        continue;
                    }

                    for (Iterator it2 = definition.getAdviceDefinitions().iterator(); it2.hasNext();) {
                        String expression = pointcutName + counter;

                        // create and add a new pointcut def
                        PointcutDefinition pointcutDef = new PointcutDefinition();
                        pointcutDef.setName(expression);
                        pointcutDef.setClassPattern(className);
                        pointcutDef.setPattern(createMethodPattern(javaMethods[i]));
                        pointcutDef.setType(PointcutDefinition.METHOD);
                        pointcutDef.setNonReentrant(isNonReentrant);
                        definition.getAspectDefinition(AspectWerkzDefinition.SYSTEM_ASPECT).
                                addPointcutDef(pointcutDef);

                        String adviceAttribute = ((AdviceDefinition)it2.next()).getAttribute();
                        if (adviceAttribute == null) {
                            continue;
                        }
                        if (adviceAttribute.equals(attribute)) {
                            // get the advice ref
                            String adviceRef = definition.getAdviceNameByAttribute(adviceAttribute);
                            if (adviceRef == null) {
                                // TODO: log a warning
                                continue; // attribute not mapped to an advice
                            }
                            // create and add a new weaving rule def
                            AdviceWeavingRule weavingRule = new AdviceWeavingRule();
                            weavingRule.setExpression(expression);
                            weavingRule.setCFlowExpression(cflowRef);
                            weavingRule.addAdviceRef(adviceRef);
                            definition.getAspectDefinition(AspectWerkzDefinition.SYSTEM_ASPECT).
                                    addAdviceWeavingRule(weavingRule);

                            // add the pointcut pattern
                            weavingRule.addMethodPointcutPattern(pointcutDef);

                            counter++;
                            break;
                        }
                    }
                }
            }
        }
    }

    /**
     * Weaves the set field pointcut attributes.
     *
     * @param definition the definition
     * @param className the name of the parsed class
     * @param qdoxParser the QDox parser
     */
    private static void parseSetFieldPointcutAttributes(
            final AspectWerkzDefinition definition,
            final String className,
            final QDoxParser qdoxParser) {
        String pointcutName = SETFIELD_POINTCUT_NAME + Strings.replaceSubString(className, ".", "_");

        int counter = 0;
        final JavaField[] javaFields = qdoxParser.getJavaFields();
        for (int i = 0; i < javaFields.length; i++) {

            DocletTag[] setFieldTags = javaFields[i].getTagsByName(AttributeTag.SET_FIELD);
            for (int j = 0; j < setFieldTags.length; j++) {
                if (setFieldTags[j] == null) {
                    continue;
                }

                String[] setFieldAttributes = setFieldTags[j].getParameters();
                for (int k = 0; k < setFieldAttributes.length; k++) {

                    String attribute = setFieldAttributes[k];
                    for (Iterator it2 = definition.getAdviceDefinitions().iterator(); it2.hasNext();) {
                        String expression = pointcutName + counter;

                        // create and add a new pointcut def
                        PointcutDefinition pointcutDef = new PointcutDefinition();
                        pointcutDef.setName(expression);
                        pointcutDef.setClassPattern(className);
                        pointcutDef.setPattern(createFieldPattern(javaFields[i]));
                        pointcutDef.setType(PointcutDefinition.SET_FIELD);
                        definition.getAspectDefinition(AspectWerkzDefinition.SYSTEM_ASPECT).
                                addPointcutDef(pointcutDef);

                        String adviceAttribute = ((AdviceDefinition)it2.next()).getAttribute();
                        if (adviceAttribute == null) {
                            continue;
                        }
                        if (adviceAttribute.equals(attribute)) {
                            // get the advice ref
                            String adviceRef = definition.getAdviceNameByAttribute(adviceAttribute);
                            if (adviceRef == null) {
                                // TODO: log a warning
                                continue; // attribute not mapped to an advice
                            }

                            // create and add a new weaving rule def
                            AdviceWeavingRule weavingRule = new AdviceWeavingRule();
                            weavingRule.setExpression(expression);
                            weavingRule.addAdviceRef(adviceRef);
                            definition.getAspectDefinition(AspectWerkzDefinition.SYSTEM_ASPECT).
                                    addAdviceWeavingRule(weavingRule);

                            // add the pointcut pattern
                            weavingRule.addSetFieldPointcutPattern(pointcutDef);

                            counter++;
                            break;
                        }
                    }
                }
            }
        }
    }

    /**
     * Weaves the get field pointcut attributes.
     *
     * @param definition the definition
     * @param className the name of the parsed class
     * @param qdoxParser the QDox parser
     */
    private static void parseGetFieldPointcutAttributes(
            final AspectWerkzDefinition definition,
            final String className,
            final QDoxParser qdoxParser) {
        String pointcutName = GETFIELD_POINTCUT_NAME + Strings.replaceSubString(className, ".", "_");

        int counter = 0;
        final JavaField[] javaFields = qdoxParser.getJavaFields();
        for (int i = 0; i < javaFields.length; i++) {

            DocletTag[] getFieldTags = javaFields[i].getTagsByName(AttributeTag.GET_FIELD);
            for (int j = 0; j < getFieldTags.length; j++) {
                if (getFieldTags[j] == null) {
                    continue;
                }

                String[] getFieldAttributes = getFieldTags[j].getParameters();
                for (int k = 0; k < getFieldAttributes.length; k++) {
                    String attribute = getFieldAttributes[k];

                    for (Iterator it2 = definition.getAdviceDefinitions().iterator(); it2.hasNext();) {
                        String expression = pointcutName + counter;

                        // create and add a new pointcut def
                        PointcutDefinition pointcutDef = new PointcutDefinition();
                        pointcutDef.setName(expression);
                        pointcutDef.setClassPattern(className);
                        pointcutDef.setPattern(createFieldPattern(javaFields[i]));
                        pointcutDef.setType(PointcutDefinition.GET_FIELD);
                        definition.getAspectDefinition(AspectWerkzDefinition.SYSTEM_ASPECT).
                                addPointcutDef(pointcutDef);

                        String adviceAttribute = ((AdviceDefinition)it2.next()).getAttribute();
                        if (adviceAttribute == null) {
                            continue;
                        }
                        if (adviceAttribute.equals(attribute)) {
                            // get the advice ref
                            String adviceRef = definition.getAdviceNameByAttribute(adviceAttribute);
                            if (adviceRef == null) {
                                // TODO: log a warning
                                continue; // attribute not mapped to an advice
                            }

                            // create and add a new weaving rule def
                            AdviceWeavingRule weavingRule = new AdviceWeavingRule();
                            weavingRule.setExpression(expression);
                            weavingRule.addAdviceRef(adviceRef);
                            definition.getAspectDefinition(AspectWerkzDefinition.SYSTEM_ASPECT).
                                    addAdviceWeavingRule(weavingRule);

                            // add the pointcut pattern
                            weavingRule.addGetFieldPointcutPattern(pointcutDef);

                            counter++;
                            break;
                        }
                    }
                }
            }
        }
    }

    /**
     * Weaves the throws attributes.
     *
     * @param definition the definition
     * @param className the name of the parsed class
     * @param qdoxParser the QDox parser
     */
    private static void parseThrowsPointcutAttributes(
            final AspectWerkzDefinition definition,
            final String className,
            final QDoxParser qdoxParser) {
        String pointcutName = THROWS_POINTCUT_NAME + Strings.replaceSubString(className, ".", "_");

        int counter = 0;
        final JavaMethod[] javaMethods = qdoxParser.getJavaMethods();
        for (int i = 0; i < javaMethods.length; i++) {

            DocletTag[] throwsTags = javaMethods[i].getTagsByName(AttributeTag.THROWS);
            for (int j = 0; j < throwsTags.length; j++) {
                if (throwsTags[j] == null) {
                    continue;
                }

                String exceptionClassPattern = throwsTags[j].getNamedParameter("exception");

                if (exceptionClassPattern == null) {
                    throw new DefinitionException("exception class not specified for throws attribute at method <" + javaMethods[i].getName() + ">");
                }

                String[] attributes = throwsTags[j].getParameters();
                for (int k = 0; k < attributes.length; k++) {
                    String attribute = attributes[k];
                    if (attribute.startsWith("exception=")) {
                        continue;
                    }
                    for (Iterator it2 = definition.getAdviceDefinitions().iterator(); it2.hasNext();) {
                        String expression = pointcutName + counter;

                        // create and add a new pointcut def
                        PointcutDefinition pointcutDef = new PointcutDefinition();
                        pointcutDef.setName(expression);
                        pointcutDef.setClassPattern(className);
                        pointcutDef.setPattern(createThrowsPattern(
                                exceptionClassPattern, javaMethods[i]));
                        pointcutDef.setType(PointcutDefinition.THROWS);
                        definition.getAspectDefinition(AspectWerkzDefinition.SYSTEM_ASPECT).
                                addPointcutDef(pointcutDef);

                        String adviceAttribute = ((AdviceDefinition)it2.next()).getAttribute();
                        if (adviceAttribute == null) {
                            continue;
                        }
                        if (adviceAttribute.equals(attribute)) {
                            // get the advice ref
                            String adviceRef = definition.getAdviceNameByAttribute(adviceAttribute);
                            if (adviceRef == null) {
                                // TODO: log a warning
                                continue; // attribute not mapped to an advice
                            }

                            // create and add a new weaving rule def
                            AdviceWeavingRule weavingRule = new AdviceWeavingRule();
                            weavingRule.setExpression(expression);
                            weavingRule.addAdviceRef(adviceRef);
                            definition.getAspectDefinition(AspectWerkzDefinition.SYSTEM_ASPECT).
                                    addAdviceWeavingRule(weavingRule);

                            // add the pointcut pattern
                            weavingRule.addThrowsPointcutPattern(pointcutDef);

                            counter++;
                            break;
                        }
                    }
                }
            }
        }
    }

    /**
     * Weaves the caller side pointcut attributes.
     *
     * @param definition the definition
     * @param className the name of the parsed class
     * @param qdoxParser the QDox parser
     */
    private static void parseCallerSidePointcutAttributes(
            final AspectWerkzDefinition definition,
            final String className,
            final QDoxParser qdoxParser) {
        String pointcutName = CALLERSIDE_POINTCUT_NAME + Strings.replaceSubString(className, ".", "_");

        int counter = 0;
        final JavaMethod[] javaMethods = qdoxParser.getJavaMethods();
        for (int i = 0; i < javaMethods.length; i++) {

            DocletTag[] callerSideTags = javaMethods[i].getTagsByName(AttributeTag.CALLER_SIDE);
            for (int j = 0; j < callerSideTags.length; j++) {
                if (callerSideTags[j] == null) {
                    continue;
                }
                String callerClassPattern = callerSideTags[j].getNamedParameter("callerclass");
                if (callerClassPattern == null) {
                    throw new DefinitionException("caller class not specified for caller side attribute at method <" + javaMethods[i].getName() + ">");
                }

                String[] callerSideAttributes = callerSideTags[j].getParameters();
                for (int k = 0; k < callerSideAttributes.length; k++) {
                    String attribute = callerSideAttributes[k];
                    if (attribute.startsWith("callerclass=")) {
                        continue;
                    }
                    for (Iterator it2 = definition.getAdviceDefinitions().iterator(); it2.hasNext();) {
                        String expression = pointcutName + counter;

                        // create and add a new pointcut def
                        PointcutDefinition pointcutDef = new PointcutDefinition();
                        pointcutDef.setName(expression);
                        pointcutDef.setClassPattern(callerClassPattern);
                        pointcutDef.setPattern(createCallerSidePattern(className, javaMethods[i]));
                        pointcutDef.setType(PointcutDefinition.CALLER_SIDE);
                        definition.getAspectDefinition(AspectWerkzDefinition.SYSTEM_ASPECT).
                                addPointcutDef(pointcutDef);

                        String adviceAttribute = ((AdviceDefinition)it2.next()).getAttribute();
                        if (adviceAttribute == null) {
                            continue;
                        }

                        if (adviceAttribute.equals(attribute)) {
                            // get the advice ref
                            String adviceRef = definition.getAdviceNameByAttribute(adviceAttribute);
                            if (adviceRef == null) {
                                // TODO: log a warning
                                continue; // attribute not mapped to an advice
                            }

                            // create and add a new weaving rule def
                            AdviceWeavingRule weavingRule = new AdviceWeavingRule();
                            weavingRule.setExpression(expression);
                            weavingRule.addAdviceRef(adviceRef);
                            definition.getAspectDefinition(AspectWerkzDefinition.SYSTEM_ASPECT).
                                    addAdviceWeavingRule(weavingRule);

                            // add the pointcut pattern
                            weavingRule.addCallerSidePointcutPattern(pointcutDef);

                            counter++;
                            break;
                        }
                    }
                }
            }
        }
    }

    /**
     * Weaves the cflow attributes.
     *
     * @param definition the definition
     * @param className the name of the parsed class
     * @param qdoxParser the QDox parser
     */
    private static void parseCFlowPointcutAttributes(
            final AspectWerkzDefinition definition,
            final String className,
            final QDoxParser qdoxParser) {

        final JavaMethod[] javaMethods = qdoxParser.getJavaMethods();
        for (int i = 0; i < javaMethods.length; i++) {

            DocletTag[] cflowTags = javaMethods[i].getTagsByName(AttributeTag.CFLOW);
            for (int j = 0; j < cflowTags.length; j++) {
                if (cflowTags[j] == null) {
                    continue;
                }
                String[] attributes = cflowTags[j].getParameters();
                if (attributes.length == 0) {
                    continue;
                }

                // get the user defined name for the cflow pointcut
                String name = attributes[0];

                // create and add a new pointcut def
                PointcutDefinition pointcutDef = new PointcutDefinition();
                pointcutDef.setName(name);
                pointcutDef.setClassPattern("*");
                String callerSidePattern = createCallerSidePattern(className, javaMethods[i]);
                pointcutDef.setPattern(callerSidePattern);
                pointcutDef.setType(PointcutDefinition.CFLOW);

                definition.getAspectDefinition(AspectWerkzDefinition.SYSTEM_ASPECT).
                        addPointcutDef(pointcutDef);

                // create and add a new weaving rule def
                AdviceWeavingRule weavingRule = new AdviceWeavingRule();
                weavingRule.setExpression(name);
                weavingRule.addAdviceRef(CFlowPreAdvice.NAME);
                weavingRule.addAdviceRef(CFlowPostAdvice.NAME);
                definition.getAspectDefinition(AspectWerkzDefinition.SYSTEM_ASPECT).
                        addAdviceWeavingRule(weavingRule);

                // add the pointcut pattern (a method patterns since the cflow pointcut
                // is dependent on having a method pointcut)
                weavingRule.addCallerSidePointcutPattern(pointcutDef);

                break;
            }
        }
    }

    /**
     * Creates a method regular expression pattern.
     *
     * @param javaMethod the method
     * @return the pattern
     */
    private static String createMethodPattern(final JavaMethod javaMethod) {
        final StringBuffer pattern = new StringBuffer();
        pattern.append(javaMethod.getReturns().getValue());
        pattern.append(' ');
        pattern.append(javaMethod.getName());
        pattern.append('(');
        JavaParameter[] parameters = javaMethod.getParameters();
        for (int l = 0; l < parameters.length; l++) {
            JavaParameter parameter = parameters[l];
            String value = parameter.getType().getValue();
            for (int i = 1; i <= parameter.getType().getDimensions(); i++) {
                value += "[]";
            }
            pattern.append(value);
            if (l != parameters.length - 1) {
                pattern.append(',');
            }
        }
        pattern.append(')');
        return pattern.toString();
    }

    /**
     * Creates a field regular expression pattern.
     *
     * @param javaField the field
     * @return the pattern
     */
    private static String createFieldPattern(final JavaField javaField) {
        final StringBuffer pattern = new StringBuffer();
        String value = javaField.getType().getValue();
        for (int i = 1; i <= javaField.getType().getDimensions(); i++) {
            value += "[]";
        }
        pattern.append(value);
        pattern.append(' ');
        pattern.append(javaField.getName());
        return pattern.toString();
    }

    /**
     * Creates a throws regular expression pattern.
     *
     * @param exceptionClassPattern the name of the exception class
     * @param javaMethod the method
     * @return the pattern
     */
    private static String createThrowsPattern(final String exceptionClassPattern,
                                              final JavaMethod javaMethod) {
        StringBuffer throwsPattern = new StringBuffer();
        throwsPattern.append(createMethodPattern(javaMethod));
        throwsPattern.append('#');
        throwsPattern.append(exceptionClassPattern);
        return throwsPattern.toString();
    }

    /**
     * Creates a caller side regular expression pattern.
     *
     * @param className the name of the class
     * @param javaMethod the method
     * @return the pattern
     */
    private static String createCallerSidePattern(final String className,
                                                  final JavaMethod javaMethod) {
        StringBuffer callerSidePattern = new StringBuffer();
        callerSidePattern.append(className);
        callerSidePattern.append('#');
        callerSidePattern.append(createMethodPattern(javaMethod));
        return callerSidePattern.toString();
    }

    /**
     * Validates the definition.
     *
     * @param definition the definition
     */
    private static void validate(final AspectWerkzDefinition definition) {
        if (System.getProperty("aspectwerkz.definition.validate", "false").equals("true")) {
            // validate the definition
            DefinitionValidator validator = new DefinitionValidator(definition);
            validator.validate();

            // handle errors in definition
            List errors = validator.getErrorMessages();
            for (Iterator i = errors.iterator(); i.hasNext();) {
                String errorMsg = (String)i.next();

                // TODO: use logger instead of System.out
                System.out.println(errorMsg);
            }
        }
    }

    /**
     * Runs the compiler from the command line.
     *
     * @param args
     */
    public static void main(String[] args) {
        if (args.length < 2) {
            System.out.println("usage: java [options...] org.codehaus.aspectwerkz.metadata.AttributeC <path to src dir> <file name> -merge <file name to merge with> -uuid <uuid for definition>");
            System.out.println("       -merge (or -m) <file name to merge with> tells the compiler which file it should append the compiled attributes to");
            System.out.println("       -uuid (or -u) <uuid for definition> is optional (if not specified one will be generated)");
            System.exit(0);
        }
        String mergeFile = null;
        String uuid = null;
        if ((args[2].equals("-m") || args[2].equals("-merge")) && args[3] != null) {
            mergeFile = args[3];
        }
        else if ((args[2].equals("-u") || args[2].equals("-uuid")) && args[3] != null) {
            uuid = args[3];
        }
        if ((args[4].equals("-m") || args[4].equals("-merge")) && args[5] != null) {
            mergeFile = args[5];
        }
        else if ((args[4].equals("-u") || args[4].equals("-uuid")) && args[5] != null) {
            uuid = args[5];
        }

        System.out.println("compiling XML definition...");
        if (args.length == 2) {
            AttributeC.compile(args[0], args[1]);
        }
        else {
            AttributeC.compile(args[0], args[1], mergeFile, uuid);
        }
        System.out.println("XML definition for classes in " + args[0] + " have been compiled to " + args[1]);
    }
}
TOP

Related Classes of org.codehaus.aspectwerkz.metadata.AttributeC

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.