summaryrefslogtreecommitdiffstats
path: root/bridge
diff options
context:
space:
mode:
authorwisberg <wisberg>2002-12-16 17:09:36 +0000
committerwisberg <wisberg>2002-12-16 17:09:36 +0000
commitc3300283ecc397d26ad9dfe31d1710ec45db2af0 (patch)
treee9acb7f3d33c1499975cec9ef3cc7ea151078344 /bridge
parent3cde920c3f7eb8241bf569007e25225d80b43c0f (diff)
downloadaspectj-c3300283ecc397d26ad9dfe31d1710ec45db2af0.tar.gz
aspectj-c3300283ecc397d26ad9dfe31d1710ec45db2af0.zip
initial version
Diffstat (limited to 'bridge')
-rw-r--r--bridge/src/.cvsignore1
-rw-r--r--bridge/src/org/aspectj/bridge/AbortException.java225
-rw-r--r--bridge/src/org/aspectj/bridge/CountingMessageHandler.java129
-rw-r--r--bridge/src/org/aspectj/bridge/ICommand.java42
-rw-r--r--bridge/src/org/aspectj/bridge/IMessage.java110
-rw-r--r--bridge/src/org/aspectj/bridge/IMessageHandler.java69
-rw-r--r--bridge/src/org/aspectj/bridge/IMessageHolder.java70
-rw-r--r--bridge/src/org/aspectj/bridge/ISourceLocation.java59
-rw-r--r--bridge/src/org/aspectj/bridge/Message.java166
-rw-r--r--bridge/src/org/aspectj/bridge/MessageHandler.java274
-rw-r--r--bridge/src/org/aspectj/bridge/MessageUtil.java968
-rw-r--r--bridge/src/org/aspectj/bridge/MessageWriter.java67
-rw-r--r--bridge/src/org/aspectj/bridge/ReflectionFactory.java106
-rw-r--r--bridge/src/org/aspectj/bridge/SourceLocation.java132
-rw-r--r--bridge/src/org/aspectj/bridge/Version.java67
-rw-r--r--bridge/testsrc/BridgeModuleTests.java30
-rw-r--r--bridge/testsrc/org/aspectj/bridge/BridgeTests.java33
-rw-r--r--bridge/testsrc/org/aspectj/bridge/CountingMessageHandlerTest.java90
-rw-r--r--bridge/testsrc/org/aspectj/bridge/MessageTest.java300
-rw-r--r--bridge/testsrc/org/aspectj/bridge/VersionTest.java53
20 files changed, 2991 insertions, 0 deletions
diff --git a/bridge/src/.cvsignore b/bridge/src/.cvsignore
new file mode 100644
index 000000000..a3f0b1b77
--- /dev/null
+++ b/bridge/src/.cvsignore
@@ -0,0 +1 @@
+*.lst
diff --git a/bridge/src/org/aspectj/bridge/AbortException.java b/bridge/src/org/aspectj/bridge/AbortException.java
new file mode 100644
index 000000000..241b6a8d9
--- /dev/null
+++ b/bridge/src/org/aspectj/bridge/AbortException.java
@@ -0,0 +1,225 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.bridge;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+/**
+ * Signal that a process was aborted before completion.
+ * This may contain a structured IMessage which indicates
+ * why the process was aborted (e.g., the underlying exception).
+ * For processes using try/catch to complete a method abruptly
+ * but complete the process normally (e.g., a test failure
+ * causes the test to abort but the reporting and testing continues
+ * normally), use the static methods to borrow and return a "porter"
+ * to avoid the expense of constructing a stack trace each time.
+ * A porter stack trace is invalid, and it should only be used
+ * to convey a message. E.g., to print the stack of the
+ * AbortException and any contained message:
+ * <pre>catch (AbortException ae) {
+ * IMessage m = ae.getMessage();
+ * if (!ae.isPorter()) ae.printStackTrace(System.err);
+ * Throwable thrown = ae.getThrown();
+ * if (null != thrown) thrown.printStackTrace(System.err);
+ * }</pre>
+ */
+public class AbortException extends RuntimeException { // XXX move porters out, handle proxy better
+
+ /** used when message text is null */
+ public static final String NO_MESSAGE_TEXT
+ = "AbortException (no message)";
+
+ private static final ArrayList porters = new ArrayList();
+
+ /**
+ * A client may throw this rather than constructing their own
+ * if stack trace or message is not needed when caught.
+ */
+ public static final AbortException ABORT
+ = new AbortException("ABORT");
+
+ /**
+ * Get a porter exception from the pool.
+ * Porter exceptions do <b>not</b> have valid stack traces.
+ * They are used only to avoid generating stack traces when
+ * using throw/catch to abruptly complete but continue.
+ */
+ public static AbortException borrowPorter(IMessage message) {
+ AbortException result;
+ synchronized(porters) {
+ if (porters.size() > 0) {
+ result = (AbortException) porters.get(0);
+ } else {
+ result = new AbortException();
+ }
+ }
+ result.setIMessage(message);
+ result.isPorter = true;
+ return result;
+ }
+
+ /**
+ * Return (or add) a porter exception to the pool.
+ */
+ public static void returnPorter(AbortException porter) {
+ synchronized(porters) {
+ if (porters.contains(porter)) {
+ throw new IllegalStateException("already have " + porter);
+ } else {
+ porters.add(porter);
+ }
+ }
+ }
+
+ /** @return NO_MESSAGE_TEXT or message.getMessage() if not null */
+ private static String extractMessage(IMessage message) {
+ if (null == message) {
+ return NO_MESSAGE_TEXT;
+ } else {
+ String m = message.getMessage();
+ if (null == m) {
+ return NO_MESSAGE_TEXT;
+ } else {
+ return m;
+ }
+ }
+ }
+
+ /** structured message abort */
+ protected IMessage message;
+
+ /** true if this is a porter exception - only used to hold message */
+ protected boolean isPorter;
+
+ /** abort with default String message */
+ public AbortException() {
+ this((String) null);
+ }
+
+ /** abort with message */
+ public AbortException(String s) {
+ super(null != s ? s : NO_MESSAGE_TEXT);
+ this.message = null;
+ }
+
+ /** abort with structured message */
+ public AbortException(IMessage message) {
+ super(extractMessage(message));
+ this.message = message;
+ }
+
+ /** @return IMessage structured message, if set */
+ public IMessage getIMessage() {
+ return message;
+ }
+
+ /**
+ * The stack trace of a porter is invalid; it is only used
+ * to carry a message (which may itself have a wrapped exception).
+ * @return true if this exception is only to carry exception
+ */
+ public boolean isPorter() {
+ return isPorter;
+ }
+
+ /** @return Throwable at bottom of IMessage chain, if any */
+ public Throwable getThrown() {
+ Throwable result = null;
+ IMessage m = getIMessage();
+ if (null != m) {
+ result = m.getThrown();
+ if (result instanceof AbortException) {
+ return ((AbortException) result).getThrown();
+ }
+ }
+ return result;
+ }
+
+ private void setIMessage(IMessage message) {
+ this.message = message;
+ }
+
+ // ----------- proxy attempts
+ /**
+ * Get message for this AbortException,
+ * either associated explicitly as message
+ * or implicitly as IMessage message or
+ * its thrown message.
+ * @see java.lang.Throwable#getMessage()
+ */
+ public String getMessage() {
+ String message = super.getMessage();
+ if ((null == message) || (NO_MESSAGE_TEXT == message)) {
+ IMessage m = getIMessage();
+ if (null != m) {
+ message = m.getMessage();
+ if (null == message) {
+ Throwable thrown = m.getThrown();
+ if (null != thrown) {
+ message = thrown.getMessage();
+ }
+ }
+ }
+ if (null == message) {
+ message = NO_MESSAGE_TEXT; // better than nothing
+ }
+ }
+ return message;
+ }
+
+ /**
+ * @see java.lang.Throwable#printStackTrace()
+ */
+ public void printStackTrace() {
+ printStackTrace(System.out);
+ }
+
+ /**
+ * Print the stack trace of any enclosed thrown
+ * or this otherwise.
+ * @see java.lang.Throwable#printStackTrace(PrintStream)
+ */
+ public void printStackTrace(PrintStream s) {
+ IMessage m = getIMessage();
+ Throwable thrown = (null == m? null : m.getThrown());
+ if (!isPorter() || (null == thrown)) {
+ s.println("Message: " + m);
+ super.printStackTrace(s);
+ } else {
+ thrown.printStackTrace(s);
+ }
+ }
+
+ /**
+ * Print the stack trace of any enclosed thrown
+ * or this otherwise.
+ * @see java.lang.Throwable#printStackTrace(PrintWriter)
+ */
+ public void printStackTrace(PrintWriter s) {
+ IMessage m = getIMessage();
+ Throwable thrown = (null == m? null : m.getThrown());
+ if (null == thrown) { // Always print
+ if (isPorter()) {
+ s.println("(Warning porter AbortException without thrown)");
+ }
+ s.println("Message: " + m);
+ super.printStackTrace(s);
+ } else {
+ thrown.printStackTrace(s);
+ }
+ }
+
+}
diff --git a/bridge/src/org/aspectj/bridge/CountingMessageHandler.java b/bridge/src/org/aspectj/bridge/CountingMessageHandler.java
new file mode 100644
index 000000000..103461ca7
--- /dev/null
+++ b/bridge/src/org/aspectj/bridge/CountingMessageHandler.java
@@ -0,0 +1,129 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.bridge;
+
+import org.aspectj.util.LangUtil;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+
+/**
+ * Wrap an IMessageHandler to count messages handled.
+ * Messages being ignored by the delegate IMessageHandler are not counted.
+ */
+public class CountingMessageHandler implements IMessageHandler {
+
+ public final IMessageHandler delegate;
+ public final CountingMessageHandler proxy;
+ private final Hashtable counters;
+
+ public CountingMessageHandler(IMessageHandler delegate) {
+ LangUtil.throwIaxIfNull(delegate, "delegate");
+ this.delegate = delegate;
+ this.counters = new Hashtable();
+ proxy = (delegate instanceof CountingMessageHandler
+ ? (CountingMessageHandler) delegate
+ : null);
+ }
+
+ /** @return delegate.handleMessage(IMessage) */
+ public boolean handleMessage(IMessage message) throws AbortException {
+ if (null != proxy) {
+ return proxy.handleMessage(message);
+ }
+ if (null != message) {
+ IMessage.Kind kind = message.getKind();
+ if (!isIgnoring(kind)) {
+ increment(kind);
+ }
+ }
+ return delegate.handleMessage(message);
+ }
+
+ /** @return delegate.isIgnoring(IMessage.Kind) */
+ public boolean isIgnoring(IMessage.Kind kind) {
+ return delegate.isIgnoring(kind);
+ }
+
+ /** @return delegate.toString() */
+ public String toString() {
+ return delegate.toString();
+ }
+
+ /**
+ * Return count of messages seen through this interface.
+ * @param kind the IMessage.Kind of the messages to count
+ * (if null, count all)
+ * @param orGreater if true, then count this kind and any
+ * considered greater by the ordering of
+ * IMessage.Kind.COMPARATOR
+ * @return number of messages of this kind (optionally or greater)
+ * @see IMessage.Kind.COMPARATOR
+ */
+ public int numMessages(IMessage.Kind kind, boolean orGreater) {
+ if (null != proxy) {
+ return proxy.numMessages(kind, orGreater);
+ }
+ int result = 0;
+ if (null == kind) {
+ for (Enumeration enum = counters.elements(); enum.hasMoreElements();) {
+ result += ((IntHolder) enum.nextElement()).count;
+ }
+ } else if (!orGreater) {
+ result = numMessages(kind);
+ } else {
+ for (Iterator iter = IMessage.KINDS.iterator(); iter.hasNext();) {
+ IMessage.Kind k = (IMessage.Kind) iter.next();
+ if (0 >= IMessage.Kind.COMPARATOR.compare(kind, k)) {
+ result += numMessages(k);
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * @return true if 0 is less than
+ * <code>numMessages(IMessage.ERROR, true)</code>
+ */
+ public boolean hasErrors() {
+ return (0 < numMessages(IMessage.ERROR, true));
+ }
+
+ private int numMessages(IMessage.Kind kind) {
+ if (null != proxy) {
+ return proxy.numMessages(kind);
+ }
+ IntHolder counter = (IntHolder) counters.get(kind);
+ return (null == counter ? 0 : counter.count);
+ }
+
+ private void increment(IMessage.Kind kind) {
+ if (null != proxy) {
+ throw new IllegalStateException("not called when proxying");
+ }
+
+ IntHolder counter = (IntHolder) counters.get(kind);
+ if (null == counter) {
+ counter = new IntHolder();
+ counters.put(kind, counter);
+ }
+ counter.count++;
+ }
+
+ private static class IntHolder {
+ int count;
+ }
+}
diff --git a/bridge/src/org/aspectj/bridge/ICommand.java b/bridge/src/org/aspectj/bridge/ICommand.java
new file mode 100644
index 000000000..22521f10e
--- /dev/null
+++ b/bridge/src/org/aspectj/bridge/ICommand.java
@@ -0,0 +1,42 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.bridge;
+
+import java.util.*;
+
+
+
+/**
+ * Command wrapper with collecting parameter for messages.
+ */
+public interface ICommand {
+ /**
+ * Run command with the given options.
+ * @param args the String[] options for the command
+ * @param handler the IMessageHandler for all output from
+ * the command
+ * @return true if the command completed successfully
+ */
+ boolean runCommand(String[] args, IMessageHandler handler);
+
+ /**
+ * Rerun the command.
+ *
+ * @param handler the IMessageHandler for all output from the command
+ *
+ * @return true if the command completed successfully
+ */
+ boolean repeatCommand(IMessageHandler handler);
+}
diff --git a/bridge/src/org/aspectj/bridge/IMessage.java b/bridge/src/org/aspectj/bridge/IMessage.java
new file mode 100644
index 000000000..7cb22910c
--- /dev/null
+++ b/bridge/src/org/aspectj/bridge/IMessage.java
@@ -0,0 +1,110 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.bridge;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * Wrap message with any associated throwable or source location.
+ */
+public interface IMessage {
+ /** no messages */
+ public static final IMessage[] RA_IMessage = new IMessage[0];
+
+ // int values must sync with KINDS order below
+ public static final Kind INFO = new Kind("info", 10);
+ public static final Kind DEBUG = new Kind("debug", 20);
+ public static final Kind WARNING = new Kind("warning", 30);
+ public static final Kind ERROR = new Kind("error", 40);
+ public static final Kind FAIL = new Kind("fail", 50);
+ public static final Kind ABORT = new Kind("abort", 60);
+ // XXX prefer another Kind to act as selector for "any",
+ // but can't prohibit creating messages with it.
+ //public static final Kind ANY = new Kind("any-selector", 0);
+
+ /** list of Kind in precedence order. 0 is less than
+ * IMessage.Kind.COMPARATOR.compareTo(KINDS.get(i), KINDS.get(i + 1))
+ */
+ public static final List KINDS =
+ Collections.unmodifiableList(
+ Arrays.asList(
+ new Kind[] { INFO, DEBUG, WARNING, ERROR, FAIL, ABORT }));
+
+ /** @return non-null String with simple message */
+ String getMessage();
+
+ /** @return the kind of this message */
+ Kind getKind();
+
+ /** @return true if this is an error */
+ boolean isError();
+
+ /** @return true if this is a warning */
+ boolean isWarning();
+
+ /** @return true if this is an internal debug message */
+ boolean isDebug();
+
+ /** @return true if this is information for the user */
+ boolean isInfo();
+
+ /** @return true if the process is aborting */
+ boolean isAbort(); // XXX ambiguous
+
+ /** @return true if something failed */
+ boolean isFailed();
+
+ /** @return Throwable associated with this message, or null if none */
+ Throwable getThrown();
+
+ /** @return source location associated with this message, or null if none */
+ ISourceLocation getISourceLocation();
+
+ public static final class Kind implements Comparable {
+ public static final Comparator COMPARATOR = new Comparator() {
+ public int compare(Object o1, Object o2) {
+ Kind one = (Kind) o1;
+ Kind two = (Kind) o2;
+ if (null == one) {
+ return (null == two ? 0 : 1);
+ } else if (null == two) {
+ return -1;
+ } else if (one == two) {
+ return 0;
+ } else {
+ return (one.precedence - two.precedence);
+ }
+ }
+ };
+
+ public int compareTo(Object other) {
+ return COMPARATOR.compare(this, other);
+ }
+
+ private final int precedence;
+ private final String name;
+
+ private Kind(String name, int precedence) {
+ this.name = name;
+ this.precedence = precedence;
+ }
+ public String toString() {
+ return name;
+ }
+ }
+}
diff --git a/bridge/src/org/aspectj/bridge/IMessageHandler.java b/bridge/src/org/aspectj/bridge/IMessageHandler.java
new file mode 100644
index 000000000..76b76ec0b
--- /dev/null
+++ b/bridge/src/org/aspectj/bridge/IMessageHandler.java
@@ -0,0 +1,69 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.bridge;
+
+import java.io.PrintWriter;
+
+/**
+ * Handle messages, logging and/or aborting as appropriate.
+ * Implementations define which messages are logged and whether
+ * the handler aborts the process.
+ * For messages that are costly to construct, clients may query
+ * {@link #isIgnoring(IMessage.Kind)}
+ * to avoid construction if the message will be ignored.
+ * Clients passing messages to an IMessageHandler should not
+ * interfere with aborts by catching AbortException unless
+ * otherwise required by their logic or the message handler.
+ */
+public interface IMessageHandler {
+ /** print all to System.err and throw AbortException on failure or abort messages */
+ public static final IMessageHandler SYSTEM_ERR =
+ new MessageWriter(new PrintWriter(System.err, true), true);
+
+ /** print all to System.out but do not throw AbortException on failure or abort messages */
+ public static final IMessageHandler SYSTEM_OUT =
+ new MessageWriter(new PrintWriter(System.out, true), false);
+
+ /** Throw exceptions for anything with ERROR or greater severity */
+ public static final IMessageHandler THROW =
+ new IMessageHandler() {
+ public boolean handleMessage(IMessage message) {
+ if (message.getKind().compareTo(IMessage.ERROR) >= 0) {
+ throw new AbortException(message);
+ } else {
+ return SYSTEM_OUT.handleMessage(message);
+ }
+ }
+ public boolean isIgnoring(IMessage.Kind kind) {
+ return false;
+ }
+ };
+
+ /**
+ * Handle message, by reporting and/or throwing an AbortException.
+ * @param message the IMessage to handle - never null
+ * @return true if this message was handled by this handler
+ * @throws IllegalArgumentException if message is null
+ * @throws AbortException depending on handler logic.
+ */
+ boolean handleMessage(IMessage message) throws AbortException;
+
+ /**
+ * Signal clients whether this will ignore messages of a given type.
+ * Clients may use this to avoid constructing or sending certain messages.
+ * @return true if this handler is ignoring all messages of this type
+ */
+ boolean isIgnoring(IMessage.Kind kind);
+}
diff --git a/bridge/src/org/aspectj/bridge/IMessageHolder.java b/bridge/src/org/aspectj/bridge/IMessageHolder.java
new file mode 100644
index 000000000..cd36cb703
--- /dev/null
+++ b/bridge/src/org/aspectj/bridge/IMessageHolder.java
@@ -0,0 +1,70 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.bridge;
+
+import java.util.List;
+
+/**
+ * Hold and query a collection of messages.
+ */
+public interface IMessageHolder
+ extends IMessageHandler { // XXX do not extend - mix instead
+ // XXX go to LT EQ GT GE LE rather than simple orGreater
+ /** value for orGreater parameter */
+ public static final boolean ORGREATER = true;
+
+ /** value for orGreater parameter */
+ public static final boolean EQUAL = false;
+
+ /**
+ * Tell whether this holder has any message of this kind
+ * (optionally or greater).
+ * @param kind the IMessage.Kind to check for - accept any if null
+ * @param orGreater if true, also any greater than the target kind
+ * as determined by IMessage.Kind.COMPARATOR
+ * @return true if this holder has any message of this kind,
+ * or if orGreater and any message has a greater kind,
+ * as determined by IMessage.Kind.COMPARATOR
+ */
+ boolean hasAnyMessage(IMessage.Kind kind, boolean orGreater);
+
+ /**
+ * Count the messages currently held by this holder.
+ * Pass null to get all kinds.
+ * @param kind the IMessage.Kind expected, or null for all messages
+ * @param orGreater if true, also any greater than the target kind
+ * as determined by IMessage.Kind.COMPARATOR
+ * @return number of IMessage held (now) by this holder
+ */
+ int numMessages(IMessage.Kind kind, boolean orGreater);
+
+ /**
+ * Get all messages or those of a specific kind.
+ * Pass null to get all kinds.
+ * @param kind the IMessage.Kind expected, or null for all messages
+ * @param orGreater if true, also get any greater than the target kind
+ * as determined by IMessage.Kind.COMPARATOR
+ * @return IMessage[] of messages of the right kind, or IMessage.NONE
+ */
+ IMessage[] getMessages(IMessage.Kind kind, boolean orGreater);
+
+ /** @return unmodifiable List view of underlying collection of IMessage */
+ List getUnmodifiableListView();
+
+ /**
+ * Clear any messages.
+ * @throws UnsupportedOperationException if message list is read-only
+ */
+ void clearMessages() throws UnsupportedOperationException;
+}
diff --git a/bridge/src/org/aspectj/bridge/ISourceLocation.java b/bridge/src/org/aspectj/bridge/ISourceLocation.java
new file mode 100644
index 000000000..8dc343f5e
--- /dev/null
+++ b/bridge/src/org/aspectj/bridge/ISourceLocation.java
@@ -0,0 +1,59 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.bridge;
+
+import java.io.File;
+
+/**
+ * Represent source location as a starting line/column and ending
+ * line in a source file.
+ * Implementations should be immutable. XXX why?
+ * @see org.aspectj.lang.reflect.SourceLocation
+ * @see org.aspectj.compiler.base.parser.SourceInfo
+ * @see org.aspectj.tools.ide.SourceLine
+ * @see org.aspectj.testing.harness.ErrorLine
+ */
+public interface ISourceLocation {
+ static final int MAX_LINE = Integer.MAX_VALUE / 2;
+ static final int MAX_COLUMN = MAX_LINE;
+
+ /** non-null but empty (nonexisting) File constant */
+ static final File NO_FILE = new File("ISourceLocation.NO_FILE");
+
+ /** signal that column is not known */
+ static final int NO_COLUMN = Integer.MIN_VALUE +1;
+
+ /** non-null but empty constant source location */
+ static final ISourceLocation EMPTY = new SourceLocation(NO_FILE, 0, 0, 0);
+
+ /**
+ * @return File source or NO_FILE if the implementation requires
+ * a non-null result or null otherwise
+ */
+ File getSourceFile();
+
+ /** @return 0..MAX_LINE */
+ int getLine();
+
+ /**
+ * @return int 0..MAX_COLUMN actual column
+ * or 0 if column input was ISourceLocation.NO_COLUMN
+ */
+ int getColumn();
+
+ /** @return getLine()..MAX_LINE */
+ int getEndLine();
+
+}
diff --git a/bridge/src/org/aspectj/bridge/Message.java b/bridge/src/org/aspectj/bridge/Message.java
new file mode 100644
index 000000000..56e2275b7
--- /dev/null
+++ b/bridge/src/org/aspectj/bridge/Message.java
@@ -0,0 +1,166 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.bridge;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.InvocationTargetException;
+
+
+/**
+ * Implement messages.
+ * This implementation is immutable if ISourceLocation is immutable.
+ */
+public class Message implements IMessage { // XXX toString or renderer?
+ private final String message;
+ private final IMessage.Kind kind;
+ private final Throwable thrown;
+ private final ISourceLocation sourceLocation;
+
+ /** convenience for constructing failure messages */
+ public static Message fail(String message, Throwable thrown) {
+ return new Message(message, IMessage.FAIL, thrown, null);
+ }
+
+ /**
+ * Create a (compiler) error or warning message
+ * @param message the String used as the underlying message
+ * @param sourceLocation the ISourceLocation, if any, associated with this message
+ * @param isError if true, use IMessage.ERROR; else use IMessage.WARNING
+ */
+ public Message(String message, ISourceLocation location, boolean isError) {
+ this(message, (isError ? IMessage.ERROR : IMessage.WARNING), null,
+ location);
+ }
+
+ /**
+ * Create a message, handling null values for message and kind
+ * if thrown is not null.
+ * @param message the String used as the underlying message
+ * @param kind the IMessage.Kind of message - not null
+ * @param thrown the Throwable, if any, associated with this message
+ * @param sourceLocation the ISourceLocation, if any, associated with this message
+ * @throws IllegalArgumentException if message is null and
+ * thrown is null or has a null message, or if kind is null
+ * and thrown is null.
+ */
+ public Message(String message, IMessage.Kind kind, Throwable thrown,
+ ISourceLocation sourceLocation) {
+ this.message = message;
+ this.kind = kind;
+ this.thrown = thrown;
+ this.sourceLocation = sourceLocation;
+ if (null == message) {
+ if (null != thrown) {
+ message = thrown.getMessage();
+ }
+ if (null == message) {
+ throw new IllegalArgumentException("null message");
+ }
+ }
+ if (null == kind) {
+ throw new IllegalArgumentException("null kind");
+ }
+ }
+
+ /** @return the kind of this message */
+ public IMessage.Kind getKind() {
+ return kind;
+ }
+
+ /** @return true if kind == IMessage.ERROR */
+ public boolean isError() {
+ return kind == IMessage.ERROR;
+ }
+
+ /** @return true if kind == IMessage.WARNING */
+ public boolean isWarning() {
+ return kind == IMessage.WARNING;
+ }
+
+ /** @return true if kind == IMessage.DEBUG */
+ public boolean isDebug() {
+ return kind == IMessage.DEBUG;
+ }
+
+ /**
+ * @return true if kind == IMessage.INFO
+ */
+ public boolean isInfo() {
+ return kind == IMessage.INFO;
+ }
+
+ /** @return true if kind == IMessage.ABORT */
+ public boolean isAbort() {
+ return kind == IMessage.ABORT;
+ }
+
+ /**
+ * @return true if kind == IMessage.FAIL
+ */
+ public boolean isFailed() {
+ return kind == IMessage.FAIL;
+ }
+
+ /** @return non-null String with simple message */
+ final public String getMessage() {
+ return message;
+ }
+
+ /** @return Throwable associated with this message, or null if none */
+ final public Throwable getThrown() {
+ return thrown;
+ }
+
+ /** @return ISourceLocation associated with this message, or null if none */
+ final public ISourceLocation getISourceLocation() {
+ return sourceLocation;
+ }
+
+ public String toString() {
+ return Message.renderToString(this);
+ }
+
+ public static String renderToString(IMessage message) {
+ ISourceLocation loc = message.getISourceLocation();
+ String locString = (null == loc ? "" : " at " + loc);
+ Throwable thrown = message.getThrown();
+ return message.getKind() + locString + ": " + message.getMessage()
+ + (null == thrown ? "" : render(thrown));
+ }
+
+ public static String render(Throwable thrown) { // XXX cf LangUtil.debugStr
+ if (null == thrown) return "null throwable";
+ Throwable t = null;
+ if (thrown instanceof InvocationTargetException) {
+ t = ((InvocationTargetException)thrown).getTargetException();
+ } else if (thrown instanceof ClassNotFoundException) {
+ t = ((ClassNotFoundException) thrown).getException();
+ }
+ if (null != t) {
+ return render(t);
+ }
+ StringWriter buf = new StringWriter();
+ PrintWriter writer = new PrintWriter(buf);
+ writer.println(" Message rendering thrown=" + thrown.getClass().getName());
+ writer.println(thrown.getMessage());
+ thrown.printStackTrace(writer);
+ try { buf.close(); }
+ catch (IOException ioe) {}
+ return buf.getBuffer().toString();
+ }
+
+}
diff --git a/bridge/src/org/aspectj/bridge/MessageHandler.java b/bridge/src/org/aspectj/bridge/MessageHandler.java
new file mode 100644
index 000000000..3ffb1aa54
--- /dev/null
+++ b/bridge/src/org/aspectj/bridge/MessageHandler.java
@@ -0,0 +1,274 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.bridge;
+
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * This handler accumulates messages.
+ * To control messages accumulated,
+ * clients can ignore messages of a given kind,
+ * or install a listener/interceptor.
+ * The interceptor handles all messages (even null) first,
+ * and can halt further processing/accumlation by returning true.
+ * Clients can obtain messages accumulated using the get... methods.
+ * XXX this does not permit messages to be removed.
+ */
+public class MessageHandler implements IMessageHolder {
+
+ /** messages accumulated */
+ protected final ArrayList messages;
+ /** kinds of messages to be ignored */
+ protected final ArrayList ignoring;
+ /** result of handleMessage(..) for messages not accumulated (ignored) */
+ protected boolean handleMessageResult;
+ /** listener which can halt processing by returning true */
+ protected IMessageHandler interceptor;
+
+ /**
+ * same as MessageHandler(false)
+ */
+ public MessageHandler() {
+ this(false);
+ }
+
+ /**
+ * @param accumulateOnly the result of handleMessage
+ * (i.e., if true, then only accumulate messages - stop processing
+ */
+ public MessageHandler(boolean accumulateOnly) {
+ messages = new ArrayList();
+ ignoring = new ArrayList();
+ init(accumulateOnly);
+ }
+
+ /**
+ * Initialize this, removing any messages accumulated,
+ * kinds being ignored, or interceptor.
+ * Assume that this should return false from handleMessage(..).
+ */
+ public void init() { init(false); }
+
+ /**
+ * Initialize this, removing any messages accumulated,
+ * kinds being ignored, or interceptor.
+ * @param accumulateOnly boolean value returned from handleMessage
+ * after accumulating in list
+ */
+ public void init(boolean accumulateOnly) {
+ handleMessageResult = accumulateOnly;
+ if (0 < messages.size()) {
+ messages.clear();
+ }
+ if (0 < ignoring.size()) {
+ ignoring.clear();
+ }
+ if (null != interceptor) {
+ interceptor = null;
+ }
+ }
+
+ /**
+ * Clear the messages without changing other behavior.
+ */
+ public void clearMessages() {
+ if (0 < messages.size()) {
+ messages.clear();
+ }
+ }
+
+ // ---------------------- IMessageHandler implementation
+ /**
+ * This implementation accumulates message.
+ * If an interceptor is installed and returns true (message handled),
+ * then processing halts and the message is not accumulated.
+ * @see org.aspectj.bridge.IMessageHandler#handleMessage(IMessage)
+ * @return true on interception or the constructor value otherwise
+ */
+ public boolean handleMessage(IMessage message) {
+ if ((null != interceptor) && (interceptor.handleMessage(message))) {
+ return true;
+ }
+ if (null == message) {
+ throw new IllegalArgumentException("null message");
+ }
+ if (!ignoring.contains(message.getKind())) {
+ messages.add(message);
+ }
+ return handleMessageResult;
+ }
+
+ /**
+ * @return true if this kind has been flagged to be ignored.
+ * @see #ignore(IMessage.Kind)
+ * @see org.aspectj.bridge.IMessageHandler#isIgnoring(Kind)
+ */
+ public boolean isIgnoring(IMessage.Kind kind) {
+ return ((null != kind) && (ignoring.contains(kind)));
+ }
+
+ // ---------------------- end of IMessageHandler implementation
+
+
+ /**
+ * Set a message kind to be ignored from now on
+ */
+ public void ignore(IMessage.Kind kind) { // XXX sync
+ if ((null != kind) && (!ignoring.contains(kind))) {
+ ignoring.add(kind);
+ }
+ }
+
+ /**
+ * Remove a message kind from the list of those ignored from now on.
+ */
+ public void dontIgnore(IMessage.Kind kind) {
+ if (null != kind) {
+ ignoring.remove(kind);
+ }
+ }
+
+ /**
+ * @see org.aspectj.bridge.IMessageHolder#hasAnyMessage(Kind, boolean)
+ */
+ public boolean hasAnyMessage(final IMessage.Kind kind, final boolean orGreater) {
+ if (null == kind) {
+ return (0 < messages.size());
+ }
+ if (!orGreater) {
+ for (Iterator iter = messages.iterator(); iter.hasNext();) {
+ if (kind == ((IMessage) iter.next()).getKind()) {
+ return true;
+ }
+ }
+ } else {
+ final Comparator c = IMessage.Kind.COMPARATOR;
+ for (Iterator iter = messages.iterator(); iter.hasNext();) {
+ IMessage m = (IMessage) iter.next();
+ if (0 >= c.compare(kind, m.getKind())) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @return number of messages accumulated of a given kind
+ */
+ public int numMessages(IMessage.Kind kind, final boolean orGreater) {
+ if (null == kind) {
+ return messages.size();
+ }
+ int result = 0;
+ if (!orGreater) {
+ for (Iterator iter = messages.iterator(); iter.hasNext();) {
+ if (kind == ((IMessage) iter.next()).getKind()) {
+ result++;
+ }
+ }
+ } else {
+ final Comparator c = IMessage.Kind.COMPARATOR;
+ for (Iterator iter = messages.iterator(); iter.hasNext();) {
+ IMessage m = (IMessage) iter.next();
+ if (0 >= c.compare(kind, m.getKind())) {
+ result++;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * @see org.aspectj.bridge.IMessageHolder#getUnmodifiableListView()
+ */
+ public List getUnmodifiableListView() {
+ return Collections.unmodifiableList(messages);
+ }
+
+ /**
+ * Get all messages or those of a specific kind.
+ * Pass null to get all kinds.
+ * @param kind the IMessage.Kind expected, or null for all messages
+ * @return IMessage[] of messages of the right kind
+ */
+ public IMessage[] getMessages(IMessage.Kind kind, final boolean orGreater) {
+ if (null == kind) {
+ return (IMessage[]) messages.toArray(IMessage.RA_IMessage);
+ }
+ ArrayList result = new ArrayList();
+ if (!orGreater) {
+ for (Iterator iter = messages.iterator(); iter.hasNext();) {
+ IMessage m = (IMessage) iter.next();
+ if (kind == m.getKind()) {
+ result.add(m);
+ }
+ }
+ } else {
+ final Comparator c = IMessage.Kind.COMPARATOR;
+ for (Iterator iter = messages.iterator(); iter.hasNext();) {
+ IMessage m = (IMessage) iter.next();
+ if (0 >= c.compare(kind, m.getKind())) {
+ result.add(m);
+ }
+ }
+ }
+ if (0 == result.size()) {
+ return IMessage.RA_IMessage;
+ }
+ return (IMessage[]) result.toArray(IMessage.RA_IMessage);
+ }
+
+ /**
+ * @return array of error messages, or IMessage.NONE
+ */
+ public IMessage[] getErrors() {
+ return getMessages(IMessage.ERROR, false);
+ }
+
+ /**
+ * @return array of warning messages, or IMessage.NONE
+ */
+ public IMessage[] getWarnings() {
+ return getMessages(IMessage.WARNING, false);
+ }
+
+ /**
+ * Set the interceptor which gets any message before we process it.
+ * @param interceptor the IMessageHandler passed the message.
+ * Pass null to remove the old interceptor.
+ */
+ public void setInterceptor(IMessageHandler interceptor) {
+ this.interceptor = interceptor;
+ }
+
+ /**
+ * @return String containing list of messages
+ */
+ public String toString() {
+ if (0 == messages.size()) {
+ return "MessageHandler: no messages";
+ } else {
+ return "MessageHandler: " + messages;
+ }
+
+ }
+
+}
diff --git a/bridge/src/org/aspectj/bridge/MessageUtil.java b/bridge/src/org/aspectj/bridge/MessageUtil.java
new file mode 100644
index 000000000..13ab1a1fe
--- /dev/null
+++ b/bridge/src/org/aspectj/bridge/MessageUtil.java
@@ -0,0 +1,968 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.bridge;
+
+import org.aspectj.bridge.IMessage.Kind;
+import org.aspectj.util.LangUtil;
+import org.aspectj.util.LineReader;
+
+import java.io.File;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Convenience API's for constructing, printing, and sending messages.
+ */
+public class MessageUtil {
+
+ // ------ some constant, content-less messages
+ // no variants for "info" or "debug", which should always have content
+ public static final IMessage ABORT_NOTHING_TO_RUN
+ = new Message("aborting - nothing to run", IMessage.ABORT, null, null);
+
+ public static final IMessage FAIL_INCOMPLETE
+ = new Message("run not completed", IMessage.FAIL, null, null);
+
+ public static final IMessage ABORT_NOMESSAGE
+ = new Message("", IMessage.ABORT, null, null);
+
+ public static final IMessage FAIL_NOMESSAGE
+ = new Message("", IMessage.FAIL, null, null);
+
+ public static final IMessage ERROR_NOMESSAGE
+ = new Message("", IMessage.ERROR, null, null);
+
+ public static final IMessage WARNING_NOMESSAGE
+ = new Message("", IMessage.WARNING, null, null);
+
+
+ /** handle abort message (ignored if handler is null) */
+ public static boolean abort(IMessageHandler handler, String message) {
+ return ((null != handler)
+ && handler.handleMessage(abort(message)));
+ }
+
+ /** create and handle exception message (ignored if handler is null) */
+ public static boolean abort(IMessageHandler handler, String message, Throwable t) {
+ if (handler != null) return handler.handleMessage(abort(message, t));
+ return false;
+ }
+
+ /** create and handle fail message (ignored if handler is null) */
+ public static boolean fail(IMessageHandler handler, String message) {
+ return ((null != handler)
+ && handler.handleMessage(fail(message)));
+ }
+
+ /** create and handle fail message from reader (ignored if handler is null) */
+ public static boolean fail(IMessageHandler handler, String message, LineReader reader) {
+ return ((null != handler)
+ && handler.handleMessage(fail(message, reader)));
+ }
+
+ /** create and handle fail message (ignored if handler is null) */
+ public static boolean fail(IMessageHandler handler, String message, Throwable thrown) {
+ return ((null != handler)
+ && handler.handleMessage(fail(message, thrown)));
+ }
+
+ /** create and handle error message (ignored if handler is null) */
+ public static boolean error(IMessageHandler handler, String message) {
+ return ((null != handler)
+ && handler.handleMessage(error(message)));
+ }
+
+ /** create and handle warn message (ignored if handler is null) */
+ public static boolean warn(IMessageHandler handler, String message) {
+ return ((null != handler)
+ && handler.handleMessage(warn(message)));
+ }
+
+ /** create and handle debug message (ignored if handler is null) */
+ public static boolean debug(IMessageHandler handler, String message) {
+ return ((null != handler)
+ && handler.handleMessage(debug(message)));
+ }
+
+ /** create and handle info message (ignored if handler is null) */
+ public static boolean info(IMessageHandler handler, String message) {
+ return ((null != handler)
+ && handler.handleMessage(info(message)));
+ }
+
+ /** @return ABORT_NOMESSAGE if message is empty or IMessage otherwise */ //
+ public static IMessage abort(String message) {
+ if (LangUtil.isEmpty(message)) {
+ return ABORT_NOMESSAGE;
+ } else {
+ return new Message(message, IMessage.ABORT, null, null);
+ }
+ }
+
+ /** @return abort IMessage with thrown and message o
+ * ABORT_NOMESSAGE if both are empty/null */ //
+ public static IMessage abort(String message, Throwable thrown) {
+ if (!LangUtil.isEmpty(message)) {
+ return new Message(message, IMessage.ABORT, thrown, null);
+ } else if (null == thrown) {
+ return ABORT_NOMESSAGE;
+ } else {
+ return new Message(thrown.getMessage(), IMessage.ABORT, thrown, null);
+ }
+ }
+
+ /** @return FAIL_NOMESSAGE if message is empty or IMessage otherwise */
+ public static IMessage fail(String message) {
+ if (LangUtil.isEmpty(message)) {
+ return FAIL_NOMESSAGE;
+ } else {
+ return fail(message, (LineReader) null);
+ }
+ }
+
+ /**
+ * Create fail message.
+ * If message is empty but thrown is not, use thrown.getMessage() as the message.
+ * If message is empty and thrown is null, return FAIL_NOMESSAGE.
+ * @return FAIL_NOMESSAGE if thrown is null and message is empty
+ * or IMessage FAIL with message and thrown otherwise
+ */
+ public static IMessage fail(String message, Throwable thrown) {
+ if (LangUtil.isEmpty(message)) {
+ if (null == thrown) {
+ return FAIL_NOMESSAGE;
+ } else {
+ return new Message(thrown.getMessage(), IMessage.FAIL, thrown, null);
+ }
+ } else {
+ return new Message(message, IMessage.FAIL, thrown, null);
+ }
+ }
+
+ /**
+ * @return IMessage with IMessage.Kind FAIL and message as text
+ * and soure location from reader
+ */
+ public static IMessage fail(String message, LineReader reader) {
+ ISourceLocation loc = null;
+ if (null == reader) {
+ loc = ISourceLocation.EMPTY;
+ } else {
+ int line = (null == reader ? 0 : reader.getLineNumber());
+ if (0 < line) {
+ line = 0;
+ }
+ loc = new SourceLocation(reader.getFile(), line, line, 0);
+ }
+ return new Message(message, IMessage.FAIL, null, loc);
+ }
+
+ /** @return ERROR_NOMESSAGE if message is empty or IMessage otherwise */ //
+ public static IMessage error(String message, ISourceLocation location) {
+ if (LangUtil.isEmpty(message)) {
+ return ERROR_NOMESSAGE;
+ } else {
+ return new Message(message, IMessage.ERROR, null, location);
+ }
+ }
+
+ /** @return ERROR_NOMESSAGE if message is empty or IMessage otherwise */ //
+ public static IMessage error(String message) {
+ if (LangUtil.isEmpty(message)) {
+ return ERROR_NOMESSAGE;
+ } else {
+ return new Message(message, IMessage.ERROR, null, null);
+ }
+ }
+
+ /** @return WARNING_NOMESSAGE if message is empty or IMessage otherwise */ //
+ public static IMessage warn(String message) {
+ if (LangUtil.isEmpty(message)) {
+ return WARNING_NOMESSAGE;
+ } else {
+ return new Message(message, IMessage.WARNING, null, null);
+ }
+ }
+
+ /** @return IMessage.DEBUG message with message content */
+ public static IMessage debug(String message) {
+ return new Message(message, IMessage.DEBUG, null, null);
+ }
+
+ /** @return IMessage.INFO message with message content */
+ public static IMessage info(String message) {
+ return new Message(message, IMessage.INFO, null, null);
+ }
+
+ /** @return ISourceLocation with the current File/line of the reader */
+ public static ISourceLocation makeSourceLocation(LineReader reader) {
+ LangUtil.throwIaxIfNull(reader, "reader");
+
+ int line = reader.getLineNumber();
+ if (0 < line) {
+ line = 0;
+ }
+ return new SourceLocation(reader.getFile(), line, line, 0);
+ }
+
+ // ------------------------ printing messages
+ /**
+ * Print total counts message to the print stream, starting each on a new line
+ * @param messageHolder
+ * @param out
+ */
+ public static void printMessageCounts(PrintStream out, IMessageHolder messageHolder) {
+ if ((null == out) || (null == messageHolder)) {
+ return;
+ }
+ printMessageCounts(out, messageHolder, "");
+ }
+
+ public static void printMessageCounts(PrintStream out, IMessageHolder holder, String prefix) {
+ out.println(prefix + "MessageHolder: " + MessageUtil.renderCounts(holder));
+ }
+ /**
+ * Print all message to the print stream, starting each on a new line
+ * @param messageHolder
+ * @param out
+ * @see #print(PrintStream, String, IMessageHolder, IMessageRenderer, IMessageHandler)
+ */
+ public static void print(PrintStream out, IMessageHolder messageHolder) {
+ print(out, messageHolder, (String) null, (IMessageRenderer) null, (IMessageHandler) null);
+ }
+
+ /**
+ * Print all message to the print stream, starting each on a new line,
+ * with a prefix.
+ * @param messageHolder
+ * @param out
+ * @see #print(PrintStream, String, IMessageHolder, IMessageRenderer, IMessageHandler)
+ */
+ public static void print(PrintStream out, IMessageHolder holder, String prefix) {
+ print(out, holder, prefix, (IMessageRenderer) null, (IMessageHandler) null);
+ }
+
+ /**
+ * Print all message to the print stream, starting each on a new line,
+ * with a prefix and using a renderer.
+ * @param messageHolder
+ * @param out
+ * @param renderer IMessageRender to render result - use MESSAGE_LINE if null
+ * @see #print(PrintStream, String, IMessageHolder, IMessageRenderer, IMessageHandler)
+ */
+ public static void print(PrintStream out, IMessageHolder holder, String prefix,
+ IMessageRenderer renderer) {
+ print(out, holder, prefix, renderer, (IMessageHandler) null);
+ }
+
+ /**
+ * Print all message to the print stream, starting each on a new line,
+ * with a prefix and using a renderer.
+ * The first line renders a summary: {prefix}MessageHolder: {summary}
+ * Each message line has the following form:
+ * <pre>{prefix}[{kind} {index}]: {rendering}</pre>
+ * (where "{index}" (length 3) is the position within
+ * the set of like-kinded messages, ignoring selector omissions.
+ * Renderers are free to render multi-line output.
+ * @param out the PrintStream sink - return silently if null
+ * @param messageHolder the IMessageHolder with the messages to print
+ * @param renderer IMessageRender to render result - use MESSAGE_ALL if null
+ * @param selector IMessageHandler to select messages to render - if null, do all non-null
+ */
+ public static void print(PrintStream out, IMessageHolder holder, String prefix,
+ IMessageRenderer renderer, IMessageHandler selector) {
+ print(out, holder, prefix, renderer, selector, true);
+ }
+
+ public static void print(PrintStream out, IMessageHolder holder, String prefix,
+ IMessageRenderer renderer, IMessageHandler selector, boolean printSummary) {
+ if ((null == out) || (null == holder)) {
+ return;
+ }
+ if (null == renderer) {
+ renderer = MESSAGE_ALL;
+ }
+ if (null == selector) {
+ selector = PICK_ALL;
+ }
+ if (printSummary) {
+ out.println(prefix + "MessageHolder: " + MessageUtil.renderCounts(holder));
+ }
+ for (Iterator iter = IMessage.KINDS.iterator(); iter.hasNext();) {
+ IMessage.Kind kind = (IMessage.Kind) iter.next();
+ if (!selector.isIgnoring(kind)) {
+ IMessage[] messages = holder.getMessages(kind, IMessageHolder.EQUAL);
+ for (int i = 0; i < messages.length; i++) {
+ if (selector.handleMessage(messages[i])) {
+ String label = (null == prefix
+ ? ""
+ : prefix + "[" + kind + " " + LangUtil.toSizedString(i, 3) + "]: ");
+ out.println(label + renderer.renderToString(messages[i]));
+ }
+ }
+ }
+ }
+ }
+
+ public static String toShortString(IMessage message) {
+ if (null == message) {
+ return "null";
+ }
+ String m = message.getMessage();
+ Throwable t = message.getThrown();
+
+ return (message.getKind() + (null == m ? "" : ": " + m)
+ + (null == t ? "" : ": " + LangUtil.unqualifiedClassName(t)));
+ }
+
+ /** @return int number of message of this kind (optionally or greater) in list */
+ public static int numMessages(ArrayList messages, Kind kind, boolean orGreater) {
+ if (LangUtil.isEmpty(messages)) {
+ return 0;
+ }
+ IMessageHandler selector = makeSelector(kind, orGreater, null);
+ IMessage[] result = visitMessages(messages, selector, true, false);
+ return result.length;
+ }
+
+
+ /** @return unmodifiable list of IMessage complying with parameters */
+ public static List getMessages(IMessageHolder holder,
+ IMessage.Kind kind, boolean orGreater, String infix) { // XXX untested
+ if (null == holder) {
+ return Collections.EMPTY_LIST;
+ }
+ if ((null == kind) && LangUtil.isEmpty(infix)) {
+ return holder.getUnmodifiableListView();
+ }
+ IMessageHandler selector = makeSelector(kind, orGreater, infix);
+ IMessage[] messages = visitMessages(holder, selector, true, false);
+ if (LangUtil.isEmpty(messages)) {
+ return Collections.EMPTY_LIST;
+ }
+ return Collections.unmodifiableList(Arrays.asList(messages));
+ }
+
+ /**
+ * Extract messages of type kind from the input list.
+ *
+ * @param messages if null, return EMPTY_LIST
+ * @param kind if null, return messages
+ * @see MessageHandler#getMessages(Kind)
+ */
+ public static List getMessages(List messages, IMessage.Kind kind) {
+ if (null == messages) {
+ return Collections.EMPTY_LIST;
+ }
+ if (null == kind) {
+ return messages;
+ }
+ ArrayList result = new ArrayList();
+ for (Iterator iter = messages.iterator(); iter.hasNext();) {
+ IMessage element = (IMessage) iter.next();
+ if (kind == element.getKind()) {
+ result.add(element);
+ }
+ }
+ if (0 == result.size()) {
+ return Collections.EMPTY_LIST;
+ }
+ return result;
+ }
+
+ /**
+ * Map to the kind of messages associated with this string key.
+ * @param kind the String representing the kind of message (IMessage.Kind.toString())
+ * @return Kind the associated IMessage.Kind, or null if not found
+ */
+ public static IMessage.Kind getKind(String kind) {
+ if (null != kind) {
+ kind = kind.toLowerCase();
+ for (Iterator iter = IMessage.KINDS.iterator(); iter.hasNext();) {
+ IMessage.Kind k = (IMessage.Kind) iter.next();
+ if (kind.equals(k.toString())) {
+ return k;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Run visitor over the set of messages in holder,
+ * optionally accumulating those accepted by the visitor
+ */
+ public static IMessage[] visitMessages(IMessageHolder holder,
+ IMessageHandler visitor, boolean accumulate, boolean abortOnFail) {
+ if (null == holder) {
+ return IMessage.RA_IMessage;
+ } else {
+ return visitMessages(holder.getUnmodifiableListView(), visitor, accumulate, abortOnFail);
+ }
+ }
+
+ /**
+ * Run visitor over the set of messages in holder,
+ * optionally accumulating those accepted by the visitor
+ */
+ public static IMessage[] visitMessages(IMessage[] messages,
+ IMessageHandler visitor, boolean accumulate, boolean abortOnFail) {
+ if (LangUtil.isEmpty(messages)) {
+ return IMessage.RA_IMessage;
+ } else {
+ return visitMessages(Arrays.asList(messages), visitor, accumulate, abortOnFail);
+ }
+ }
+
+ /**
+ * Run visitor over a collection of messages,
+ * optionally accumulating those accepted by the visitor
+ * @param messages if null or empty, return IMessage.RA_IMessage
+ * @param visitor run visitor.handleMessage(message) on each
+ * message - if null and messages not empty, IllegalArgumentException
+ * @param accumulate if true, then return accepted IMessage[]
+ * @param abortOnFail if true and visitor returns false, stop visiting
+ * @return IMessage.RA_IMessage if collection is empty, if not accumulate,
+ * or if visitor accepted no IMessage,
+ * or IMessage[] of accepted messages otherwise
+ * @throws IllegalArgumentException if any in collection are not instanceof IMessage
+ */
+ public static IMessage[] visitMessages(Collection /*IMessage*/ messages,
+ IMessageHandler visitor, final boolean accumulate, final boolean abortOnFail) {
+ if (LangUtil.isEmpty(messages)) {
+ return IMessage.RA_IMessage;
+ }
+ LangUtil.throwIaxIfNull(visitor, "visitor");
+ ArrayList result = (accumulate ? new ArrayList() : null);
+ for (Iterator iter = messages.iterator(); iter.hasNext();) {
+ Object o = iter.next();
+ LangUtil.throwIaxIfFalse(o instanceof IMessage, "expected IMessage, got " + o);
+ IMessage m = (IMessage) o;
+ if (visitor.handleMessage(m)) {
+ if (accumulate) {
+ result.add(m);
+ }
+ } else if (abortOnFail) {
+ break;
+ }
+ }
+ if (!accumulate || (0 == result.size())) {
+ return IMessage.RA_IMessage;
+ } else {
+ return (IMessage[]) result.toArray(IMessage.RA_IMessage);
+ }
+ }
+
+ /**
+ * Make an IMessageHandler that handles IMessage if they have the right kind
+ * (or greater) and contain some infix String.
+ * @param kind the IMessage.Kind required of the message
+ * @param orGreater if true, also accept messages with greater kinds, as
+ * defined by IMessage.Kind.COMPARATOR
+ * @param infix the String text to require in the message - may be null or empty
+ * to accept any message with the specified kind.
+ * @return IMessageHandler selector that works to param specs
+ */
+ public static IMessageHandler makeSelector(IMessage.Kind kind, boolean orGreater, String infix) {
+ if (!orGreater && LangUtil.isEmpty(infix)) {
+ if (kind == IMessage.ABORT) {
+ return PICK_ABORT;
+ } else if (kind == IMessage.DEBUG) {
+ return PICK_DEBUG;
+ } else if (kind == IMessage.DEBUG) {
+ return PICK_DEBUG;
+ } else if (kind == IMessage.ERROR) {
+ return PICK_ERROR;
+ } else if (kind == IMessage.FAIL) {
+ return PICK_FAIL;
+ } else if (kind == IMessage.INFO) {
+ return PICK_INFO;
+ } else if (kind == IMessage.WARNING) {
+ return PICK_WARNING;
+ }
+ }
+ return new KindSelector(kind, orGreater, infix);
+ }
+
+ // ------------------ visitors to select messages
+ public static final IMessageHandler PICK_ALL = new KindSelector((IMessage.Kind) null);
+ public static final IMessageHandler PICK_ABORT = new KindSelector(IMessage.ABORT);
+ public static final IMessageHandler PICK_DEBUG = new KindSelector(IMessage.DEBUG);
+ public static final IMessageHandler PICK_ERROR = new KindSelector(IMessage.ERROR);
+ public static final IMessageHandler PICK_FAIL = new KindSelector(IMessage.FAIL);
+ public static final IMessageHandler PICK_INFO = new KindSelector(IMessage.INFO);
+ public static final IMessageHandler PICK_WARNING = new KindSelector(IMessage.WARNING);
+ public static final IMessageHandler PICK_ABORT_PLUS = new KindSelector(IMessage.ABORT, true);
+ public static final IMessageHandler PICK_DEBUG_PLUS = new KindSelector(IMessage.DEBUG, true);
+ public static final IMessageHandler PICK_ERROR_PLUS = new KindSelector(IMessage.ERROR, true);
+ public static final IMessageHandler PICK_FAIL_PLUS = new KindSelector(IMessage.FAIL, true);
+ public static final IMessageHandler PICK_INFO_PLUS = new KindSelector(IMessage.INFO, true);
+ public static final IMessageHandler PICK_WARNING_PLUS = new KindSelector(IMessage.WARNING, true);
+
+
+ /** implementation for PICK_... constants */
+ private static class KindSelector implements IMessageHandler {
+ final IMessage.Kind sought;
+ final boolean floor;
+ final String infix;
+
+ KindSelector(IMessage.Kind sought) {
+ this(sought, false);
+ }
+
+ KindSelector(IMessage.Kind sought, boolean floor) {
+ this(sought, floor, null);
+ }
+
+ KindSelector(IMessage.Kind sought, boolean floor, String infix) {
+ this.sought = sought;
+ this.floor = floor;
+ this.infix = (LangUtil.isEmpty(infix) ? null : infix);
+ }
+
+ /** @return false if this message is null,
+ * of true if we seek any kind (null)
+ * or if this has the exact kind we seek
+ * and this has any text sought
+ */
+ public boolean handleMessage(IMessage message) {
+ return ((null != message) && !isIgnoring(message.getKind())
+ && textIn(message));
+ }
+
+ /** @return true if handleMessage would return false for a message of this kind */
+ public boolean isIgnoring(IMessage.Kind kind) {
+ if (!floor) {
+ return ((null != sought) && (sought != kind));
+ } else if (null == sought) {
+ return false;
+ } else {
+ return (0 < IMessage.Kind.COMPARATOR.compare(sought, kind));
+ }
+ }
+
+ private boolean textIn(IMessage message) {
+ if (null == infix) {
+ return true;
+ }
+ String text = message.getMessage();
+ return ((null != message) && (-1 != text.indexOf(infix)));
+ }
+ }
+
+ // ------------------ components to render messages
+ /** parameterize rendering behavior for messages */
+ public static interface IMessageRenderer {
+ String renderToString(IMessage message);
+ }
+
+
+ /** render message more verbosely if it is worse */
+ public static final IMessageRenderer MESSAGE_SCALED = new IMessageRenderer() {
+ public String toString() { return "MESSAGE_SCALED"; }
+ public String renderToString(IMessage message) {
+ if (null == message) {
+ return "((IMessage) null)";
+ }
+ IMessage.Kind kind = message.getKind();
+ int level = 3;
+ if ((kind == IMessage.ABORT) || (kind == IMessage.FAIL)) {
+ level = 1;
+ } else if ((kind == IMessage.ERROR) || (kind == IMessage.WARNING)) {
+ level = 2;
+ } else {
+ level = 3;
+ }
+ String result = null;
+ switch (level) {
+ case (1) :
+ result = MESSAGE_TOSTRING.renderToString(message);
+ break;
+ case (2) :
+ result = MESSAGE_LINE.renderToString(message);
+ break;
+ case (3) :
+ result = MESSAGE_SHORT.renderToString(message);
+ break;
+ }
+ Throwable thrown = message.getThrown();
+ if (null != thrown) {
+ if (level == 3) {
+ result += "Thrown: \n" + LangUtil.renderExceptionShort(thrown);
+ } else {
+ result += "Thrown: \n" + LangUtil.renderException(thrown);
+ }
+ }
+
+ return result;
+ }
+ };
+
+ /** render message as label, i.e., less than 33 char */
+ public static final IMessageRenderer MESSAGE_LABEL = new IMessageRenderer() {
+ public String toString() { return "MESSAGE_LABEL"; }
+ public String renderToString(IMessage message) {
+ if (null == message) {
+ return "((IMessage) null)";
+ }
+ return renderMessageLine(message, 5, 5, 32);
+ }
+ };
+
+ /** render message as label, i.e., less than 33 char, with no source location */
+ public static final IMessageRenderer MESSAGE_LABEL_NOLOC = new IMessageRenderer() {
+ public String toString() { return "MESSAGE_LABEL_NOLOC"; }
+ public String renderToString(IMessage message) {
+ if (null == message) {
+ return "((IMessage) null)";
+ }
+ return renderMessageLine(message, 10, 0, 32);
+ }
+ };
+
+ /** render message as line, i.e., less than 75 char, no internal line sep */
+ public static final IMessageRenderer MESSAGE_LINE = new IMessageRenderer() {
+ public String toString() { return "MESSAGE_LINE"; }
+ public String renderToString(IMessage message) {
+ if (null == message) {
+ return "((IMessage) null)";
+ }
+ return renderMessageLine(message, 8, 2, 74);
+ }
+ };
+
+ /** render message as line, i.e., less than 75 char, no internal line sep,
+ * trying to trim text as needed to end with a full source location */
+ public static final IMessageRenderer MESSAGE_LINE_FORCE_LOC = new IMessageRenderer() {
+ public String toString() { return "MESSAGE_LINE_FORCE_LOC"; }
+ public String renderToString(IMessage message) {
+ if (null == message) {
+ return "((IMessage) null)";
+ }
+ return renderMessageLine(message, 2, 40, 74);
+ }
+ };
+
+ /** render message without restriction, up to 10K, including throwable */
+ public static final IMessageRenderer MESSAGE_ALL = new IMessageRenderer() {
+ public String toString() { return "MESSAGE_ALL"; }
+ public String renderToString(IMessage message) {
+ return renderMessage(message);
+ }
+ };
+
+// /** render message without restriction, up to 10K, including (but eliding) throwable */
+// public static final IMessageRenderer MESSAGE_ALL_ELIDED= new IMessageRenderer() {
+// public String toString() { return "MESSAGE_ALL_ELIDED"; }
+// public String renderToString(IMessage message) {
+// return renderMessage(message, true);
+// }
+// };
+
+ /** render message without restriction, except any Throwable thrown */
+ public static final IMessageRenderer MESSAGE_MOST = new IMessageRenderer() {
+ public String toString() { return "MESSAGE_MOST"; }
+ public String renderToString(IMessage message) {
+ if (null == message) {
+ return "((IMessage) null)";
+ }
+ return renderMessageLine(message, 1, 1, 10000);
+ }
+ };
+
+ /** render message as wide line, i.e., less than 256 char, no internal line sep,
+ * except any Throwable thrown
+ */
+ public static final IMessageRenderer MESSAGE_WIDELINE = new IMessageRenderer() {
+ public String toString() { return "MESSAGE_WIDELINE"; }
+ public String renderToString(IMessage message) {
+ if (null == message) {
+ return "((IMessage) null)";
+ }
+ return renderMessageLine(message, 8, 2, 255); // XXX revert to 256
+ }
+ };
+ /** render message using its toString() or "((IMessage) null)" */
+ public static final IMessageRenderer MESSAGE_TOSTRING = new IMessageRenderer() {
+ public String toString() { return "MESSAGE_TOSTRING"; }
+ public String renderToString(IMessage message) {
+ if (null == message) {
+ return "((IMessage) null)";
+ }
+ return message.toString();
+ }
+ };
+
+ /** render message using toShortString(IMessage)" */
+ public static final IMessageRenderer MESSAGE_SHORT = new IMessageRenderer() {
+ public String toString() { return "MESSAGE_SHORT"; }
+ public String renderToString(IMessage message) {
+ return toShortString(message);
+ }
+ };
+
+ /**
+ * This renders IMessage as String, ignoring empty elements
+ * and eliding any thrown stack traces.
+ * @return "((IMessage) null)" if null or String rendering otherwise,
+ * including everything (esp. throwable stack trace)
+ * @see renderSourceLocation(ISourceLocation loc)
+ */
+ public static String renderMessage(IMessage message) {
+ return renderMessage(message, true);
+ }
+
+ /**
+ * This renders IMessage as String, ignoring empty elements
+ * and eliding any thrown.
+ * @return "((IMessage) null)" if null or String rendering otherwise,
+ * including everything (esp. throwable stack trace)
+ * @see renderSourceLocation(ISourceLocation loc)
+ */
+ public static String renderMessage(IMessage message, boolean elide) {
+ if (null == message) {
+ return "((IMessage) null)";
+ }
+ StringBuffer result = new StringBuffer();
+
+ result.append(message.getKind().toString());
+ result.append(" ");
+
+ String messageString = message.getMessage();
+ if (!LangUtil.isEmpty(messageString)) {
+ result.append(messageString);
+ result.append(" ");
+ }
+
+ ISourceLocation loc = message.getISourceLocation();
+ if ((null != loc) && (loc != ISourceLocation.EMPTY)) {
+ result.append("at " + renderSourceLocation(loc));
+ }
+ Throwable thrown = message.getThrown();
+ if (null != thrown) {
+ result.append(" -- " + LangUtil.renderExceptionShort(thrown));
+ result.append("\n" + LangUtil.renderException(thrown, elide));
+ }
+ return result.toString();
+ }
+
+ /**
+ * Render ISourceLocation to String, ignoring empty elements
+ * (null or ISourceLocation.NO_FILE or ISourceLocation.NO_COLUMN
+ * (though implementations may return 0 from getColumn() when
+ * passed NO_COLUMN as input)).
+ * @return "((ISourceLocation) null)" if null or String rendering
+ * <pre>{file:}line{:column}</pre>
+ *
+ */
+ public static String renderSourceLocation(ISourceLocation loc) {
+ if (null == loc) {
+ return "((ISourceLocation) null)";
+ }
+ StringBuffer sb = new StringBuffer();
+
+ File sourceFile = loc.getSourceFile();
+ if (sourceFile != ISourceLocation.NO_FILE) {
+ sb.append(sourceFile.getPath());
+ sb.append(":");
+ }
+ int line = loc.getLine();
+ sb.append("" + line);
+
+ int column = loc.getColumn();
+ if (column != ISourceLocation.NO_COLUMN) {
+ sb.append(":" + column);
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Render message in a line.
+ * IMessage.Kind is always printed, then any unqualified exception class,
+ * then the remainder of text and location according to their relative scale,
+ * all to fit in max characters or less.
+ * This does not render thrown except for the unqualified class name
+ * @param max the number of characters - forced to 32..10000
+ * @param textScale relative proportion to spend on message and/or exception
+ * message, relative to source location - if 0, message is suppressed
+ * @param locScale relative proportion to spend on source location
+ * suppressed if 0
+ * @return "((IMessage) null)" or message per spec
+ */
+ public static String renderMessageLine(
+ IMessage message,
+ int textScale,
+ int locScale,
+ int max) {
+
+ if (null == message) {
+ return "((IMessage) null)";
+ }
+ if (max < 32) {
+ max = 32;
+ } else if (max > 10000) {
+ max = 10000;
+ }
+ if (0 > textScale) {
+ textScale = -textScale;
+ }
+ if (0 > locScale) {
+ locScale = -locScale;
+ }
+
+ String text = message.getMessage();
+ Throwable thrown = message.getThrown();
+ ISourceLocation sl = message.getISourceLocation();
+ IMessage.Kind kind = message.getKind();
+ StringBuffer result = new StringBuffer();
+ result.append(kind.toString());
+ result.append(": ");
+ if (null != thrown) {
+ result.append(LangUtil.unqualifiedClassName(thrown) + " ");
+ if ((null == text) || ("".equals(text))) {
+ text = thrown.getMessage();
+ }
+ }
+
+ if (0 == textScale) {
+ text = "";
+ } else if ((null != text) && (null != thrown)) {
+ // decide between message and exception text?
+ String s = thrown.getMessage();
+ if ((null != s) && (0 < s.length())) {
+ text += " - " + s;
+ }
+ }
+ String loc = "";
+ if ((0 != locScale) && (null != sl)) {
+ File f = sl.getSourceFile();
+ if (f == ISourceLocation.NO_FILE) {
+ f = null;
+ }
+ if (null != f) {
+ loc = f.getName();
+ }
+ int line = sl.getLine();
+ int col = sl.getColumn();
+ int end = sl.getEndLine();
+ if ((0 == line) && (0 == col) && (0 == end)) {
+ // ignore numbers if default
+ } else {
+ loc += ":" + line + (col == 0 ? "" : ":" + col);
+ if (line != end) { // XXX consider suppressing nonstandard...
+ loc += ":" + end;
+ }
+ }
+ if (!LangUtil.isEmpty(loc)) {
+ loc = "@[" + loc; // matching "]" added below after clipping
+ }
+ }
+
+ // now budget between text and loc
+ float totalScale = locScale + textScale;
+ float remainder = max - result.length() - 4;
+ if ((remainder > 0) && (0 < totalScale)) {
+ int textSize = (int) (remainder * textScale/totalScale);
+ int locSize = (int) (remainder * locScale/totalScale);
+ // adjust for underutilization
+ int extra = locSize - loc.length();
+ if (0 < extra) {
+ locSize = loc.length();
+ textSize += extra;
+ }
+ extra = textSize - text.length();
+ if (0 < extra) {
+ textSize = text.length();
+ if (locSize < loc.length()) {
+ locSize += extra;
+ }
+ }
+ if (locSize > loc.length()) {
+ locSize = loc.length();
+ }
+ if (textSize > text.length()) {
+ textSize = text.length();
+ }
+ if (0 < textSize) {
+ result.append(text.substring(0, textSize));
+ }
+ if (0 < locSize) {
+ if (0 < textSize) {
+ result.append(" ");
+ }
+ result.append(loc.substring(0, locSize) + "]");
+ }
+ }
+ return result.toString();
+ }
+
+ /** @return String of the form "{(# {type}) }.." for message kinds, skipping 0 */
+ public static String renderCounts(IMessageHolder holder) {
+ if (0 == holder.numMessages(null, false)) {
+ return "(0 messages)";
+ }
+ StringBuffer sb = new StringBuffer();
+ for (Iterator iter = IMessage.KINDS.iterator(); iter.hasNext();) {
+ IMessage.Kind kind = (IMessage.Kind) iter.next();
+ int num = holder.numMessages(kind, false);
+ if (0 < num) {
+ sb.append(" (" + num + " " + kind + ") ");
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Factory for handler adapted to PrintStream
+ * XXX weak - only handles println(String)
+ * @param handler the IMessageHandler sink for the messages generated
+ * @param kind the IMessage.Kind of message to create
+ * @param overage the OuputStream for text not captured by the handler
+ * (if null, System.out used)
+ * @throws IllegalArgumentException if kind or handler is null
+ */
+ public static PrintStream handlerPrintStream(final IMessageHandler handler,
+ final IMessage.Kind kind, final OutputStream overage, final String prefix) {
+ LangUtil.throwIaxIfNull(handler, "handler");
+ LangUtil.throwIaxIfNull(kind, "kind");
+ class HandlerPrintStream extends PrintStream {
+ HandlerPrintStream() {
+ super(null == overage ? System.out : overage);
+ }
+ public void println() {
+ println("");
+ }
+ public void println(Object o) {
+ println(null == o ? "null" : o.toString());
+ }
+ public void println(String input) {
+ String textMessage = (null == prefix ? input : prefix + input);
+ IMessage m = new Message(textMessage, kind, null, null);
+ handler.handleMessage(m);
+ }
+ }
+ return new HandlerPrintStream();
+ }
+
+ /** utility class */
+ private MessageUtil() {}
+}
diff --git a/bridge/src/org/aspectj/bridge/MessageWriter.java b/bridge/src/org/aspectj/bridge/MessageWriter.java
new file mode 100644
index 000000000..467002c3b
--- /dev/null
+++ b/bridge/src/org/aspectj/bridge/MessageWriter.java
@@ -0,0 +1,67 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.bridge;
+
+import java.io.PrintWriter;
+
+/**
+ * An IMessageHandler implementation that writes all to a PrintWriter.
+ * Clients may set this up to throw AbortException for FAIL or ERROR messages.
+ * Subclasses may control whether messages are printed and how they
+ * are rendered by overriding render(IMessage).
+ */
+public class MessageWriter implements IMessageHandler {
+
+ protected PrintWriter writer;
+ protected boolean abortOnFailure;
+ public MessageWriter(PrintWriter writer, boolean abortOnFailure) {
+ this.writer = (null != writer ? writer : new PrintWriter(System.out));
+ this.abortOnFailure = abortOnFailure;
+ }
+
+ /**
+ * Handle message by printing and
+ * (if abortOnFailure) throwing an AbortException if
+ * the messages is a failure or an abort (but not for errors).
+ * @see org.aspectj.bridge.IMessageHandler#handleMessage(IMessage)
+ */
+ public boolean handleMessage(IMessage message) throws AbortException {
+ if ((null != message) && !isIgnoring(message.getKind())) {
+ String result = render(message);
+ if (null != result) {
+ writer.println(result);
+ writer.flush();
+ if (abortOnFailure
+ && (message.isFailed() || message.isAbort())) {
+ throw new AbortException(message);
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * @see org.aspectj.bridge.IMessageHandler#isIgnoring(Kind)
+ */
+ public boolean isIgnoring(IMessage.Kind kind) {
+ // XXX share MessageHandler implementation in superclass
+ return false;
+ }
+
+ /** @return null to not print, or message rendering (including newlines) */
+ protected String render(IMessage message) {
+ return message.toString();
+ }
+
+}
diff --git a/bridge/src/org/aspectj/bridge/ReflectionFactory.java b/bridge/src/org/aspectj/bridge/ReflectionFactory.java
new file mode 100644
index 000000000..f78352416
--- /dev/null
+++ b/bridge/src/org/aspectj/bridge/ReflectionFactory.java
@@ -0,0 +1,106 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.bridge;
+
+import java.lang.reflect.Constructor;
+import java.util.Arrays;
+
+/**
+ *
+ */
+public class ReflectionFactory { // XXX lease, pool
+ public static final String OLD_AJC = "bridge.tools.impl.OldAjc";
+ public static final String ECLIPSE = "org.aspectj.ajdt.ajc.AjdtCommand";
+
+ private static final Object[] NONE = new Object[0];
+
+ /**
+ * Produce a compiler as an ICommand.
+ * @param cname the fully-qualified class name of the command
+ * to create by reflection (assuming a public no-argument constructor).
+ * @return ICommand compiler or null
+ */
+ public static ICommand makeCommand(String cname,
+ IMessageHandler errorSink) {
+ return (ICommand) make(ICommand.class, cname, NONE, errorSink);
+ }
+
+ /**
+ * Make an object of type c by reflectively loading the class
+ * cname and creating an instance using args (if any),
+ * signalling errors (if any) to any errorSink.
+ */
+ private static Object make(Class c, String cname, Object[] args,
+ IMessageHandler errorSink) {
+ final boolean makeErrors = (null != errorSink);
+ Object result = null;
+ try {
+ final Class cfn = Class.forName(cname);
+ String error = null;
+ if (args == NONE) {
+ result = cfn.newInstance();
+ } else {
+ Class[] types = getTypes(args);
+ Constructor constructor = cfn.getConstructor(types);
+ if (null != constructor) {
+ result = constructor.newInstance(args);
+ } else {
+ if (makeErrors) {
+ error = "no constructor for " + c + " using "
+ + Arrays.asList(types);
+ }
+ }
+ }
+ if (null != result) {
+ if (!c.isAssignableFrom(result.getClass())) {
+ if (makeErrors) {
+ error = "expecting type " + c + " got " + result.getClass();
+ }
+ result = null;
+ }
+ }
+ if (null != error) {
+ IMessage mssg = new Message(error, IMessage.FAIL, null, null);
+ errorSink.handleMessage(mssg);
+ }
+ } catch (Throwable t) {
+ if (makeErrors) {
+ String mssg = "ReflectionFactory unable to load "
+ + cname + " as " + c.getName();
+ IMessage m = new Message(mssg, IMessage.FAIL, t, null);
+ errorSink.handleMessage(m);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * @return Class[] with types of args or matching null elements
+ */
+ private static Class[] getTypes(Object[] args) {
+ if ((null == args) || (0 < args.length)) {
+ return new Class[0];
+ } else {
+ Class[] result = new Class[args.length];
+ for (int i = 0; i < result.length; i++) {
+ if (null != args[i]) {
+ result[i] = args[i].getClass();
+ }
+ }
+ return result;
+ }
+ }
+
+ private ReflectionFactory(){}
+}
diff --git a/bridge/src/org/aspectj/bridge/SourceLocation.java b/bridge/src/org/aspectj/bridge/SourceLocation.java
new file mode 100644
index 000000000..5579082b6
--- /dev/null
+++ b/bridge/src/org/aspectj/bridge/SourceLocation.java
@@ -0,0 +1,132 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.bridge;
+
+
+import org.aspectj.util.LangUtil;
+
+import java.io.File;
+
+/**
+ * Immutable source location.
+ * This guarantees that the source file is not null
+ * and that the numeric values are positive and line <= endLine.
+ * @see org.aspectj.lang.reflect.SourceLocation
+ * @see org.aspectj.compiler.base.parser.SourceInfo
+ * @see org.aspectj.tools.ide.SourceLine
+ * @see org.aspectj.testing.harness.ErrorLine
+ */
+public class SourceLocation implements ISourceLocation, java.io.Serializable {
+
+ /** used when SourceLocation is not available */
+ public static final ISourceLocation UNKNOWN
+ = new SourceLocation(ISourceLocation.NO_FILE, 0, 0, 0);
+
+ /** @throws IllegalArgumentException if the input would not be a valid line */
+ public static final void validLine(int line) {
+ if (line < 0) {
+ throw new IllegalArgumentException("negative line: " + line);
+ } else if (line > ISourceLocation.MAX_LINE) {
+ throw new IllegalArgumentException("line too large: " + line);
+ }
+ }
+
+ /** @throws IllegalArgumentException if the input would not be a valid column */
+ public static final void validColumn(int column) {
+ if (column < 0) {
+ throw new IllegalArgumentException("negative column: " + column);
+ } else if (column > ISourceLocation.MAX_COLUMN) {
+ throw new IllegalArgumentException("column too large: " + column);
+ }
+ }
+
+ private final File sourceFile;
+ private final int line;
+ private final int column;
+ private final int endLine;
+ private boolean noColumn;
+
+ /**
+ * Same as SourceLocation(file, line, line, 0),
+ * except that column is not rendered during toString()
+ */
+ public SourceLocation(File file, int line) {
+ this(file, line, line, NO_COLUMN);
+ }
+
+ /** same as SourceLocation(file, line, endLine, ISourceLocation.NO_COLUMN) */
+ public SourceLocation(File file, int line, int endLine) {
+ this(file, line, endLine, ISourceLocation.NO_COLUMN);
+ }
+
+ /**
+ * @param file File of the source; if null, use ISourceLocation.NO_FILE, not null
+ * @param line int starting line of the location - positive number
+ * @param endLine int ending line of the location - <= starting line
+ * @param column int character position of starting location - positive number
+ */
+ public SourceLocation(File file, int line, int endLine, int column) {
+ if (column == NO_COLUMN) {
+ column = 0;
+ noColumn = true;
+ }
+ if (null == file) {
+ file = ISourceLocation.NO_FILE;
+ }
+ validLine(line);
+ validLine(endLine);
+ LangUtil.throwIaxIfFalse(line <= endLine , line + " > " + endLine);
+ LangUtil.throwIaxIfFalse(column >= 0, "negative column: " + column);
+ this.sourceFile = file;
+ this.line = line;
+ this.column = column;
+ this.endLine = endLine;
+ }
+
+ public File getSourceFile() {
+ return sourceFile;
+ }
+ public int getLine() {
+ return line;
+ }
+
+ /**
+ * @return int actual column or 0 if not available per constructor treatment
+ * of ISourceLocation.NO_COLUMN
+ */
+ public int getColumn() {
+ return column;
+ }
+
+ public int getEndLine() {
+ return line;
+ }
+
+ /** @return String {file:}line{:column} */
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+
+ if (sourceFile != ISourceLocation.NO_FILE) {
+ sb.append(sourceFile.getPath());
+ sb.append(":");
+ }
+ sb.append("" + line);
+ if (!noColumn) {
+ sb.append(":" + column);
+ }
+ return sb.toString();
+ }
+
+
+}
diff --git a/bridge/src/org/aspectj/bridge/Version.java b/bridge/src/org/aspectj/bridge/Version.java
new file mode 100644
index 000000000..bbaa2dad3
--- /dev/null
+++ b/bridge/src/org/aspectj/bridge/Version.java
@@ -0,0 +1,67 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2002 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.bridge;
+
+import java.text.ParsePosition;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/** release-specific version information */
+public class Version {
+
+ /** default version value for development version */
+ public static final String DEVELOPMENT = "DEVELOPMENT";
+
+ /** default time value for development version */
+ public static final long NOTIME = 0L;
+
+ /** set by build script */
+ public static final String text = DEVELOPMENT;
+
+ /**
+ * Time text set by build script using SIMPLE_DATE_FORMAT.
+ * (if DEVELOPMENT version, invalid)
+ */
+ public static final String time_text = "";
+
+ /**
+ * time in seconds-since-... format, used by programmatic clients.
+ * (if DEVELOPMENT version, NOTIME)
+ */
+ public static final long time;
+
+ /** format used by build script to set time_text */
+ public static final String SIMPLE_DATE_FORMAT = "";
+
+ // if not DEVELOPMENT version, read time text using format used to set time
+ static {
+ long foundTime = NOTIME;
+ if (!DEVELOPMENT.equals(text)) {
+ try {
+ SimpleDateFormat format = new SimpleDateFormat(SIMPLE_DATE_FORMAT);
+ ParsePosition pos = new ParsePosition(0);
+ Date date = format.parse(time_text, pos);
+ foundTime = date.getTime();
+ } catch (Throwable t) {
+ }
+ }
+ time = foundTime;
+ }
+}
+
+
+
+
+
diff --git a/bridge/testsrc/BridgeModuleTests.java b/bridge/testsrc/BridgeModuleTests.java
new file mode 100644
index 000000000..db563fd49
--- /dev/null
+++ b/bridge/testsrc/BridgeModuleTests.java
@@ -0,0 +1,30 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+
+// default package
+
+import junit.framework.*;
+import junit.framework.Test;
+
+public class BridgeModuleTests extends TestCase {
+
+ public static Test suite() {
+ TestSuite suite = new TestSuite(BridgeModuleTests.class.getName());
+ suite.addTest(org.aspectj.bridge.BridgeTests.suite());
+ return suite;
+ }
+
+ public BridgeModuleTests(String name) { super(name); }
+
+}
diff --git a/bridge/testsrc/org/aspectj/bridge/BridgeTests.java b/bridge/testsrc/org/aspectj/bridge/BridgeTests.java
new file mode 100644
index 000000000..2ab9b9ac1
--- /dev/null
+++ b/bridge/testsrc/org/aspectj/bridge/BridgeTests.java
@@ -0,0 +1,33 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.bridge;
+
+import junit.framework.*;
+
+public class BridgeTests extends TestCase {
+
+ public static Test suite() {
+ TestSuite suite = new TestSuite(BridgeTests.class.getName());
+ //$JUnit-BEGIN$
+ suite.addTestSuite(CountingMessageHandlerTest.class);
+ suite.addTestSuite(MessageTest.class);
+ suite.addTestSuite(VersionTest.class);
+ //$JUnit-END$
+ return suite;
+ }
+
+ public BridgeTests(String name) { super(name); }
+
+}
diff --git a/bridge/testsrc/org/aspectj/bridge/CountingMessageHandlerTest.java b/bridge/testsrc/org/aspectj/bridge/CountingMessageHandlerTest.java
new file mode 100644
index 000000000..423501e13
--- /dev/null
+++ b/bridge/testsrc/org/aspectj/bridge/CountingMessageHandlerTest.java
@@ -0,0 +1,90 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.bridge;
+
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Comparator;
+import java.util.List;
+import java.util.ListIterator;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+import junit.textui.TestRunner;
+
+/**
+ *
+ */
+public class CountingMessageHandlerTest extends TestCase {
+
+ private static final String ME
+ = "org.aspectj.bridge.CountingMessageHandlerTest"; // XXX
+
+ /** @param args ignored */
+ public static void main(String[] args) {
+ TestRunner.main(new String[] {ME});
+ }
+
+ /**
+ * Constructor for MessageTest.
+ * @param name
+ */
+ public CountingMessageHandlerTest(String name) {
+ super(name);
+ }
+
+ public void testSimpleWrapping() {
+ MessageHandler m = new MessageHandler();
+ CountingMessageHandler me = new CountingMessageHandler(m);
+ checkCountingMessageHandler(me);
+ }
+
+ public void testCounterWrapping() {
+ MessageHandler m = new MessageHandler();
+ CountingMessageHandler first = new CountingMessageHandler(m);
+ CountingMessageHandler me = new CountingMessageHandler(first);
+ checkCountingMessageHandler(me);
+ }
+
+ void checkCountingMessageHandler(CountingMessageHandler me) {
+ MessageUtil.warn(me, "warn 1");
+ assertTrue(!me.hasErrors());
+ assertEquals(0 , me.numMessages(IMessage.ERROR, false));
+ assertEquals(1 , me.numMessages(IMessage.WARNING, false));
+ assertEquals(0 , me.numMessages(IMessage.INFO, false));
+ assertEquals(0 , me.numMessages(IMessage.ERROR, true));
+ assertEquals(1 , me.numMessages(IMessage.WARNING, true));
+ assertEquals(1 , me.numMessages(IMessage.INFO, true));
+
+ MessageUtil.info(me, "info 1");
+ assertTrue(!me.hasErrors());
+ assertEquals(0 , me.numMessages(IMessage.ERROR, false));
+ assertEquals(1 , me.numMessages(IMessage.WARNING, false));
+ assertEquals(1 , me.numMessages(IMessage.INFO, false));
+ assertEquals(0 , me.numMessages(IMessage.ERROR, true));
+ assertEquals(1 , me.numMessages(IMessage.WARNING, true));
+ assertEquals(2 , me.numMessages(IMessage.INFO, true));
+
+ MessageUtil.error(me, "error 1");
+ assertTrue(me.hasErrors());
+ assertEquals(1 , me.numMessages(IMessage.ERROR, false));
+ assertEquals(1 , me.numMessages(IMessage.WARNING, false));
+ assertEquals(1 , me.numMessages(IMessage.INFO, false));
+ assertEquals(1 , me.numMessages(IMessage.ERROR, true));
+ assertEquals(2 , me.numMessages(IMessage.WARNING, true));
+ assertEquals(3 , me.numMessages(IMessage.INFO, true));
+ }
+}
diff --git a/bridge/testsrc/org/aspectj/bridge/MessageTest.java b/bridge/testsrc/org/aspectj/bridge/MessageTest.java
new file mode 100644
index 000000000..6f370eeb3
--- /dev/null
+++ b/bridge/testsrc/org/aspectj/bridge/MessageTest.java
@@ -0,0 +1,300 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.bridge;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Comparator;
+import java.util.List;
+import java.util.ListIterator;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+import junit.textui.TestRunner;
+
+/**
+ *
+ */
+public class MessageTest extends TestCase {
+
+ private static final String ME
+ = "org.aspectj.bridge.MessageTest"; // XXX
+
+ /** @param args ignored */
+ public static void main(String[] args) {
+ TestRunner.main(new String[] {ME});
+ }
+
+ /**
+ * Constructor for MessageTest.
+ * @param name
+ */
+ public MessageTest(String name) {
+ super(name);
+ }
+
+ void checkListOrder(List list, Comparator c) { // XXX util
+ assertNotNull(list);
+ assertNotNull(c);
+ ListIterator it = list.listIterator();
+ Object last = null;
+ Object current = null;
+ while (it.hasNext()) {
+ current = it.next();
+ if (null != last) {
+ int i = c.compare(last, current);
+ if (i > 0) {
+ assertTrue( last + " > " + current + " (" + i + ")", false);
+ }
+ }
+ last = current;
+ }
+ }
+
+ public void testKindOrder() {
+ // first briefly validate the checker
+ checkListOrder(Arrays.asList(new String[] { "a", "b", "C" }),
+ String.CASE_INSENSITIVE_ORDER);
+ checkListOrder(IMessage.KINDS, IMessage.Kind.COMPARATOR);
+ }
+
+ public void testMessageHandler() {
+ boolean handleMessageResult = true;
+ checkEmptyMessageHolder(new MessageHandler(handleMessageResult), handleMessageResult);
+ handleMessageResult = false;
+ checkEmptyMessageHolder(new MessageHandler(handleMessageResult), handleMessageResult);
+ }
+
+ public void checkEmptyMessageHolder(
+ IMessageHolder h,
+ final boolean handleMessageResult) {
+ // { INFO, DEBUG, WARNING, ERROR, FAIL, ABORT }));
+ assertNotNull(h);
+ assertTrue(!h.hasAnyMessage(null, true));
+ assertTrue(!h.hasAnyMessage(null, false));
+ assertTrue(!h.hasAnyMessage(IMessage.INFO, true));
+ assertTrue(!h.hasAnyMessage(IMessage.INFO, false));
+
+ assertTrue(handleMessageResult == h.handleMessage(make("error 1", IMessage.ERROR)));
+ assertTrue(handleMessageResult == h.handleMessage(make("error 2", IMessage.ERROR)));
+ assertTrue(handleMessageResult == h.handleMessage(make("fail 1", IMessage.FAIL)));
+ assertTrue(handleMessageResult == h.handleMessage(make("fail 2", IMessage.FAIL)));
+ assertTrue(handleMessageResult == h.handleMessage(make("debug 1", IMessage.DEBUG)));
+ assertTrue(handleMessageResult == h.handleMessage(make("debug 2", IMessage.DEBUG)));
+
+ assertTrue(h.hasAnyMessage(null, true));
+ assertTrue(h.hasAnyMessage(null, false));
+ assertTrue(h.hasAnyMessage(IMessage.ERROR, true));
+ assertTrue(h.hasAnyMessage(IMessage.ERROR, false));
+ assertTrue(h.hasAnyMessage(IMessage.FAIL, true));
+ assertTrue(h.hasAnyMessage(IMessage.FAIL, false));
+ assertTrue(h.hasAnyMessage(IMessage.DEBUG, true));
+ assertTrue(h.hasAnyMessage(IMessage.DEBUG, false));
+
+ assertTrue(!h.hasAnyMessage(IMessage.INFO, IMessageHolder.EQUAL));
+ assertTrue(!h.hasAnyMessage(IMessage.WARNING, IMessageHolder.EQUAL));
+ assertTrue(!h.hasAnyMessage(IMessage.ABORT, IMessageHolder.EQUAL));
+ assertTrue(h.hasAnyMessage(IMessage.INFO, IMessageHolder.ORGREATER));
+ assertTrue(h.hasAnyMessage(IMessage.WARNING, IMessageHolder.ORGREATER));
+ assertTrue(!h.hasAnyMessage(IMessage.ABORT, IMessageHolder.ORGREATER));
+
+ assertTrue(0 == h.numMessages(IMessage.INFO, IMessageHolder.EQUAL));
+ assertTrue(0 == h.numMessages(IMessage.WARNING, IMessageHolder.EQUAL));
+ assertTrue(0 == h.numMessages(IMessage.ABORT, IMessageHolder.EQUAL));
+
+ assertTrue(6 == h.numMessages(null, IMessageHolder.ORGREATER));
+ assertTrue(6 == h.numMessages(null, IMessageHolder.EQUAL));
+ assertTrue(6 == h.numMessages(IMessage.INFO, IMessageHolder.ORGREATER));
+ assertTrue(6 == h.numMessages(IMessage.DEBUG, IMessageHolder.ORGREATER));
+ assertTrue(4 == h.numMessages(IMessage.WARNING, IMessageHolder.ORGREATER));
+ assertTrue(4 == h.numMessages(IMessage.ERROR, IMessageHolder.ORGREATER));
+ assertTrue(2 == h.numMessages(IMessage.FAIL, IMessageHolder.ORGREATER));
+ assertTrue(0 == h.numMessages(IMessage.ABORT, IMessageHolder.ORGREATER));
+
+ }
+
+ public void testMessage() {
+ String input = "input";
+ Throwable thrown = null;
+ ISourceLocation sl = null;
+ Class exClass = null;
+ String descriptor = "Message"; // for make(...)
+ IMessage.Kind kind = IMessage.INFO;
+
+ // -- kind variants
+ roundTrip(input, kind, thrown, sl, descriptor, exClass);
+ kind = IMessage.WARNING;
+ roundTrip(input, kind, thrown, sl, descriptor, exClass);
+ kind = IMessage.ERROR;
+ roundTrip(input, kind, thrown, sl, descriptor, exClass);
+ kind = IMessage.DEBUG;
+ roundTrip(input, kind, thrown, sl, descriptor, exClass);
+ kind = IMessage.FAIL;
+ roundTrip(input, kind, thrown, sl, descriptor, exClass);
+
+ // -- throwable
+ kind = IMessage.FAIL;
+ thrown = AbortException.ABORT;
+ input = null;
+ roundTrip(input, kind, thrown, sl, descriptor, exClass);
+
+ // -- source location
+ kind = IMessage.WARNING;
+ thrown = null;
+ input = "type not found";
+ File f = new File("some/file.java"); // XXX unchecked
+ sl = new SourceLocation(f, 0, 0, 0);
+ roundTrip(input, kind, thrown, sl, descriptor, exClass);
+ sl = new SourceLocation(f, 1, 1, 0);
+ roundTrip(input, kind, thrown, sl, descriptor, exClass);
+
+ // -- input error tests - null kind, null input (factory-dependent)
+ kind = null;
+ exClass = IllegalArgumentException.class;
+ roundTrip(input, kind, thrown, sl, descriptor, exClass);
+ input = null;
+ kind = IMessage.INFO;
+ roundTrip(input, kind, thrown, sl, descriptor, exClass);
+ }
+
+ protected IMessage make(String message, IMessage.Kind kind) {
+ return new Message(message, kind, null, null);
+ }
+
+ /** make a Message per descriptor and input */
+ protected IMessage make(String input, IMessage.Kind kind,
+ Throwable thrown, ISourceLocation sourceLocation,
+ String descriptor) { // XXX ignored for now
+ return new Message(input, kind, thrown, sourceLocation);
+ }
+
+ /**
+ * Simple round-trip on the message
+ */
+ protected void roundTrip(String input, IMessage.Kind kind,
+ Throwable thrown, ISourceLocation sourceLocation,
+ String descriptor, Class exClass) {
+ try {
+ IMessage m = make(input, kind, thrown, sourceLocation, descriptor);
+ roundTripCheck(m, input, kind, thrown, sourceLocation);
+ } catch (AssertionFailedError x) {
+ throw x;
+ } catch (Throwable t) {
+ assertTrue(null != exClass);
+ assertTrue(exClass.isAssignableFrom(t.getClass()));
+ }
+ }
+
+ protected void roundTripCheck(IMessage message, String input, IMessage.Kind kind,
+ Throwable thrown, ISourceLocation sourceLocation) {
+ IMessage m = message;
+ assertTrue("not null", null != m);
+ assertTrue(""+input, equals(input, m.getMessage()));
+ assertTrue(""+kind, kind == m.getKind());
+ assertTrue(""+thrown, equals(thrown, m.getThrown()));
+ assertTrue(""+sourceLocation,
+ equals(sourceLocation, m.getISourceLocation()));
+ String err = new KindTest().testKindSet(message, kind);
+ if (null != err) {
+ assertTrue(err, false);
+ }
+ }
+
+ protected static boolean equals(Object one, Object two) {
+ if (null == one) {
+ return (null == two);
+ } else if (null == two) {
+ return false;
+ } else {
+ return one.equals(two);
+ }
+ }
+}
+
+/** test correlation between message and enclosed kind */
+class KindTest {
+ /** order tracked in checkKindMethods() */
+ static final IMessage.Kind[] KINDS = new IMessage.Kind[]
+ { IMessage.ABORT, IMessage.DEBUG, IMessage.ERROR,
+ IMessage.INFO, IMessage.WARNING, IMessage.FAIL };
+
+ static final List KINDLIST = Arrays.asList(KINDS);
+
+ /** used to clear instance BitSet */
+ static final BitSet UNSET = new BitSet(KINDS.length);
+
+
+ final BitSet expected = new BitSet(KINDS.length);
+ IMessage.Kind kind = IMessage.INFO;
+
+ /** @return error if failed */
+ public String testKindSet(IMessage m, IMessage.Kind newKind) {
+ IMessage.Kind oldKind = this.kind;
+ String result = setKind(newKind);
+ if (null == result) {
+ result = checkKindSet(m, newKind);
+ }
+ if (null == result) {
+ result = checkExpectedKind(m);
+ }
+ return (null != result? result : setKind(oldKind));
+ }
+
+ /** @return error if failed */
+ private String setKind(IMessage.Kind kind) {
+ this.kind = kind;
+ int index = KINDLIST.indexOf(kind);
+ if (-1 == index) {
+ return "unknown kind: " + kind;
+ }
+ expected.and(UNSET);
+ expected.set(index);
+ return null;
+ }
+
+ /** @return error if failed */
+ String checkExpectedKind(IMessage m) {
+ StringBuffer result = new StringBuffer();
+ for (int i = 0; i < KINDS.length; i++) {
+ if (expected.get(i) != checkKindMethods(m, i)) {
+ String s = "expected " + expected.get(i)
+ + " for is{Method} for " + KINDS[i];
+ result.append(s + "\n");
+ }
+ }
+ return (0 < result.length() ? result.toString() : null);
+ }
+
+ String checkKindSet(IMessage m, IMessage.Kind kind) {
+ if (kind != m.getKind()) {
+ return "expected kind " + kind + " got " + m.getKind();
+ }
+ return null;
+ }
+
+ /** @return true if index matches isFoo() reporting */
+ boolean checkKindMethods(IMessage m, int index) {
+ switch (index) {
+ case (0) : return m.isAbort();
+ case (1) : return m.isDebug();
+ case (2) : return m.isError();
+ case (3) : return m.isInfo();
+ case (4) : return m.isWarning();
+ case (5) : return m.isFailed();
+ default : throw new IllegalArgumentException("index=" + index);
+
+ }
+ }
+}
diff --git a/bridge/testsrc/org/aspectj/bridge/VersionTest.java b/bridge/testsrc/org/aspectj/bridge/VersionTest.java
new file mode 100644
index 000000000..2dcc1d056
--- /dev/null
+++ b/bridge/testsrc/org/aspectj/bridge/VersionTest.java
@@ -0,0 +1,53 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.bridge;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import junit.framework.TestCase;
+import junit.textui.TestRunner;
+
+/**
+ *
+ */
+public class VersionTest extends TestCase {
+
+ private static final String ME
+ = "org.aspectj.bridge.VersionTest";
+
+ /** @param args ignored */
+ public static void main(String[] args) {
+ TestRunner.main(new String[] {ME});
+ }
+
+ /**
+ * Constructor for MessageTest.
+ * @param name
+ */
+ public VersionTest(String name) {
+ super(name);
+ }
+
+ public void testVersion() {
+ if (Version.DEVELOPMENT.equals(Version.text)) {
+ assertEquals(Version.time, Version.NOTIME);
+ } else {
+ Date date = new Date(Version.time);
+ SimpleDateFormat format = new SimpleDateFormat(Version.SIMPLE_DATE_FORMAT);
+ String timeString = format.format(date);
+ assertEquals(Version.time_text, timeString);
+ }
+ }
+}