diff options
author | jhugunin <jhugunin> | 2003-04-22 21:58:02 +0000 |
---|---|---|
committer | jhugunin <jhugunin> | 2003-04-22 21:58:02 +0000 |
commit | 6c9118bfa40d75467085d23a3b0d103199e137b2 (patch) | |
tree | 1ed9f725110d254582163a1eddcc54b60fb40bdc /tests/bugs/messyAround | |
parent | 0a8dbdeed13fe79ddfd7a291e2b45b50b9a90579 (diff) | |
download | aspectj-6c9118bfa40d75467085d23a3b0d103199e137b2.tar.gz aspectj-6c9118bfa40d75467085d23a3b0d103199e137b2.zip |
tests and fixes for
Bugzilla Bug 29665
Inconsistant stack height
Diffstat (limited to 'tests/bugs/messyAround')
-rw-r--r-- | tests/bugs/messyAround/DebugTrace.aj | 34 | ||||
-rw-r--r-- | tests/bugs/messyAround/aspects/Trace.aj | 490 | ||||
-rw-r--r-- | tests/bugs/messyAround/cap/OptionList.java | 138 |
3 files changed, 662 insertions, 0 deletions
diff --git a/tests/bugs/messyAround/DebugTrace.aj b/tests/bugs/messyAround/DebugTrace.aj new file mode 100644 index 000000000..7e8c55432 --- /dev/null +++ b/tests/bugs/messyAround/DebugTrace.aj @@ -0,0 +1,34 @@ +import aspects.*;
+//import org.apache.log4j.*;
+//import com.checkfree.common.util.*;
+import java.lang.reflect.*;
+import java.util.*;
+import org.aspectj.lang.reflect.*;
+/**
+* This concrete trace aspect specifies what we should trace.
+ */
+
+privileged aspect DebugTrace extends Trace
+
+{
+ declare precedence: DebugTrace, *;
+
+ //private static Logger _log = null;
+
+ static
+ {
+ //String log4jPath = GlobalPaths.getPath("properties_dir")+"log4j.properties";
+ //PropertyConfigurator.configure(log4jPath);
+ //_log = Logger.getLogger(TestLog.class);
+ }
+
+ /** define the pointcut for what we trace */
+ protected pointcut lexicalScope() :within(cap.OptionList);
+
+ protected void log(String data)
+ {
+ System.err.println("data: " + data);
+ //_log.debug(data);
+ }
+
+}
diff --git a/tests/bugs/messyAround/aspects/Trace.aj b/tests/bugs/messyAround/aspects/Trace.aj new file mode 100644 index 000000000..780ba6651 --- /dev/null +++ b/tests/bugs/messyAround/aspects/Trace.aj @@ -0,0 +1,490 @@ +package aspects;
+
+import java.io.*;
+import java.util.*;
+import org.aspectj.runtime.*;
+import org.aspectj.lang.*;
+import org.aspectj.lang.reflect.*;
+import java.lang.reflect.*;
+
+/** Trace is an aspect that traces execution through code.
+ *
+ */
+public abstract aspect Trace issingleton()
+{
+ // our internal instance
+ private static Trace _trace;
+
+ // Call depth on trace
+ private static final ThreadLocal traceDepths = new ThreadLocal();
+
+ // An object to synchronize on
+ protected static final Object lock = new Object();
+
+ private static final String NL = System.getProperty("line.separator");
+
+ // Space indentation increment
+ private static final int INDENT = 4;
+
+ // Used for indentation
+ private static final byte[] SPACES = new byte[100];
+
+ private static boolean traceActive = true;
+
+ static
+ {
+ Arrays.fill(SPACES,(byte)' ');
+ }
+
+
+ /** Trace constructor. Since this aspect is a singleton, we can be
+ * assured that only a single instance exists.
+ */
+ protected Trace() {_trace = this;}
+
+ /**
+ * This abstract pointcut indicates what classes we should trace. Typically
+ * you will define this using a within() PCD. We leave that up to concrete aspects.
+ */
+ protected abstract pointcut lexicalScope();
+
+ /**
+ * Common scope for all traces - includes lexicalScope
+ */
+ final pointcut scope() : if(_trace != null && _trace.canTraceJoinpoint(thisJoinPoint)) && lexicalScope() && !within(Trace+);
+
+ /**
+ * This pointcut designates tracing constructors within lexicalScope()
+ */
+ protected final pointcut constructorTrace() : scope() && (call( new(..) ) || execution( new(..)));
+ /**
+ * This pointcut designates tracing method executions within lexicalScope()
+ */
+ protected final pointcut methodTrace() : scope() && (call(* *(..)) || execution(* *(..)));
+
+ /**
+ * This pointcut designates tracing exception handlers within lexicalScope()
+ */
+ protected final pointcut handlerTrace(Exception e) : scope() && args(e) && handler(Exception+);
+
+
+ /**
+ * This pointcut picks out joinpoints within this aspect that implement
+ * the actual tracing. Since parameters and return values are printed
+ * out via implicit or explicit call to Object.toString(), there is the possibility
+ * of an execution joinpoint on toString() causing the trace logic
+ * to be re-entered. This is undesireable because it makes the trace output
+ * difficult to read and adds unecessary overhead. <p>
+ * This pointcut is used within a cflowbelow pointcut to prevent recursive
+ * trace calls.
+ */
+ private pointcut internalMethods() :
+ execution( void Trace.trace*(..,(JoinPoint||JoinPoint.StaticPart),..) );
+
+ /**
+ * For methods, we use around() advice to capture calls/executions.
+ */
+ Object around() : methodTrace() && !cflowbelow(internalMethods())
+ {
+ traceEnter(thisJoinPoint);
+ try
+ {
+ Object result = proceed();
+ traceResult(result,thisJoinPoint);
+ return result;
+ }
+ finally
+ {
+ traceExit(thisJoinPoint);
+ }
+ }
+
+ /**
+ * For Constructors, we use around() advice to capture calls/executions.
+ */
+ Object around() : constructorTrace() && !cflowbelow(internalMethods())
+ {
+ traceEnter(thisJoinPoint);
+ try
+ {
+ return proceed();
+ }
+ finally
+ {
+ traceExit(thisJoinPoint);
+ }
+ }
+
+
+ /**
+ * Trace Exceptions that may occur with constructors or methods
+ */
+ after() throwing(Throwable e): (constructorTrace() || methodTrace()) && !cflowbelow(internalMethods())
+ {
+ traceThrowable(e,thisJoinPoint);
+ }
+
+
+ /**
+ * Trace Exception handlers entry
+ */
+ before(Exception e) : handlerTrace(e) && !cflowbelow(internalMethods())
+ {
+ traceHandlerEntry(e,thisJoinPointStaticPart);
+ }
+ /**
+ * Trace Exception handlers exit
+ */
+ after(Exception e) : handlerTrace(e) && !cflowbelow(internalMethods())
+ {
+ traceHandlerExit();
+ }
+
+
+ /**
+ * Subaspects can override this method to log the data as needed. The default
+ * mechanism is to log to System.out
+ *
+ * Clients should be aware that this method is not synchronized.
+ */
+ protected void log(String data) {System.out.println(data);}
+
+ /**
+ * Can be overridden by subaspects to filter what constructors/methods should be
+ * traced at runtime. This method is always called prior to the log()
+ * method. The default always returns true.<p> Note that exceptions thrown
+ * by constructors/methods are filtered through this method.
+ * @param currentlyExecutingClass The Class that is currently executing.
+ * @param signature The signature of the member being traced
+ * @param traceType The type of trace entry (see AspectJ doc for the available types)
+ */
+ protected boolean isTraceable(Class currentlyExecutingClass, CodeSignature signature,String traceType) {return true;}
+
+ /**
+ * Can be overridden by subaspects to filter what exception handlers should be
+ * traced at runtime. This method is always called prior to the log()
+ * method. The default always returns false.<p>
+ * Note that exception handlers are catch(...){} blocks and are filtered
+ * independently from constructor/method calls and execution.
+ * @param currentlyExecutingClass The Class that is currently executing.
+ * @param signature The signature of the member being traced
+ */
+ protected boolean isTraceable(Class currentlyExecutingClass, CatchClauseSignature signature) {return false;}
+
+ /**
+ * Retrieves the signature of the joinpoint and asks if it can be traced
+ */
+ private boolean canTraceJoinpoint(JoinPoint jp)
+ {
+ if ( !traceActive ) return false;
+ final Signature sig = jp.getSignature();
+ final Object o = jp.getThis(); // current object
+ Class currentType;
+ if ( o == null ) // must be a static
+ currentType = jp.getStaticPart().getSourceLocation().getWithinType();
+ else
+ currentType = o.getClass();
+
+ // dispatch the correct filter method
+ if ( sig instanceof CodeSignature )
+ return isTraceable(currentType,(CodeSignature)sig,jp.getKind());
+ else
+ return isTraceable(currentType,(CatchClauseSignature)sig);
+ }
+
+
+ /**
+ * This method creates a trace entry line based on information in the
+ * supplied join point.
+ */
+ private void traceEnter(JoinPoint thisJoinPoint)
+ {
+
+ // Get the indent level (call depth for current thread * 4).
+ int depth = getTraceDepth(INDENT);
+
+ Class[] parameterTypes = ((CodeSignature)thisJoinPoint.getSignature()).getParameterTypes();
+ String[] parameterNames = ((CodeSignature)thisJoinPoint.getSignature()).getParameterNames();
+
+ boolean isCall = thisJoinPoint.getKind().endsWith("call");
+
+ StringBuffer enterPhrase = new StringBuffer(100);
+ enterPhrase.append(getSpaces(depth));
+ if ( isCall )
+ enterPhrase.append("Call ");
+ else
+ enterPhrase.append("Entering ");
+ enterPhrase.append(methodSignature(parameterNames,parameterTypes,thisJoinPoint));
+
+// if ( isCall )
+// enterPhrase.append(" From: ").append(thisJoinPoint.getSourceLocation().getWithinType());
+
+ // Prepare the methods parameter list
+ String parmStr = null;
+ Object[] parameters = thisJoinPoint.getArgs();
+ if (parameters.length > 0)
+ {
+ String spaces = getSpaces(depth + 6);
+ StringBuffer parms = new StringBuffer();
+ for (int i = 0; i < parameters.length; i++)
+ {
+ if (parameters[i] != null && parameters[i].getClass().isArray())
+ {
+ // arrays can be huge...limit to first 100 elements
+ final int len = Math.min(Array.getLength(parameters[i]),100);
+ if ( len == 0 )
+ {
+ parms.append(spaces);
+ parms.append(parameterNames[i]);
+ parms.append(": 0 length array");
+ parms.append(NL);
+ }
+ else
+ {
+ Object o = null;
+ for ( int x = 0; x < len; x++ )
+ {
+ parms.append(spaces);
+ parms.append(parameterNames[i]);
+ parms.append("[");
+ parms.append(x);
+ parms.append("]:");
+ o = Array.get(parameters[i],x);
+ try{parms.append(" " + (o != null?o:"null"));} // implicit toString()
+ catch(Throwable t) {parms.append(" " + parameters[i]);}
+ parms.append(NL);
+ }
+ }
+ }
+ else
+ {
+ // Not an array.
+ parms.append(spaces);
+ parms.append(parameterNames[i]);
+ parms.append(": ");
+ try
+ {
+ parms.append("" + parameters[i]);
+ }
+ catch (Throwable t ) {parms.append("" + parameters[i].getClass().getName());}
+ }
+
+ parmStr = parms.toString();
+
+ }
+
+ }
+
+ if (parmStr != null)
+ enterPhrase.append(NL).append(parmStr);
+ log(enterPhrase.toString());
+ }
+
+ /**
+ * This method creates an exception handler trace entry based on a Throwable
+ * and information contained in the join point.
+ */
+ private void traceHandlerEntry(Throwable t, JoinPoint.StaticPart thisJoinPoint)
+ {
+
+ int depth = getTraceDepth(INDENT);
+ String phrase = getSpaces(depth) +
+ "Exception caught at: " +
+ thisJoinPoint;
+ log(printStackTrace(phrase,t));
+
+ }
+ /**
+ * This method simply adjusts the trace depth - no other information printed.
+ */
+ private void traceHandlerExit()
+ {
+ getTraceDepth(-INDENT);
+ }
+ /**
+ * This method creates a stack trace entry based on a Throwable and
+ * information contained in the join point.
+ */
+ private void traceThrowable(Throwable t, JoinPoint thisJoinPoint)
+ {
+
+ int depth = getTraceDepth(0);
+ String phrase = getSpaces(depth+4) +
+ "Throwing Exception at: " +
+ thisJoinPoint;
+ log(printStackTrace(phrase,t));
+ }
+
+
+ private String printStackTrace(String phrase, Throwable t)
+ {
+ try {
+ StringWriter sw = new StringWriter(4096);
+ PrintWriter pw = new PrintWriter(sw,true);
+
+ pw.println(phrase);
+
+ pw.println();
+
+ pw.println("Exception Stack Trace:");
+
+ pw.println();
+
+ t.printStackTrace(pw);
+
+ pw.println();
+
+ pw.flush();
+ sw.flush();
+
+ pw.close();
+ sw.close();
+ return sw.toString();
+ }
+ catch(IOException IOE) {
+ log(IOE.toString());
+ return IOE.getMessage();
+ }
+ }
+
+ /**
+ * This method creates a trace exit entry based on the join point
+ * information.
+ */
+ private void traceExit(JoinPoint thisJoinPoint)
+ {
+
+ int depth = getTraceDepth(-INDENT);
+
+ // Assemble the method's signature.
+ Class[] parameterTypes = ((CodeSignature)thisJoinPoint.getSignature()).getParameterTypes();
+ String[] parameterNames = ((CodeSignature)thisJoinPoint.getSignature()).getParameterNames();
+
+ boolean isCall = thisJoinPoint.getKind().endsWith("call");
+
+ StringBuffer exitPhrase = new StringBuffer(100);
+ exitPhrase.append(getSpaces(depth));
+ if ( isCall )
+ exitPhrase.append("Return ");
+ else
+ exitPhrase.append("Exiting ");
+ exitPhrase.append(methodSignature(parameterNames,parameterTypes,thisJoinPoint)).append(NL);
+
+
+ log(exitPhrase.toString());
+
+ }
+
+ /**
+ * This method creates a trace result entry based on a result and the
+ * join point.
+ */
+ private void traceResult(Object thisResult, JoinPoint thisJoinPoint)
+ {
+
+ Class returnType = ((MethodSignature)thisJoinPoint.getSignature()).getReturnType();
+ if ( returnType.toString().equals("void") )
+ return;
+
+ int depth = getTraceDepth(0);
+ if ( thisResult == null )
+ thisResult = "null";
+
+ if ( thisResult.getClass().isArray() )
+ {
+ // arrays can be Oprah-sized - limit to 100 elements
+ final int len = Math.min(Array.getLength(thisResult),100);
+ StringBuffer buf = new StringBuffer();
+ if ( len == 0 )
+ buf.append(">>>zero-length array<<<");
+ else
+ {
+ Object o;
+ for ( int i = 0; i < len; i++ )
+ {
+ o = Array.get(thisResult,i);
+ buf.append("data[").append(i).append("] ");
+ try{buf.append(o != null?o:"null");} // implicit toString()
+ catch(Throwable t) {buf.append(thisResult);}
+ buf.append(NL);
+ }
+ }
+ thisResult = buf.toString();
+ }
+ thisResult = thisResult.toString();
+
+ StringBuffer returnPhrase = new StringBuffer(100);
+ returnPhrase.append(getSpaces(depth+2)).append(thisJoinPoint);
+ returnPhrase.append(" returned >>>>>>> ").append(thisResult);
+
+ log(returnPhrase.toString());
+ }
+
+ /**
+ * This method returns the current trace line indentation for the
+ * thread.
+ */
+ private int getTraceDepth(int incr)
+ {
+ int rc = 0;
+ Integer depth = (Integer) traceDepths.get();
+ if (depth == null)
+ {
+ if ( incr > 0 )
+ {
+ traceDepths.set(new Integer(incr));
+ return incr;
+ }
+ else return rc;
+ }
+
+ rc = depth.intValue();
+
+ if ( incr > 0 )
+ {
+ depth = new Integer(rc += incr);
+ traceDepths.set(depth);
+ }
+ else if ( incr < 0 )
+ {
+ depth = new Integer(rc + incr);
+ traceDepths.set(depth);
+ }
+
+ return rc;
+ }
+
+ /**
+ * This method returns a String containing the number of spaces desired to
+ * be used as padding for formatting trace log entries.
+ */
+ private String getSpaces(int num)
+ {
+ return new String(SPACES,0,Math.min(num,SPACES.length));
+ }
+
+ /**
+ * Create a method signature
+ */
+ private String methodSignature(String[] parameterNames,
+ Class[] parameterTypes,
+ JoinPoint thisJoinPoint)
+ {
+ // Assemble the method's signature.
+ StringBuffer signature = new StringBuffer("(");
+ for (int i = 0; i < parameterTypes.length; i++)
+ {
+ signature.append(parameterTypes[i].getName());
+ signature.append(" ");
+ signature.append(parameterNames[i]);
+ if (i < (parameterTypes.length-1))
+ signature.append(", ");
+ }
+ signature.append(")");
+
+ return thisJoinPoint.getSignature().getDeclaringType().getName() + "." +
+ thisJoinPoint.getSignature().getName() +
+ signature;
+ }
+
+}
\ No newline at end of file diff --git a/tests/bugs/messyAround/cap/OptionList.java b/tests/bugs/messyAround/cap/OptionList.java new file mode 100644 index 000000000..1e4a9349c --- /dev/null +++ b/tests/bugs/messyAround/cap/OptionList.java @@ -0,0 +1,138 @@ +package cap; + +import java.lang.reflect.*; +import java.util.*; +import java.net.*; +import java.text.*; + +/** + * This class builds a list of <option> HTML elements given a data object, + * typically a GAPI output object, and a list of accessor method names. + * <p> + * <b>Usage:</b><pre> + * // Create the bank account list select + * RBBankAcctList2Input acctIn = new RBBankAcctList2Input(); + * initApiHeader(acctIn.getHeader(),sessInfo); + * ArrayList accts = new ArrayList(); + * getBankAccounts(acctIn,accts); + * + * String ol = OptionList.createListHtmlFromApi(accts.toArray(), + * new String[]{"getBankAcctNbr","getBankRtgNbr","getBankAcctTyp"}, + * new String[]{"getBankAcctNbr"}, + * new MessageFormat("{0}"), + * Integer.parseInt(acctIndex)); + * + * </pre> + * @author Rich Price + */ +class OptionList +{ + private static final String OPTION_PATTERN = "<option value=\"{0}\" {1}>{2}</option>"; + private static final Object[] GETTER_ARGS = new Object[0]; + private static final Class[] GETTER_ARG_TYPES = new Class[0]; + private static final String DELIM = "&"; + + /** + * Parses the value string and returns a HashMap of name/value pairs + * @return A HashMap of name/value pairs. + * @see createListHtmlFromApi + */ + public static HashMap getSelectedValues(String optionListValueString) + { + HashMap map = new HashMap(); + if ( optionListValueString != null ) + { + StringTokenizer lex = new StringTokenizer(optionListValueString,DELIM + "=",false); + while ( lex.hasMoreTokens() ) + map.put(lex.nextToken(),lex.nextToken()); + } + return map; + } + + /** + * This method creates a String of HTML <option> elements in the following + * format:<p> + * <pre> + * <option value="valueName1=value1^valueName2=value2"> optionValues <option> + * </pre> + * @param api An array of Objects, typically a GAPI output object, from which data + * will be retrieved by name(s). + * @param valueNames An array of method names declared in <code>api</code>. Only + * public methods taking zero arguments can be used. Each non-null value + * is used to create a value string for the particular HTML option element in the form: + * valueName1=value1^valueName2=value2...where valueName[n] is the method name. + * For convenience, the getValues() method will return a HashMap of these name/value + * pairs. + * @param optionNames An array of method names declared in <code>api</code>. Only + * public methods taking zero arguments can be listed. Each non-null value + * is used to create a parameter list to pass to a supplied MessageFormat object. + * Each value retrieved from the api object will be substituted using the MessageFormat + * object, the resulting String is used to create the optionValues string that is + * displayed to the user. + * @param selectedIndex The index of the option that should be selected. If -1, nothing + * will be selected. + * + */ + public static String createListHtmlFromApi(Object[] api, + String[] valueNames, + String[] optionNames, + MessageFormat optionFormat, + int selectedIndex ) + { + StringBuffer html = new StringBuffer(); + for ( int apiIndex = 0; apiIndex < api.length; apiIndex++ ) + { + final String[] messageArgs = new String[3]; + // for each valueName, use reflection to look up data from the api + StringBuffer buf = new StringBuffer(); + for ( int i = 0; i < valueNames.length; i++ ) + { + try + { + Method m = api[apiIndex].getClass().getMethod(valueNames[i], GETTER_ARG_TYPES); + String value = m.invoke(api[apiIndex],GETTER_ARGS).toString(); + + if ( value != null && value.length() > 0 ) + { + if ( buf.length() > 0 ) + buf.append(DELIM); + buf.append(valueNames[i]).append("=").append(value); + } + } + catch (Exception e) {} + } + // set the first and second value arguments for the pattern + messageArgs[0] = buf.toString(); + if ( apiIndex == selectedIndex ) + messageArgs[1] = "selected"; + else + messageArgs[1] = ""; + + // now, handle the option part + buf.setLength(0); + String[] optionFormatArgs = new String[optionNames.length]; + for ( int i = 0; i < optionNames.length; i++ ) + { + try + { + optionFormatArgs[i] = ""; + Method m = api[apiIndex].getClass().getMethod(optionNames[i],GETTER_ARG_TYPES); + String value = m.invoke(api[apiIndex],GETTER_ARGS).toString(); + if ( value != null ) + optionFormatArgs[i] = value; + } + catch(Exception e) {} + } + + messageArgs[2] = optionFormat.format(optionFormatArgs,buf,new FieldPosition(0)).toString(); + html.append(MessageFormat.format(OPTION_PATTERN,messageArgs)); + } + return html.toString(); + } + + public static void main(String[] args) throws Exception + { + OptionList.createListHtmlFromApi(new Object[]{new String()},new String[]{"getFoo"},new String[]{"getFoo"},new MessageFormat("{0}"),-1); + } + +}
\ No newline at end of file |