- /*
- * Copyright 2003-2004 The Apache Software Foundation
- *
- * Licensed 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
- *
- * http://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.loader;
-
- import java.io.File;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- import java.io.Reader;
- import org.apache.tools.ant.AntClassLoader;
- import org.apache.tools.ant.Project;
- import java.util.jar.Manifest;
- import java.util.jar.JarFile;
- import java.util.zip.ZipFile;
- import java.util.jar.Attributes;
- import java.util.jar.Attributes.Name;
- import java.net.URL;
- import java.net.MalformedURLException;
- import java.util.zip.ZipEntry;
- import java.util.Collections;
- import java.util.HashMap;
- import java.util.Map;
- import java.util.StringTokenizer;
- import org.apache.tools.ant.util.FileUtils;
-
- /**
- * An implementation of the AntClassLoader suitable for use on post JDK 1.1
- * platforms
- *
- */
- public class AntClassLoader2 extends AntClassLoader {
- /** Instance of a utility class to use for file operations. */
- private FileUtils fileUtils;
-
- /** Static map of jar file/time to manifiest class-path entries */
- private static Map pathMap = Collections.synchronizedMap(new HashMap());
-
- /**
- * Constructor
- */
- public AntClassLoader2() {
- fileUtils = FileUtils.newFileUtils();
- }
-
- /**
- * Define a class given its bytes
- *
- * @param container the container from which the class data has been read
- * may be a directory or a jar/zip file.
- *
- * @param classData the bytecode data for the class
- * @param className the name of the class
- *
- * @return the Class instance created from the given data
- *
- * @throws IOException if the class data cannot be read.
- */
- protected Class defineClassFromData(File container, byte[] classData,
- String className) throws IOException {
-
- definePackage(container, className);
- return defineClass(className, classData, 0, classData.length,
- Project.class.getProtectionDomain());
-
- }
-
- /**
- * Get the manifest from the given jar, if it is indeed a jar and it has a
- * manifest
- *
- * @param container the File from which a manifest is required.
- *
- * @return the jar's manifest or null is the container is not a jar or it
- * has no manifest.
- *
- * @exception IOException if the manifest cannot be read.
- */
- private Manifest getJarManifest(File container) throws IOException {
- if (container.isDirectory()) {
- return null;
- }
- JarFile jarFile = null;
- try {
- jarFile = new JarFile(container);
- return jarFile.getManifest();
- } finally {
- if (jarFile != null) {
- jarFile.close();
- }
- }
- }
-
- /**
- * Define the package information associated with a class.
- *
- * @param container the file containing the class definition.
- * @param className the class name of for which the package information
- * is to be determined.
- *
- * @exception IOException if the package information cannot be read from the
- * container.
- */
- protected void definePackage(File container, String className)
- throws IOException {
- int classIndex = className.lastIndexOf('.');
- if (classIndex == -1) {
- return;
- }
-
- String packageName = className.substring(0, classIndex);
- if (getPackage(packageName) != null) {
- // already defined
- return;
- }
-
- // define the package now
- Manifest manifest = getJarManifest(container);
-
- if (manifest == null) {
- definePackage(packageName, null, null, null, null, null,
- null, null);
- } else {
- definePackage(container, packageName, manifest);
- }
- }
-
- /**
- * Define the package information when the class comes from a
- * jar with a manifest
- *
- * @param container the jar file containing the manifest
- * @param packageName the name of the package being defined.
- * @param manifest the jar's manifest
- */
- protected void definePackage(File container, String packageName,
- Manifest manifest) {
- String sectionName = packageName.replace('.', '/') + "/";
-
- String specificationTitle = null;
- String specificationVendor = null;
- String specificationVersion = null;
- String implementationTitle = null;
- String implementationVendor = null;
- String implementationVersion = null;
- String sealedString = null;
- URL sealBase = null;
-
- Attributes sectionAttributes = manifest.getAttributes(sectionName);
- if (sectionAttributes != null) {
- specificationTitle
- = sectionAttributes.getValue(Name.SPECIFICATION_TITLE);
- specificationVendor
- = sectionAttributes.getValue(Name.SPECIFICATION_VENDOR);
- specificationVersion
- = sectionAttributes.getValue(Name.SPECIFICATION_VERSION);
- implementationTitle
- = sectionAttributes.getValue(Name.IMPLEMENTATION_TITLE);
- implementationVendor
- = sectionAttributes.getValue(Name.IMPLEMENTATION_VENDOR);
- implementationVersion
- = sectionAttributes.getValue(Name.IMPLEMENTATION_VERSION);
- sealedString
- = sectionAttributes.getValue(Name.SEALED);
- }
-
- Attributes mainAttributes = manifest.getMainAttributes();
- if (mainAttributes != null) {
- if (specificationTitle == null) {
- specificationTitle
- = mainAttributes.getValue(Name.SPECIFICATION_TITLE);
- }
- if (specificationVendor == null) {
- specificationVendor
- = mainAttributes.getValue(Name.SPECIFICATION_VENDOR);
- }
- if (specificationVersion == null) {
- specificationVersion
- = mainAttributes.getValue(Name.SPECIFICATION_VERSION);
- }
- if (implementationTitle == null) {
- implementationTitle
- = mainAttributes.getValue(Name.IMPLEMENTATION_TITLE);
- }
- if (implementationVendor == null) {
- implementationVendor
- = mainAttributes.getValue(Name.IMPLEMENTATION_VENDOR);
- }
- if (implementationVersion == null) {
- implementationVersion
- = mainAttributes.getValue(Name.IMPLEMENTATION_VERSION);
- }
- if (sealedString == null) {
- sealedString
- = mainAttributes.getValue(Name.SEALED);
- }
- }
-
- if (sealedString != null && sealedString.equalsIgnoreCase("true")) {
- try {
- sealBase = new URL("file:" + container.getPath());
- } catch (MalformedURLException e) {
- // ignore
- }
- }
-
- definePackage(packageName, specificationTitle, specificationVersion,
- specificationVendor, implementationTitle,
- implementationVersion, implementationVendor, sealBase);
- }
-
-
- /**
- * Add a file to the path. This classloader reads the manifest, if
- * available, and adds any additional class path jars specified in the
- * manifest.
- *
- * @param pathComponent the file which is to be added to the path for
- * this class loader
- *
- * @throws IOException if data needed from the file cannot be read.
- */
- protected void addPathFile(File pathComponent) throws IOException {
- super.addPathFile(pathComponent);
-
- if (pathComponent.isDirectory()) {
- return;
- }
-
- String absPathPlusTimeAndLength =
- pathComponent.getAbsolutePath() + pathComponent.lastModified() + "-"
- + pathComponent.length();
- String classpath = (String) pathMap.get(absPathPlusTimeAndLength);
- if (classpath == null) {
- ZipFile jarFile = null;
- InputStream manifestStream = null;
- try {
- jarFile = new ZipFile(pathComponent);
- manifestStream
- = jarFile.getInputStream(new ZipEntry("META-INF/MANIFEST.MF"));
-
- if (manifestStream == null) {
- return;
- }
- Reader manifestReader
- = new InputStreamReader(manifestStream, "UTF-8");
- org.apache.tools.ant.taskdefs.Manifest manifest
- = new org.apache.tools.ant.taskdefs.Manifest(manifestReader);
- classpath
- = manifest.getMainSection().getAttributeValue("Class-Path");
-
- } catch (org.apache.tools.ant.taskdefs.ManifestException e) {
- // ignore
- } finally {
- if (manifestStream != null) {
- manifestStream.close();
- }
- if (jarFile != null) {
- jarFile.close();
- }
- }
- if (classpath == null) {
- classpath = "";
- }
- pathMap.put(absPathPlusTimeAndLength, classpath);
- }
-
- if (!"".equals(classpath)) {
- URL baseURL = fileUtils.getFileURL(pathComponent);
- StringTokenizer st = new StringTokenizer(classpath);
- while (st.hasMoreTokens()) {
- String classpathElement = st.nextToken();
- URL libraryURL = new URL(baseURL, classpathElement);
- if (!libraryURL.getProtocol().equals("file")) {
- log("Skipping jar library " + classpathElement
- + " since only relative URLs are supported by this"
- + " loader", Project.MSG_VERBOSE);
- continue;
- }
- File libraryFile = new File(libraryURL.getFile());
- if (libraryFile.exists() && !isInPath(libraryFile)) {
- addPathFile(libraryFile);
- }
- }
- }
- }
- }
-