Package org.codehaus.aspectwerkz.definition

Source Code of org.codehaus.aspectwerkz.definition.XmlDefinitionParser

/**************************************************************************************
* 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.definition;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.net.MalformedURLException;
import java.net.URL;

import org.dom4j.Document;
import org.dom4j.Attribute;
import org.dom4j.Element;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;

import org.codehaus.aspectwerkz.exception.WrappedRuntimeException;
import org.codehaus.aspectwerkz.exception.DefinitionException;
import org.codehaus.aspectwerkz.AspectWerkz;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;

/**
* Parses the XML definition file using <tt>dom4j</tt>.
*
* @author <a href="mailto:jboner@codehaus.org">Jonas Bon�r</a>
*/
public class XmlDefinitionParser {

    /**
     * The current DTD public id. The matching dtd will be searched as a resource.
     */
    private final static String DTD_PUBLIC_ID = "-//AspectWerkz//DTD 0.8//EN";

    /**
     * The timestamp, holding the last time that the definition was parsed.
     */
    private static File s_timestamp = new File(".timestamp");

    /**
     * The AspectWerkz definition.
     */
    private static AspectWerkzDefinition s_definition;

    /**
     * Parses the XML definition file.
     *
     * @param definitionFile the definition file
     * @return the definition object
     */
    public static AspectWerkzDefinition parse(final File definitionFile) {
        return parse(definitionFile, false);
    }

    /**
     * Parses the XML definition file, only if it has been updated.
     * Uses a timestamp to check for modifications.
     *
     * @param definitionFile the definition file
     * @param isDirty flag to mark the the definition as updated or not
     * @return the definition object
     */
    public static AspectWerkzDefinition parse(final File definitionFile, boolean isDirty) {
        if (definitionFile == null) throw new IllegalArgumentException("definition file can not be null");
        if (!definitionFile.exists()) throw new DefinitionException("definition file " + definitionFile.toString() + " does not exist");

        // if definition is not updated; don't parse but return it right away
        if (isNotUpdated(definitionFile)) {
            isDirty = false;
            return s_definition;
        }

        // updated definition, ready to be parsed
        try {
            Document document = createDocument(definitionFile.toURL());
            s_definition = parse(document);

            setParsingTimestamp();
            isDirty = true;

            return s_definition;
        }
        catch (MalformedURLException e) {
            throw new DefinitionException(definitionFile + " does not exist");
        }
        catch (DocumentException e) {
            e.printStackTrace();
            throw new DefinitionException("XML definition file <" + definitionFile + "> has errors: " + e.getMessage());

        }
    }

    /**
     * Parses the XML definition file retrieved from an input stream.
     *
     * @param stream the input stream containing the document
     * @return the definition object
     */
    public static AspectWerkzDefinition parse(final InputStream stream) {
        try {
            Document document = createDocument(stream);
            s_definition = parse(document);
            return s_definition;
        }
        catch (DocumentException e) {
            throw new DefinitionException("XML definition file on classpath has errors: " + e.getMessage());
        }
    }

    /**
     * Parses the XML definition file not using the cache.
     *
     * @param url the URL to the definition file
     * @return the definition object
     */
    public static AspectWerkzDefinition parseNoCache(final URL url) {
        try {
            Document document = createDocument(url);
            s_definition = parse(document);
            return s_definition;
        }
        catch (Exception e) {
            throw new WrappedRuntimeException(e);
        }
    }

    /**
     * Parses the definition DOM document.
     *
     * @param document the defintion as a document
     * @return the definition
     */
    public static AspectWerkzDefinition parse(final Document document) {
        final AspectWerkzDefinition definition = new AspectWerkzDefinition();
        final Element root = document.getRootElement();

        String uuid = root.attributeValue("id");
        if (uuid == null || uuid.equals("")) {
            // TODO: log a warning "no id specified in the definition, using default (AspectWerkz.DEFAULT_SYSTEM)"
            uuid = AspectWerkz.DEFAULT_SYSTEM;
        }
        definition.setUuid(uuid);

        // get the base package
        final String basePackage = getBasePackage(root);

        // parse the transformation scopes
        parseTransformationScopes(root, definition, basePackage);

        // parse without package elements
        parseIntroductionElements(root, definition, basePackage);
        parseAdviceElements(root, definition, basePackage);
        parseAdviceStackElements(root, definition);
        parseAspectElements(root, definition, basePackage);

        // parse with package elements
        parsePackageElements(root, definition, basePackage);

        return definition;
    }

