| /* ******************************************************************* |
| * Copyright (c) 2004,2010 Contributors |
| * All rights reserved. |
| * This program and the accompanying materials are made available |
| * under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Matthew Webster, IBM |
| * ******************************************************************/ |
| package org.aspectj.weaver; |
| |
| import java.io.File; |
| import java.io.FileOutputStream; |
| import java.io.PrintStream; |
| import java.net.URL; |
| import java.text.SimpleDateFormat; |
| import java.util.Date; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Properties; |
| |
| import org.aspectj.bridge.IMessage; |
| import org.aspectj.bridge.IMessageHolder; |
| import org.aspectj.bridge.Version; |
| import org.aspectj.weaver.tools.Trace; |
| import org.aspectj.weaver.tools.TraceFactory; |
| import org.aspectj.weaver.tools.Traceable; |
| |
| /** |
| * @author Matthew Webster |
| */ |
| public class Dump { |
| |
| public final static String DUMP_CONDITION_PROPERTY = "org.aspectj.weaver.Dump.condition"; |
| public final static String DUMP_DIRECTORY_PROPERTY = "org.aspectj.dump.directory"; |
| |
| /* Format for unique filename based on date & time */ |
| private static final String FILENAME_PREFIX = "ajcore"; |
| // private static final DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd"); |
| // private static final DateFormat timeFormat = new SimpleDateFormat("HHmmss.SSS"); |
| private static final String FILENAME_SUFFIX = "txt"; |
| |
| public static final String UNKNOWN_FILENAME = "Unknown"; |
| public static final String DUMP_EXCLUDED = "Excluded"; |
| public static final String NULL_OR_EMPTY = "Empty"; |
| |
| private static Class<?> exceptionClass; |
| private static IMessage.Kind conditionKind = IMessage.ABORT; |
| private static File directory = new File("."); |
| |
| private String reason; |
| private String fileName; |
| private PrintStream print; |
| |
| private static String[] savedCommandLine; |
| private static List<String> savedFullClasspath; |
| private static IMessageHolder savedMessageHolder; |
| |
| // private static Map<INode, WeakReference<INode>> nodes = Collections |
| // .synchronizedMap(new WeakHashMap<INode, WeakReference<INode>>()); |
| private static String lastDumpFileName = UNKNOWN_FILENAME; |
| |
| private static boolean preserveOnNextReset = false; |
| |
| private static Trace trace = TraceFactory.getTraceFactory().getTrace(Dump.class); |
| |
| /** |
| * for testing only, so that we can verify dump contents after compilation has completely finished |
| */ |
| public static void preserveOnNextReset() { |
| preserveOnNextReset = true; |
| } |
| |
| public static void reset() { |
| if (preserveOnNextReset) { |
| preserveOnNextReset = false; |
| return; |
| } else { |
| // nodes.clear(); |
| savedMessageHolder = null; |
| } |
| } |
| |
| /* |
| * Dump methods |
| */ |
| public static String dump(String reason) { |
| String fileName = UNKNOWN_FILENAME; |
| Dump dump = null; |
| try { |
| dump = new Dump(reason); |
| fileName = dump.getFileName(); |
| dump.dumpDefault(); |
| } finally { |
| if (dump != null) { |
| dump.close(); |
| } |
| } |
| return fileName; |
| } |
| |
| public static String dumpWithException(Throwable th) { |
| return dumpWithException(savedMessageHolder, th); |
| } |
| |
| public static String dumpWithException(IMessageHolder messageHolder, Throwable th) { |
| if (!getDumpOnException()) { |
| return null; |
| } |
| if (trace.isTraceEnabled()) { |
| trace.enter("dumpWithException", null, new Object[] { messageHolder, th }); |
| } |
| |
| String fileName = UNKNOWN_FILENAME; |
| Dump dump = null; |
| try { |
| dump = new Dump(th.getClass().getName()); |
| fileName = dump.getFileName(); |
| dump.dumpException(messageHolder, th); |
| } finally { |
| if (dump != null) { |
| dump.close(); |
| } |
| } |
| |
| if (trace.isTraceEnabled()) { |
| trace.exit("dumpWithException", fileName); |
| } |
| return fileName; |
| } |
| |
| public static String dumpOnExit() { |
| return dumpOnExit(savedMessageHolder, false); |
| } |
| |
| public static String dumpOnExit(IMessageHolder messageHolder, boolean reset) { |
| if (!getDumpOnException()) { |
| return null; |
| } |
| if (trace.isTraceEnabled()) { |
| trace.enter("dumpOnExit", null, messageHolder); |
| } |
| String fileName = UNKNOWN_FILENAME; |
| |
| if (!shouldDumpOnExit(messageHolder)) { |
| fileName = DUMP_EXCLUDED; |
| } else { |
| Dump dump = null; |
| try { |
| dump = new Dump(conditionKind.toString()); |
| fileName = dump.getFileName(); |
| dump.dumpDefault(messageHolder); |
| } finally { |
| if (dump != null) { |
| dump.close(); |
| } |
| } |
| } |
| |
| if (reset) { |
| messageHolder.clearMessages(); |
| } |
| |
| if (trace.isTraceEnabled()) { |
| trace.exit("dumpOnExit", fileName); |
| } |
| return fileName; |
| } |
| |
| private static boolean shouldDumpOnExit(IMessageHolder messageHolder) { |
| if (trace.isTraceEnabled()) { |
| trace.enter("shouldDumpOnExit", null, messageHolder); |
| } |
| if (trace.isTraceEnabled()) { |
| trace.event("shouldDumpOnExit", null, conditionKind); |
| } |
| boolean result = (messageHolder == null) || messageHolder.hasAnyMessage(conditionKind, true); |
| |
| if (trace.isTraceEnabled()) { |
| trace.exit("shouldDumpOnExit", result); |
| } |
| return result; |
| } |
| |
| /* |
| * Dump configuration |
| */ |
| public static void setDumpOnException(boolean b) { |
| if (b) { |
| exceptionClass = java.lang.Throwable.class; |
| } else { |
| exceptionClass = null; |
| } |
| } |
| |
| public static boolean setDumpDirectory(String directoryName) { |
| if (trace.isTraceEnabled()) { |
| trace.enter("setDumpDirectory", null, directoryName); |
| } |
| boolean success = false; |
| |
| File newDirectory = new File(directoryName); |
| if (newDirectory.exists()) { |
| directory = newDirectory; |
| success = true; |
| } |
| |
| if (trace.isTraceEnabled()) { |
| trace.exit("setDumpDirectory", success); |
| } |
| return success; |
| |
| } |
| |
| public static boolean getDumpOnException() { |
| return (exceptionClass != null); |
| } |
| |
| public static boolean setDumpOnExit(IMessage.Kind condition) { |
| if (trace.isTraceEnabled()) { |
| trace.event("setDumpOnExit", null, condition); |
| } |
| |
| conditionKind = condition; |
| return true; |
| } |
| |
| public static boolean setDumpOnExit(String condition) { |
| for (IMessage.Kind kind : IMessage.KINDS) { |
| if (kind.toString().equals(condition)) { |
| return setDumpOnExit(kind); |
| } |
| } |
| return false; |
| } |
| |
| public static IMessage.Kind getDumpOnExit() { |
| return conditionKind; |
| } |
| |
| public static String getLastDumpFileName() { |
| return lastDumpFileName; |
| } |
| |
| public static void saveCommandLine(String[] args) { |
| savedCommandLine = new String[args.length]; |
| System.arraycopy(args, 0, savedCommandLine, 0, args.length); |
| } |
| |
| public static void saveFullClasspath(List<String> list) { |
| savedFullClasspath = list; |
| } |
| |
| public static void saveMessageHolder(IMessageHolder holder) { |
| savedMessageHolder = holder; |
| } |
| |
| // public static void registerNode(Class<?> module, INode newNode) { |
| // if (trace.isTraceEnabled()) { |
| // trace.enter("registerNode", null, new Object[] { module, newNode }); |
| // } |
| // |
| // // TODO surely this should preserve the module???? it never has.... |
| // nodes.put(newNode, new WeakReference<INode>(newNode)); |
| // |
| // if (trace.isTraceEnabled()) { |
| // trace.exit("registerNode", nodes.size()); |
| // } |
| // } |
| |
| private Dump(String reason) { |
| if (trace.isTraceEnabled()) { |
| trace.enter("<init>", this, reason); |
| } |
| |
| this.reason = reason; |
| |
| openDump(); |
| dumpAspectJProperties(); |
| dumpDumpConfiguration(); |
| |
| if (trace.isTraceEnabled()) { |
| trace.exit("<init>", this); |
| } |
| } |
| |
| public String getFileName() { |
| return fileName; |
| } |
| |
| private void dumpDefault() { |
| dumpDefault(savedMessageHolder); |
| } |
| |
| private void dumpDefault(IMessageHolder holder) { |
| dumpSytemProperties(); |
| dumpCommandLine(); |
| dumpFullClasspath(); |
| dumpCompilerMessages(holder); |
| |
| // dumpNodes(); |
| } |
| |
| // private void dumpNodes() { |
| // |
| // IVisitor dumpVisitor = new IVisitor() { |
| // |
| // public void visitObject(Object obj) { |
| // println(formatObj(obj)); |
| // } |
| // |
| // public void visitList(List list) { |
| // println(list); |
| // } |
| // }; |
| // |
| // Set<INode> keys = nodes.keySet(); |
| // for (INode dumpNode : keys) { |
| // println("---- " + formatObj(dumpNode) + " ----"); |
| // try { |
| // dumpNode.accept(dumpVisitor); |
| // } catch (Exception ex) { |
| // trace.error(formatObj(dumpNode).toString(), ex); |
| // } |
| // } |
| // } |
| |
| private void dumpException(IMessageHolder messageHolder, Throwable th) { |
| println("---- Exception Information ---"); |
| println(th); |
| dumpDefault(messageHolder); |
| } |
| |
| private void dumpAspectJProperties() { |
| println("---- AspectJ Properties ---"); |
| println("AspectJ Compiler " + Version.getText() + " built on " + Version.getTimeText()); |
| } |
| |
| private void dumpDumpConfiguration() { |
| println("---- Dump Properties ---"); |
| println("Dump file: " + fileName); |
| println("Dump reason: " + reason); |
| println("Dump on exception: " + (exceptionClass != null)); |
| println("Dump at exit condition: " + conditionKind); |
| } |
| |
| private void dumpFullClasspath() { |
| println("---- Full Classpath ---"); |
| if (savedFullClasspath != null && savedFullClasspath.size() > 0) { |
| for (String fileName : savedFullClasspath) { |
| File file = new File(fileName); |
| println(file); |
| } |
| } else { |
| println(NULL_OR_EMPTY); |
| } |
| } |
| |
| private void dumpSytemProperties() { |
| println("---- System Properties ---"); |
| Properties props = System.getProperties(); |
| println(props); |
| } |
| |
| private void dumpCommandLine() { |
| println("---- Command Line ---"); |
| println(savedCommandLine); |
| } |
| |
| private void dumpCompilerMessages(IMessageHolder messageHolder) { |
| println("---- Compiler Messages ---"); |
| if (messageHolder != null) { |
| for (Iterator<IMessage> i = messageHolder.getUnmodifiableListView().iterator(); i.hasNext();) { |
| IMessage message = i.next(); |
| println(message.toString()); |
| } |
| } else { |
| println(NULL_OR_EMPTY); |
| } |
| } |
| |
| /* |
| * Dump output |
| */ |
| private void openDump() { |
| if (print != null) { |
| return; |
| } |
| |
| Date now = new Date(); |
| fileName = FILENAME_PREFIX + "." + new SimpleDateFormat("yyyyMMdd").format(now) + "." |
| + new SimpleDateFormat("HHmmss.SSS").format(now) + "." + FILENAME_SUFFIX; |
| try { |
| File file = new File(directory, fileName); |
| print = new PrintStream(new FileOutputStream(file), true); |
| trace.info("Dumping to " + file.getAbsolutePath()); |
| } catch (Exception ex) { |
| print = System.err; |
| trace.info("Dumping to stderr"); |
| fileName = UNKNOWN_FILENAME; |
| } |
| |
| lastDumpFileName = fileName; |
| } |
| |
| public void close() { |
| print.close(); |
| } |
| |
| private void println(Object obj) { |
| print.println(obj); |
| } |
| |
| private void println(Object[] array) { |
| if (array == null) { |
| println(NULL_OR_EMPTY); |
| return; |
| } |
| |
| for (int i = 0; i < array.length; i++) { |
| print.println(array[i]); |
| } |
| } |
| |
| private void println(Properties props) { |
| Iterator iter = props.keySet().iterator(); |
| while (iter.hasNext()) { |
| String key = (String) iter.next(); |
| String value = props.getProperty(key); |
| print.println(key + "=" + value); |
| } |
| } |
| |
| private void println(Throwable th) { |
| th.printStackTrace(print); |
| } |
| |
| private void println(File file) { |
| print.print(file.getAbsolutePath()); |
| if (!file.exists()) { |
| println("(missing)"); |
| } else if (file.isDirectory()) { |
| int count = file.listFiles().length; |
| println("(" + count + " entries)"); |
| } else { |
| println("(" + file.length() + " bytes)"); |
| } |
| } |
| |
| @SuppressWarnings("rawtypes") |
| private void println(List list) { |
| if (list == null || list.isEmpty()) { |
| println(NULL_OR_EMPTY); |
| } else { |
| for (Iterator i = list.iterator(); i.hasNext();) { |
| Object o = i.next(); |
| if (o instanceof Exception) { |
| println((Exception) o); |
| } else { |
| println(o.toString()); |
| } |
| } |
| } |
| } |
| |
| private static Object formatObj(Object obj) { |
| |
| /* These classes have a safe implementation of toString() */ |
| if (obj == null || obj instanceof String || obj instanceof Number || obj instanceof Boolean || obj instanceof Exception |
| || obj instanceof Character || obj instanceof Class || obj instanceof File || obj instanceof StringBuffer |
| || obj instanceof URL) { |
| return obj; |
| } else { |
| try { |
| |
| /* Classes can provide an alternative implementation of toString() */ |
| if (obj instanceof Traceable) { |
| Traceable t = (Traceable) obj; |
| return t.toTraceString(); |
| } else { |
| return obj.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(obj)); |
| } |
| |
| /* Object.hashCode() can be override and may thow an exception */ |
| } catch (Exception ex) { |
| return obj.getClass().getName() + "@FFFFFFFF"; |
| } |
| } |
| } |
| |
| static { |
| String exceptionName = System.getProperty("org.aspectj.weaver.Dump.exception", "true"); |
| if (!exceptionName.equals("false")) { |
| setDumpOnException(true); |
| } |
| |
| String conditionName = System.getProperty(DUMP_CONDITION_PROPERTY); |
| if (conditionName != null) { |
| setDumpOnExit(conditionName); |
| } |
| |
| String directoryName = System.getProperty(DUMP_DIRECTORY_PROPERTY); |
| if (directoryName != null) { |
| setDumpDirectory(directoryName); |
| } |
| } |
| |
| public interface INode { |
| |
| public void accept(IVisitor visior); |
| |
| } |
| |
| public interface IVisitor { |
| |
| public void visitObject(Object s); |
| |
| public void visitList(List list); |
| } |
| |
| } |