--- /dev/null
+package aspects;\r
+\r
+import java.io.*;\r
+import java.util.*;\r
+import org.aspectj.runtime.*;\r
+import org.aspectj.lang.*;\r
+import org.aspectj.lang.reflect.*;\r
+import java.lang.reflect.*;\r
+\r
+/** Trace is an aspect that traces execution through code. \r
+ * \r
+ */\r
+public abstract aspect Trace issingleton()\r
+{ \r
+ // our internal instance\r
+ private static Trace _trace;\r
+ \r
+ // Call depth on trace\r
+ private static final ThreadLocal traceDepths = new ThreadLocal();\r
+\r
+ // An object to synchronize on\r
+ protected static final Object lock = new Object();\r
+\r
+ private static final String NL = System.getProperty("line.separator");\r
+ \r
+ // Space indentation increment\r
+ private static final int INDENT = 4;\r
+\r
+ // Used for indentation\r
+ private static final byte[] SPACES = new byte[100];\r
+ \r
+ private static boolean traceActive = true;\r
+\r
+ static\r
+ {\r
+ Arrays.fill(SPACES,(byte)' ');\r
+ }\r
+\r
+ \r
+ /** Trace constructor. Since this aspect is a singleton, we can be\r
+ * assured that only a single instance exists. \r
+ */\r
+ protected Trace() {_trace = this;}\r
+ \r
+ /**\r
+ * This abstract pointcut indicates what classes we should trace. Typically\r
+ * you will define this using a within() PCD. We leave that up to concrete aspects.\r
+ */\r
+ protected abstract pointcut lexicalScope();\r
+ \r
+ /**\r
+ * Common scope for all traces - includes lexicalScope\r
+ */\r
+ final pointcut scope() : if(_trace != null && _trace.canTraceJoinpoint(thisJoinPoint)) && lexicalScope() && !within(Trace+);\r
+\r
+ /**\r
+ * This pointcut designates tracing constructors within lexicalScope()\r
+ */\r
+ protected final pointcut constructorTrace() : scope() && (call( new(..) ) || execution( new(..)));\r
+ /**\r
+ * This pointcut designates tracing method executions within lexicalScope()\r
+ */\r
+ protected final pointcut methodTrace() : scope() && (call(* *(..)) || execution(* *(..)));\r
+\r
+ /**\r
+ * This pointcut designates tracing exception handlers within lexicalScope()\r
+ */\r
+ protected final pointcut handlerTrace(Exception e) : scope() && args(e) && handler(Exception+);\r
+\r
+\r
+ /**\r
+ * This pointcut picks out joinpoints within this aspect that implement\r
+ * the actual tracing. Since parameters and return values are printed\r
+ * out via implicit or explicit call to Object.toString(), there is the possibility\r
+ * of an execution joinpoint on toString() causing the trace logic\r
+ * to be re-entered. This is undesireable because it makes the trace output\r
+ * difficult to read and adds unecessary overhead. <p>\r
+ * This pointcut is used within a cflowbelow pointcut to prevent recursive\r
+ * trace calls.\r
+ */\r
+ private pointcut internalMethods() : \r
+ execution( void Trace.trace*(..,(JoinPoint||JoinPoint.StaticPart),..) );\r
+\r
+ /**\r
+ * For methods, we use around() advice to capture calls/executions.\r
+ */\r
+ Object around() : methodTrace() && !cflowbelow(internalMethods())\r
+ {\r
+ traceEnter(thisJoinPoint); \r
+ try\r
+ {\r
+ Object result = proceed();\r
+ traceResult(result,thisJoinPoint);\r
+ return result;\r
+ }\r
+ finally\r
+ {\r
+ traceExit(thisJoinPoint);\r
+ }\r
+ }\r
+ \r
+ /**\r
+ * For Constructors, we use around() advice to capture calls/executions.\r
+ */\r
+ Object around() : constructorTrace() && !cflowbelow(internalMethods())\r
+ {\r
+ traceEnter(thisJoinPoint); \r
+ try\r
+ {\r
+ return proceed();\r
+ }\r
+ finally\r
+ {\r
+ traceExit(thisJoinPoint);\r
+ }\r
+ }\r
+ \r
+\r
+ /**\r
+ * Trace Exceptions that may occur with constructors or methods\r
+ */\r
+ after() throwing(Throwable e): (constructorTrace() || methodTrace()) && !cflowbelow(internalMethods())\r
+ { \r
+ traceThrowable(e,thisJoinPoint);\r
+ }\r
+\r
+\r
+ /**\r
+ * Trace Exception handlers entry\r
+ */ \r
+ before(Exception e) : handlerTrace(e) && !cflowbelow(internalMethods())\r
+ {\r
+ traceHandlerEntry(e,thisJoinPointStaticPart);\r
+ }\r
+ /**\r
+ * Trace Exception handlers exit\r
+ */\r
+ after(Exception e) : handlerTrace(e) && !cflowbelow(internalMethods())\r
+ {\r
+ traceHandlerExit();\r
+ }\r
+\r
+\r
+ /**\r
+ * Subaspects can override this method to log the data as needed. The default\r
+ * mechanism is to log to System.out\r
+ * \r
+ * Clients should be aware that this method is not synchronized.\r
+ */\r
+ protected void log(String data) {System.out.println(data);}\r
+ \r
+ /**\r
+ * Can be overridden by subaspects to filter what constructors/methods should be \r
+ * traced at runtime. This method is always called prior to the log()\r
+ * method. The default always returns true.<p> Note that exceptions thrown\r
+ * by constructors/methods are filtered through this method.\r
+ * @param currentlyExecutingClass The Class that is currently executing.\r
+ * @param signature The signature of the member being traced\r
+ * @param traceType The type of trace entry (see AspectJ doc for the available types)\r
+ */\r
+ protected boolean isTraceable(Class currentlyExecutingClass, CodeSignature signature,String traceType) {return true;}\r
+\r
+ /**\r
+ * Can be overridden by subaspects to filter what exception handlers should be \r
+ * traced at runtime. This method is always called prior to the log()\r
+ * method. The default always returns false.<p>\r
+ * Note that exception handlers are catch(...){} blocks and are filtered\r
+ * independently from constructor/method calls and execution.\r
+ * @param currentlyExecutingClass The Class that is currently executing.\r
+ * @param signature The signature of the member being traced\r
+ */\r
+ protected boolean isTraceable(Class currentlyExecutingClass, CatchClauseSignature signature) {return false;}\r
+ \r
+ /**\r
+ * Retrieves the signature of the joinpoint and asks if it can be traced\r
+ */\r
+ private boolean canTraceJoinpoint(JoinPoint jp)\r
+ {\r
+ if ( !traceActive ) return false;\r
+ final Signature sig = jp.getSignature();\r
+ final Object o = jp.getThis(); // current object\r
+ Class currentType;\r
+ if ( o == null ) // must be a static\r
+ currentType = jp.getStaticPart().getSourceLocation().getWithinType();\r
+ else\r
+ currentType = o.getClass();\r
+ \r
+ // dispatch the correct filter method\r
+ if ( sig instanceof CodeSignature ) \r
+ return isTraceable(currentType,(CodeSignature)sig,jp.getKind());\r
+ else\r
+ return isTraceable(currentType,(CatchClauseSignature)sig); \r
+ }\r
+ \r
+\r
+ /**\r
+ * This method creates a trace entry line based on information in the\r
+ * supplied join point.\r
+ */\r
+ private void traceEnter(JoinPoint thisJoinPoint)\r
+ { \r
+ \r
+ // Get the indent level (call depth for current thread * 4).\r
+ int depth = getTraceDepth(INDENT);\r
+ \r
+ Class[] parameterTypes = ((CodeSignature)thisJoinPoint.getSignature()).getParameterTypes();\r
+ String[] parameterNames = ((CodeSignature)thisJoinPoint.getSignature()).getParameterNames();\r
+ \r
+ boolean isCall = thisJoinPoint.getKind().endsWith("call");\r
+\r
+ StringBuffer enterPhrase = new StringBuffer(100);\r
+ enterPhrase.append(getSpaces(depth));\r
+ if ( isCall )\r
+ enterPhrase.append("Call ");\r
+ else\r
+ enterPhrase.append("Entering ");\r
+ enterPhrase.append(methodSignature(parameterNames,parameterTypes,thisJoinPoint));\r
+ \r
+// if ( isCall )\r
+// enterPhrase.append(" From: ").append(thisJoinPoint.getSourceLocation().getWithinType());\r
+\r
+ // Prepare the methods parameter list\r
+ String parmStr = null;\r
+ Object[] parameters = thisJoinPoint.getArgs();\r
+ if (parameters.length > 0)\r
+ {\r
+ String spaces = getSpaces(depth + 6);\r
+ StringBuffer parms = new StringBuffer();\r
+ for (int i = 0; i < parameters.length; i++)\r
+ {\r
+ if (parameters[i] != null && parameters[i].getClass().isArray())\r
+ {\r
+ // arrays can be huge...limit to first 100 elements\r
+ final int len = Math.min(Array.getLength(parameters[i]),100);\r
+ if ( len == 0 )\r
+ {\r
+ parms.append(spaces);\r
+ parms.append(parameterNames[i]);\r
+ parms.append(": 0 length array");\r
+ parms.append(NL);\r
+ }\r
+ else\r
+ {\r
+ Object o = null;\r
+ for ( int x = 0; x < len; x++ )\r
+ {\r
+ parms.append(spaces);\r
+ parms.append(parameterNames[i]);\r
+ parms.append("[");\r
+ parms.append(x);\r
+ parms.append("]:");\r
+ o = Array.get(parameters[i],x);\r
+ try{parms.append(" " + (o != null?o:"null"));} // implicit toString()\r
+ catch(Throwable t) {parms.append(" " + parameters[i]);}\r
+ parms.append(NL); \r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ // Not an array.\r
+ parms.append(spaces);\r
+ parms.append(parameterNames[i]);\r
+ parms.append(": ");\r
+ try\r
+ {\r
+ parms.append("" + parameters[i]);\r
+ }\r
+ catch (Throwable t ) {parms.append("" + parameters[i].getClass().getName());}\r
+ }\r
+\r
+ parmStr = parms.toString();\r
+\r
+ }\r
+\r
+ }\r
+\r
+ if (parmStr != null)\r
+ enterPhrase.append(NL).append(parmStr);\r
+ log(enterPhrase.toString());\r
+ }\r
+\r
+ /**\r
+ * This method creates an exception handler trace entry based on a Throwable\r
+ * and information contained in the join point.\r
+ */\r
+ private void traceHandlerEntry(Throwable t, JoinPoint.StaticPart thisJoinPoint)\r
+ {\r
+\r
+ int depth = getTraceDepth(INDENT);\r
+ String phrase = getSpaces(depth) +\r
+ "Exception caught at: " +\r
+ thisJoinPoint;\r
+ log(printStackTrace(phrase,t));\r
+\r
+ }\r
+ /**\r
+ * This method simply adjusts the trace depth - no other information printed.\r
+ */\r
+ private void traceHandlerExit()\r
+ {\r
+ getTraceDepth(-INDENT);\r
+ }\r
+ /**\r
+ * This method creates a stack trace entry based on a Throwable and\r
+ * information contained in the join point.\r
+ */\r
+ private void traceThrowable(Throwable t, JoinPoint thisJoinPoint)\r
+ {\r
+\r
+ int depth = getTraceDepth(0);\r
+ String phrase = getSpaces(depth+4) +\r
+ "Throwing Exception at: " +\r
+ thisJoinPoint;\r
+ log(printStackTrace(phrase,t));\r
+ }\r
+\r
+\r
+ private String printStackTrace(String phrase, Throwable t)\r
+ {\r
+ try {\r
+ StringWriter sw = new StringWriter(4096);\r
+ PrintWriter pw = new PrintWriter(sw,true);\r
+\r
+ pw.println(phrase);\r
+\r
+ pw.println();\r
+\r
+ pw.println("Exception Stack Trace:");\r
+\r
+ pw.println();\r
+\r
+ t.printStackTrace(pw);\r
+\r
+ pw.println();\r
+\r
+ pw.flush();\r
+ sw.flush();\r
+\r
+ pw.close();\r
+ sw.close();\r
+ return sw.toString();\r
+ }\r
+ catch(IOException IOE) {\r
+ log(IOE.toString());\r
+ return IOE.getMessage();\r
+ }\r
+ }\r
+\r
+ /**\r
+ * This method creates a trace exit entry based on the join point\r
+ * information.\r
+ */\r
+ private void traceExit(JoinPoint thisJoinPoint)\r
+ {\r
+\r
+ int depth = getTraceDepth(-INDENT);\r
+\r
+ // Assemble the method's signature.\r
+ Class[] parameterTypes = ((CodeSignature)thisJoinPoint.getSignature()).getParameterTypes();\r
+ String[] parameterNames = ((CodeSignature)thisJoinPoint.getSignature()).getParameterNames();\r
+\r
+ boolean isCall = thisJoinPoint.getKind().endsWith("call");\r
+\r
+ StringBuffer exitPhrase = new StringBuffer(100);\r
+ exitPhrase.append(getSpaces(depth));\r
+ if ( isCall )\r
+ exitPhrase.append("Return ");\r
+ else\r
+ exitPhrase.append("Exiting ");\r
+ exitPhrase.append(methodSignature(parameterNames,parameterTypes,thisJoinPoint)).append(NL);\r
+ \r
+\r
+ log(exitPhrase.toString());\r
+\r
+ }\r
+\r
+ /**\r
+ * This method creates a trace result entry based on a result and the\r
+ * join point.\r
+ */\r
+ private void traceResult(Object thisResult, JoinPoint thisJoinPoint)\r
+ {\r
+\r
+ Class returnType = ((MethodSignature)thisJoinPoint.getSignature()).getReturnType();\r
+ if ( returnType.toString().equals("void") )\r
+ return;\r
+\r
+ int depth = getTraceDepth(0);\r
+ if ( thisResult == null )\r
+ thisResult = "null";\r
+\r
+ if ( thisResult.getClass().isArray() )\r
+ {\r
+ // arrays can be Oprah-sized - limit to 100 elements\r
+ final int len = Math.min(Array.getLength(thisResult),100);\r
+ StringBuffer buf = new StringBuffer();\r
+ if ( len == 0 )\r
+ buf.append(">>>zero-length array<<<");\r
+ else\r
+ {\r
+ Object o;\r
+ for ( int i = 0; i < len; i++ )\r
+ {\r
+ o = Array.get(thisResult,i);\r
+ buf.append("data[").append(i).append("] ");\r
+ try{buf.append(o != null?o:"null");} // implicit toString() \r
+ catch(Throwable t) {buf.append(thisResult);}\r
+ buf.append(NL);\r
+ }\r
+ }\r
+ thisResult = buf.toString(); \r
+ }\r
+ thisResult = thisResult.toString();\r
+ \r
+ StringBuffer returnPhrase = new StringBuffer(100);\r
+ returnPhrase.append(getSpaces(depth+2)).append(thisJoinPoint);\r
+ returnPhrase.append(" returned >>>>>>> ").append(thisResult);\r
+\r
+ log(returnPhrase.toString());\r
+ }\r
+\r
+ /**\r
+ * This method returns the current trace line indentation for the\r
+ * thread.\r
+ */\r
+ private int getTraceDepth(int incr)\r
+ {\r
+ int rc = 0;\r
+ Integer depth = (Integer) traceDepths.get();\r
+ if (depth == null)\r
+ {\r
+ if ( incr > 0 )\r
+ {\r
+ traceDepths.set(new Integer(incr));\r
+ return incr;\r
+ }\r
+ else return rc;\r
+ } \r
+ \r
+ rc = depth.intValue();\r
+ \r
+ if ( incr > 0 )\r
+ {\r
+ depth = new Integer(rc += incr); \r
+ traceDepths.set(depth);\r
+ }\r
+ else if ( incr < 0 )\r
+ {\r
+ depth = new Integer(rc + incr); \r
+ traceDepths.set(depth);\r
+ }\r
+ \r
+ return rc;\r
+ }\r
+\r
+ /**\r
+ * This method returns a String containing the number of spaces desired to\r
+ * be used as padding for formatting trace log entries.\r
+ */\r
+ private String getSpaces(int num)\r
+ {\r
+ return new String(SPACES,0,Math.min(num,SPACES.length));\r
+ }\r
+\r
+ /**\r
+ * Create a method signature\r
+ */\r
+ private String methodSignature(String[] parameterNames,\r
+ Class[] parameterTypes,\r
+ JoinPoint thisJoinPoint)\r
+ {\r
+ // Assemble the method's signature.\r
+ StringBuffer signature = new StringBuffer("(");\r
+ for (int i = 0; i < parameterTypes.length; i++)\r
+ {\r
+ signature.append(parameterTypes[i].getName());\r
+ signature.append(" ");\r
+ signature.append(parameterNames[i]);\r
+ if (i < (parameterTypes.length-1))\r
+ signature.append(", ");\r
+ }\r
+ signature.append(")");\r
+\r
+ return thisJoinPoint.getSignature().getDeclaringType().getName() + "." +\r
+ thisJoinPoint.getSignature().getName() +\r
+ signature;\r
+ }\r
+ \r
+}
\ No newline at end of file
--- /dev/null
+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