    /**
     * Merges two DOM documents.
     *
     * @param document1 the first document
     * @param document2 the second document
     * @return the definition merged document
     */
    public static Document mergeDocuments(final Document document1, final Document document2) {
        if (document2 == null && document1 != null) return document1;
        if (document1 == null && document2 != null) return document2;
        if (document1 == null && document2 == null) return null;
        try {

            Element root1 = document1.getRootElement();
            Element root2 = document2.getRootElement();
            for (Iterator it1 = root2.elementIterator(); it1.hasNext();) {
                Element element = (Element)it1.next();
                element.setParent(null);
                root1.add(element);
            }
        }
        catch (Exception e) {
            throw new WrappedRuntimeException(e);
        }
        return document1;
    }

    /**
     * Creates a DOM document.
     *
     * @param url the URL to the file containing the XML
     * @return the DOM document
     * @throws DocumentException
     * @throws MalformedURLException
     */
    public static Document createDocument(final URL url) throws DocumentException {
        SAXReader reader = new SAXReader();
        setEntityResolver(reader);
        return reader.read(url);
    }

    /**
     * Creates a DOM document.
     *
     * @param stream the stream containing the XML
     * @return the DOM document
     * @throws DocumentException
     * @throws MalformedURLException
     */
    public static Document createDocument(final InputStream stream) throws DocumentException {
        SAXReader reader = new SAXReader();
        setEntityResolver(reader);
        return reader.read(stream);
    }

    /**
     * Sets the entity resolver which is created based on the DTD from in the root
     * dir of the AspectWerkz distribution.
     *
     * @param reader the reader to set the resolver in
     */
    private static void setEntityResolver(final SAXReader reader) {
        EntityResolver resolver = new EntityResolver() {
            public InputSource resolveEntity(String publicId, String systemId) {
                if ( publicId.equals(DTD_PUBLIC_ID) ) {
                    InputStream in = getClass().getResourceAsStream("/aspectwerkz.dtd");
                    return new InputSource(in);
                }
                return null;
            }
        };
        reader.setEntityResolver(resolver);
    }

    /**
     * Checks if the definition file has been updated since the last parsing.
     *
     * @param definitionFile the definition file
     * @return boolean
     */
    private static boolean isNotUpdated(final File definitionFile) {
        return definitionFile.lastModified() < getParsingTimestamp() && s_definition != null;
    }

    /**
     * Sets the timestamp for the latest parsing of the definition file.
     */
    private static void setParsingTimestamp() {
        final long newModifiedTime = System.currentTimeMillis();
        s_timestamp.setLastModified(newModifiedTime);
    }

    /**
     * Returns the timestamp for the last parsing of the definition file.
     *
     * @return the timestamp
     */
    private static long getParsingTimestamp() {
        final long modifiedTime = s_timestamp.lastModified();
        if (modifiedTime == 0L) {
            // no timestamp, create a new one
            try {
                s_timestamp.createNewFile();
            }
            catch (IOException e) {
                throw new RuntimeException("could not create timestamp file: " + s_timestamp.getAbsolutePath());
            }
        }
        return modifiedTime;
    }

    /**
     * Parses the <tt>transformation-scope</tt> elements.
     *
     * @param root the root element
     * @param definition the definition object
     * @param packageName the package name
     */
    private static void parseTransformationScopes(final Element root,
                                                  final AspectWerkzDefinition definition,
                                                  final String packageName) {
        for (Iterator it1 = root.elementIterator("transformation-scope"); it1.hasNext();) {
            String transformationScope = "";
            Element scope = (Element)it1.next();
            for (Iterator it2 = scope.attributeIterator(); it2.hasNext();) {
                Attribute attribute = (Attribute)it2.next();
                if (attribute.getName().trim().equals("package")) {
                    transformationScope = attribute.getValue().trim();
                    if (packageName.endsWith(".*")) {
                        transformationScope = packageName.substring(0, packageName.length() - 2);
                    }
                    else if (packageName.endsWith(".")) {
                        transformationScope = packageName.substring(0, packageName.length() - 1);
                    }
                    transformationScope = packageName + transformationScope;
                    break;
                }
                else {
                    continue;
                }
            }
            if (transformationScope.length() != 0) {
                definition.addTransformationScope(transformationScope);
            }
        }
    }

    /**
     * Parses the definition DOM document.
     *
     * @param root the root element
     * @param definition the definition
     * @param basePackage the base package
     */
    private static void parsePackageElements(final Element root,
                                             final AspectWerkzDefinition definition,
                                             final String basePackage) {
        for (Iterator it1 = root.elementIterator("package"); it1.hasNext();) {
            final Element packageElement = ((Element)it1.next());
            final String packageName = basePackage + getPackage(packageElement);

            parseIntroductionElements(packageElement, definition, packageName);
            parseAdviceElements(packageElement, definition, packageName);
            parseAdviceStackElements(packageElement, definition);
            parseAspectElements(packageElement, definition, packageName);
        }
    }

