001: /**************************************************************************************
002: * Copyright (c) Jonas BonŽr, Alexandre Vasseur. All rights reserved. *
003: * http://aspectwerkz.codehaus.org *
004: * ---------------------------------------------------------------------------------- *
005: * The software in this package is published under the terms of the LGPL license *
006: * a copy of which has been included with this distribution in the license.txt file. *
007: **************************************************************************************/package org.codehaus.aspectwerkz.definition;
008:
009: import org.codehaus.aspectwerkz.expression.ExpressionInfo;
010: import org.codehaus.aspectwerkz.expression.ExpressionNamespace;
011: import org.codehaus.aspectwerkz.expression.regexp.Pattern;
012: import org.codehaus.aspectwerkz.util.Strings;
013: import org.codehaus.aspectwerkz.aspect.AdviceType;
014: import org.codehaus.aspectwerkz.DeploymentModel;
015: import org.codehaus.aspectwerkz.reflect.MethodInfo;
016: import org.codehaus.aspectwerkz.reflect.ClassInfo;
017: import org.codehaus.aspectwerkz.exception.DefinitionException;
018:
019: import java.util.Iterator;
020: import java.util.Collection;
021:
022: /**
023: * Helper class for the attribute and the XML definition parsers.
024: *
025: * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
026: * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
027: */
028: public class DefinitionParserHelper {
029: public static final String EXPRESSION_PREFIX = "AW_";
030:
031: /**
032: * Creates and adds pointcut definition to aspect definition.
033: *
034: * @param name
035: * @param expression
036: * @param aspectDef
037: */
038: public static void createAndAddPointcutDefToAspectDef(
039: final String name, final String expression,
040: final AspectDefinition aspectDef) {
041: PointcutDefinition pointcutDef = new PointcutDefinition(
042: expression);
043: aspectDef.addPointcutDefinition(pointcutDef);
044:
045: // name can be the "pcName(paramType paramName)"
046: // extract the parameter name to type map
047: // and register the pointcut using its name
048: //TODO: support for same pc name and different signature
049: String pointcutName = name;
050: String pointcutCallSignature = null;
051: if (name.indexOf("(") > 0) {
052: pointcutName = name.substring(0, name.indexOf("("));
053: pointcutCallSignature = name.substring(
054: name.indexOf("(") + 1, name.lastIndexOf(")"));
055: }
056:
057: // do a lookup first to avoid infinite recursion when:
058: // <pointcut name="pc" ...> [will be registered as pc]
059: // <advice bind-to="pc" ...> [will be registered as pc and should not override previous one !]
060: ExpressionNamespace namespace = ExpressionNamespace
061: .getNamespace(aspectDef.getQualifiedName());
062: ExpressionInfo info = namespace
063: .getExpressionInfoOrNull(pointcutName);
064: if (info == null) {
065: info = new ExpressionInfo(expression, aspectDef
066: .getQualifiedName());
067: // extract the pointcut signature map
068: if (pointcutCallSignature != null) {
069: String[] parameters = Strings.splitString(
070: pointcutCallSignature, ",");
071: for (int i = 0; i < parameters.length; i++) {
072: String[] parameterInfo = Strings.splitString(
073: Strings.replaceSubString(parameters[i]
074: .trim(), " ", " "), " ");
075: info.addArgument(parameterInfo[1],
076: parameterInfo[0], aspectDef.getClassInfo()
077: .getClassLoader());
078: }
079: }
080: }
081: ExpressionNamespace.getNamespace(aspectDef.getQualifiedName())
082: .addExpressionInfo(pointcutName, info);
083: }
084:
085: /**
086: * Creates and adds a prepared pointcut definition to virtual aspect definition.
087: *
088: * @param name
089: * @param expression
090: * @param systemDef
091: */
092: public static void createAndAddDeploymentScopeDef(
093: final String name, final String expression,
094: final SystemDefinition systemDef) {
095: AspectDefinition aspectDef = systemDef
096: .getAspectDefinition(Virtual.class.getName());
097: aspectDef.addPointcutDefinition(new PointcutDefinition(
098: expression));
099: systemDef.addDeploymentScope(new DeploymentScope(name,
100: expression));
101: }
102:
103: /**
104: * Creates and adds an advisable definition to virtual aspect definition.
105: *
106: * @param expression
107: * @param systemDef
108: */
109: public static void createAndAddAdvisableDef(
110: final String expression, final SystemDefinition systemDef) {
111: AspectDefinition virtualAspectDef = systemDef
112: .getAspectDefinition(Virtual.class.getName());
113: virtualAspectDef.addPointcutDefinition(new PointcutDefinition(
114: expression));
115:
116: AdviceDefinition virtualAdviceDef = (AdviceDefinition) virtualAspectDef
117: .getBeforeAdviceDefinitions().get(0);
118: ExpressionInfo oldExpressionInfo = virtualAdviceDef
119: .getExpressionInfo();
120: String newExpression;
121: if (oldExpressionInfo != null) {
122: String oldExpression = oldExpressionInfo.toString();
123: newExpression = oldExpression + " || " + expression;
124: } else {
125: newExpression = expression;
126: }
127:
128: virtualAdviceDef.setExpressionInfo(new ExpressionInfo(
129: newExpression, virtualAspectDef.getQualifiedName()));
130: }
131:
132: /**
133: * Attaches all deployment scopes in a system to the virtual advice.
134: *
135: * @param systemDef the system definition
136: */
137: public static void attachDeploymentScopeDefsToVirtualAdvice(
138: final SystemDefinition systemDef) {
139: final AspectDefinition virtualAspectDef = systemDef
140: .getAspectDefinition(Virtual.class.getName());
141: final AdviceDefinition virtualAdviceDef = (AdviceDefinition) virtualAspectDef
142: .getBeforeAdviceDefinitions().get(0);
143:
144: final StringBuffer newExpression = new StringBuffer();
145: final ExpressionInfo oldExpressionInfo = virtualAdviceDef
146: .getExpressionInfo();
147: if (oldExpressionInfo != null) {
148: String oldExpression = oldExpressionInfo.toString();
149: newExpression.append(oldExpression);
150: }
151: final Collection deploymentScopes = systemDef
152: .getDeploymentScopes();
153: if (deploymentScopes.size() != 0 && oldExpressionInfo != null) {
154: newExpression.append(" || ");
155: }
156: for (Iterator it = deploymentScopes.iterator(); it.hasNext();) {
157: DeploymentScope deploymentScope = (DeploymentScope) it
158: .next();
159: newExpression.append(deploymentScope.getExpression());
160: if (it.hasNext()) {
161: newExpression.append(" || ");
162: }
163: }
164: if (newExpression.length() != 0) {
165: virtualAdviceDef.setExpressionInfo(new ExpressionInfo(
166: newExpression.toString(), virtualAspectDef
167: .getQualifiedName()));
168: }
169: }
170:
171: /**
172: * Creates and add mixin definition to system definition.
173: *
174: * @param mixinClassInfo
175: * @param expression
176: * @param deploymentModel
177: * @param isTransient
178: * @param systemDef
179: * @return the mixin definition
180: */
181: public static MixinDefinition createAndAddMixinDefToSystemDef(
182: final ClassInfo mixinClassInfo, final String expression,
183: final DeploymentModel deploymentModel,
184: final boolean isTransient, final SystemDefinition systemDef) {
185: final MixinDefinition mixinDef = createMixinDefinition(
186: mixinClassInfo, expression, deploymentModel,
187: isTransient, systemDef);
188:
189: // check doublons - TODO change ArrayList to HashMap since NAME is a key
190: MixinDefinition doublon = null;
191: for (Iterator intros = systemDef.getMixinDefinitions()
192: .iterator(); intros.hasNext();) {
193: MixinDefinition intro = (MixinDefinition) intros.next();
194: if (intro.getMixinImpl().getName().equals(
195: mixinDef.getMixinImpl().getName())) {
196: doublon = intro;
197: intro.addExpressionInfos(mixinDef.getExpressionInfos());
198: break;
199: }
200: }
201: if (doublon == null) {
202: systemDef.addMixinDefinition(mixinDef);
203: }
204: return mixinDef;
205: }
206:
207: /**
208: * Creates and add interface introduction definition to aspect definition.
209: *
210: * @param expression
211: * @param introductionName
212: * @param interfaceClassName
213: * @param aspectDef
214: */
215: public static void createAndAddInterfaceIntroductionDefToAspectDef(
216: final String expression, final String introductionName,
217: final String interfaceClassName,
218: final AspectDefinition aspectDef) {
219: // Introduction name is unique within an aspectDef only
220: InterfaceIntroductionDefinition introDef = createInterfaceIntroductionDefinition(
221: introductionName, expression, interfaceClassName,
222: aspectDef);
223: aspectDef.addInterfaceIntroductionDefinition(introDef);
224: }
225:
226: /**
227: * Creates a new advice definition.
228: *
229: * @param adviceName the advice name
230: * @param adviceType the advice type
231: * @param expression the advice expression
232: * @param specialArgumentType the arg
233: * @param aspectName the aspect name
234: * @param aspectClassName the aspect class name
235: * @param methodInfo the advice methodInfo
236: * @param aspectDef the aspect definition
237: * @return the new advice definition
238: */
239: public static AdviceDefinition createAdviceDefinition(
240: final String adviceName, final AdviceType adviceType,
241: final String expression, final String specialArgumentType,
242: final String aspectName, final String aspectClassName,
243: final MethodInfo methodInfo,
244: final AspectDefinition aspectDef) {
245: ExpressionInfo expressionInfo = new ExpressionInfo(expression,
246: aspectDef.getQualifiedName());
247:
248: // support for pointcut signature
249: String adviceCallSignature = null;
250: String resolvedSpecialArgumentType = specialArgumentType;
251: if (adviceName.indexOf('(') > 0) {
252: adviceCallSignature = adviceName.substring(adviceName
253: .indexOf('(') + 1, adviceName.lastIndexOf(')'));
254: String[] parameters = Strings.splitString(
255: adviceCallSignature, ",");
256: for (int i = 0; i < parameters.length; i++) {
257: String[] parameterInfo = Strings.splitString(Strings
258: .replaceSubString(parameters[i].trim(), " ",
259: " "), " ");
260: // Note: for XML defined aspect, we support anonymous parameters like
261: // advice(JoinPoint, Rtti) as well as abbreviations, so we have to assign
262: // them a name here, as well as their real type
263: String paramName, paramType = null;
264: if (parameterInfo.length == 2) {
265: paramName = parameterInfo[1];
266: paramType = parameterInfo[0];
267: } else {
268: paramName = "anonymous_" + i;
269: paramType = (String) Pattern.ABBREVIATIONS
270: .get(parameterInfo[0]);
271: }
272: // skip the parameter if this ones is a after returning / throwing binding
273: if (paramName.equals(specialArgumentType)) {
274: resolvedSpecialArgumentType = paramType;
275: expressionInfo.setSpecialArgumentName(paramName);
276: } else {
277: expressionInfo.addArgument(paramName, paramType,
278: aspectDef.getClassInfo().getClassLoader());
279: }
280: }
281: }
282:
283: // check that around advice return Object else the compiler will fail
284: if (adviceType.equals(AdviceType.AROUND)) {
285: if (!"java.lang.Object".equals(methodInfo.getReturnType()
286: .getName())) {
287: throw new DefinitionException(
288: "around advice must return java.lang.Object : "
289: + aspectClassName + "."
290: + methodInfo.getName());
291: }
292: }
293:
294: final AdviceDefinition adviceDef = new AdviceDefinition(
295: adviceName, adviceType, resolvedSpecialArgumentType,
296: aspectName, aspectClassName, expressionInfo,
297: methodInfo, aspectDef);
298: return adviceDef;
299: }
300:
301: /**
302: * Creates an introduction definition.
303: *
304: * @param mixinClassInfo
305: * @param expression
306: * @param deploymentModel
307: * @param isTransient
308: * @param systemDef
309: * @return
310: */
311: public static MixinDefinition createMixinDefinition(
312: final ClassInfo mixinClassInfo, final String expression,
313: final DeploymentModel deploymentModel,
314: final boolean isTransient, final SystemDefinition systemDef) {
315: final MixinDefinition mixinDef = new MixinDefinition(
316: mixinClassInfo, deploymentModel, isTransient, systemDef);
317: if (expression != null) {
318: ExpressionInfo expressionInfo = new ExpressionInfo(
319: expression, systemDef.getUuid());
320:
321: // auto-name the pointcut which is anonymous for introduction
322: ExpressionNamespace.getNamespace(systemDef.getUuid())
323: .addExpressionInfo(
324: EXPRESSION_PREFIX + expression.hashCode(),
325: expressionInfo);
326: mixinDef.addExpressionInfo(expressionInfo);
327: }
328: return mixinDef;
329: }
330:
331: /**
332: * Creates a new interface introduction definition.
333: *
334: * @param introductionName the introduction name
335: * @param expression the pointcut expression
336: * @param interfaceClassName the class name of the interface
337: * @param aspectDef the aspect definition
338: * @return the new introduction definition
339: */
340: public static InterfaceIntroductionDefinition createInterfaceIntroductionDefinition(
341: final String introductionName, final String expression,
342: final String interfaceClassName,
343: final AspectDefinition aspectDef) {
344: final InterfaceIntroductionDefinition introDef = new InterfaceIntroductionDefinition(
345: introductionName, interfaceClassName);
346: if (expression != null) {
347: ExpressionInfo expressionInfo = new ExpressionInfo(
348: expression, aspectDef.getQualifiedName());
349:
350: // auto-name the pointcut which is anonymous for introduction
351: ExpressionNamespace.getNamespace(
352: aspectDef.getQualifiedName()).addExpressionInfo(
353: EXPRESSION_PREFIX + expression.hashCode(),
354: expressionInfo);
355: introDef.addExpressionInfo(expressionInfo);
356: }
357: return introDef;
358: }
359:
360: }
|