/* ******************************************************************* * 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 Eclipse Public License v 2.0 * which accompanies this distribution and is available at * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt * * Contributors: * Xerox/PARC initial implementation * ******************************************************************/ package org.aspectj.testing.xml; import java.io.File; import java.util.ArrayList; //import java.util.Collections; import java.util.List; import org.aspectj.bridge.IMessage; import org.aspectj.bridge.IMessageHolder; import org.aspectj.bridge.ISourceLocation; import org.aspectj.bridge.MessageUtil; import org.aspectj.bridge.SourceLocation; import org.aspectj.util.LangUtil; /** * Implement messages. * This implementation is immutable if ISourceLocation is immutable, * except for adding source locations. */ public class SoftMessage implements IMessage { public static String XMLNAME = "message"; public static final File NO_FILE = ISourceLocation.NO_FILE; private String message; private IMessage.Kind kind; private Throwable thrown; private ISourceLocation sourceLocation; private String details; private int id; private int sourceStart,sourceEnd; private final List extraSourceLocations = new ArrayList(); //private ISourceLocation pseudoSourceLocation; // set directly // collapse enclosed source location for shorter, property-based xml private String file; private int line = Integer.MAX_VALUE; /** convenience for constructing failure messages */ public static SoftMessage fail(String message, Throwable thrown) { return new SoftMessage(message, IMessage.FAIL, thrown, null); } /** * Print messages. * @param messages List of IMessage */ public static void writeXml(XMLWriter out, IMessageHolder messages) { if ((null == out) || (null == messages) || (0 == messages.numMessages(null, true))) { return; } List list = messages.getUnmodifiableListView(); for (Object o : list) { writeXml(out, (IMessage) o); } } /** * Print messages. * @param messages IMessage[] */ public static void writeXml(XMLWriter out, IMessage[] messages) { if ((null == out) || (null == messages)) { return; } for (IMessage iMessage : messages) { writeXml(out, iMessage); } } /** print message as an element * XXX has to sync with ajcTests.dtd * @throws IllegalArgumentException if message.getThrown() is not null */ public static void writeXml( XMLWriter out, IMessage message) { // XXX short form only, no files if ((null == out) || (null == message)) { return; } Throwable thrown = message.getThrown(); if (null != thrown) { String m = "unable to write " + message + " thrown not permitted"; throw new IllegalArgumentException(m); } final String elementName = XMLNAME; out.startElement(elementName, false); out.printAttribute("kind", message.getKind().toString()); String value = message.getMessage(); if (null != value) { value = XMLWriter.attributeValue(value); out.printAttribute("text", value); } value = message.getDetails(); if (null != value) { value = XMLWriter.attributeValue(value); out.printAttribute("details", value); } ISourceLocation sl = message.getSourceLocation(); if (null != sl) { int line = sl.getLine(); if (-1 < line) { out.printAttribute("line", "" + line); } File file = sl.getSourceFile(); if ((null != file) && !ISourceLocation.NO_FILE.equals(file)) { value = XMLWriter.attributeValue(file.getPath()); out.printAttribute("file", value); } } List extras = message.getExtraSourceLocations(); if (!LangUtil.isEmpty(extras)) { out.endAttributes(); for (Object extra : extras) { /*ISourceLocation element = (ISourceLocation)*/ SoftSourceLocation.writeXml(out, sl); } } out.endElement(elementName); } public SoftMessage() { } // XXX programmatic only /** * 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 SoftMessage( 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 SoftMessage( 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.USAGE */ public boolean isUsage() { return kind == IMessage.USAGE; } /** * @return true if kind == IMessage.INFO */ public boolean isInfo() { return kind == IMessage.INFO; } public boolean isTaskTag() { return kind == IMessage.TASKTAG; } /** @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; } public boolean getDeclared() { return false; } /** @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; } /** * This returns any ISourceLocation set or a mock-up * if file and/or line were set. * @return ISourceLocation associated with this message, * a mock-up if file or line is available, or null if none */ final public ISourceLocation getSourceLocation() { if ((null == sourceLocation) && ((null != file) || (line != Integer.MAX_VALUE))) { File f = (null == file ? NO_FILE : new File(file)); int line = (this.line == Integer.MAX_VALUE ? 0 : this.line); sourceLocation = new SourceLocation(f, line); } return sourceLocation; } /** set the kind of this message */ public void setMessageKind(IMessage.Kind kind) { this.kind = (null == kind ? IMessage.ERROR : kind); } /** set the file for the underlying source location of this message * @throws IllegalStateException if source location was set directly * or indirectly by calling getSourceLocation after setting * file or line. */ public void setFile(String path) { LangUtil.throwIaxIfFalse(!LangUtil.isEmpty(path), "empty path"); if (null != sourceLocation) { throw new IllegalStateException("cannot set line after creating source location"); } this.file = path; } /** set the kind of this message */ public void setKindAsString(String kind) { setMessageKind(MessageUtil.getKind(kind)); } public void setSourceLocation(ISourceLocation sourceLocation) { this.sourceLocation = sourceLocation; } /** * Set the line for the underlying source location. * @throws IllegalStateException if source location was set directly * or indirectly by calling getSourceLocation after setting * file or line. */ public void setLineAsString(String line) { if (null != sourceLocation) { throw new IllegalStateException("cannot set line after creating source location"); } this.line = Integer.parseInt(line); SourceLocation.validLine(this.line); } public void setText(String text) { this.message = (null == text ? "" : text); } public String toString() { StringBuilder result = new StringBuilder(); result.append(null == getKind() ? "" : getKind().toString()); String messageString = getMessage(); if (!LangUtil.isEmpty(messageString)) { result.append(messageString); } ISourceLocation loc = getSourceLocation(); if ((null != loc) && (loc != ISourceLocation.NO_FILE)) { result.append(" at " + loc); } if (null != thrown) { result.append(" -- " + LangUtil.renderExceptionShort(thrown)); } return result.toString(); } public String getDetails() { return details; } public void setDetails(String string) { details = string; } public int getID() { return id; } public void setID(int id) { this.id = id; } public int getSourceStart() { return sourceStart; } public void setSourceStart(int s) { sourceStart = s; } public int getSourceEnd() { return sourceStart; } public void setSourceEnd(int s) { sourceEnd = s; } /* (non-Javadoc) * @see org.aspectj.bridge.IMessage#getExtraSourceLocations() */ public List getExtraSourceLocations() { return extraSourceLocations; } public void addSourceLocation(ISourceLocation location) { if (null != location) { extraSourceLocations.add(location); } } }