    /**
     * Parses the <tt>introduction</tt> elements.
     *
     * @param root the root element
     * @param definition the definition object
     * @param packageName the package name
     */
    private static void parseIntroductionElements(final Element root,
                                                  final AspectWerkzDefinition definition,
                                                  final String packageName) {
        for (Iterator it1 = root.elementIterator("introduction-def"); it1.hasNext();) {
            final IntroductionDefinition introDef = new IntroductionDefinition();

            Element introduction = (Element)it1.next();
            for (Iterator it2 = introduction.attributeIterator(); it2.hasNext();) {
                Attribute attribute = (Attribute)it2.next();

                final String name = attribute.getName().trim();
                final String value = attribute.getValue().trim();
                if (name.equals("name")) {
                    introDef.setName(value);
                }
                else if (name.equals("interface")) {
                    introDef.setInterface(packageName + value);
                }
                else if (name.equals("implementation")) {
                    introDef.setImplementation(packageName + value);
                }
                else if (name.equals("deploymentModel") ||
                        name.equals("deployment-model")) {
                    introDef.setDeploymentModel(value);
                }
                else if (name.equals("persistent")) {
                    throw new DefinitionException("persistent introductions are not supported");
//                    introDef.setIsPersistent(value);
                }
                else if (name.equals("attribute")) {
                    introDef.setAttribute(value);
                }
            }
            definition.addIntroduction(introDef);
        }
    }

    /**
     * Parses the <tt>advice</tt> elements.
     *
     * @param root the root element
     * @param definition the definition object
     * @param packageName the package name
     */
    private static void parseAdviceElements(final Element root,
                                            final AspectWerkzDefinition definition,
                                            final String packageName) {
        for (Iterator it1 = root.elementIterator("advice-def"); it1.hasNext();) {
            final AdviceDefinition adviceDef = new AdviceDefinition();

            Element advice = (Element)it1.next();
            for (Iterator it2 = advice.attributeIterator(); it2.hasNext();) {
                Attribute attribute = (Attribute)it2.next();
                final String name = attribute.getName().trim();
                final String value = attribute.getValue().trim();

                if (name.equals("name")) {
                    adviceDef.setName(value);
                }
                else if (name.equals("advice") || (name.equals("class"))) {
                    adviceDef.setAdviceClassName(packageName + value);
                }
                else if (name.equals("deployment-model") ||
                        name.equals("deploymentModel")) {
                    adviceDef.setDeploymentModel(value);
                }
                else if (name.equals("persistent")) {
                    throw new DefinitionException("persistent advices are not supported");
//                    adviceDef.setIsPersistent(value);
                }
                else if (name.equals("attribute")) {
                    adviceDef.setAttribute(value);
                }
            }
            for (Iterator it2 = advice.elementIterator(); it2.hasNext();) {
                Element nestedAdviceElement = (Element)it2.next();
                if (nestedAdviceElement.getName().trim().equals("param")) {
                    adviceDef.addParameter(
                            nestedAdviceElement.attributeValue("name"),
                            nestedAdviceElement.attributeValue("value"));
                }
            }
            definition.addAdvice(adviceDef);
        }
    }

    /**
     * Parses the <tt>aspect</tt> elements.
     *
     * @param root the root element
     * @param definition the definition object
     * @param packageName the package name
     */
    private static void parseAspectElements(final Element root,
                                            final AspectWerkzDefinition definition,
                                            final String packageName) {
        for (Iterator it1 = root.elementIterator("abstract-aspect"); it1.hasNext();) {
            final AspectDefinition aspectDef = new AspectDefinition();
            aspectDef.setAbstract(true);

            final Element aspect = (Element)it1.next();
            for (Iterator it2 = aspect.attributeIterator(); it2.hasNext();) {
                Attribute attribute = (Attribute)it2.next();
                final String name = attribute.getName().trim();
                final String value = attribute.getValue().trim();
                if (name.equals("name")) {
                    aspectDef.setName(value);
                }
            }
            parsePointcutElements(aspect, aspectDef, packageName);
            parseControllerElements(aspect, aspectDef);
            parseBindIntroductionElements(aspect, aspectDef, packageName);
            parseBindAdviceElements(aspect, aspectDef);

            definition.addAbstractAspect(aspectDef);
        }
        for (Iterator it1 = root.elementIterator("aspect"); it1.hasNext();) {
            final AspectDefinition aspectDef = new AspectDefinition();
            final Element aspect = (Element)it1.next();
            for (Iterator it2 = aspect.attributeIterator(); it2.hasNext();) {
                Attribute attribute = (Attribute)it2.next();
                final String name = attribute.getName().trim();
                final String value = attribute.getValue().trim();
                if (name.equals("name")) {
                    aspectDef.setName(value);
                }
                else if (name.equals("extends")) {
                    aspectDef.setExtends(value);
                    continue;
                }
            }

            parsePointcutElements(aspect, aspectDef, packageName);
            parseControllerElements(aspect, aspectDef);
            parseBindIntroductionElements(aspect, aspectDef, packageName);
            parseBindAdviceElements(aspect, aspectDef);

            handleAbstractAspectDependencies(aspectDef, definition);

            definition.addAspect(aspectDef);
        }
    }

