| /* |
| * The Apache Software License, Version 1.1 |
| * |
| * Copyright (c) 2002 The Apache Software Foundation. All rights |
| * reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * 3. The end-user documentation included with the redistribution, if |
| * any, must include the following acknowlegement: |
| * "This product includes software developed by the |
| * Apache Software Foundation (http://www.apache.org/)." |
| * Alternately, this acknowlegement may appear in the software itself, |
| * if and wherever such third-party acknowlegements normally appear. |
| * |
| * 4. The names "The Jakarta Project", "Ant", and "Apache Software |
| * Foundation" must not be used to endorse or promote products derived |
| * from this software without prior written permission. For written |
| * permission, please contact apache@apache.org. |
| * |
| * 5. Products derived from this software may not be called "Apache" |
| * nor may "Apache" appear in their names without prior written |
| * permission of the Apache Group. |
| * |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR |
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| * ==================================================================== |
| * |
| * This software consists of voluntary contributions made by many |
| * individuals on behalf of the Apache Software Foundation. For more |
| * information on the Apache Software Foundation, please see |
| * <http://www.apache.org/>. |
| */ |
| package org.apache.ant.antcore.antlib; |
| import java.io.File; |
| import java.io.FileNotFoundException; |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import org.apache.ant.antcore.xml.ParseContext; |
| import org.apache.ant.antcore.xml.XMLParseException; |
| import org.apache.ant.common.util.CircularDependencyChecker; |
| import org.apache.ant.common.util.CircularDependencyException; |
| import org.apache.ant.common.util.ExecutionException; |
| import org.apache.ant.init.InitConfig; |
| import org.apache.ant.init.InitUtils; |
| import org.apache.ant.init.LoaderUtils; |
| |
| /** |
| * This class manages the configuration of Ant Libraries |
| * |
| * @author <a href="mailto:conor@apache.org">Conor MacNeill</a> |
| * @created 29 January 2002 |
| */ |
| public class AntLibManager { |
| |
| /** The list of extensions which are examined for ant libraries */ |
| public static final String[] ANTLIB_EXTENSIONS |
| = new String[]{".tsk", ".jar", ".zip"}; |
| |
| /** Flag which indicates whether non-file URLS are used */ |
| private boolean remoteAllowed; |
| |
| /** |
| * Constructor for the AntLibManager object |
| * |
| * @param remoteAllowed true if remote libraries can be used and |
| * configured |
| */ |
| public AntLibManager(boolean remoteAllowed) { |
| this.remoteAllowed = remoteAllowed; |
| } |
| |
| /** |
| * Add all the Ant libraries that can be found at the given URL |
| * |
| * @param librarySpecs A map to which additional library specifications |
| * are added. |
| * @param libURL the URL from which Ant libraries are to be loaded |
| * @exception MalformedURLException if the URL for the individual |
| * library components cannot be formed |
| * @exception ExecutionException if the library specs cannot be parsed |
| */ |
| public void addAntLibraries(Map librarySpecs, URL libURL) |
| throws MalformedURLException, ExecutionException { |
| URL[] libURLs = LoaderUtils.getLocationURLs(libURL, libURL.toString(), |
| ANTLIB_EXTENSIONS); |
| |
| if (libURLs == null) { |
| return; |
| } |
| |
| // parse each task library to get its library definition |
| for (int i = 0; i < libURLs.length; ++i) { |
| URL antLibraryURL = new URL("jar:" + libURLs[i] |
| + "!/META-INF/antlib.xml"); |
| try { |
| AntLibrarySpec antLibrarySpec = parseLibraryDef(antLibraryURL); |
| if (antLibrarySpec != null) { |
| String libraryId = antLibrarySpec.getLibraryId(); |
| if (librarySpecs.containsKey(libraryId)) { |
| AntLibrarySpec currentSpec |
| = (AntLibrarySpec)librarySpecs.get(libraryId); |
| throw new ExecutionException("Found more than one " |
| + "copy of library with id = " + libraryId |
| + " (" + libURLs[i] + ") + existing library at (" |
| + currentSpec.getLibraryURL() + ")"); |
| } |
| antLibrarySpec.setLibraryURL(libURLs[i]); |
| librarySpecs.put(libraryId, antLibrarySpec); |
| } |
| } catch (XMLParseException e) { |
| Throwable t = e.getCause(); |
| // ignore file not found exceptions - means the |
| // jar does not provide META-INF/antlib.xml |
| if (!(t instanceof FileNotFoundException)) { |
| throw new ExecutionException("Unable to parse Ant library " |
| + libURLs[i], e); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Configures the Ant Libraries. Configuration of an Ant Library |
| * involves resolving any dependencies between libraries and then |
| * creating the class loaders for the library |
| * |
| * @param librarySpecs the loaded specifications of the Ant libraries |
| * @param initConfig the Ant initialization configuration |
| * @param libraries the collection of libraries already configured |
| * @param libPathsMap a map of lists of library patsh fro each library |
| * @exception ExecutionException if a library cannot be configured from |
| * the given specification |
| */ |
| public void configLibraries(InitConfig initConfig, Map librarySpecs, |
| Map libraries, Map libPathsMap) |
| throws ExecutionException { |
| |
| // check if any already defined |
| for (Iterator i = librarySpecs.keySet().iterator(); i.hasNext(); ) { |
| String libraryId = (String)i.next(); |
| if (libraries.containsKey(libraryId)) { |
| AntLibrary currentVersion |
| = (AntLibrary)libraries.get(libraryId); |
| throw new ExecutionException("Ant Library \"" + libraryId |
| + "\" is already loaded from " |
| + currentVersion.getDefinitionURL()); |
| } |
| } |
| |
| CircularDependencyChecker configuring |
| = new CircularDependencyChecker("configuring Ant libraries"); |
| for (Iterator i = librarySpecs.keySet().iterator(); i.hasNext(); ) { |
| String libraryId = (String)i.next(); |
| if (!libraries.containsKey(libraryId)) { |
| configLibrary(initConfig, librarySpecs, libraryId, |
| configuring, libraries, libPathsMap); |
| } |
| } |
| } |
| |
| /** |
| * Load either a set of libraries or a single library. |
| * |
| * @param libLocationURL URL where libraries can be found |
| * @param librarySpecs A collection of library specs which will be |
| * populated with the libraries found |
| * @exception ExecutionException if the libraries cannot be loaded |
| * @exception MalformedURLException if the library's location cannot be |
| * formed |
| */ |
| public void loadLibs(Map librarySpecs, URL libLocationURL) |
| throws ExecutionException, MalformedURLException { |
| if (!libLocationURL.getProtocol().equals("file") |
| && !remoteAllowed) { |
| throw new ExecutionException("The config library " |
| + "location \"" + libLocationURL |
| + "\" cannot be used because config does " |
| + "not allow remote libraries"); |
| } |
| addAntLibraries(librarySpecs, libLocationURL); |
| } |
| |
| /** |
| * Load either a set of libraries or a single library. |
| * |
| * @param libLocationString URL or file where libraries can be found |
| * @param librarySpecs A collection of library specs which will be |
| * populated with the libraries found |
| * @exception ExecutionException if the libraries cannot be loaded |
| * @exception MalformedURLException if the library's location cannot be |
| * formed |
| */ |
| public void loadLibs(Map librarySpecs, String libLocationString) |
| throws ExecutionException, MalformedURLException { |
| |
| File libLocation = new File(libLocationString); |
| if (!libLocation.exists()) { |
| try { |
| loadLibs(librarySpecs, new URL(libLocationString)); |
| } catch (MalformedURLException e) { |
| // XXX |
| } |
| } else { |
| addAntLibraries(librarySpecs, InitUtils.getFileURL(libLocation)); |
| } |
| } |
| |
| /** |
| * add a library path to the given library |
| * |
| * @param antLibrary the library to which the path is to be added |
| * @param path the path to be added |
| * @exception ExecutionException if remote paths are not allowed by |
| * configuration |
| */ |
| public void addLibPath(AntLibrary antLibrary, URL path) |
| throws ExecutionException { |
| if (!path.getProtocol().equals("file") |
| && !remoteAllowed) { |
| throw new ExecutionException("Remote libpaths are not" |
| + " allowed: " + path); |
| } |
| antLibrary.addLibraryURL(path); |
| } |
| |
| /** |
| * Configure a library from a specification and the Ant init config. |
| * |
| * @param initConfig Ant's init config passed in from the front end. |
| * @param librarySpecs the library specs from which this library is to |
| * be configured. |
| * @param libraryId the global identifier for the library |
| * @param configuring A circualr dependency chcker for library |
| * dependencies. |
| * @param libraries the collection of libraries which have already been |
| * configured |
| * @param libPathsMap a map of lists of library patsh fro each library |
| * @exception ExecutionException if the library cannot be configured. |
| */ |
| private void configLibrary(InitConfig initConfig, Map librarySpecs, |
| String libraryId, |
| CircularDependencyChecker configuring, |
| Map libraries, Map libPathsMap) |
| throws ExecutionException { |
| |
| try { |
| configuring.visitNode(libraryId); |
| |
| AntLibrarySpec librarySpec |
| = (AntLibrarySpec)librarySpecs.get(libraryId); |
| String extendsId = librarySpec.getExtendsLibraryId(); |
| if (extendsId != null) { |
| if (!libraries.containsKey(extendsId)) { |
| if (!librarySpecs.containsKey(extendsId)) { |
| throw new ExecutionException("Could not find library, " |
| + extendsId + ", upon which library " |
| + libraryId + " depends"); |
| } |
| configLibrary(initConfig, librarySpecs, extendsId, |
| configuring, libraries, libPathsMap); |
| } |
| } |
| |
| // now create the library for the specification |
| AntLibrary antLibrary = new AntLibrary(librarySpec); |
| |
| // determine the URLs required for this task. These are the |
| // task URL itself, the XML parser URLs if required, the |
| // tools jar URL if required |
| List urlsList = new ArrayList(); |
| |
| if (librarySpec.getLibraryURL() != null) { |
| urlsList.add(librarySpec.getLibraryURL()); |
| } |
| if (librarySpec.isToolsJarRequired() |
| && initConfig.getToolsJarURL() != null) { |
| urlsList.add(initConfig.getToolsJarURL()); |
| } |
| |
| if (librarySpec.usesAntXML()) { |
| URL[] parserURLs = initConfig.getParserURLs(); |
| for (int i = 0; i < parserURLs.length; ++i) { |
| urlsList.add(parserURLs[i]); |
| } |
| } |
| |
| for (Iterator i = urlsList.iterator(); i.hasNext(); ) { |
| antLibrary.addLibraryURL((URL)i.next()); |
| } |
| if (extendsId != null) { |
| AntLibrary extendsLibrary |
| = (AntLibrary)libraries.get(extendsId); |
| antLibrary.setExtendsLibrary(extendsLibrary); |
| } |
| antLibrary.setParentLoader(initConfig.getCommonLoader()); |
| libraries.put(libraryId, antLibrary); |
| |
| List libPaths = (List)libPathsMap.get(libraryId); |
| if (libPaths != null) { |
| for (Iterator j = libPaths.iterator(); j.hasNext(); ) { |
| URL pathURL = (URL)j.next(); |
| addLibPath(antLibrary, pathURL); |
| } |
| } |
| |
| configuring.leaveNode(libraryId); |
| } catch (CircularDependencyException e) { |
| throw new ExecutionException(e); |
| } |
| } |
| |
| |
| /** |
| * Read an Ant library definition from a URL |
| * |
| * @param antlibURL the URL of the library definition |
| * @return the AntLibrary specification read from the library XML |
| * definition |
| * @exception XMLParseException if the library cannot be parsed |
| */ |
| private AntLibrarySpec parseLibraryDef(URL antlibURL) |
| throws XMLParseException { |
| ParseContext context = new ParseContext(); |
| AntLibHandler libHandler = new AntLibHandler(); |
| |
| context.parse(antlibURL, "antlib", libHandler); |
| |
| return libHandler.getAntLibrarySpec(); |
| } |
| |
| } |
| |