alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 *
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 *
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2004 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.apache.tools.ant.module.api.support;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import javax.swing.event.ChangeListener;
import org.apache.tools.ant.module.api.AntProjectCookie;
import org.apache.tools.ant.module.xml.AntProjectSupport;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.loaders.DataObject;
import org.openide.loaders.DataObjectNotFoundException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * Provides a way to find targets from an Ant build script.
 * 

* Note that scripts may import other scripts using * the <import> pseudotask, so you may need * to use {@link Target#getScript} to check which script a target came from. *

*

* Warning: the current implementation does not attempt to handle * import statements which use Ant properties in the imported file name, since * it is not possible to determine what the value of the file path will actually * be at runtime, at least not with complete accuracy. A future implementation * may be enhanced to handle most such cases, based on property definitions found * in the Ant script. Currently such imports are quietly ignored. *

*

* The imported file path is considered relative to the project * base directory, hopefully according to Ant's own rules. *

*

* If an import statement is marked as optional, and the imported script cannot * be found, it will be silently skipped (as Ant does). If it is marked as mandatory * (the default), this situation will result in an {@link IOException}. *

* @author Jesse Glick * @since org.apache.tools.ant.module/3 3.11 */ public class TargetLister { private TargetLister() {} /** * Gets all targets in an Ant script. * Some may come from imported scripts. * There is no guarantee that the actual {@link Target} objects will be * the same from call to call. * @param script an Ant build script * @return an immutable, unchanging set of {@link Target}s; may be empty * @throws IOException in case there is a problem reading the script (or a subscript) */ public static Set/**/ getTargets(AntProjectCookie script) throws IOException { Script main = new Script(null, script); Set/**/ targets = new HashSet(); Set/**/ visitedScripts = new HashSet(); traverseScripts(main, targets, visitedScripts); return targets; } /** * Walk import tree in a depth-first search. * At each node, collect the targets. * Skip over nodes representing scripts which were already imported via a different path. */ private static void traverseScripts(Script script, Set/**/ targets, Set/**/ visitedScripts) throws IOException { if (!visitedScripts.add(script.getScript())) { return; } targets.addAll(script.getTargets()); Iterator it = script.getImports().iterator(); while (it.hasNext()) { Script imported = (Script) it.next(); traverseScripts(imported, targets, visitedScripts); } } /** * Representation of a target from an Ant script. */ public static final class Target { private final Script script; private final Element el; private final String name; Target(Script script, Element el, String name) { this.script = script; this.el = el; this.name = name; } /** * Gets the simple name of the target. * This is just whatever is declared in the name attribute. * @return the target name */ public String getName() { return name; } /** * Gets the qualified name of the target. * This consists of the name of the project followed by a dot (.) * followed by the simple target name. * (Or just the simple target name in case the project has no defined name; * questionable whether this is even legal.) * The qualified name may be used in a depends attribute to * distinguish an imported target from a target of the same name in the * importing script. * @return the qualified name */ public String getQualifiedName() { String n = script.getName(); if (n != null) { return n + '.' + getName(); } else { return getName(); } } /** * Gets the XML element that defines the target. * @return an element with local name target */ public Element getElement() { return el; } /** * Gets the actual Ant script this target was found in. * {@link #getElement} should be owned by {@link AntProjectCookie#getDocument}. * @return the script which defines this target */ public AntProjectCookie getScript() { return script.getScript(); } /** * Tests whether this target has a description. * This is the description attribute in XML. * Typically, targets with descriptions are intended to be exposed to the * user of the script, whereas undescribed targets may not be intended * for general use. However not all script authors use descriptions, so * described targets should only be given UI precedence. * @return true if the target has a description */ public boolean isDescribed() { return el.getAttribute("description").length() > 0; } /** * Tests whether a target is marked as internal to the script. * Currently this means that the target name begins with a hyphen (-), * though the precise semantics may be changed according to changes in Ant. * Conventionally, internal targets are not intended to be run directly, and only * exist to be called from other targets. As such, they should not normally * be presented in the context of targets you might want to run. * @return true if this is marked as an internal target, false for a regular target * @see Ant issue #22020 */ public boolean isInternal() { String n = getName(); return n.length() > 0 && n.charAt(0) == '-'; } /** * Tests whether this target is overridden in an importing script. * If an importing script has a target of the same name as a target * in an imported script, the latter is considered overridden, and may * not be called directly (though it may be used as a dependency, if * qualified via {@link #getQualifiedName}). * Note that this flag may be true when asked of a {@link Target} gotten * via the importing script, while false when asked of the same target * gotten directly from the imported script, since the meaning is dependent * on the import chain. * @return true if the target is overridden */ public boolean isOverridden() { return !script.defines(getName()); } /** * Tests whether this target is the default for the main script. * Note that a set of targets will have at most one default target; * any default attribute in an imported script is ignored. * However the default target might come from an imported script. * @return true if the target is the default target */ public boolean isDefault() { return !isOverridden() && getName().equals(script.getMainScript().getDefaultTargetName()); } public String toString() { return "Target " + getName() + " in " + getScript(); // NOI18N } } /** * Representation of one script full of targets. */ private static final class Script { private final AntProjectCookie apc; private final Script importingScript; private final Map/**/ targets; private final String defaultTarget; private final List/*