    /**
     * Handles the abstract dependencies for a concrete aspect.
     *
     * @param aspectDef the aspect definition
     * @param definition the aspectwerkz definition
     */
    private static void handleAbstractAspectDependencies(final AspectDefinition aspectDef,
                                                         final AspectWerkzDefinition definition) {
        String extendsRef = aspectDef.getExtends();
        if (extendsRef != null) {
            final AspectDefinition abstractAspect = definition.getAbstractAspectDefinition(extendsRef);
            if (abstractAspect == null) {
                throw new DefinitionException("abstract aspect <" + aspectDef.getExtends() + "> is not defined");
            }
            for (Iterator it = abstractAspect.getPointcutDefs().iterator(); it.hasNext();) {
                final PointcutDefinition pointcutDef = (PointcutDefinition)it.next();
                aspectDef.addPointcutDef(pointcutDef);
            }
            for (Iterator it = abstractAspect.getAdviceWeavingRules().iterator(); it.hasNext();) {
                final AdviceWeavingRule weavingRule = (AdviceWeavingRule)it.next();
                for (Iterator it2 = aspectDef.getPointcutDefs().iterator(); it2.hasNext();) {
                    addPointcutPattern((PointcutDefinition)it2.next(), weavingRule);
                }
                aspectDef.addAdviceWeavingRule(weavingRule);
            }
            for (Iterator it = abstractAspect.getIntroductionWeavingRules().iterator(); it.hasNext();) {
                final IntroductionWeavingRule weavingRule = (IntroductionWeavingRule)it.next();
                aspectDef.addIntroductionWeavingRule(weavingRule);
            }
        }
    }

    /**
     * Parses the pointcut elements.
     *
     * @param aspect the aspect element
     * @param aspectDef the aspect definition
     * @param packageName the name of the package
     */
    private static void parsePointcutElements(final Element aspect,
                                              final AspectDefinition aspectDef,
                                              final String packageName) {
        for (Iterator it2 = aspect.elementIterator(); it2.hasNext();) {
            final Element nestedAdviceElement = (Element)it2.next();
            if (nestedAdviceElement.getName().trim().equals("pointcut-def") ||
                    nestedAdviceElement.getName().trim().equals("pointcut")) {
                try {
                    final PointcutDefinition pointcutDef = new PointcutDefinition();

                    for (Iterator it3 = nestedAdviceElement.attributeIterator(); it3.hasNext();) {
                        Attribute attribute = (Attribute)it3.next();
                        final String name = attribute.getName().trim();
                        final String value = attribute.getValue().trim();
                        if (name.equals("name")) {
                            pointcutDef.setName(value);
                        }
                        else if (name.equals("type")) {
                            pointcutDef.setType(value);
                        }
                        else if (name.equals("non-reentrant")) {
                            pointcutDef.setNonReentrant(value);
                        }
                    }

                    // handle the pointcut pattern, split the pattern in a class and
                    // a method/field/throws/callerside pattern
                    final String pattern = nestedAdviceElement.attributeValue("pattern");
                    try {
                        if (pointcutDef.getType().equalsIgnoreCase(PointcutDefinition.METHOD)) {
                            createMethodPattern(pattern, pointcutDef, packageName);
                        }
                        else if (pointcutDef.getType().equalsIgnoreCase(PointcutDefinition.CFLOW)) {
                            // make a 'match all caller side classes' pattern out of the regular method pattern
                            createCallerSidePattern(pattern, pointcutDef, packageName);
                        }
                        else if (pointcutDef.getType().equalsIgnoreCase(PointcutDefinition.GET_FIELD) ||
                                pointcutDef.getType().equalsIgnoreCase(PointcutDefinition.SET_FIELD)) {
                            createFieldPattern(pattern, pointcutDef, packageName);
                        }
                        else if (pointcutDef.getType().equalsIgnoreCase(PointcutDefinition.THROWS)) {
                            createThrowsPattern(pattern, pointcutDef, packageName);
                        }
                        else if (pointcutDef.getType().equalsIgnoreCase(PointcutDefinition.CALLER_SIDE)) {
                            createCallerSidePattern(pattern, pointcutDef, packageName);
                        }
                    }
                    catch (Exception e) {
                        throw new WrappedRuntimeException(e);
                    }
                    aspectDef.addPointcutDef(pointcutDef);
                }
                catch (Exception e) {
                    throw new DefinitionException("pointcut definition in aspect " + aspectDef.getName() + " is not well-formed: " + e.getMessage());
                }
            }
        }
    }

