diff options
author | wisberg <wisberg> | 2002-12-16 17:09:36 +0000 |
---|---|---|
committer | wisberg <wisberg> | 2002-12-16 17:09:36 +0000 |
commit | c3300283ecc397d26ad9dfe31d1710ec45db2af0 (patch) | |
tree | e9acb7f3d33c1499975cec9ef3cc7ea151078344 /bridge | |
parent | 3cde920c3f7eb8241bf569007e25225d80b43c0f (diff) | |
download | aspectj-c3300283ecc397d26ad9dfe31d1710ec45db2af0.tar.gz aspectj-c3300283ecc397d26ad9dfe31d1710ec45db2af0.zip |
initial version
Diffstat (limited to 'bridge')
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); + } + } +} |