/* *******************************************************************
 * 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
/** * @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
/** * 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); } }