    /**
     * Parses the controller elements.
     *
     * @param aspect the aspect element
     * @param aspectDef the aspect definition
     * @param packageName the package name
     */
    private static void parseControllerElements(final Element aspect,
                                                final AspectDefinition aspectDef) {
        for (Iterator it2 = aspect.elementIterator(); it2.hasNext();) {
            final Element nestedAdviceElement = (Element)it2.next();
            if (nestedAdviceElement.getName().trim().equals("controller-def") ||
                    nestedAdviceElement.getName().trim().equals("controller")) {
                try {
                    final ControllerDefinition controllerDef = new ControllerDefinition();

                    for (Iterator it3 = nestedAdviceElement.attributeIterator(); it3.hasNext();) {
                        Attribute attribute = (Attribute)it3.next();
                        final String name = attribute.getName().trim();
                        final String value = attribute.getValue().trim();
                        if (name.equals("pointcut") || name.equals("expression")) {
                            controllerDef.setExpression(value);
                        }
                        else if (name.equals("class")) {
                            controllerDef.setClassName(value);
                        }
                    }
                    // add the pointcut patterns to simplify the matching
                    if (!aspectDef.isAbstract()) {
                        for (Iterator it = aspectDef.getPointcutDefs().iterator(); it.hasNext();) {
                            final PointcutDefinition pointcutDef = (PointcutDefinition)it.next();
                            if (pointcutDef.getType().equalsIgnoreCase(PointcutDefinition.METHOD)) {
                                controllerDef.addMethodPointcutPattern(pointcutDef);
                            }
                        }
                    }
                    aspectDef.addControllerDef(controllerDef);
                }
                catch (Exception e) {
                    throw new DefinitionException("controller definition in aspect " + aspectDef.getName() + " is not well-formed: " + e.getMessage());
                }
            }
        }
    }

    /**
     * Parses the introduce elements.
     *
     * @param aspect the aspect element
     * @param aspectDef the aspect definition
     * @param packageName the name of the package
     */
    private static void parseBindIntroductionElements(final Element aspect,
                                                      final AspectDefinition aspectDef,
                                                      final String packageName) {
        for (Iterator it2 = aspect.elementIterator(); it2.hasNext();) {
            final Element nestedAdviceElement = (Element)it2.next();
            if (nestedAdviceElement.getName().trim().equals("bind-introduction") ||
                    nestedAdviceElement.getName().trim().equals("introduction")) {
                try {
                    final IntroductionWeavingRule introWeavingRule = new IntroductionWeavingRule();

                    for (Iterator it3 = nestedAdviceElement.attributeIterator(); it3.hasNext();) {
                        Attribute attribute = (Attribute)it3.next();
                        final String name = attribute.getName().trim();
                        final String value = attribute.getValue().trim();
                        if (name.equals("class")) {
                            introWeavingRule.setClassPattern(packageName + value);
                        }
                        else if (name.equals("introduction-ref")) {
                            introWeavingRule.addIntroductionRef(value);
                            break; // if introduction-ref as an attribute => no more introductions
                        }
                    }
                    parseIntroductionWeavingRuleNestedElements(nestedAdviceElement, introWeavingRule);
                    aspectDef.addIntroductionWeavingRule(introWeavingRule);
                }
                catch (Exception e) {
                    throw new DefinitionException("introduction definition in aspect " + aspectDef.getName() + " is not well-formed: " + e.getMessage());
                }
            }
        }
    }

