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.cflow;
005:
006: import com.tc.aspectwerkz.aspect.AdviceType;
007: import com.tc.aspectwerkz.definition.AdviceDefinition;
008: import com.tc.aspectwerkz.definition.AspectDefinition;
009: import com.tc.aspectwerkz.definition.SystemDefinition;
010: import com.tc.aspectwerkz.reflect.impl.java.JavaClassInfo;
011: import com.tc.aspectwerkz.reflect.MethodInfo;
012: import com.tc.aspectwerkz.reflect.ClassInfo;
013: import com.tc.aspectwerkz.expression.ExpressionInfo;
014:
015: import java.util.List;
016: import java.util.ArrayList;
017:
018: /**
019: * A Cflow binding represents an extracted cflow or cflowbelow subexpression
020: * <p/>
021: * For a given pointcut "pcA and cflowA or cflowbelowB", we will extract two bindings.
022: * The m_cflowID must be unique on a per cflow sub expresion basis ie JVM wide.
023: * <p/>
024: * Note: CflowBinding hashcode depends on Cflow_ID (sub expr) + isCflowBelow only.
025: *
026: * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
027: */
028: public class CflowBinding {
029:
030: /**
031: * the base implementation that hosts the cflow advices
032: */
033: private final static ClassInfo ABSTRACT_CFLOWCLASS = JavaClassInfo
034: .getClassInfo(AbstractCflowSystemAspect.class);
035: private final static MethodInfo CFLOW_ENTER_ADVICE;
036: private final static MethodInfo CFLOW_EXIT_ADVICE;
037:
038: static {
039: MethodInfo enter = null;
040: MethodInfo exit = null;
041: for (int i = 0; i < ABSTRACT_CFLOWCLASS.getMethods().length; i++) {
042: MethodInfo methodInfo = ABSTRACT_CFLOWCLASS.getMethods()[i];
043: if (methodInfo.getName().equals("enter")) {
044: enter = methodInfo;
045: } else if (methodInfo.getName().equals("exit")) {
046: exit = methodInfo;
047: }
048: }
049: if (enter == null || exit == null) {
050: throw new Error("Could not gather cflow advices from "
051: + AbstractCflowSystemAspect.class);
052: } else {
053: CFLOW_ENTER_ADVICE = enter;
054: CFLOW_EXIT_ADVICE = exit;
055: }
056: }
057:
058: /**
059: * cflow unique id
060: */
061: private int m_cflowID;
062:
063: /**
064: * pointcut that represents this cflow sub-expression
065: */
066: private ExpressionInfo m_cflowSubExpression;
067:
068: /**
069: * pointcut that represents the containing expression
070: */
071: private ExpressionInfo m_outerExpression;
072:
073: /**
074: * marker if this binding is a cflow below, not used at the moment
075: */
076: private boolean m_isCflowBelow;
077:
078: /**
079: * Cosntructs a new cflow binding
080: *
081: * @param cflowID
082: * @param cflowSubExpression
083: * @param isCflowBelow
084: */
085: public CflowBinding(int cflowID, ExpressionInfo cflowSubExpression,
086: ExpressionInfo outerExpression, boolean isCflowBelow) {
087: m_cflowID = cflowID;
088: m_cflowSubExpression = cflowSubExpression;
089: m_outerExpression = outerExpression;
090: m_isCflowBelow = isCflowBelow;
091: }
092:
093: /**
094: * @return the sub expression
095: */
096: public ExpressionInfo getExpression() {
097: return m_cflowSubExpression;
098: }
099:
100: /**
101: * Extract the cflow bindings from any pointcut
102: * This includes both cflow and cflowbelow
103: *
104: * @param expressionInfo the pointcut expression frow where to extract the cflow bindings
105: * @return a list of CflowBinding, can be empty
106: */
107: public static List getCflowBindingsForCflowOf(
108: ExpressionInfo expressionInfo) {
109: List cflowBindings = new ArrayList();
110: if (expressionInfo != null) {
111: expressionInfo.getCflowAspectExpression()
112: .populateCflowAspectBindings(cflowBindings);
113: }
114: return cflowBindings;
115: }
116:
117: /**
118: * Create an aspect definition for this cflow binding in the given system.
119: * The cflow jit aspects will gets compiled and loaded
120: *
121: * @param systemDefinition
122: * @param loader
123: * @return the cflow aspect definition
124: */
125: public AspectDefinition getAspectDefinition(
126: SystemDefinition systemDefinition, ClassLoader loader) {
127: String aspectName = CflowCompiler
128: .getCflowAspectClassName(m_cflowID);
129:
130: // check if we have already register this aspect
131: // TODO: it may happen that the aspect gets register somewhere up in the hierarchy ??
132: // it is optim only
133:
134: // TODO: how to do this class define lazyly and not pass in a classloader ?
135: // could be done in the JIT jp clinit when 1+ advice has a cflow binding
136: Class aspectClass = CflowCompiler
137: .compileCflowAspectAndAttachToClassLoader(loader,
138: m_cflowID);
139: ClassInfo cflowAspectInfo = JavaClassInfo
140: .getClassInfo(aspectClass);
141:
142: AspectDefinition aspectDef = new AspectDefinition(aspectName
143: .replace('/', '.'), cflowAspectInfo, systemDefinition);
144: aspectDef.addBeforeAdviceDefinition(new AdviceDefinition(
145: CFLOW_ENTER_ADVICE.getName(), AdviceType.BEFORE, null,
146: aspectName, aspectName, m_cflowSubExpression,
147: CFLOW_ENTER_ADVICE, aspectDef));
148: aspectDef.addAfterAdviceDefinition(new AdviceDefinition(
149: CFLOW_EXIT_ADVICE.getName(), AdviceType.AFTER_FINALLY,
150: null, aspectName, aspectName, m_cflowSubExpression,
151: CFLOW_EXIT_ADVICE, aspectDef));
152:
153: return aspectDef;
154: }
155:
156: public boolean isCflowBelow() {
157: return m_isCflowBelow;
158: }
159:
160: public int getCflowID() {
161: return m_cflowID;
162: }
163:
164: public boolean equals(Object o) {
165: if (this == o)
166: return true;
167: if (!(o instanceof CflowBinding))
168: return false;
169:
170: final CflowBinding cflowBinding = (CflowBinding) o;
171:
172: if (m_cflowID != cflowBinding.m_cflowID)
173: return false;
174: if (m_isCflowBelow != cflowBinding.m_isCflowBelow)
175: return false;
176:
177: return true;
178: }
179:
180: public int hashCode() {
181: int result;
182: result = m_cflowID;
183: result = 29 * result + (m_isCflowBelow ? 1 : 0);
184: return result;
185: }
186: }
|