@@ -0,0 +1,147 @@ | |||
<!--***************************************************************************************************************************** | |||
/******************************************************************************* | |||
* Copyright (c) 2005 Contributors. | |||
* All rights reserved. | |||
* This program and the accompanying materials are made available | |||
* under the terms of the Eclipse Public License v1.0 | |||
* which accompanies this distribution and is available at | |||
* http://eclipse.org/legal/epl-v10.html | |||
* | |||
* Contributors: | |||
* Alexandre Vasseur initial implementation | |||
*******************************************************************************/ | |||
AspectJ 5 DTD | |||
To use this DTD, start your defintion file with | |||
<!DOCTYPE aspectj PUBLIC | |||
"-//AspectJ//DTD 1.5.0//EN" | |||
"http://.../dtd/aspectj_1_5_0.dtd"> | |||
You can also use the "aliasing DTD" that matchs always the latest release of AspectJ | |||
<!DOCTYPE aspectj PUBLIC | |||
"-//AspectJ//DTD//EN" | |||
"http://.../dtd/aspectj.dtd"> | |||
To not use this DTD, start your definition file with | |||
<?xml version="1.0"?> | |||
******************************************************************************************************************************--> | |||
<!--***************************************************************************************************************************** | |||
aspectj | |||
********************************************************************************************************************************* | |||
[aspectj] defines the root element | |||
******************************************************************************************************************************--> | |||
<!ELEMENT aspectj ( | |||
weaver?, | |||
aspects? | |||
)> | |||
<!--***************************************************************************************************************************** | |||
weaver | |||
********************************************************************************************************************************* | |||
[weaver] defines the weaver configuration | |||
@options defines a command like line of option | |||
When multiple aspectj DD are found, the options are simply toggled | |||
TODO: Note: the scope of the options can be ClassLoader aware but should be assumed JVM wide | |||
******************************************************************************************************************************--> | |||
<!ELEMENT weaver ( | |||
(include | exclude | dump)* | |||
)> | |||
<!ATTLIST weaver | |||
options CDATA #IMPLIED | |||
> | |||
<!--***************************************************************************************************************************** | |||
include | |||
********************************************************************************************************************************* | |||
[include] narrows the scope of the weaver | |||
A class must be matched by ALL the include elements to be exposed to the weaver | |||
@within defines a type pattern | |||
(it is not a startWith) | |||
******************************************************************************************************************************--> | |||
<!ELEMENT include EMPTY> | |||
<!ATTLIST include | |||
within CDATA #REQUIRED | |||
> | |||
<!--***************************************************************************************************************************** | |||
exclude | |||
********************************************************************************************************************************* | |||
[exclude] narrows the scope of the weaver | |||
A class must be matched by NONE of the exclude elements to be exposed to the weaver | |||
@within defines a type pattern | |||
(it is not a startWith) | |||
TODO should it be called @from: "<exclude from=..> instead of <exclude within=..> | |||
TODO: AND must be written that way and not with the "&&" symbol. Thus NOT and OR exists as well. | |||
******************************************************************************************************************************--> | |||
<!ELEMENT exclude EMPTY> | |||
<!ATTLIST exclude | |||
within CDATA #REQUIRED | |||
> | |||
<!--***************************************************************************************************************************** | |||
dump | |||
********************************************************************************************************************************* | |||
[dump] control post-weaving dump to the "./_dump" folder (debugging purpose only) | |||
@within defines a type pattern | |||
(it is not a startWith) | |||
******************************************************************************************************************************--> | |||
<!ELEMENT dump EMPTY> | |||
<!ATTLIST dump | |||
within CDATA #REQUIRED | |||
> | |||
<!--***************************************************************************************************************************** | |||
aspects | |||
********************************************************************************************************************************* | |||
[aspects] defines a set of aspects | |||
Note: include only include among Union{aspect, concrete-aspect} WITHIN THIS SOLE aop.xml | |||
******************************************************************************************************************************--> | |||
<!ELEMENT aspects ( | |||
(aspect | exclude | include | concrete-aspect)* | |||
)> | |||
<!--***************************************************************************************************************************** | |||
aspect | |||
********************************************************************************************************************************* | |||
[aspect] defines an aspect to include | |||
@name FQN of the aspect, nested class must use $ | |||
******************************************************************************************************************************--> | |||
<!ELEMENT aspect EMPTY> | |||
<!ATTLIST aspect | |||
name CDATA #REQUIRED | |||
> | |||
<!--***************************************************************************************************************************** | |||
exclude | |||
********************************************************************************************************************************* | |||
[exclude] defines a set of aspect to exclude | |||
@within within pattern (even from other systems / parent classloader) | |||
SAME AS FOR weaver/exclude | |||
******************************************************************************************************************************--> | |||
<!--***************************************************************************************************************************** | |||
concrete-aspect | |||
********************************************************************************************************************************* | |||
[concrete-aspect] defines a concrete aspect from an abstract one | |||
@name FQN of the concrete aspect (use $ for nested class) [will be jit generated] | |||
@extends FQN of the abstract aspect (use $ for nested class) | |||
******************************************************************************************************************************--> | |||
<!ELEMENT concrete-aspect ( | |||
pointcut+ | |||
)> | |||
<!ATTLIST concrete-aspect | |||
name CDATA #REQUIRED | |||
extends CDATA #REQUIRED | |||
precedence CDATA #IMPLIED | |||
perclause CDATA #IMPLIED | |||
> | |||
<!--***************************************************************************************************************************** | |||
pointcut | |||
********************************************************************************************************************************* | |||
[pointcut] defines a concrete pointcut within a concrete aspect from an abstract one | |||
@name name of the abstract pointcut (method name, unique in aspect class hierarchy) | |||
@expression pointcut expression | |||
Note: for argument binding, the bounded arguments must be present and bounded: | |||
<pointcut name="myAdvice(int i)" expression="... AND args(i)"/> | |||
TODO: AND must be written that way and not with the "&&" symbol. Thus NOT and OR exists as well. | |||
******************************************************************************************************************************--> | |||
<!ELEMENT pointcut EMPTY> | |||
<!ATTLIST pointcut | |||
name CDATA #REQUIRED | |||
expression CDATA #REQUIRED | |||
> |
@@ -0,0 +1,147 @@ | |||
/******************************************************************************* | |||
* Copyright (c) 2005 Contributors. | |||
* All rights reserved. | |||
* This program and the accompanying materials are made available | |||
* under the terms of the Eclipse Public License v1.0 | |||
* which accompanies this distribution and is available at | |||
* http://eclipse.org/legal/epl-v10.html | |||
* | |||
* Contributors: | |||
* Alexandre Vasseur initial implementation | |||
*******************************************************************************/ | |||
package org.aspectj.weaver.loadtime.definition; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
/** | |||
* A POJO that contains raw strings from the XML (sort of XMLBean for our simple LTW DTD) | |||
* | |||
* @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a> | |||
*/ | |||
public class Definition { | |||
private final StringBuffer m_weaverOptions; | |||
private final List m_dumpPatterns; | |||
private boolean m_dumpBefore; | |||
private boolean perClassloaderDumpDir; | |||
private final List m_includePatterns; | |||
private final List m_excludePatterns; | |||
private final List m_aspectClassNames; | |||
private final List m_aspectExcludePatterns; | |||
private final List m_aspectIncludePatterns; | |||
private final List m_concreteAspects; | |||
public Definition() { | |||
m_weaverOptions = new StringBuffer(); | |||
m_dumpBefore = false; | |||
perClassloaderDumpDir = false; | |||
m_dumpPatterns = new ArrayList(0); | |||
m_includePatterns = new ArrayList(0); | |||
m_excludePatterns = new ArrayList(0); | |||
m_aspectClassNames = new ArrayList(); | |||
m_aspectExcludePatterns = new ArrayList(0); | |||
m_aspectIncludePatterns = new ArrayList(0); | |||
m_concreteAspects = new ArrayList(0); | |||
} | |||
public String getWeaverOptions() { | |||
return m_weaverOptions.toString(); | |||
} | |||
public List getDumpPatterns() { | |||
return m_dumpPatterns; | |||
} | |||
public void setDumpBefore(boolean b) { | |||
m_dumpBefore = b; | |||
} | |||
public boolean shouldDumpBefore() { | |||
return m_dumpBefore; | |||
} | |||
public void setCreateDumpDirPerClassloader(boolean b) { | |||
perClassloaderDumpDir = b; | |||
} | |||
public boolean createDumpDirPerClassloader() { | |||
return perClassloaderDumpDir; | |||
} | |||
public List getIncludePatterns() { | |||
return m_includePatterns; | |||
} | |||
public List getExcludePatterns() { | |||
return m_excludePatterns; | |||
} | |||
public List getAspectClassNames() { | |||
return m_aspectClassNames; | |||
} | |||
public List getAspectExcludePatterns() { | |||
return m_aspectExcludePatterns; | |||
} | |||
public List getAspectIncludePatterns() { | |||
return m_aspectIncludePatterns; | |||
} | |||
public List getConcreteAspects() { | |||
return m_concreteAspects; | |||
} | |||
public static class ConcreteAspect { | |||
public final String name; | |||
public final String extend; | |||
public final String precedence; | |||
public final List pointcuts; | |||
public final String perclause; | |||
public ConcreteAspect(String name, String extend) { | |||
this(name, extend, null, null); | |||
} | |||
public ConcreteAspect(String name, String extend, String precedence, String perclause) { | |||
this.name = name; | |||
// make sure extend set to null if "" | |||
if (extend == null || extend.length() == 0) { | |||
this.extend = null; | |||
if (precedence == null || precedence.length() == 0) { | |||
throw new RuntimeException("Not allowed"); | |||
} | |||
} else { | |||
this.extend = extend; | |||
} | |||
this.precedence = precedence; | |||
this.pointcuts = new ArrayList(); | |||
this.perclause = perclause; | |||
} | |||
} | |||
public static class Pointcut { | |||
public final String name; | |||
public final String expression; | |||
public Pointcut(String name, String expression) { | |||
this.name = name; | |||
this.expression = expression; | |||
} | |||
} | |||
public void appendWeaverOptions(String option) { | |||
m_weaverOptions.append(option.trim()).append(' '); | |||
} | |||
} |
@@ -0,0 +1,272 @@ | |||
/******************************************************************************* | |||
* Copyright (c) 2005 Contributors. | |||
* All rights reserved. | |||
* This program and the accompanying materials are made available | |||
* under the terms of the Eclipse Public License v1.0 | |||
* which accompanies this distribution and is available at | |||
* http://eclipse.org/legal/epl-v10.html | |||
* | |||
* Contributors: | |||
* Alexandre Vasseur initial implementation | |||
*******************************************************************************/ | |||
package org.aspectj.weaver.loadtime.definition; | |||
import java.io.InputStream; | |||
import java.net.URL; | |||
import javax.xml.parsers.ParserConfigurationException; | |||
import javax.xml.parsers.SAXParserFactory; | |||
import org.aspectj.util.LangUtil; | |||
import org.xml.sax.Attributes; | |||
import org.xml.sax.InputSource; | |||
import org.xml.sax.SAXException; | |||
import org.xml.sax.SAXParseException; | |||
import org.xml.sax.XMLReader; | |||
import org.xml.sax.helpers.DefaultHandler; | |||
import org.xml.sax.helpers.XMLReaderFactory; | |||
/** | |||
* FIXME AV - doc, concrete aspect | |||
* | |||
* @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a> | |||
*/ | |||
public class DocumentParser extends DefaultHandler { | |||
/** | |||
* The current DTD public id. The matching dtd will be searched as a resource. | |||
*/ | |||
private final static String DTD_PUBLIC_ID = "-//AspectJ//DTD 1.5.0//EN"; | |||
/** | |||
* The DTD alias, for better user experience. | |||
*/ | |||
private final static String DTD_PUBLIC_ID_ALIAS = "-//AspectJ//DTD//EN"; | |||
/** | |||
* A handler to the DTD stream so that we are only using one file descriptor | |||
*/ | |||
private final static InputStream DTD_STREAM = DocumentParser.class.getResourceAsStream("/aspectj_1_5_0.dtd"); | |||
private final static String ASPECTJ_ELEMENT = "aspectj"; | |||
private final static String WEAVER_ELEMENT = "weaver"; | |||
private final static String DUMP_ELEMENT = "dump"; | |||
private final static String DUMP_BEFOREANDAFTER_ATTRIBUTE = "beforeandafter"; | |||
private final static String DUMP_PERCLASSLOADERDIR_ATTRIBUTE = "perclassloaderdumpdir"; | |||
private final static String INCLUDE_ELEMENT = "include"; | |||
private final static String EXCLUDE_ELEMENT = "exclude"; | |||
private final static String OPTIONS_ATTRIBUTE = "options"; | |||
private final static String ASPECTS_ELEMENT = "aspects"; | |||
private final static String ASPECT_ELEMENT = "aspect"; | |||
private final static String CONCRETE_ASPECT_ELEMENT = "concrete-aspect"; | |||
private final static String NAME_ATTRIBUTE = "name"; | |||
private final static String EXTEND_ATTRIBUTE = "extends"; | |||
private final static String PRECEDENCE_ATTRIBUTE = "precedence"; | |||
private final static String PERCLAUSE_ATTRIBUTE = "perclause"; | |||
private final static String POINTCUT_ELEMENT = "pointcut"; | |||
private final static String WITHIN_ATTRIBUTE = "within"; | |||
private final static String EXPRESSION_ATTRIBUTE = "expression"; | |||
private final Definition m_definition; | |||
private boolean m_inAspectJ; | |||
private boolean m_inWeaver; | |||
private boolean m_inAspects; | |||
private Definition.ConcreteAspect m_lastConcreteAspect; | |||
private DocumentParser() { | |||
m_definition = new Definition(); | |||
} | |||
public static Definition parse(final URL url) throws Exception { | |||
InputStream in = null; | |||
try { | |||
DocumentParser parser = new DocumentParser(); | |||
XMLReader xmlReader = getXMLReader(); | |||
xmlReader.setContentHandler(parser); | |||
xmlReader.setErrorHandler(parser); | |||
try { | |||
xmlReader.setFeature("http://xml.org/sax/features/validation", false); | |||
} catch (SAXException e) { | |||
// fine, the parser don't do validation | |||
} | |||
try { | |||
xmlReader.setFeature("http://xml.org/sax/features/external-general-entities", false); | |||
} catch (SAXException e) { | |||
// fine, the parser don't do validation | |||
} | |||
try { | |||
xmlReader.setFeature("http://xml.org/sax/features/external-parameter-entities", false); | |||
} catch (SAXException e) { | |||
// fine, the parser don't do validation | |||
} | |||
xmlReader.setEntityResolver(parser); | |||
in = url.openStream(); | |||
xmlReader.parse(new InputSource(in)); | |||
return parser.m_definition; | |||
} finally { | |||
try { | |||
in.close(); | |||
} catch (Throwable t) { | |||
} | |||
} | |||
} | |||
private static XMLReader getXMLReader() throws SAXException, ParserConfigurationException { | |||
XMLReader xmlReader = null; | |||
/* Try this first for Java 5 */ | |||
try { | |||
xmlReader = XMLReaderFactory.createXMLReader(); | |||
} | |||
/* .. and ignore "System property ... not set" and then try this instead */ | |||
catch (SAXException ex) { | |||
xmlReader = SAXParserFactory.newInstance().newSAXParser().getXMLReader(); | |||
} | |||
return xmlReader; | |||
} | |||
public InputSource resolveEntity(String publicId, String systemId) throws SAXException { | |||
if (publicId.equals(DTD_PUBLIC_ID) || publicId.equals(DTD_PUBLIC_ID_ALIAS)) { | |||
InputStream in = DTD_STREAM; | |||
if (in == null) { | |||
System.err.println("AspectJ - WARN - could not read DTD " + publicId); | |||
return null; | |||
} else { | |||
return new InputSource(in); | |||
} | |||
} else { | |||
System.err.println("AspectJ - WARN - unknown DTD " + publicId + " - consider using " + DTD_PUBLIC_ID); | |||
return null; | |||
} | |||
} | |||
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { | |||
if (ASPECT_ELEMENT.equals(qName)) { | |||
String name = attributes.getValue(NAME_ATTRIBUTE); | |||
if (!isNull(name)) { | |||
m_definition.getAspectClassNames().add(name); | |||
} | |||
} else if (WEAVER_ELEMENT.equals(qName)) { | |||
String options = attributes.getValue(OPTIONS_ATTRIBUTE); | |||
if (!isNull(options)) { | |||
m_definition.appendWeaverOptions(options); | |||
} | |||
m_inWeaver = true; | |||
} else if (CONCRETE_ASPECT_ELEMENT.equals(qName)) { | |||
String name = attributes.getValue(NAME_ATTRIBUTE); | |||
String extend = attributes.getValue(EXTEND_ATTRIBUTE); | |||
String precedence = attributes.getValue(PRECEDENCE_ATTRIBUTE); | |||
String perclause = attributes.getValue(PERCLAUSE_ATTRIBUTE); | |||
if (!isNull(name)) { | |||
m_lastConcreteAspect = new Definition.ConcreteAspect(name, extend, precedence, perclause); | |||
// if (isNull(precedence) && !isNull(extend)) {// if no precedence, then extends must be there | |||
// m_lastConcreteAspect = new Definition.ConcreteAspect(name, extend); | |||
// } else if (!isNull(precedence)) { | |||
// // wether a pure precedence def, or an extendsANDprecedence def. | |||
// m_lastConcreteAspect = new Definition.ConcreteAspect(name, extend, precedence, perclause); | |||
// } | |||
m_definition.getConcreteAspects().add(m_lastConcreteAspect); | |||
} | |||
} else if (POINTCUT_ELEMENT.equals(qName) && m_lastConcreteAspect != null) { | |||
String name = attributes.getValue(NAME_ATTRIBUTE); | |||
String expression = attributes.getValue(EXPRESSION_ATTRIBUTE); | |||
if (!isNull(name) && !isNull(expression)) { | |||
m_lastConcreteAspect.pointcuts.add(new Definition.Pointcut(name, replaceXmlAnd(expression))); | |||
} | |||
} else if (ASPECTJ_ELEMENT.equals(qName)) { | |||
if (m_inAspectJ) { | |||
throw new SAXException("Found nested <aspectj> element"); | |||
} | |||
m_inAspectJ = true; | |||
} else if (ASPECTS_ELEMENT.equals(qName)) { | |||
m_inAspects = true; | |||
} else if (INCLUDE_ELEMENT.equals(qName) && m_inWeaver) { | |||
String typePattern = getWithinAttribute(attributes); | |||
if (!isNull(typePattern)) { | |||
m_definition.getIncludePatterns().add(typePattern); | |||
} | |||
} else if (EXCLUDE_ELEMENT.equals(qName) && m_inWeaver) { | |||
String typePattern = getWithinAttribute(attributes); | |||
if (!isNull(typePattern)) { | |||
m_definition.getExcludePatterns().add(typePattern); | |||
} | |||
} else if (DUMP_ELEMENT.equals(qName) && m_inWeaver) { | |||
String typePattern = getWithinAttribute(attributes); | |||
if (!isNull(typePattern)) { | |||
m_definition.getDumpPatterns().add(typePattern); | |||
} | |||
String beforeAndAfter = attributes.getValue(DUMP_BEFOREANDAFTER_ATTRIBUTE); | |||
if (isTrue(beforeAndAfter)) { | |||
m_definition.setDumpBefore(true); | |||
} | |||
String perWeaverDumpDir = attributes.getValue(DUMP_PERCLASSLOADERDIR_ATTRIBUTE); | |||
if (isTrue(perWeaverDumpDir)) { | |||
m_definition.setCreateDumpDirPerClassloader(true); | |||
} | |||
} else if (EXCLUDE_ELEMENT.equals(qName) && m_inAspects) { | |||
String typePattern = getWithinAttribute(attributes); | |||
if (!isNull(typePattern)) { | |||
m_definition.getAspectExcludePatterns().add(typePattern); | |||
} | |||
} else if (INCLUDE_ELEMENT.equals(qName) && m_inAspects) { | |||
String typePattern = getWithinAttribute(attributes); | |||
if (!isNull(typePattern)) { | |||
m_definition.getAspectIncludePatterns().add(typePattern); | |||
} | |||
} else { | |||
throw new SAXException("Unknown element while parsing <aspectj> element: " + qName); | |||
} | |||
super.startElement(uri, localName, qName, attributes); | |||
} | |||
private String getWithinAttribute(Attributes attributes) { | |||
return replaceXmlAnd(attributes.getValue(WITHIN_ATTRIBUTE)); | |||
} | |||
public void endElement(String uri, String localName, String qName) throws SAXException { | |||
if (CONCRETE_ASPECT_ELEMENT.equals(qName)) { | |||
m_lastConcreteAspect = null; | |||
} else if (ASPECTJ_ELEMENT.equals(qName)) { | |||
m_inAspectJ = false; | |||
} else if (WEAVER_ELEMENT.equals(qName)) { | |||
m_inWeaver = false; | |||
} else if (ASPECTS_ELEMENT.equals(qName)) { | |||
m_inAspects = false; | |||
} | |||
super.endElement(uri, localName, qName); | |||
} | |||
// TODO AV - define what we want for XML parser error - for now stderr | |||
public void warning(SAXParseException e) throws SAXException { | |||
super.warning(e); | |||
} | |||
public void error(SAXParseException e) throws SAXException { | |||
super.error(e); | |||
} | |||
public void fatalError(SAXParseException e) throws SAXException { | |||
super.fatalError(e); | |||
} | |||
private static String replaceXmlAnd(String expression) { | |||
// TODO AV do we need to handle "..)AND" or "AND(.." ? | |||
return LangUtil.replace(expression, " AND ", " && "); | |||
} | |||
private boolean isNull(String s) { | |||
return (s == null || s.length() <= 0); | |||
} | |||
private boolean isTrue(String s) { | |||
return (s != null && s.equals("true")); | |||
} | |||
} |