    /**
     * Parses the advise elements.
     *
     * @param aspect the aspect element
     * @param aspectDef the aspect definition
     */
    private static void parseBindAdviceElements(final Element aspect,
                                                final AspectDefinition aspectDef) {
        for (Iterator it2 = aspect.elementIterator(); it2.hasNext();) {
            final Element nestedAdviceElement = (Element)it2.next();
            if (nestedAdviceElement.getName().trim().equals("bind-advice") ||
                    nestedAdviceElement.getName().trim().equals("advice")) {
                try {
                    final AdviceWeavingRule adviceWeavingRule = new AdviceWeavingRule();

                    for (Iterator it3 = nestedAdviceElement.attributeIterator(); it3.hasNext();) {
                        Attribute attribute = (Attribute)it3.next();
                        final String name = attribute.getName().trim();
                        final String value = attribute.getValue().trim();
                        if (name.equals("cflow")) {
                            adviceWeavingRule.setCFlowExpression(value);
                        }
                        else if (name.equals("pointcut") || name.equals("expression")) {
                            adviceWeavingRule.setExpression(value);
                        }
                        else if (name.equals("advice-ref")) {
                            adviceWeavingRule.addAdviceRef(value);
                            break; // if advice-ref as an attribute => no more advices
                        }
                    }
                    parseAdviceWeavingRuleNestedElements(nestedAdviceElement, adviceWeavingRule);
                    aspectDef.addAdviceWeavingRule(adviceWeavingRule);

                    // add the pointcut patterns to simplify the matching
                    if (!aspectDef.isAbstract()) {
                        for (Iterator it = aspectDef.getPointcutDefs().iterator(); it.hasNext();) {
                            addPointcutPattern((PointcutDefinition)it.next(), adviceWeavingRule);
                        }
                    }
                }
                catch (Exception e) {
                    throw new DefinitionException("advice definition in aspect " + aspectDef.getName() + " is not well-formed: " + e.getMessage());
                }
            }
        }
    }

    /**
     * Adds a pointcut pattern to the weaving rule.
     *
     * @param pointcutDef the pointcut definition
     * @param adviceWeavingRule the weaving rule
     */
    private static void addPointcutPattern(final PointcutDefinition pointcutDef,
                                           final AdviceWeavingRule adviceWeavingRule) {
        if (pointcutDef.getType().equalsIgnoreCase(PointcutDefinition.METHOD)) {
            adviceWeavingRule.addMethodPointcutPattern(pointcutDef);
        }
        else if (pointcutDef.getType().equalsIgnoreCase(PointcutDefinition.SET_FIELD)) {
            adviceWeavingRule.addSetFieldPointcutPattern(pointcutDef);
        }
        else if (pointcutDef.getType().equalsIgnoreCase(PointcutDefinition.GET_FIELD)) {
            adviceWeavingRule.addGetFieldPointcutPattern(pointcutDef);
        }
        else if (pointcutDef.getType().equalsIgnoreCase(PointcutDefinition.THROWS)) {
            adviceWeavingRule.addThrowsPointcutPattern(pointcutDef);
        }
        else if (pointcutDef.getType().equalsIgnoreCase(PointcutDefinition.CALLER_SIDE)) {
            adviceWeavingRule.addCallerSidePointcutPattern(pointcutDef);
        }
        else if (pointcutDef.getType().equalsIgnoreCase(PointcutDefinition.CFLOW)) {
            adviceWeavingRule.addCallerSidePointcutPattern(pointcutDef);
        }
    }

    /**
     * Parses the nested <tt>introduction-ref</tt> and <tt>advice-ref</tt> elements.
     *
     * @param introductionElement the root introduction element
     * @param introWeavingRule the IntroducutionWeavingRule definition
     */
    private static void parseIntroductionWeavingRuleNestedElements(
            final Element introductionElement,
            final IntroductionWeavingRule introWeavingRule) {
        for (Iterator it = introductionElement.elementIterator(); it.hasNext();) {
            Element nestedElement = (Element)it.next();
            if (nestedElement.getName().trim().equals("introduction-ref")) {
                introWeavingRule.addIntroductionRef(nestedElement.attributeValue("name"));
            }
        }
    }

    /**
     * Parses the nested <tt>advice-ref</tt> elements.
     *
     * @param adviceElement the root advice element
     * @param adviceWeavingRule the AdviceWeavingRule definition
     */
    private static void parseAdviceWeavingRuleNestedElements(
            final Element adviceElement,
            final AdviceWeavingRule adviceWeavingRule) {
        for (Iterator it = adviceElement.elementIterator(); it.hasNext();) {
            Element nestedElement = (Element)it.next();
            if (nestedElement.getName().trim().equals("advice-ref")) {
                adviceWeavingRule.addAdviceRef(nestedElement.attributeValue("name"));
            }
            else if (nestedElement.getName().trim().equals("advices-ref")) {
                adviceWeavingRule.addAdviceStackRef(nestedElement.attributeValue("name"));
            }
        }
    }

