All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.tools.ant.ProjectHelperRepository Maven / Gradle / Ivy

The newest version!
/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */
package org.apache.tools.ant;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Stream;

import org.apache.tools.ant.helper.ProjectHelper2;
import org.apache.tools.ant.types.Resource;
import org.apache.tools.ant.util.LoaderUtils;
import org.apache.tools.ant.util.StreamUtils;

/**
 * Repository of {@link ProjectHelper} found in the classpath or via
 * some System properties.
 *
 * 

See the ProjectHelper documentation in the manual.

* * @since Ant 1.8.0 */ public class ProjectHelperRepository { private static final String DEBUG_PROJECT_HELPER_REPOSITORY = "ant.project-helper-repo.debug"; // The message log level is not accessible here because everything // is instantiated statically private static final boolean DEBUG = "true".equals(System.getProperty(DEBUG_PROJECT_HELPER_REPOSITORY)); private static ProjectHelperRepository instance = new ProjectHelperRepository(); private List> helpers = new ArrayList<>(); private static Constructor PROJECTHELPER2_CONSTRUCTOR; static { try { PROJECTHELPER2_CONSTRUCTOR = ProjectHelper2.class.getConstructor(); } catch (Exception e) { // ProjectHelper2 must be available throw new BuildException(e); } } public static ProjectHelperRepository getInstance() { return instance; } private ProjectHelperRepository() { collectProjectHelpers(); } private void collectProjectHelpers() { // First, try the system property registerProjectHelper(getProjectHelperBySystemProperty()); // A JDK1.3 'service' (like in JAXP). That will plug a helper // automatically if in CLASSPATH, with the right META-INF/services. try { ClassLoader classLoader = LoaderUtils.getContextClassLoader(); if (classLoader != null) { for (URL resource : Collections.list(classLoader.getResources(MagicNames.PROJECT_HELPER_SERVICE))) { URLConnection conn = resource.openConnection(); conn.setUseCaches(false); registerProjectHelper(getProjectHelperByService(conn.getInputStream())); } } InputStream systemResource = ClassLoader.getSystemResourceAsStream(MagicNames.PROJECT_HELPER_SERVICE); if (systemResource != null) { registerProjectHelper(getProjectHelperByService(systemResource)); } } catch (Exception e) { System.err.println("Unable to load ProjectHelper from service " + MagicNames.PROJECT_HELPER_SERVICE + " (" + e.getClass().getName() + ": " + e.getMessage() + ")"); if (DEBUG) { e.printStackTrace(System.err); //NOSONAR } } } /** * Register the specified project helper into the repository. *

* The helper will be added after all the already registered helpers, but * before the default one (ProjectHelper2) * * @param helperClassName * the fully qualified name of the helper * @throws BuildException * if the class cannot be loaded or if there is no constructor * with no argument * @since Ant 1.8.2 */ public void registerProjectHelper(String helperClassName) throws BuildException { registerProjectHelper(getHelperConstructor(helperClassName)); } /** * Register the specified project helper into the repository. *

* The helper will be added after all the already registered helpers, but * before the default one (ProjectHelper2) * * @param helperClass * the class of the helper * @throws BuildException * if there is no constructor with no argument * @since Ant 1.8.2 */ public void registerProjectHelper(Class helperClass) throws BuildException { try { registerProjectHelper(helperClass.getConstructor()); } catch (NoSuchMethodException e) { throw new BuildException("Couldn't find no-arg constructor in " + helperClass.getName()); } } private void registerProjectHelper(Constructor helperConstructor) { if (helperConstructor == null) { return; } if (DEBUG) { System.out.println("ProjectHelper " + helperConstructor.getClass().getName() + " registered."); } helpers.add(helperConstructor); } private Constructor getProjectHelperBySystemProperty() { String helperClass = System.getProperty(MagicNames.PROJECT_HELPER_CLASS); try { if (helperClass != null) { return getHelperConstructor(helperClass); } } catch (SecurityException e) { System.err.println("Unable to load ProjectHelper class \"" + helperClass + " specified in system property " + MagicNames.PROJECT_HELPER_CLASS + " (" + e.getMessage() + ")"); if (DEBUG) { e.printStackTrace(System.err); //NOSONAR } } return null; } private Constructor getProjectHelperByService(InputStream is) { try { // This code is needed by EBCDIC and other strange systems. // It's a fix for bugs reported in xerces BufferedReader rd = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8)); String helperClassName = rd.readLine(); rd.close(); if (helperClassName != null && !helperClassName.isEmpty()) { return getHelperConstructor(helperClassName); } } catch (Exception e) { System.out.println("Unable to load ProjectHelper from service " + MagicNames.PROJECT_HELPER_SERVICE + " (" + e.getMessage() + ")"); if (DEBUG) { e.printStackTrace(System.err); //NOSONAR } } return null; } /** * Get the constructor with not argument of an helper from its class name. * It'll first try the thread class loader, then Class.forName() will load * from the same loader that loaded this class. * * @param helperClass * The name of the class to create an instance of. Must not be * null. * * @return the constructor of the specified class. * * @exception BuildException * if the class cannot be found or if a constructor with no * argument cannot be found. */ private Constructor getHelperConstructor(String helperClass) throws BuildException { ClassLoader classLoader = LoaderUtils.getContextClassLoader(); try { Class clazz = null; if (classLoader != null) { try { clazz = classLoader.loadClass(helperClass); } catch (ClassNotFoundException ex) { // try next method } } if (clazz == null) { clazz = Class.forName(helperClass); } return clazz.asSubclass(ProjectHelper.class).getConstructor(); } catch (Exception e) { throw new BuildException(e); } } /** * Get the helper that will be able to parse the specified build file. The helper * will be chosen among the ones found in the classpath * * @param buildFile Resource * @return the first ProjectHelper that fit the requirement (never null). */ public ProjectHelper getProjectHelperForBuildFile(Resource buildFile) throws BuildException { ProjectHelper ph = StreamUtils.iteratorAsStream(getHelpers()) .filter(helper -> helper.canParseBuildFile(buildFile)) .findFirst().orElse(null); if (ph == null) { throw new BuildException("BUG: at least the ProjectHelper2 should " + "have supported the file " + buildFile); } if (DEBUG) { System.out.println("ProjectHelper " + ph.getClass().getName() + " selected for the build file " + buildFile); } return ph; } /** * Get the helper that will be able to parse the specified antlib. The helper * will be chosen among the ones found in the classpath * * @param antlib Resource * @return the first ProjectHelper that fit the requirement (never null). */ public ProjectHelper getProjectHelperForAntlib(Resource antlib) throws BuildException { ProjectHelper ph = StreamUtils.iteratorAsStream(getHelpers()) .filter(helper -> helper.canParseAntlibDescriptor(antlib)) .findFirst().orElse(null); if (ph == null) { throw new BuildException("BUG: at least the ProjectHelper2 should " + "have supported the file " + antlib); } if (DEBUG) { System.out.println("ProjectHelper " + ph.getClass().getName() + " selected for the antlib " + antlib); } return ph; } /** * Get an iterator on the list of project helpers configured. The iterator * will always return at least one element as there will always be the * default project helper configured. * * @return an iterator of {@link ProjectHelper} */ public Iterator getHelpers() { Stream.Builder> b = Stream.builder(); helpers.forEach(b::add); return b.add(PROJECTHELPER2_CONSTRUCTOR).build().map(c -> { try { return c.newInstance(); } catch (Exception e) { throw new BuildException("Failed to invoke no-arg constructor" + " on " + c.getName()); } }).map(ProjectHelper.class::cast).iterator(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy