001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tc.aspectwerkz.definition.aspectj5;
005:
006: import org.xml.sax.Attributes;
007: import org.xml.sax.InputSource;
008: import org.xml.sax.SAXException;
009: import org.xml.sax.SAXParseException;
010: import org.xml.sax.XMLReader;
011: import org.xml.sax.helpers.DefaultHandler;
012: import org.xml.sax.helpers.XMLReaderFactory;
013:
014: import com.tc.aspectwerkz.util.Strings;
015:
016: import java.io.InputStream;
017: import java.net.URL;
018:
019: /**
020: * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
021: */
022: public class DocumentParser extends DefaultHandler {
023:
024: /**
025: * The current DTD public id. The matching dtd will be searched as a resource.
026: */
027: private final static String DTD_PUBLIC_ID = "-//AspectJ//DTD 1.5.0//EN";
028:
029: /**
030: * The DTD alias, for better user experience.
031: */
032: private final static String DTD_PUBLIC_ID_ALIAS = "-//AspectJ//DTD//EN";
033:
034: /**
035: * A handler to the DTD stream so that we are only using one file descriptor
036: */
037: private final static InputStream DTD_STREAM = DocumentParser.class
038: .getResourceAsStream("/aspectj_1_5_0.dtd");
039:
040: private final static String ASPECTJ_ELEMENT = "aspectj";
041: private final static String WEAVER_ELEMENT = "weaver";
042: private final static String DUMP_ELEMENT = "dump";
043: private final static String INCLUDE_ELEMENT = "include";
044: private final static String EXCLUDE_ELEMENT = "exclude";
045: private final static String OPTIONS_ATTRIBUTE = "options";
046: private final static String ASPECTS_ELEMENT = "aspects";
047: private final static String ASPECT_ELEMENT = "aspect";
048: private final static String CONCRETE_ASPECT_ELEMENT = "concrete-aspect";
049: private final static String NAME_ATTRIBUTE = "name";
050: private final static String EXTEND_ATTRIBUTE = "extends";
051: private final static String POINTCUT_ELEMENT = "pointcut";
052: private final static String WITHIN_ATTRIBUTE = "within";
053: private final static String EXPRESSION_ATTRIBUTE = "expression";
054:
055: private final Definition m_definition;
056:
057: private boolean m_inAspectJ;
058: private boolean m_inWeaver;
059: private boolean m_inAspects;
060:
061: private Definition.ConcreteAspect m_lastConcreteAspect;
062:
063: private DocumentParser() {
064: m_definition = new Definition();
065: }
066:
067: public static Definition parse(final URL url) throws Exception {
068: InputStream in = null;
069: try {
070: DocumentParser parser = new DocumentParser();
071: XMLReader xmlReader = XMLReaderFactory.createXMLReader();
072: xmlReader.setContentHandler(parser);
073: xmlReader.setErrorHandler(parser);
074:
075: try {
076: xmlReader
077: .setFeature(
078: "http://xml.org/sax/features/validation",
079: false);
080: } catch (SAXException e) {
081: // fine, the parser don't do validation
082: }
083: try {
084: xmlReader
085: .setFeature(
086: "http://xml.org/sax/features/external-general-entities",
087: false);
088: } catch (SAXException e) {
089: // fine, the parser don't do validation
090: }
091: try {
092: xmlReader
093: .setFeature(
094: "http://xml.org/sax/features/external-parameter-entities",
095: false);
096: } catch (SAXException e) {
097: // fine, the parser don't do validation
098: }
099:
100: xmlReader.setEntityResolver(parser);
101: in = url.openStream();
102: xmlReader.parse(new InputSource(in));
103: return parser.m_definition;
104: } finally {
105: try {
106: in.close();
107: } catch (Throwable t) {
108: // ignore
109: }
110: }
111: }
112:
113: public InputSource resolveEntity(String publicId, String systemId) {
114: if (publicId.equals(DTD_PUBLIC_ID)
115: || publicId.equals(DTD_PUBLIC_ID_ALIAS)) {
116: InputStream in = DTD_STREAM;
117: if (in == null) {
118: System.err
119: .println("AspectJ - WARN - could not read DTD "
120: + publicId);
121: return null;
122: } else {
123: return new InputSource(in);
124: }
125: } else {
126: System.err.println("AspectJ - WARN - unknown DTD "
127: + publicId + " - consider using " + DTD_PUBLIC_ID);
128: return null;
129: }
130: }
131:
132: public void startElement(String uri, String localName,
133: String qName, Attributes attributes) throws SAXException {
134: if (ASPECT_ELEMENT.equals(qName)) {
135: String name = attributes.getValue(NAME_ATTRIBUTE);
136: if (!isNull(name)) {
137: m_definition.getAspectClassNames().add(name);
138: }
139: } else if (WEAVER_ELEMENT.equals(qName)) {
140: String options = attributes.getValue(OPTIONS_ATTRIBUTE);
141: if (!isNull(options)) {
142: m_definition.appendWeaverOptions(options);
143: }
144: m_inWeaver = true;
145: } else if (CONCRETE_ASPECT_ELEMENT.equals(qName)) {
146: String name = attributes.getValue(NAME_ATTRIBUTE);
147: String extend = attributes.getValue(EXTEND_ATTRIBUTE);
148: if (!isNull(name) && !isNull(extend)) {
149: m_lastConcreteAspect = new Definition.ConcreteAspect(
150: name, extend);
151: m_definition.getConcreteAspects().add(
152: m_lastConcreteAspect);
153: }
154: } else if (POINTCUT_ELEMENT.equals(qName)
155: && m_lastConcreteAspect != null) {
156: String name = attributes.getValue(NAME_ATTRIBUTE);
157: String expression = attributes
158: .getValue(EXPRESSION_ATTRIBUTE);
159: if (!isNull(name) && !isNull(expression)) {
160: m_lastConcreteAspect.pointcuts
161: .add(new Definition.Pointcut(name,
162: replaceXmlAnd(expression)));
163: }
164: } else if (ASPECTJ_ELEMENT.equals(qName)) {
165: if (m_inAspectJ) {
166: throw new SAXException("Found nested <aspectj> element");
167: }
168: m_inAspectJ = true;
169: } else if (ASPECTS_ELEMENT.equals(qName)) {
170: m_inAspects = true;
171: } else if (INCLUDE_ELEMENT.equals(qName) && m_inWeaver) {
172: String typePattern = attributes.getValue(WITHIN_ATTRIBUTE);
173: if (!isNull(typePattern)) {
174: m_definition.getIncludePatterns().add(typePattern);
175: }
176: } else if (EXCLUDE_ELEMENT.equals(qName) && m_inWeaver) {
177: String typePattern = attributes.getValue(WITHIN_ATTRIBUTE);
178: if (!isNull(typePattern)) {
179: m_definition.getExcludePatterns().add(typePattern);
180: }
181: } else if (DUMP_ELEMENT.equals(qName) && m_inWeaver) {
182: String typePattern = attributes.getValue(WITHIN_ATTRIBUTE);
183: if (!isNull(typePattern)) {
184: m_definition.getDumpPatterns().add(typePattern);
185: }
186: } else if (EXCLUDE_ELEMENT.equals(qName) && m_inAspects) {
187: String typePattern = attributes.getValue(WITHIN_ATTRIBUTE);
188: if (!isNull(typePattern)) {
189: m_definition.getAspectExcludePatterns()
190: .add(typePattern);
191: }
192: } else {
193: throw new SAXException(
194: "Unknown element while parsing<aspectj> element: "
195: + qName);
196: }
197: super .startElement(uri, localName, qName, attributes);
198: }
199:
200: public void endElement(String uri, String localName, String qName)
201: throws SAXException {
202: if (CONCRETE_ASPECT_ELEMENT.equals(qName)) {
203: m_lastConcreteAspect = null;
204: } else if (ASPECTJ_ELEMENT.equals(qName)) {
205: m_inAspectJ = false;
206: } else if (WEAVER_ELEMENT.equals(qName)) {
207: m_inWeaver = false;
208: } else if (ASPECTS_ELEMENT.equals(qName)) {
209: m_inAspects = false;
210: }
211: super .endElement(uri, localName, qName);
212: }
213:
214: // TODO AV - define what we want for XML parser error - for now stderr
215: public void warning(SAXParseException e) throws SAXException {
216: super .warning(e);
217: }
218:
219: public void error(SAXParseException e) throws SAXException {
220: super .error(e);
221: }
222:
223: public void fatalError(SAXParseException e) throws SAXException {
224: super .fatalError(e);
225: }
226:
227: private static String replaceXmlAnd(String expression) {
228: // TODO AV do we need to handle "..)AND" or "AND(.." ?
229: return Strings.replaceSubString(expression, " AND ", " && ");
230: }
231:
232: private boolean isNull(String s) {
233: return s == null || s.length() <= 0;
234: }
235: }
|