    /**
     * Parses the <tt>advices</tt> elements.
     *
     * @param root the root element
     * @param definition the definition object
     */
    private static void parseAdviceStackElements(final Element root,
                                                 final AspectWerkzDefinition definition) {
        for (Iterator it1 = root.elementIterator("advices-def"); it1.hasNext();) {
            final AdviceStackDefinition adviceStackDef = new AdviceStackDefinition();

            Element adviceStack = (Element)it1.next();
            for (Iterator it2 = adviceStack.attributeIterator(); it2.hasNext();) {
                Attribute attribute = (Attribute)it2.next();
                final String name = attribute.getName().trim();
                final String value = attribute.getValue().trim();
                if (name.equals("name")) {
                    adviceStackDef.setName(value);
                }
            }
            for (Iterator it2 = adviceStack.elementIterator(); it2.hasNext();) {
                Element nestedElement = (Element)it2.next();
                if (nestedElement.getName().trim().equals("advice-ref")) {
                    adviceStackDef.addAdvice(nestedElement.attributeValue("name"));
                }
            }
            definition.addAdviceStack(adviceStackDef);
        }
    }

    /**
     * Creates a method pattern and adds it to the pointcut definition.
     *
     * @param pattern the pattern
     * @param pointcutDef the pointcut definition
     * @param packageName the name of the package
     */
    private static void createMethodPattern(final String pattern,
                                            final PointcutDefinition pointcutDef,
                                            final String packageName) {
        int indexFirstSpace = pattern.indexOf(' ');
        String returnType = pattern.substring(0, indexFirstSpace + 1);
        String classNameWithMethodName = pattern.substring(
                indexFirstSpace, pattern.indexOf('(')).trim();
        String parameterTypes = pattern.substring(
                pattern.indexOf('('), pattern.length()).trim();
        int indexLastDot = classNameWithMethodName.lastIndexOf('.');

        final String methodPattern = classNameWithMethodName.substring(
                indexLastDot + 1, classNameWithMethodName.length()).trim();
        String classPattern = packageName + classNameWithMethodName.substring(0, indexLastDot);

        if (classPattern.endsWith("+")) {
            classPattern = classPattern.substring(0, classPattern.length() - 1);
            pointcutDef.markAsHierarchical();
        }

        StringBuffer buf = new StringBuffer();
        buf.append(returnType);
        buf.append(methodPattern);
        buf.append(parameterTypes);
        pointcutDef.setPattern(buf.toString());
        pointcutDef.setClassPattern(classPattern);
    }

    /**
     * Creates a field pattern and adds it to the pointcut definition.
     *
     * @param pattern the pattern
     * @param pointcutDef the pointcut definition
     * @param packageName the name of the package
     */
    private static void createFieldPattern(final String pattern,
                                           final PointcutDefinition pointcutDef,
                                           final String packageName) {
        int indexFirstSpace = pattern.indexOf(' ');
        String fieldType = pattern.substring(0, indexFirstSpace + 1);
        String classNameWithFieldName = pattern.substring(
                indexFirstSpace, pattern.length()).trim();
        int indexLastDot = classNameWithFieldName.lastIndexOf('.');

        final String fieldPattern = classNameWithFieldName.substring(
                indexLastDot + 1, classNameWithFieldName.length()).trim();
        String classPattern = packageName + classNameWithFieldName.substring(0, indexLastDot).trim();
        if (classPattern.endsWith("+")) {
            classPattern = classPattern.substring(0, classPattern.length() - 1);
            pointcutDef.markAsHierarchical();
        }

        StringBuffer buf = new StringBuffer();
        buf.append(fieldType);
        buf.append(fieldPattern);
        pointcutDef.setPattern(buf.toString());
        pointcutDef.setClassPattern(classPattern);
    }

