0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041:
0042: package org.apache.tools.ant.module.bridge.impl;
0043:
0044: import java.io.File;
0045: import java.io.IOException;
0046: import java.lang.reflect.Method;
0047: import java.net.URL;
0048: import java.util.ArrayList;
0049: import java.util.Arrays;
0050: import java.util.Collection;
0051: import java.util.Collections;
0052: import java.util.Comparator;
0053: import java.util.Enumeration;
0054: import java.util.HashMap;
0055: import java.util.LinkedHashSet;
0056: import java.util.LinkedList;
0057: import java.util.List;
0058: import java.util.Map;
0059: import java.util.Set;
0060: import java.util.regex.Matcher;
0061: import java.util.regex.Pattern;
0062: import org.apache.tools.ant.BuildEvent;
0063: import org.apache.tools.ant.BuildException;
0064: import org.apache.tools.ant.BuildListener;
0065: import org.apache.tools.ant.Location;
0066: import org.apache.tools.ant.Project;
0067: import org.apache.tools.ant.RuntimeConfigurable;
0068: import org.apache.tools.ant.Target;
0069: import org.apache.tools.ant.Task;
0070: import org.apache.tools.ant.module.bridge.AntBridge;
0071: import org.apache.tools.ant.module.run.Hyperlink;
0072: import org.apache.tools.ant.module.run.LoggerTrampoline;
0073: import org.apache.tools.ant.module.spi.AntEvent;
0074: import org.apache.tools.ant.module.spi.AntLogger;
0075: import org.apache.tools.ant.module.spi.AntSession;
0076: import org.apache.tools.ant.module.spi.TaskStructure;
0077: import org.netbeans.api.progress.ProgressHandle;
0078: import org.openide.ErrorManager;
0079: import org.openide.awt.StatusDisplayer;
0080: import org.openide.util.Lookup;
0081: import org.openide.util.NbBundle;
0082: import org.openide.util.NbCollections;
0083: import org.openide.util.RequestProcessor;
0084: import org.openide.util.WeakSet;
0085: import org.openide.windows.OutputListener;
0086: import org.openide.windows.OutputWriter;
0087:
0088: /**
0089: * NetBeans-sensitive build logger.
0090: * Just delegates all events to the registered SPI loggers
0091: * through an abstraction layer.
0092: * Synchronization: all callbacks are synchronized, both to protect access to logger
0093: * caches, and to prevent AntBridge.suspend/resumeDelegation from being called with
0094: * dynamic overlaps.
0095: * @author Jesse Glick
0096: */
0097: final class NbBuildLogger implements BuildListener,
0098: LoggerTrampoline.AntSessionImpl {
0099:
0100: private static final ErrorManager ERR = ErrorManager.getDefault()
0101: .getInstance(NbBuildLogger.class.getName());
0102: /** hack for debugging unit tests */
0103: private static final int EM_LEVEL = Boolean
0104: .getBoolean(NbBuildLogger.class.getName()
0105: + ".LOG_AT_WARNING") ? // NOI18N
0106: ErrorManager.WARNING
0107: : ErrorManager.INFORMATIONAL;
0108: private static final boolean LOGGABLE = ERR.isLoggable(EM_LEVEL);
0109:
0110: private final AntSession this Session;
0111:
0112: private final File origScript;
0113: private String[] targets = null;
0114: private final OutputWriter out;
0115: private final OutputWriter err;
0116: private final int verbosity;
0117: private final String displayName;
0118: private final Runnable interestingOutputCallback;
0119: private final ProgressHandle handle;
0120: private boolean insideRunTask = false; // #95201
0121: private final RequestProcessor.Task sleepTask = RequestProcessor
0122: .getDefault().create(new Runnable() {
0123: public void run() {
0124: handle.suspend(insideRunTask ? NbBundle.getMessage(
0125: NbBuildLogger.class, "MSG_sleep_running")
0126: : "");
0127: }
0128: });
0129: private static final int SLEEP_DELAY = 5000;
0130:
0131: private final Map<AntLogger, Object> customData = new HashMap<AntLogger, Object>();
0132:
0133: private List<AntLogger> interestedLoggers = null;
0134: private Map<File/*|null*/, Collection<AntLogger>> interestedLoggersByScript = new HashMap<File, Collection<AntLogger>>();
0135: private Map<String/*|null*/, Collection<AntLogger>> interestedLoggersByTarget = new HashMap<String, Collection<AntLogger>>();
0136: private Map<String/*|null*/, Collection<AntLogger>> interestedLoggersByTask = new HashMap<String, Collection<AntLogger>>();
0137: private Map<Integer, Collection<AntLogger>> interestedLoggersByLevel = new HashMap<Integer, Collection<AntLogger>>();
0138:
0139: private final Set<Project> projectsWithProperties = Collections
0140: .synchronizedSet(new WeakSet<Project>());
0141:
0142: private final Set<Throwable> consumedExceptions = new WeakSet<Throwable>();
0143:
0144: /** whether this process should be halted at the next safe point */
0145: private boolean stop = false;
0146: /** whether this process is thought to be still running */
0147: private boolean running = true;
0148:
0149: /**
0150: * Map from master build scripts to maps from imported target names to imported locations.
0151: * Hack for lack of Target.getLocation() in Ant 1.6.2 and earlier.
0152: * Unused if targetGetLocation is not null.
0153: */
0154: private final Map<String, Map<String, String>> knownImportedTargets = Collections
0155: .synchronizedMap(new HashMap<String, Map<String, String>>());
0156: /**
0157: * Main script known to be being parsed at the moment.
0158: * Unused if targetGetLocation is not null.
0159: */
0160: private String currentlyParsedMainScript = null;
0161: /**
0162: * Imported script known to be being parsed at the moment.
0163: * Unused if targetGetLocation is not null.
0164: */
0165: private String currentlyParsedImportedScript = null;
0166: /**
0167: * Last task which was known to be running. Heuristic. Cf. #49464.
0168: */
0169: private Task lastTask = null;
0170:
0171: public NbBuildLogger(File origScript, OutputWriter out,
0172: OutputWriter err, int verbosity, String displayName,
0173: Runnable interestingOutputCallback, ProgressHandle handle) {
0174: this Session = LoggerTrampoline.ANT_SESSION_CREATOR
0175: .makeAntSession(this );
0176: this .origScript = origScript;
0177: this .out = out;
0178: this .err = err;
0179: this .verbosity = verbosity;
0180: this .displayName = displayName;
0181: this .interestingOutputCallback = interestingOutputCallback;
0182: this .handle = handle;
0183: if (LOGGABLE) {
0184: ERR.log(EM_LEVEL, "---- Initializing build of "
0185: + origScript + " \"" + displayName
0186: + "\" at verbosity " + verbosity + " ----");
0187: }
0188: }
0189:
0190: /** Try to stop running at the next safe point. */
0191: public void stop() {
0192: stop = true;
0193: }
0194:
0195: /** Stop the build now if requested. Also restarts sleep timer. */
0196: private void checkForStop() {
0197: if (stop) {
0198: StatusDisplayer.getDefault().setStatusText(
0199: NbBundle.getMessage(NbBuildLogger.class,
0200: "MSG_stopped", displayName));
0201: throw new ThreadDeath();
0202: }
0203: if (running) {
0204: handle.switchToIndeterminate();
0205: sleepTask.schedule(SLEEP_DELAY);
0206: }
0207: }
0208:
0209: /**
0210: * Notify this process that it has been shut down.
0211: * Refuse any further queries on AntEvent etc.
0212: * @see "#71266"
0213: */
0214: public void shutdown() {
0215: running = false;
0216: out.close();
0217: err.close();
0218: handle.finish();
0219: sleepTask.cancel();
0220: }
0221:
0222: private void verifyRunning() {
0223: if (!running) {
0224: throw new IllegalStateException(
0225: "AntSession/AntEvent/TaskStructure method called after completion of Ant process"); // NOI18N
0226: }
0227: }
0228:
0229: /**
0230: * Compute a list of loggers to use for this session.
0231: * Do not do it in the constructor since the actual targets will not have been
0232: * set and some loggers may care about the targets. However if buildInitializationFailed
0233: * is called before then, initialize them anyway.
0234: */
0235: private synchronized void initInterestedLoggers() {
0236: if (interestedLoggers == null) {
0237: interestedLoggers = new ArrayList<AntLogger>();
0238: for (AntLogger l : Lookup.getDefault().lookupAll(
0239: AntLogger.class)) {
0240: if (l.interestedInSession(this Session)) {
0241: interestedLoggers.add(l);
0242: }
0243: }
0244: if (LOGGABLE) {
0245: ERR.log(EM_LEVEL, "getInterestedLoggers: loggers="
0246: + interestedLoggers);
0247: }
0248: }
0249: }
0250:
0251: @SuppressWarnings("unchecked")
0252: // could use List<Collection<AntLogger>> but too slow?
0253: private final Collection<AntLogger>[] interestedLoggersByVariousCriteria = new Collection[4];
0254: private static final Comparator<Collection<AntLogger>> INTERESTED_LOGGERS_SORTER = new Comparator<Collection<AntLogger>>() {
0255: public int compare(Collection<AntLogger> c1,
0256: Collection<AntLogger> c2) {
0257: int x = c1.size() - c2.size(); // reverse sort by size
0258: if (x != 0) {
0259: return x;
0260: } else {
0261: return System.identityHashCode(c1)
0262: - System.identityHashCode(c2);
0263: }
0264: }
0265: };
0266:
0267: /**
0268: * Get those loggers interested in a given event.
0269: */
0270: private synchronized Collection<AntLogger> getInterestedLoggersByEvent(
0271: AntEvent e) {
0272: initInterestedLoggers();
0273: // Start with the smallest one and go down.
0274: interestedLoggersByVariousCriteria[0] = getInterestedLoggersByScript(e
0275: .getScriptLocation());
0276: interestedLoggersByVariousCriteria[1] = getInterestedLoggersByTarget(e
0277: .getTargetName());
0278: interestedLoggersByVariousCriteria[2] = getInterestedLoggersByTask(e
0279: .getTaskName());
0280: interestedLoggersByVariousCriteria[3] = getInterestedLoggersByLevel(e
0281: .getLogLevel());
0282: Arrays.sort(interestedLoggersByVariousCriteria,
0283: INTERESTED_LOGGERS_SORTER);
0284: if (LOGGABLE) {
0285: ERR
0286: .log(
0287: EM_LEVEL,
0288: "getInterestedLoggersByVariousCriteria: event="
0289: + e
0290: + " loggers="
0291: + Arrays
0292: .asList(interestedLoggersByVariousCriteria));
0293: }
0294: // XXX could probably be even a bit more efficient by iterating on the fly...
0295: // and by skipping the sorting which is probably overkill for a small number of a loggers (or hardcode the sort)
0296: List<AntLogger> loggers = new LinkedList<AntLogger>(
0297: interestedLoggersByVariousCriteria[0]);
0298: for (int i = 1; i < 4; i++) {
0299: loggers.retainAll(interestedLoggersByVariousCriteria[i]);
0300: }
0301: if (LOGGABLE) {
0302: ERR.log(EM_LEVEL, "getInterestedLoggersByEvent: event=" + e
0303: + " loggers=" + loggers);
0304: }
0305: return loggers;
0306: }
0307:
0308: private synchronized Collection<AntLogger> getInterestedLoggersByScript(
0309: File script) {
0310: Collection<AntLogger> c = interestedLoggersByScript.get(script);
0311: if (c == null) {
0312: c = new LinkedHashSet<AntLogger>(interestedLoggers.size());
0313: interestedLoggersByScript.put(script, c);
0314: for (AntLogger l : interestedLoggers) {
0315: if (l.interestedInAllScripts(this Session)
0316: || (script != null && l.interestedInScript(
0317: script, this Session))) {
0318: c.add(l);
0319: }
0320: }
0321: if (LOGGABLE) {
0322: ERR.log(EM_LEVEL,
0323: "getInterestedLoggersByScript: script="
0324: + script + " loggers=" + c);
0325: }
0326: }
0327: return c;
0328: }
0329:
0330: private synchronized Collection<AntLogger> getInterestedLoggersByTarget(
0331: String target) {
0332: Collection<AntLogger> c = interestedLoggersByTarget.get(target);
0333: if (c == null) {
0334: c = new LinkedHashSet<AntLogger>(interestedLoggers.size());
0335: interestedLoggersByTarget.put(target, c);
0336: for (AntLogger l : interestedLoggers) {
0337: String[] interestingTargets = l
0338: .interestedInTargets(this Session);
0339: if (interestingTargets == AntLogger.ALL_TARGETS
0340: || (target != null && Arrays.asList(
0341: interestingTargets).contains(target))
0342: || (target == null && interestingTargets == AntLogger.NO_TARGETS)) {
0343: c.add(l);
0344: }
0345: }
0346: if (LOGGABLE) {
0347: ERR.log(EM_LEVEL,
0348: "getInterestedLoggersByTarget: target="
0349: + target + " loggers=" + c);
0350: }
0351: }
0352: return c;
0353: }
0354:
0355: private synchronized Collection<AntLogger> getInterestedLoggersByTask(
0356: String task) {
0357: Collection<AntLogger> c = interestedLoggersByTask.get(task);
0358: if (c == null) {
0359: c = new LinkedHashSet<AntLogger>(interestedLoggers.size());
0360: interestedLoggersByTask.put(task, c);
0361: for (AntLogger l : interestedLoggers) {
0362: String[] tasks = l.interestedInTasks(this Session);
0363: if (tasks == AntLogger.ALL_TASKS
0364: || (task != null && Arrays.asList(tasks)
0365: .contains(task))
0366: || (task == null && tasks == AntLogger.NO_TASKS)) {
0367: c.add(l);
0368: }
0369: }
0370: if (LOGGABLE) {
0371: ERR.log(EM_LEVEL, "getInterestedLoggersByTask: task="
0372: + task + " loggers=" + c);
0373: }
0374: }
0375: return c;
0376: }
0377:
0378: private synchronized Collection<AntLogger> getInterestedLoggersByLevel(
0379: int level) {
0380: Collection<AntLogger> c = interestedLoggersByLevel.get(level);
0381: if (c == null) {
0382: c = new LinkedHashSet<AntLogger>(interestedLoggers.size());
0383: interestedLoggersByLevel.put(level, c);
0384: for (AntLogger l : interestedLoggers) {
0385: if (level == -1) {
0386: c.add(l);
0387: } else {
0388: int[] levels = l.interestedInLogLevels(this Session);
0389: for (int _level : levels) {
0390: if (_level == level) {
0391: c.add(l);
0392: break;
0393: }
0394: }
0395: }
0396: }
0397: if (LOGGABLE) {
0398: ERR.log(EM_LEVEL, "getInterestedLoggersByLevel: level="
0399: + level + " loggers=" + c);
0400: }
0401: }
0402: return c;
0403: }
0404:
0405: synchronized void setActualTargets(String[] targets) {
0406: this .targets = targets;
0407: }
0408:
0409: void buildInitializationFailed(BuildException be) {
0410: initInterestedLoggers();
0411: AntEvent ev = LoggerTrampoline.ANT_EVENT_CREATOR
0412: .makeAntEvent(new Event(be));
0413: if (LOGGABLE) {
0414: ERR.log(EM_LEVEL, "buildInitializationFailed: " + ev);
0415: }
0416: for (AntLogger l : getInterestedLoggersByScript(null)) {
0417: l.buildInitializationFailed(ev);
0418: }
0419: }
0420:
0421: public void buildStarted(BuildEvent ev) {
0422: AntBridge.suspendDelegation();
0423: try {
0424: checkForStop();
0425: initInterestedLoggers();
0426: AntEvent e = LoggerTrampoline.ANT_EVENT_CREATOR
0427: .makeAntEvent(new Event(ev, false));
0428: if (LOGGABLE) {
0429: ERR.log(EM_LEVEL, "buildStarted: " + e);
0430: }
0431: for (AntLogger l : interestedLoggers) {
0432: try {
0433: l.buildStarted(e);
0434: } catch (RuntimeException x) {
0435: ERR.notify(EM_LEVEL, x);
0436: }
0437: }
0438: } finally {
0439: AntBridge.resumeDelegation();
0440: }
0441: }
0442:
0443: public void buildFinished(BuildEvent ev) {
0444: AntBridge.suspendDelegation();
0445: try {
0446: // #82160: do not call checkForStop() here
0447: stop = false; // do not throw ThreadDeath on messageLogged from BridgeImpl cleanup code
0448: lastTask = null;
0449: initInterestedLoggers(); // just in case
0450: AntEvent e = LoggerTrampoline.ANT_EVENT_CREATOR
0451: .makeAntEvent(new Event(ev, false));
0452: if (LOGGABLE) {
0453: ERR.log(EM_LEVEL, "buildFinished: " + e);
0454: if (e.getException() != null) {
0455: ERR.notify(EM_LEVEL, e.getException());
0456: }
0457: }
0458: for (AntLogger l : interestedLoggers) {
0459: try {
0460: l.buildFinished(e);
0461: } catch (RuntimeException x) {
0462: ERR.notify(EM_LEVEL, x);
0463: } catch (Error x) {
0464: ERR.notify(EM_LEVEL, x);
0465: }
0466: }
0467: } finally {
0468: AntBridge.resumeDelegation();
0469: }
0470: }
0471:
0472: public void targetStarted(BuildEvent ev) {
0473: AntBridge.suspendDelegation();
0474: try {
0475: checkForStop();
0476: lastTask = null;
0477: AntEvent e = LoggerTrampoline.ANT_EVENT_CREATOR
0478: .makeAntEvent(new Event(ev, false));
0479: if (LOGGABLE) {
0480: ERR.log(EM_LEVEL, "targetStarted: " + e);
0481: }
0482: for (AntLogger l : getInterestedLoggersByEvent(e)) {
0483: try {
0484: l.targetStarted(e);
0485: } catch (RuntimeException x) {
0486: ERR.notify(EM_LEVEL, x);
0487: }
0488: }
0489: // Update progress handle label so user can see what is being run.
0490: Project p = ev.getProject();
0491: String projectName = null;
0492: if (p != null) {
0493: projectName = p.getName();
0494: }
0495: String targetName = e.getTargetName();
0496: if (targetName != null) {
0497: String message;
0498: if (projectName != null) {
0499: message = NbBundle.getMessage(NbBuildLogger.class,
0500: "MSG_progress_target", projectName,
0501: targetName);
0502: } else {
0503: message = targetName;
0504: }
0505: /*
0506: if (message.equals(displayName)) {
0507: // Redundant in this case.
0508: message = "";
0509: }
0510: */
0511: handle.progress(message);
0512: }
0513: } finally {
0514: AntBridge.resumeDelegation();
0515: }
0516: }
0517:
0518: public void targetFinished(BuildEvent ev) {
0519: AntBridge.suspendDelegation();
0520: try {
0521: checkForStop();
0522: lastTask = null;
0523: AntEvent e = LoggerTrampoline.ANT_EVENT_CREATOR
0524: .makeAntEvent(new Event(ev, false));
0525: if (LOGGABLE) {
0526: ERR.log(EM_LEVEL, "targetFinished: " + e);
0527: }
0528: for (AntLogger l : getInterestedLoggersByEvent(e)) {
0529: try {
0530: l.targetFinished(e);
0531: } catch (RuntimeException x) {
0532: ERR.notify(EM_LEVEL, x);
0533: }
0534: }
0535: } finally {
0536: AntBridge.resumeDelegation();
0537: }
0538: }
0539:
0540: public void taskStarted(BuildEvent ev) {
0541: AntBridge.suspendDelegation();
0542: try {
0543: checkForStop();
0544: lastTask = ev.getTask();
0545: AntEvent e = LoggerTrampoline.ANT_EVENT_CREATOR
0546: .makeAntEvent(new Event(ev, false));
0547: if (LOGGABLE) {
0548: ERR.log(EM_LEVEL, "taskStarted: " + e);
0549: }
0550: for (AntLogger l : getInterestedLoggersByEvent(e)) {
0551: try {
0552: l.taskStarted(e);
0553: } catch (RuntimeException x) {
0554: ERR.notify(EM_LEVEL, x);
0555: }
0556: }
0557: if ("input".equals(e.getTaskName())) { // #81139; NOI18N
0558: TaskStructure s = e.getTaskStructure();
0559: if (s != null) {
0560: String def = s.getAttribute("defaultvalue"); // NOI18N
0561: if (def != null) {
0562: NbInputHandler.setDefaultValue(e.evaluate(def));
0563: }
0564: }
0565: }
0566: if (isRunTask(e)) {
0567: insideRunTask = true;
0568: }
0569: } finally {
0570: AntBridge.resumeDelegation();
0571: }
0572: }
0573:
0574: private boolean isRunTask(AntEvent event) { // #95201
0575: String taskName = event.getTaskName();
0576: return "java".equals(taskName) || "exec".equals(taskName); // NOI18N
0577: }
0578:
0579: public void taskFinished(BuildEvent ev) {
0580: AntBridge.suspendDelegation();
0581: try {
0582: checkForStop();
0583: lastTask = null;
0584: AntEvent e = LoggerTrampoline.ANT_EVENT_CREATOR
0585: .makeAntEvent(new Event(ev, false));
0586: if (LOGGABLE) {
0587: ERR.log(EM_LEVEL, "taskFinished: " + e);
0588: }
0589: for (AntLogger l : getInterestedLoggersByEvent(e)) {
0590: try {
0591: l.taskFinished(e);
0592: } catch (RuntimeException x) {
0593: ERR.notify(EM_LEVEL, x);
0594: }
0595: }
0596: NbInputHandler.setDefaultValue(null);
0597: if (isRunTask(e)) {
0598: insideRunTask = false;
0599: }
0600: } finally {
0601: AntBridge.resumeDelegation();
0602: }
0603: }
0604:
0605: /**
0606: * Pattern matching an Ant message logged when it is parsing a build script.
0607: * Hack for lack of Target.getLocation() in Ant 1.6.2 and earlier.
0608: * Captured groups:
0609: * <ol>
0610: * <li>absolute path of build script
0611: * </ol>
0612: */
0613: private static final Pattern PARSING_BUILDFILE_MESSAGE = Pattern
0614: .compile("parsing buildfile (.+) with URI = (?:.+)"); // NOI18N
0615:
0616: /**
0617: * Pattern matching an Ant message logged when it is importing a build script.
0618: * Hack for lack of Target.getLocation() in Ant 1.6.2 and earlier.
0619: * Captured groups:
0620: * <ol>
0621: * <li>absolute path of build script which is doing the importing
0622: * </ol>
0623: */
0624: private static final Pattern IMPORTING_FILE_MESSAGE = Pattern
0625: .compile("Importing file (?:.+) from (.+)"); // NOI18N
0626:
0627: /**
0628: * Pattern matching an Ant message logged when it has encountered a target in some build script.
0629: * Hack for lack of Target.getLocation() in Ant 1.6.2 and earlier.
0630: * Captured groups:
0631: * <ol>
0632: * <li>target name
0633: * </ol>
0634: */
0635: private static final Pattern PARSED_TARGET_MESSAGE = Pattern
0636: .compile(" \\+Target: (.+)"); // NOI18N
0637:
0638: public void messageLogged(BuildEvent ev) {
0639: AntBridge.suspendDelegation();
0640: try {
0641: checkForStop();
0642: AntEvent e = LoggerTrampoline.ANT_EVENT_CREATOR
0643: .makeAntEvent(new Event(ev, true));
0644: if (LOGGABLE) {
0645: ERR.log(EM_LEVEL, "messageLogged: " + e);
0646: }
0647: for (AntLogger l : getInterestedLoggersByEvent(e)) {
0648: try {
0649: l.messageLogged(e);
0650: } catch (RuntimeException x) {
0651: ERR.notify(EM_LEVEL, x);
0652: }
0653: }
0654: // Let the hacks begin!
0655: String msg = ev.getMessage();
0656: if (msg.contains("ant.PropertyHelper")
0657: || /* #71816 */msg.contains("ant.projectHelper")) { // NOI18N
0658: // Only after this has been defined can we get any properties.
0659: // Even trying earlier will give a recursion error since this pseudoprop
0660: // is set lazily, which produces a new message logged event.
0661: projectsWithProperties.add(ev.getProject());
0662: }
0663: if (targetGetLocation == null) {
0664: // Try to figure out which imported targets belong to which actual scripts.
0665: // XXX consider keeping a singleton Matcher for each pattern and reusing it
0666: // or just doing string comparisons
0667: Matcher matcher;
0668: if ((matcher = PARSING_BUILDFILE_MESSAGE.matcher(msg))
0669: .matches()) {
0670: if (currentlyParsedMainScript != null) {
0671: currentlyParsedImportedScript = matcher
0672: .group(1);
0673: }
0674: if (LOGGABLE) {
0675: ERR
0676: .log(
0677: EM_LEVEL,
0678: "Got PARSING_BUILDFILE_MESSAGE: "
0679: + currentlyParsedImportedScript);
0680: }
0681: lastTask = null;
0682: } else if ((matcher = IMPORTING_FILE_MESSAGE
0683: .matcher(msg)).matches()) {
0684: currentlyParsedMainScript = matcher.group(1);
0685: currentlyParsedImportedScript = null;
0686: if (LOGGABLE) {
0687: ERR.log(EM_LEVEL,
0688: "Got IMPORTING_FILE_MESSAGE: "
0689: + currentlyParsedMainScript);
0690: }
0691: lastTask = null;
0692: } else if ((matcher = PARSED_TARGET_MESSAGE
0693: .matcher(msg)).matches()) {
0694: if (currentlyParsedMainScript != null
0695: && currentlyParsedImportedScript != null) {
0696: Map<String, String> targetLocations = knownImportedTargets
0697: .get(currentlyParsedMainScript);
0698: if (targetLocations == null) {
0699: targetLocations = new HashMap<String, String>();
0700: knownImportedTargets.put(
0701: currentlyParsedMainScript,
0702: targetLocations);
0703: }
0704: targetLocations.put(matcher.group(1),
0705: currentlyParsedImportedScript);
0706: }
0707: if (LOGGABLE) {
0708: ERR.log(EM_LEVEL, "Got PARSED_TARGET_MESSAGE: "
0709: + matcher.group(1));
0710: }
0711: lastTask = null;
0712: }
0713: }
0714: } finally {
0715: AntBridge.resumeDelegation();
0716: }
0717: }
0718:
0719: public File getOriginatingScript() {
0720: verifyRunning();
0721: return origScript;
0722: }
0723:
0724: public String[] getOriginatingTargets() {
0725: verifyRunning();
0726: return targets != null ? targets : new String[0];
0727: }
0728:
0729: public synchronized Object getCustomData(AntLogger logger) {
0730: verifyRunning();
0731: return customData.get(logger);
0732: }
0733:
0734: public synchronized void putCustomData(AntLogger logger, Object data) {
0735: verifyRunning();
0736: customData.put(logger, data);
0737: }
0738:
0739: public void println(String message, boolean error,
0740: OutputListener listener) {
0741: verifyRunning();
0742: if (LOGGABLE) {
0743: ERR.log(EM_LEVEL, "println: error=" + error + " listener="
0744: + listener + " message=" + message);
0745: }
0746: OutputWriter ow = error ? err : out;
0747: try {
0748: if (listener != null) {
0749: // XXX factor out into AntLogger API!
0750: boolean important = (message.indexOf("[deprecation]") == -1
0751: && message.indexOf("warning") == -1 && message
0752: .indexOf("stopped") == -1);
0753: ow.println(message, listener, important);
0754: interestingOutputCallback.run();
0755: } else {
0756: ow.println(message);
0757: }
0758: } catch (IOException e) {
0759: ERR.notify(e);
0760: }
0761: }
0762:
0763: public void deliverMessageLogged(AntEvent originalEvent,
0764: String message, int level) {
0765: verifyRunning();
0766: if (originalEvent == null) {
0767: throw new IllegalArgumentException(
0768: "Must pass an original event to deliverMessageLogged"); // NOI18N
0769: }
0770: if (message == null) {
0771: throw new IllegalArgumentException(
0772: "Must pass a message to deliverMessageLogged"); // NOI18N
0773: }
0774: if (level < AntEvent.LOG_ERR || level > AntEvent.LOG_DEBUG) {
0775: throw new IllegalArgumentException(
0776: "Unknown log level for reposted log event: "
0777: + level); // NOI18N
0778: }
0779: if (LOGGABLE) {
0780: ERR.log(EM_LEVEL, "deliverMessageLogged: level=" + level
0781: + " message=" + message);
0782: }
0783: AntEvent newEvent = LoggerTrampoline.ANT_EVENT_CREATOR
0784: .makeAntEvent(new RepostedEvent(originalEvent, message,
0785: level));
0786: for (AntLogger l : getInterestedLoggersByEvent(newEvent)) {
0787: try {
0788: l.messageLogged(newEvent);
0789: } catch (RuntimeException x) {
0790: ERR.notify(EM_LEVEL, x);
0791: }
0792: }
0793: }
0794:
0795: public synchronized void consumeException(Throwable t)
0796: throws IllegalStateException {
0797: verifyRunning();
0798: if (isExceptionConsumed(t)) {
0799: throw new IllegalStateException("Already consumed " + t); // NOI18N
0800: }
0801: consumedExceptions.add(t);
0802: }
0803:
0804: public synchronized boolean isExceptionConsumed(Throwable t) {
0805: verifyRunning();
0806: if (consumedExceptions.contains(t)) {
0807: return true;
0808: }
0809: // Check for nested exceptions too.
0810: Throwable nested = t.getCause();
0811: if (nested != null && isExceptionConsumed(nested)) {
0812: // cache that
0813: consumedExceptions.add(t);
0814: return true;
0815: }
0816: return false;
0817: }
0818:
0819: public int getVerbosity() {
0820: verifyRunning();
0821: return verbosity;
0822: }
0823:
0824: String getDisplayNameNoLock() {
0825: return displayName;
0826: }
0827:
0828: public String getDisplayName() {
0829: verifyRunning();
0830: return displayName;
0831: }
0832:
0833: public OutputListener createStandardHyperlink(URL file,
0834: String message, int line1, int column1, int line2,
0835: int column2) {
0836: verifyRunning();
0837: return new Hyperlink(file, message, line1, column1, line2,
0838: column2);
0839: }
0840:
0841: // Accessors for stuff which is specific to particular versions of Ant.
0842: private static final Method targetGetLocation; // 1.6.2+
0843: private static final Method locationGetFileName; // 1.6+
0844: private static final Method locationGetLineNumber; // 1.6+
0845: private static final Method runtimeConfigurableGetAttributeMap; // 1.6+
0846: private static final Method runtimeConfigurableGetChildren; // 1.6+
0847: private static final Method runtimeConfigurableGetText; // 1.6+
0848: static {
0849: Method _targetGetLocation = null;
0850: try {
0851: _targetGetLocation = Target.class.getMethod("getLocation"); // NOI18N
0852: if (AntBridge.getInterface().getAntVersion().indexOf(
0853: "1.6.2") != -1) { // NOI18N
0854: // Unfortunately in 1.6.2 the method exists but it doesn't work (Ant #28599):
0855: _targetGetLocation = null;
0856: }
0857: } catch (NoSuchMethodException e) {
0858: // OK
0859: } catch (Exception e) {
0860: ERR.notify(EM_LEVEL, e);
0861: }
0862: targetGetLocation = _targetGetLocation;
0863: Method _locationGetFileName = null;
0864: try {
0865: _locationGetFileName = Location.class
0866: .getMethod("getFileName"); // NOI18N
0867: } catch (NoSuchMethodException e) {
0868: // OK
0869: } catch (Exception e) {
0870: ERR.notify(EM_LEVEL, e);
0871: }
0872: locationGetFileName = _locationGetFileName;
0873: Method _locationGetLineNumber = null;
0874: try {
0875: _locationGetLineNumber = Location.class
0876: .getMethod("getLineNumber"); // NOI18N
0877: } catch (NoSuchMethodException e) {
0878: // OK
0879: } catch (Exception e) {
0880: ERR.notify(EM_LEVEL, e);
0881: }
0882: locationGetLineNumber = _locationGetLineNumber;
0883: Method _runtimeConfigurableGetAttributeMap = null;
0884: try {
0885: _runtimeConfigurableGetAttributeMap = RuntimeConfigurable.class
0886: .getMethod("getAttributeMap"); // NOI18N
0887: } catch (NoSuchMethodException e) {
0888: // OK
0889: } catch (Exception e) {
0890: ERR.notify(EM_LEVEL, e);
0891: }
0892: runtimeConfigurableGetAttributeMap = _runtimeConfigurableGetAttributeMap;
0893: Method _runtimeConfigurableGetChildren = null;
0894: try {
0895: _runtimeConfigurableGetChildren = RuntimeConfigurable.class
0896: .getMethod("getChildren"); // NOI18N
0897: } catch (NoSuchMethodException e) {
0898: // OK
0899: } catch (Exception e) {
0900: ERR.notify(EM_LEVEL, e);
0901: }
0902: runtimeConfigurableGetChildren = _runtimeConfigurableGetChildren;
0903: Method _runtimeConfigurableGetText = null;
0904: try {
0905: _runtimeConfigurableGetText = RuntimeConfigurable.class
0906: .getMethod("getText"); // NOI18N
0907: } catch (NoSuchMethodException e) {
0908: // OK
0909: } catch (Exception e) {
0910: ERR.notify(EM_LEVEL, e);
0911: }
0912: runtimeConfigurableGetText = _runtimeConfigurableGetText;
0913: }
0914:
0915: /**
0916: * Try to find the location of an Ant target.
0917: * @param project if not null, the main project from which this target might have been imported
0918: */
0919: private Location getLocationOfTarget(Target target, Project project) {
0920: if (targetGetLocation != null) {
0921: try {
0922: return (Location) targetGetLocation.invoke(target);
0923: } catch (Exception e) {
0924: ERR.notify(EM_LEVEL, e);
0925: }
0926: }
0927: // For Ant 1.6.2 and earlier, hope we got the right info from the hacks above.
0928: if (LOGGABLE) {
0929: ERR.log(EM_LEVEL, "knownImportedTargets: "
0930: + knownImportedTargets);
0931: }
0932: if (project != null) {
0933: String file = project.getProperty("ant.file"); // NOI18N
0934: if (file != null) {
0935: Map<String, String> targetLocations = knownImportedTargets
0936: .get(file);
0937: if (targetLocations != null) {
0938: String importedFile = targetLocations.get(target
0939: .getName());
0940: if (importedFile != null) {
0941: // Have no line number, note.
0942: return new Location(importedFile);
0943: }
0944: }
0945: }
0946: }
0947: // Dunno.
0948: return null;
0949: }
0950:
0951: private static String getFileNameOfLocation(Location loc) {
0952: if (locationGetFileName != null) {
0953: try {
0954: return (String) locationGetFileName.invoke(loc);
0955: } catch (Exception e) {
0956: ERR.notify(EM_LEVEL, e);
0957: }
0958: }
0959: // OK, using Ant 1.5.x.
0960: String locs = loc.toString();
0961: // Format: "$file:$line: " or "$file: " or ""
0962: int x = locs.indexOf(':');
0963: if (x != -1) {
0964: return locs.substring(0, x);
0965: } else {
0966: return null;
0967: }
0968: }
0969:
0970: private static int getLineNumberOfLocation(Location loc) {
0971: if (locationGetLineNumber != null) {
0972: try {
0973: return (Integer) locationGetLineNumber.invoke(loc);
0974: } catch (Exception e) {
0975: ERR.notify(EM_LEVEL, e);
0976: }
0977: }
0978: // OK, using Ant 1.5.x.
0979: String locs = loc.toString();
0980: // Format: "$file:$line: " or "$file: " or ""
0981: int x = locs.indexOf(':');
0982: if (x != -1) {
0983: int x2 = locs.indexOf(':', x + 1);
0984: if (x2 != -1) {
0985: String line = locs.substring(x + 1, x2);
0986: try {
0987: return Integer.parseInt(line);
0988: } catch (NumberFormatException e) {
0989: // ignore?
0990: }
0991: }
0992: }
0993: return 0;
0994: }
0995:
0996: @SuppressWarnings("unchecked")
0997: private static Map<String, String> getAttributeMapOfRuntimeConfigurable(
0998: RuntimeConfigurable rc) {
0999: if (runtimeConfigurableGetAttributeMap != null) {
1000: try {
1001: return (Map<String, String>) runtimeConfigurableGetAttributeMap
1002: .invoke(rc);
1003: } catch (Exception e) {
1004: ERR.notify(EM_LEVEL, e);
1005: }
1006: }
1007: return Collections.emptyMap();
1008: }
1009:
1010: @SuppressWarnings("unchecked")
1011: private static Enumeration<RuntimeConfigurable> getChildrenOfRuntimeConfigurable(
1012: RuntimeConfigurable rc) {
1013: if (runtimeConfigurableGetChildren != null) {
1014: try {
1015: return (Enumeration<RuntimeConfigurable>) runtimeConfigurableGetChildren
1016: .invoke(rc);
1017: } catch (Exception e) {
1018: ERR.notify(EM_LEVEL, e);
1019: }
1020: }
1021: return Collections.enumeration(Collections
1022: .<RuntimeConfigurable> emptySet());
1023: }
1024:
1025: private static String getTextOfRuntimeConfigurable(
1026: RuntimeConfigurable rc) {
1027: if (runtimeConfigurableGetText != null) {
1028: try {
1029: return ((StringBuffer) runtimeConfigurableGetText
1030: .invoke(rc)).toString();
1031: } catch (Exception e) {
1032: ERR.notify(EM_LEVEL, e);
1033: }
1034: }
1035: return "";
1036: }
1037:
1038: /**
1039: * Standard event implemention, delegating to the Ant BuildEvent and Project.
1040: */
1041: private final class Event implements LoggerTrampoline.AntEventImpl {
1042:
1043: private boolean consumed = false;
1044: private final BuildEvent e;
1045: private final Throwable exception;
1046: private final int level;
1047: private File scriptLocation;
1048:
1049: /**
1050: * Create a new regular event.
1051: * @param e the Ant build event
1052: * @param msgLogged true for logged events
1053: */
1054: public Event(BuildEvent e, boolean msgLogged) {
1055: this .e = e;
1056: exception = e.getException();
1057: if (msgLogged) {
1058: level = e.getPriority();
1059: } else {
1060: level = -1;
1061: }
1062: }
1063:
1064: /**
1065: * Create a new event for buildInitializationFailed.
1066: * @param exception the problem
1067: */
1068: public Event(Throwable exception) {
1069: e = null;
1070: this .exception = exception;
1071: level = -1;
1072: }
1073:
1074: public AntSession getSession() {
1075: verifyRunning();
1076: return this Session;
1077: }
1078:
1079: public void consume() throws IllegalStateException {
1080: verifyRunning();
1081: if (consumed) {
1082: throw new IllegalStateException(
1083: "Event already consumed"); // NOI18N
1084: }
1085: consumed = true;
1086: }
1087:
1088: public boolean isConsumed() {
1089: verifyRunning();
1090: return consumed;
1091: }
1092:
1093: public File getScriptLocation() {
1094: verifyRunning();
1095: if (scriptLocation != null) {
1096: return scriptLocation;
1097: }
1098: if (e == null) {
1099: return null;
1100: }
1101: Task task = e.getTask();
1102: if (task != null) {
1103: Location l = task.getLocation();
1104: if (l != null) {
1105: String file = getFileNameOfLocation(l);
1106: if (file != null) {
1107: return scriptLocation = new File(file);
1108: }
1109: }
1110: }
1111: Target target = e.getTarget();
1112: Project project = getProjectIfPropertiesDefined();
1113: if (target != null) {
1114: Location l = getLocationOfTarget(target, project);
1115: if (l != null) {
1116: String file = getFileNameOfLocation(l);
1117: if (file != null) {
1118: return scriptLocation = new File(file);
1119: }
1120: }
1121: }
1122: if (project != null) {
1123: String file = project.getProperty("ant.file"); // NOI18N
1124: if (file != null) {
1125: return scriptLocation = new File(file);
1126: }
1127: }
1128: // #49464: guess at task.
1129: synchronized (NbBuildLogger.this ) {
1130: if (lastTask != null) {
1131: Location l = lastTask.getLocation();
1132: if (l != null) {
1133: String file = getFileNameOfLocation(l);
1134: if (file != null) {
1135: return scriptLocation = new File(file);
1136: }
1137: }
1138: }
1139: }
1140: return null;
1141: }
1142:
1143: private Project getProjectIfPropertiesDefined() {
1144: Project project = e.getProject();
1145: if (project != null
1146: && projectsWithProperties.contains(project)) {
1147: return project;
1148: } else {
1149: return null;
1150: }
1151: }
1152:
1153: public int getLine() {
1154: verifyRunning();
1155: if (e == null) {
1156: return -1;
1157: }
1158: Task task = e.getTask();
1159: if (task != null) {
1160: Location l = task.getLocation();
1161: if (l != null) {
1162: int line = getLineNumberOfLocation(l);
1163: if (line > 0) {
1164: return line;
1165: }
1166: }
1167: }
1168: Target target = e.getTarget();
1169: if (target != null) {
1170: Location l = getLocationOfTarget(target,
1171: getProjectIfPropertiesDefined());
1172: if (l != null) {
1173: int line = getLineNumberOfLocation(l);
1174: if (line > 0) {
1175: return line;
1176: }
1177: }
1178: }
1179: // #49464: guess at task.
1180: synchronized (NbBuildLogger.this ) {
1181: if (lastTask != null) {
1182: Location l = lastTask.getLocation();
1183: if (l != null) {
1184: int line = getLineNumberOfLocation(l);
1185: if (line > 0) {
1186: return line;
1187: }
1188: }
1189: }
1190: }
1191: return -1;
1192: }
1193:
1194: public String getTargetName() {
1195: verifyRunning();
1196: if (e == null) {
1197: return null;
1198: }
1199: Target target = e.getTarget();
1200: if (target != null) {
1201: String name = target.getName();
1202: if (name != null && name.length() > 0) {
1203: return name;
1204: }
1205: }
1206: // #49464: guess at task.
1207: synchronized (NbBuildLogger.this ) {
1208: if (lastTask != null) {
1209: target = lastTask.getOwningTarget();
1210: if (target != null) {
1211: String name = target.getName();
1212: if (name != null && name.length() > 0) {
1213: return name;
1214: }
1215: }
1216: }
1217: }
1218: return null;
1219: }
1220:
1221: public String getTaskName() {
1222: verifyRunning();
1223: if (e == null) {
1224: return null;
1225: }
1226: Task task = e.getTask();
1227: if (task != null) {
1228: return task.getRuntimeConfigurableWrapper()
1229: .getElementTag();
1230: }
1231: // #49464: guess at task.
1232: synchronized (NbBuildLogger.this ) {
1233: if (lastTask != null) {
1234: return lastTask.getRuntimeConfigurableWrapper()
1235: .getElementTag();
1236: }
1237: }
1238: return null;
1239: }
1240:
1241: public TaskStructure getTaskStructure() {
1242: verifyRunning();
1243: Task task = e.getTask();
1244: if (task != null) {
1245: return LoggerTrampoline.TASK_STRUCTURE_CREATOR
1246: .makeTaskStructure(new TaskStructureImpl(task
1247: .getRuntimeConfigurableWrapper()));
1248: }
1249: // #49464: guess at task.
1250: synchronized (NbBuildLogger.this ) {
1251: if (lastTask != null) {
1252: return LoggerTrampoline.TASK_STRUCTURE_CREATOR
1253: .makeTaskStructure(new TaskStructureImpl(
1254: lastTask
1255: .getRuntimeConfigurableWrapper()));
1256: }
1257: }
1258: return null;
1259: }
1260:
1261: public String getMessage() {
1262: verifyRunning();
1263: if (e == null) {
1264: return null;
1265: }
1266: return e.getMessage();
1267: }
1268:
1269: public int getLogLevel() {
1270: verifyRunning();
1271: return level;
1272: }
1273:
1274: public Throwable getException() {
1275: verifyRunning();
1276: return exception;
1277: }
1278:
1279: public String getProperty(String name) {
1280: verifyRunning();
1281: Project project = getProjectIfPropertiesDefined();
1282: if (project != null) {
1283: Object o = project.getProperty(name);
1284: if (o instanceof String) {
1285: return (String) o;
1286: } else {
1287: return null;
1288: }
1289: } else {
1290: return null;
1291: }
1292: }
1293:
1294: public Set<String> getPropertyNames() {
1295: verifyRunning();
1296: Project project = getProjectIfPropertiesDefined();
1297: if (project != null) {
1298: return NbCollections.checkedSetByFilter(project
1299: .getProperties().keySet(), String.class, true);
1300: } else {
1301: return Collections.emptySet();
1302: }
1303: }
1304:
1305: public String evaluate(String text) {
1306: verifyRunning();
1307: Project project = getProjectIfPropertiesDefined();
1308: if (project != null) {
1309: return project.replaceProperties(text);
1310: } else {
1311: return text;
1312: }
1313: }
1314:
1315: @Override
1316: public String toString() {
1317: return "Event[target=" + getTargetName() + ",task="
1318: + getTaskName() + ",message=" + getMessage()
1319: + ",scriptLocation=" + getScriptLocation()
1320: + ",exception=" + exception + ",level=" + level
1321: + ",consumed=" + consumed + "]"; // NOI18N
1322: }
1323:
1324: }
1325:
1326: /**
1327: * Reposted event delegating to an original one except for message and level.
1328: * @see #deliverMessageLogged
1329: */
1330: private final class RepostedEvent implements
1331: LoggerTrampoline.AntEventImpl {
1332:
1333: private final AntEvent originalEvent;
1334: private final String message;
1335: private final int level;
1336: private boolean consumed = false;
1337:
1338: public RepostedEvent(AntEvent originalEvent, String message,
1339: int level) {
1340: this .originalEvent = originalEvent;
1341: this .message = message;
1342: this .level = level;
1343: }
1344:
1345: public void consume() throws IllegalStateException {
1346: verifyRunning();
1347: if (consumed) {
1348: throw new IllegalStateException(
1349: "Event already consumed"); // NOI18N
1350: }
1351: consumed = true;
1352: }
1353:
1354: public boolean isConsumed() {
1355: verifyRunning();
1356: return consumed;
1357: }
1358:
1359: public AntSession getSession() {
1360: return originalEvent.getSession();
1361: }
1362:
1363: public File getScriptLocation() {
1364: return originalEvent.getScriptLocation();
1365: }
1366:
1367: public int getLine() {
1368: return originalEvent.getLine();
1369: }
1370:
1371: public String getTargetName() {
1372: return originalEvent.getTargetName();
1373: }
1374:
1375: public String getTaskName() {
1376: return originalEvent.getTaskName();
1377: }
1378:
1379: public TaskStructure getTaskStructure() {
1380: return originalEvent.getTaskStructure();
1381: }
1382:
1383: public String getMessage() {
1384: verifyRunning();
1385: return message;
1386: }
1387:
1388: public int getLogLevel() {
1389: verifyRunning();
1390: return level;
1391: }
1392:
1393: public Throwable getException() {
1394: verifyRunning();
1395: return null;
1396: }
1397:
1398: public String getProperty(String name) {
1399: return originalEvent.getProperty(name);
1400: }
1401:
1402: public Set<String> getPropertyNames() {
1403: return originalEvent.getPropertyNames();
1404: }
1405:
1406: public String evaluate(String text) {
1407: return originalEvent.evaluate(text);
1408: }
1409:
1410: @Override
1411: public String toString() {
1412: return "RepostedEvent[consumed=" + consumed + ",level="
1413: + level + ",message=" + message
1414: + /*",orig=" + originalEvent +*/"]"; // NOI18N
1415: }
1416:
1417: }
1418:
1419: /**
1420: * Implementation of TaskStructure based on an Ant Task.
1421: * @see Event#getTaskStructure
1422: */
1423: private final class TaskStructureImpl implements
1424: LoggerTrampoline.TaskStructureImpl {
1425:
1426: private final RuntimeConfigurable rc;
1427:
1428: public TaskStructureImpl(RuntimeConfigurable rc) {
1429: this .rc = rc;
1430: }
1431:
1432: public String getName() {
1433: verifyRunning();
1434: String name = rc.getElementTag();
1435: if (name != null) {
1436: return name;
1437: } else {
1438: // What does this mean?
1439: return "";
1440: }
1441: }
1442:
1443: public String getAttribute(String name) {
1444: verifyRunning();
1445: return getAttributeMapOfRuntimeConfigurable(rc).get(name);
1446: }
1447:
1448: public Set<String> getAttributeNames() {
1449: verifyRunning();
1450: return getAttributeMapOfRuntimeConfigurable(rc).keySet();
1451: }
1452:
1453: public String getText() {
1454: verifyRunning();
1455: String s = getTextOfRuntimeConfigurable(rc);
1456: if (s.length() > 0) {
1457: // XXX is it appropriate to trim() this? probably not
1458: return s;
1459: } else {
1460: return null;
1461: }
1462: }
1463:
1464: public TaskStructure[] getChildren() {
1465: verifyRunning();
1466: List<TaskStructure> structures = new ArrayList<TaskStructure>();
1467: for (RuntimeConfigurable subrc : NbCollections
1468: .iterable(getChildrenOfRuntimeConfigurable(rc))) {
1469: structures
1470: .add(LoggerTrampoline.TASK_STRUCTURE_CREATOR
1471: .makeTaskStructure(new TaskStructureImpl(
1472: subrc)));
1473: }
1474: return structures.toArray(new TaskStructure[structures
1475: .size()]);
1476: }
1477:
1478: }
1479:
1480: }
|