/* * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */package com.sun.tools.extcheck;import java.util.*;import java.net.MalformedURLException;import java.util.Vector;import java.io.*;import java.util.StringTokenizer;import java.net.URL;import java.util.jar.JarFile;import java.util.jar.JarEntry;import java.util.jar.Manifest;import java.util.jar.Attributes;import java.util.jar.Attributes.Name;import java.net.URLConnection;import java.security.Permission;import java.util.jar.*;import java.net.JarURLConnection;import sun.net.www.ParseUtil;/** * ExtCheck reports on clashes between a specified (target) * jar file and jar files already installed in the extensions * directory. * * @author Benedict Gomes * @since 1.2 */public class ExtCheck { private static final boolean DEBUG = false; // The following strings hold the values of the version variables // for the target jar file private String targetSpecTitle; private String targetSpecVersion; private String targetSpecVendor; private String targetImplTitle; private String targetImplVersion; private String targetImplVendor; private String targetsealed; /* Flag to indicate whether extra information should be dumped to stdout */ private boolean verboseFlag; /* * Create a new instance of the jar reporting tool for a particular * targetFile. * @param targetFile is the file to compare against. * @param verbose indicates whether to dump filenames and manifest * information (on conflict) to the standard output. */ static ExtCheck create(File targetFile, boolean verbose) { return new ExtCheck(targetFile, verbose); } private ExtCheck(File targetFile, boolean verbose) { verboseFlag = verbose; investigateTarget(targetFile); } private void investigateTarget(File targetFile) { verboseMessage("Target file:" + targetFile); Manifest targetManifest = null; try { File canon = new File(targetFile.getCanonicalPath()); URL url = ParseUtil.fileToEncodedURL(canon); if (url != null){ JarLoader loader = new JarLoader(url); JarFile jarFile = loader.getJarFile(); targetManifest = jarFile.getManifest(); } } catch (MalformedURLException e){ error("Malformed URL "); } catch (IOException e) { error("IO Exception "); } if (targetManifest == null) error("No manifest available in "+targetFile); Attributes attr = targetManifest.getMainAttributes(); if (attr != null) { targetSpecTitle = attr.getValue(Name.SPECIFICATION_TITLE); targetSpecVersion = attr.getValue(Name.SPECIFICATION_VERSION); targetSpecVendor = attr.getValue(Name.SPECIFICATION_VENDOR); targetImplTitle = attr.getValue(Name.IMPLEMENTATION_TITLE); targetImplVersion = attr.getValue(Name.IMPLEMENTATION_VERSION); targetImplVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR); targetsealed = attr.getValue(Name.SEALED); } else { error("No attributes available in the manifest"); } if (targetSpecTitle == null) error("The target file does not have a specification title"); if (targetSpecVersion == null) error("The target file does not have a specification version"); verboseMessage("Specification title:" + targetSpecTitle); verboseMessage("Specification version:" + targetSpecVersion); if (targetSpecVendor != null) verboseMessage("Specification vendor:" + targetSpecVendor); if (targetImplVersion != null) verboseMessage("Implementation version:" + targetImplVersion); if (targetImplVendor != null) verboseMessage("Implementation vendor:" + targetImplVendor); verboseMessage(""); } /** * Verify that none of the jar files in the install directory * has the same specification-title and the same or a newer * specification-version. * * @return Return true if the target jar file is newer * than any installed jar file with the same specification-title, * otherwise return false */ boolean checkInstalledAgainstTarget(){ String s = System.getProperty("java.ext.dirs"); File [] dirs; if (s != null) { StringTokenizer st = new StringTokenizer(s, File.pathSeparator); int count = st.countTokens(); dirs = new File[count]; for (int i = 0; i < count; i++) { dirs[i] = new File(st.nextToken()); } } else { dirs = new File[0]; } boolean result = true; for (int i = 0; i < dirs.length; i++) { String[] files = dirs[i].list(); if (files != null) { for (int j = 0; j < files.length; j++) { try { File f = new File(dirs[i],files[j]); File canon = new File(f.getCanonicalPath()); URL url = ParseUtil.fileToEncodedURL(canon); if (url != null){ result = result && checkURLRecursively(1,url); } } catch (MalformedURLException e){ error("Malformed URL"); } catch (IOException e) { error("IO Exception"); } } } } if (result) { generalMessage("No conflicting installed jar found."); } else { generalMessage("Conflicting installed jar found. " + " Use -verbose for more information."); } return result; } /** * Recursively verify that a jar file, and any urls mentioned * in its class path, do not conflict with the target jar file. * * @param indent is the current nesting level * @param url is the path to the jar file being checked. * @return true if there is no newer URL, otherwise false */ private boolean checkURLRecursively(int indent, URL url) throws IOException { verboseMessage("Comparing with " + url); JarLoader jarloader = new JarLoader(url); JarFile j = jarloader.getJarFile(); Manifest man = j.getManifest(); if (man != null) { Attributes attr = man.getMainAttributes(); if (attr != null){ String title = attr.getValue(Name.SPECIFICATION_TITLE); String version = attr.getValue(Name.SPECIFICATION_VERSION); String vendor = attr.getValue(Name.SPECIFICATION_VENDOR); String implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE); String implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION); String implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR); String sealed = attr.getValue(Name.SEALED); if (title != null){ if (title.equals(targetSpecTitle)){ if (version != null){ if (version.equals(targetSpecVersion) || isNotOlderThan(version,targetSpecVersion)){ verboseMessage(""); verboseMessage("CONFLICT DETECTED "); verboseMessage("Conflicting file:"+ url); verboseMessage("Installed Version:" + version); if (implTitle != null) verboseMessage("Implementation Title:"+ implTitle); if (implVersion != null) verboseMessage("Implementation Version:"+ implVersion); if (implVendor != null) verboseMessage("Implementation Vendor:"+ implVendor); return false; } } } } } } boolean result = true; URL[] loaderList = jarloader.getClassPath(); if (loaderList != null) { for(int i=0; i < loaderList.length; i++){ if (url != null){ boolean res = checkURLRecursively(indent+1,loaderList[i]); result = res && result; } } } return result; } /** * See comment in method java.lang.Package.isCompatibleWith. * Return true if already is not older than target. i.e. the * target file may be superseded by a file already installed */ private boolean isNotOlderThan(String already,String target) throws NumberFormatException { if (already == null || already.length() < 1) { throw new NumberFormatException("Empty version string"); } // Until it matches scan and compare numbers StringTokenizer dtok = new StringTokenizer(target, ".", true); StringTokenizer stok = new StringTokenizer(already, ".", true); while (dtok.hasMoreTokens() || stok.hasMoreTokens()) { int dver; int sver; if (dtok.hasMoreTokens()) { dver = Integer.parseInt(dtok.nextToken()); } else dver = 0; if (stok.hasMoreTokens()) { sver = Integer.parseInt(stok.nextToken()); } else sver = 0; if (sver < dver) return false; // Known to be incompatible if (sver > dver) return true; // Known to be compatible // Check for and absorb separators if (dtok.hasMoreTokens()) dtok.nextToken(); if (stok.hasMoreTokens()) stok.nextToken(); // Compare next component } // All components numerically equal return true; } /** * Prints out message if the verboseFlag is set */ void verboseMessage(String message){ if (verboseFlag) { System.err.println(message); } } void generalMessage(String message){ System.err.println(message); } /** * Throws a RuntimeException with a message describing the error. */ static void error(String message) throws RuntimeException { throw new RuntimeException(message); } /** * Inner class used to represent a loader of resources and classes * from a base URL. Somewhat modified version of code in * sun.misc.URLClassPath.JarLoader */ private static class JarLoader { private final URL base; private JarFile jar; private URL csu; /* * Creates a new Loader for the specified URL. */ JarLoader(URL url) { String urlName = url + "!/"; URL tmpBaseURL = null; try { tmpBaseURL = new URL("jar","",urlName); jar = findJarFile(url); csu = url; } catch (MalformedURLException e) { ExtCheck.error("Malformed url "+urlName); } catch (IOException e) { ExtCheck.error("IO Exception occurred"); } base = tmpBaseURL; } /* * Returns the base URL for this Loader. */ URL getBaseURL() { return base; } JarFile getJarFile() { return jar; } private JarFile findJarFile(URL url) throws IOException { // Optimize case where url refers to a local jar file if ("file".equals(url.getProtocol())) { String path = url.getFile().replace('/', File.separatorChar); File file = new File(path); if (!file.exists()) { throw new FileNotFoundException(path); } return new JarFile(path); } URLConnection uc = getBaseURL().openConnection(); //uc.setRequestProperty(USER_AGENT_JAVA_VERSION, JAVA_VERSION); return ((JarURLConnection)uc).getJarFile(); } /* * Returns the JAR file local class path, or null if none. */ URL[] getClassPath() throws IOException { Manifest man = jar.getManifest(); if (man != null) { Attributes attr = man.getMainAttributes(); if (attr != null) { String value = attr.getValue(Name.CLASS_PATH); if (value != null) { return parseClassPath(csu, value); } } } return null; } /* * Parses value of the Class-Path manifest attribute and returns * an array of URLs relative to the specified base URL. */ private URL[] parseClassPath(URL base, String value) throws MalformedURLException { StringTokenizer st = new StringTokenizer(value); URL[] urls = new URL[st.countTokens()]; int i = 0; while (st.hasMoreTokens()) { String path = st.nextToken(); urls[i] = new URL(base, path); i++; } return urls; } }}
/*
* Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.extcheck;
import java.util.*;
import java.net.MalformedURLException;
import java.util.Vector;
import java.io.*;
import java.util.StringTokenizer;
import java.net.URL;
import java.util.jar.JarFile;
import java.util.jar.JarEntry;
import java.util.jar.Manifest;
import java.util.jar.Attributes;
import java.util.jar.Attributes.Name;
import java.net.URLConnection;
import java.security.Permission;
import java.util.jar.*;
import java.net.JarURLConnection;
import sun.net.www.ParseUtil;
/**
* ExtCheck reports on clashes between a specified (target)
* jar file and jar files already installed in the extensions
* directory.
*
* @author Benedict Gomes
* @since 1.2
*/
public class ExtCheck {
private static final boolean DEBUG = false;
// The following strings hold the values of the version variables
// for the target jar file
private String targetSpecTitle;
private String targetSpecVersion;
private String targetSpecVendor;
private String targetImplTitle;
private String targetImplVersion;
private String targetImplVendor;
private String targetsealed;
/* Flag to indicate whether extra information should be dumped to stdout */
private boolean verboseFlag;
/*
* Create a new instance of the jar reporting tool for a particular
* targetFile.
* @param targetFile is the file to compare against.
* @param verbose indicates whether to dump filenames and manifest
* information (on conflict) to the standard output.
*/
static ExtCheck create(File targetFile, boolean verbose) {
return new ExtCheck(targetFile, verbose);
}
private ExtCheck(File targetFile, boolean verbose) {
verboseFlag = verbose;
investigateTarget(targetFile);
}
private void investigateTarget(File targetFile) {
verboseMessage("Target file:" + targetFile);
Manifest targetManifest = null;
try {
File canon = new File(targetFile.getCanonicalPath());
URL url = ParseUtil.fileToEncodedURL(canon);
if (url != null){
JarLoader loader = new JarLoader(url);
JarFile jarFile = loader.getJarFile();
targetManifest = jarFile.getManifest();
}
} catch (MalformedURLException e){
error("Malformed URL ");
} catch (IOException e) {
error("IO Exception ");
}
if (targetManifest == null)
error("No manifest available in "+targetFile);
Attributes attr = targetManifest.getMainAttributes();
if (attr != null) {
targetSpecTitle = attr.getValue(Name.SPECIFICATION_TITLE);
targetSpecVersion = attr.getValue(Name.SPECIFICATION_VERSION);
targetSpecVendor = attr.getValue(Name.SPECIFICATION_VENDOR);
targetImplTitle = attr.getValue(Name.IMPLEMENTATION_TITLE);
targetImplVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
targetImplVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR);
targetsealed = attr.getValue(Name.SEALED);
} else {
error("No attributes available in the manifest");
}
if (targetSpecTitle == null)
error("The target file does not have a specification title");
if (targetSpecVersion == null)
error("The target file does not have a specification version");
verboseMessage("Specification title:" + targetSpecTitle);
verboseMessage("Specification version:" + targetSpecVersion);
if (targetSpecVendor != null)
verboseMessage("Specification vendor:" + targetSpecVendor);
if (targetImplVersion != null)
verboseMessage("Implementation version:" + targetImplVersion);
if (targetImplVendor != null)
verboseMessage("Implementation vendor:" + targetImplVendor);
verboseMessage("");
}
/**
* Verify that none of the jar files in the install directory
* has the same specification-title and the same or a newer
* specification-version.
*
* @return Return true if the target jar file is newer
* than any installed jar file with the same specification-title,
* otherwise return false
*/
boolean checkInstalledAgainstTarget(){
String s = System.getProperty("java.ext.dirs");
File [] dirs;
if (s != null) {
StringTokenizer st =
new StringTokenizer(s, File.pathSeparator);
int count = st.countTokens();
dirs = new File[count];
for (int i = 0; i < count; i++) {
dirs[i] = new File(st.nextToken());
}
} else {
dirs = new File[0];
}
boolean result = true;
for (int i = 0; i < dirs.length; i++) {
String[] files = dirs[i].list();
if (files != null) {
for (int j = 0; j < files.length; j++) {
try {
File f = new File(dirs[i],files[j]);
File canon = new File(f.getCanonicalPath());
URL url = ParseUtil.fileToEncodedURL(canon);
if (url != null){
result = result && checkURLRecursively(1,url);
}
} catch (MalformedURLException e){
error("Malformed URL");
} catch (IOException e) {
error("IO Exception");
}
}
}
}
if (result) {
generalMessage("No conflicting installed jar found.");
} else {
generalMessage("Conflicting installed jar found. "
+ " Use -verbose for more information.");
}
return result;
}
/**
* Recursively verify that a jar file, and any urls mentioned
* in its class path, do not conflict with the target jar file.
*
* @param indent is the current nesting level
* @param url is the path to the jar file being checked.
* @return true if there is no newer URL, otherwise false
*/
private boolean checkURLRecursively(int indent, URL url)
throws IOException
{
verboseMessage("Comparing with " + url);
JarLoader jarloader = new JarLoader(url);
JarFile j = jarloader.getJarFile();
Manifest man = j.getManifest();
if (man != null) {
Attributes attr = man.getMainAttributes();
if (attr != null){
String title = attr.getValue(Name.SPECIFICATION_TITLE);
String version = attr.getValue(Name.SPECIFICATION_VERSION);
String vendor = attr.getValue(Name.SPECIFICATION_VENDOR);
String implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE);
String implVersion
= attr.getValue(Name.IMPLEMENTATION_VERSION);
String implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR);
String sealed = attr.getValue(Name.SEALED);
if (title != null){
if (title.equals(targetSpecTitle)){
if (version != null){
if (version.equals(targetSpecVersion) ||
isNotOlderThan(version,targetSpecVersion)){
verboseMessage("");
verboseMessage("CONFLICT DETECTED ");
verboseMessage("Conflicting file:"+ url);
verboseMessage("Installed Version:" +
version);
if (implTitle != null)
verboseMessage("Implementation Title:"+
implTitle);
if (implVersion != null)
verboseMessage("Implementation Version:"+
implVersion);
if (implVendor != null)
verboseMessage("Implementation Vendor:"+
implVendor);
return false;
}
}
}
}
}
}
boolean result = true;
URL[] loaderList = jarloader.getClassPath();
if (loaderList != null) {
for(int i=0; i < loaderList.length; i++){
if (url != null){
boolean res = checkURLRecursively(indent+1,loaderList[i]);
result = res && result;
}
}
}
return result;
}
/**
* See comment in method java.lang.Package.isCompatibleWith.
* Return true if already is not older than target. i.e. the
* target file may be superseded by a file already installed
*/
private boolean isNotOlderThan(String already,String target)
throws NumberFormatException
{
if (already == null || already.length() < 1) {
throw new NumberFormatException("Empty version string");
}
// Until it matches scan and compare numbers
StringTokenizer dtok = new StringTokenizer(target, ".", true);
StringTokenizer stok = new StringTokenizer(already, ".", true);
while (dtok.hasMoreTokens() || stok.hasMoreTokens()) {
int dver;
int sver;
if (dtok.hasMoreTokens()) {
dver = Integer.parseInt(dtok.nextToken());
} else
dver = 0;
if (stok.hasMoreTokens()) {
sver = Integer.parseInt(stok.nextToken());
} else
sver = 0;
if (sver < dver)
return false; // Known to be incompatible
if (sver > dver)
return true; // Known to be compatible
// Check for and absorb separators
if (dtok.hasMoreTokens())
dtok.nextToken();
if (stok.hasMoreTokens())
stok.nextToken();
// Compare next component
}
// All components numerically equal
return true;
}
/**
* Prints out message if the verboseFlag is set
*/
void verboseMessage(String message){
if (verboseFlag) {
System.err.println(message);
}
}
void generalMessage(String message){
System.err.println(message);
}
/**
* Throws a RuntimeException with a message describing the error.
*/
static void error(String message) throws RuntimeException {
throw new RuntimeException(message);
}
/**
* Inner class used to represent a loader of resources and classes
* from a base URL. Somewhat modified version of code in
* sun.misc.URLClassPath.JarLoader
*/
private static class JarLoader {
private final URL base;
private JarFile jar;
private URL csu;
/*
* Creates a new Loader for the specified URL.
*/
JarLoader(URL url) {
String urlName = url + "!/";
URL tmpBaseURL = null;
try {
tmpBaseURL = new URL("jar","",urlName);
jar = findJarFile(url);
csu = url;
} catch (MalformedURLException e) {
ExtCheck.error("Malformed url "+urlName);
} catch (IOException e) {
ExtCheck.error("IO Exception occurred");
}
base = tmpBaseURL;
}
/*
* Returns the base URL for this Loader.
*/
URL getBaseURL() {
return base;
}
JarFile getJarFile() {
return jar;
}
private JarFile findJarFile(URL url) throws IOException {
// Optimize case where url refers to a local jar file
if ("file".equals(url.getProtocol())) {
String path = url.getFile().replace('/', File.separatorChar);
File file = new File(path);
if (!file.exists()) {
throw new FileNotFoundException(path);
}
return new JarFile(path);
}
URLConnection uc = getBaseURL().openConnection();
//uc.setRequestProperty(USER_AGENT_JAVA_VERSION, JAVA_VERSION);
return ((JarURLConnection)uc).getJarFile();
}
/*
* Returns the JAR file local class path, or null if none.
*/
URL[] getClassPath() throws IOException {
Manifest man = jar.getManifest();
if (man != null) {
Attributes attr = man.getMainAttributes();
if (attr != null) {
String value = attr.getValue(Name.CLASS_PATH);
if (value != null) {
return parseClassPath(csu, value);
}
}
}
return null;
}
/*
* Parses value of the Class-Path manifest attribute and returns
* an array of URLs relative to the specified base URL.
*/
private URL[] parseClassPath(URL base, String value)
throws MalformedURLException
{
StringTokenizer st = new StringTokenizer(value);
URL[] urls = new URL[st.countTokens()];
int i = 0;
while (st.hasMoreTokens()) {
String path = st.nextToken();
urls[i] = new URL(base, path);
i++;
}
return urls;
}
}
}