    /**
     * Creates a throws pattern and adds it to the pointcut definition.
     *
     * @param pattern the pattern
     * @param pointcutDef the pointcut definition
     * @param packageName the name of the package
     */
    private static void createThrowsPattern(final String pattern,
                                            final PointcutDefinition pointcutDef,
                                            final String packageName) {
        String classAndMethodName = pattern.substring(0, pattern.indexOf('#')).trim();
        final String exceptionName = pattern.substring(pattern.indexOf('#') + 1).trim();
        int indexFirstSpace = classAndMethodName.indexOf(' ');
        final String returnType = classAndMethodName.substring(0, indexFirstSpace + 1);
        String classNameWithMethodName = classAndMethodName.substring(
                indexFirstSpace, classAndMethodName.indexOf('(')).trim();
        final String parameterTypes = classAndMethodName.substring(
                classAndMethodName.indexOf('('), classAndMethodName.length()).trim();
        int indexLastDot = classNameWithMethodName.lastIndexOf('.');
        final String methodPattern = classNameWithMethodName.substring(
                indexLastDot + 1, classNameWithMethodName.length()).trim();
        String classPattern = packageName + classNameWithMethodName.substring(0, indexLastDot);
        if (classPattern.endsWith("+")) {
            classPattern = classPattern.substring(0, classPattern.length() - 1);
            pointcutDef.markAsHierarchical();
        }

        StringBuffer buf = new StringBuffer();
        buf.append(returnType);
        buf.append(methodPattern);
        buf.append(parameterTypes);
        buf.append('#');
        buf.append(exceptionName);
        pointcutDef.setClassPattern(classPattern);
        pointcutDef.setPattern(buf.toString());
    }

    /**
     * Creates a caller side pattern and adds it to the pointcut definition.
     *
     * @param pattern the pattern
     * @param pointcutDef the pointcut definition
     * @param packageName the name of the package
     */
    private static void createCallerSidePattern(String pattern,
                                                final PointcutDefinition pointcutDef,
                                                final String packageName) {
        if (pattern.indexOf('>') == -1) {
            pattern = "*->" + pattern; // if no caller side pattern is specified => default to *
        }

        String callerClassPattern = packageName + pattern.substring(0, pattern.indexOf('-')).trim();
        if (callerClassPattern.endsWith("+")) {
            callerClassPattern = callerClassPattern.substring(0, callerClassPattern.length() - 1);
            pointcutDef.markAsHierarchical();
        }

        String calleePattern = pattern.substring(pattern.indexOf('>') + 1).trim();
        int indexFirstSpace = calleePattern.indexOf(' ');
        String returnType = calleePattern.substring(0, indexFirstSpace + 1);
        String classNameWithMethodName = calleePattern.substring(
                indexFirstSpace, calleePattern.indexOf('(')).trim();
        String parameterTypes = calleePattern.substring(
                calleePattern.indexOf('('), calleePattern.length()).trim();
        int indexLastDot = classNameWithMethodName.lastIndexOf('.');
        String calleeMethodPattern = classNameWithMethodName.substring(
                indexLastDot + 1, classNameWithMethodName.length()).trim();
        String calleeClassPattern = packageName + classNameWithMethodName.substring(0, indexLastDot);

        if (calleeClassPattern.endsWith("+")) {
            calleeClassPattern = calleeClassPattern.substring(0, calleeClassPattern.length() - 1);
            pointcutDef.markAsHierarchical();
        }
        calleeMethodPattern = returnType + calleeMethodPattern + parameterTypes;

        StringBuffer buf = new StringBuffer();
        buf.append(calleeClassPattern);
        buf.append('#');
        buf.append(calleeMethodPattern);
        pointcutDef.setPattern(buf.toString());
        pointcutDef.setClassPattern(callerClassPattern);
    }

    /**
     * Retrieves and returns the base package.
     *
     * @param root the root element
     * @return the base package
     */
    private static String getBasePackage(final Element root) {
        String basePackage = "";
        for (Iterator it2 = root.attributeIterator(); it2.hasNext();) {
            Attribute attribute = (Attribute)it2.next();
            if (attribute.getName().trim().equals("base-package")) {
                basePackage = attribute.getValue().trim();
                if (basePackage.endsWith(".*")) {
                    basePackage = basePackage.substring(0, basePackage.length() - 1);
                }
                else if (basePackage.endsWith(".")) {
                    ; // skip
                }
                else {
                    basePackage += ".";
                }
                break;
            }
            else {
                continue;
            }
        }
        return basePackage;
    }

    /**
     * Retrieves and returns the package.
     *
     * @param packageElement the package element
     * @return the package
     */
    private static String getPackage(final Element packageElement) {
        String packageName = "";
        for (Iterator it2 = packageElement.attributeIterator(); it2.hasNext();) {
            Attribute attribute = (Attribute)it2.next();
            if (attribute.getName().trim().equals("name")) {
                packageName = attribute.getValue().trim();
                if (packageName.endsWith(".*")) {
                    packageName = packageName.substring(0, packageName.length() - 1);
                }
                else if (packageName.endsWith(".")) {
                    ;// skip
                }
                else {
                    packageName += ".";
                }
                break;
            }
            else {
                continue;
            }
        }
        return packageName;
    }
}
TOP

Related Classes of org.codehaus.aspectwerkz.definition.XmlDefinitionParser

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.