Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/com/sun/tools/extcheck/ExtCheck.java
38920 views
/*1* Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package com.sun.tools.extcheck;2627import java.util.*;28import java.net.MalformedURLException;29import java.util.Vector;30import java.io.*;31import java.util.StringTokenizer;32import java.net.URL;33import java.util.jar.JarFile;34import java.util.jar.JarEntry;35import java.util.jar.Manifest;36import java.util.jar.Attributes;37import java.util.jar.Attributes.Name;38import java.net.URLConnection;39import java.security.Permission;40import java.util.jar.*;41import java.net.JarURLConnection;42import sun.net.www.ParseUtil;4344/**45* ExtCheck reports on clashes between a specified (target)46* jar file and jar files already installed in the extensions47* directory.48*49* @author Benedict Gomes50* @since 1.251*/5253public class ExtCheck {5455private static final boolean DEBUG = false;5657// The following strings hold the values of the version variables58// for the target jar file59private String targetSpecTitle;60private String targetSpecVersion;61private String targetSpecVendor;62private String targetImplTitle;63private String targetImplVersion;64private String targetImplVendor;65private String targetsealed;6667/* Flag to indicate whether extra information should be dumped to stdout */68private boolean verboseFlag;6970/*71* Create a new instance of the jar reporting tool for a particular72* targetFile.73* @param targetFile is the file to compare against.74* @param verbose indicates whether to dump filenames and manifest75* information (on conflict) to the standard output.76*/77static ExtCheck create(File targetFile, boolean verbose) {78return new ExtCheck(targetFile, verbose);79}8081private ExtCheck(File targetFile, boolean verbose) {82verboseFlag = verbose;83investigateTarget(targetFile);84}858687private void investigateTarget(File targetFile) {88verboseMessage("Target file:" + targetFile);89Manifest targetManifest = null;90try {91File canon = new File(targetFile.getCanonicalPath());92URL url = ParseUtil.fileToEncodedURL(canon);93if (url != null){94JarLoader loader = new JarLoader(url);95JarFile jarFile = loader.getJarFile();96targetManifest = jarFile.getManifest();97}98} catch (MalformedURLException e){99error("Malformed URL ");100} catch (IOException e) {101error("IO Exception ");102}103if (targetManifest == null)104error("No manifest available in "+targetFile);105Attributes attr = targetManifest.getMainAttributes();106if (attr != null) {107targetSpecTitle = attr.getValue(Name.SPECIFICATION_TITLE);108targetSpecVersion = attr.getValue(Name.SPECIFICATION_VERSION);109targetSpecVendor = attr.getValue(Name.SPECIFICATION_VENDOR);110targetImplTitle = attr.getValue(Name.IMPLEMENTATION_TITLE);111targetImplVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);112targetImplVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR);113targetsealed = attr.getValue(Name.SEALED);114} else {115error("No attributes available in the manifest");116}117if (targetSpecTitle == null)118error("The target file does not have a specification title");119if (targetSpecVersion == null)120error("The target file does not have a specification version");121verboseMessage("Specification title:" + targetSpecTitle);122verboseMessage("Specification version:" + targetSpecVersion);123if (targetSpecVendor != null)124verboseMessage("Specification vendor:" + targetSpecVendor);125if (targetImplVersion != null)126verboseMessage("Implementation version:" + targetImplVersion);127if (targetImplVendor != null)128verboseMessage("Implementation vendor:" + targetImplVendor);129verboseMessage("");130}131132/**133* Verify that none of the jar files in the install directory134* has the same specification-title and the same or a newer135* specification-version.136*137* @return Return true if the target jar file is newer138* than any installed jar file with the same specification-title,139* otherwise return false140*/141boolean checkInstalledAgainstTarget(){142String s = System.getProperty("java.ext.dirs");143File [] dirs;144if (s != null) {145StringTokenizer st =146new StringTokenizer(s, File.pathSeparator);147int count = st.countTokens();148dirs = new File[count];149for (int i = 0; i < count; i++) {150dirs[i] = new File(st.nextToken());151}152} else {153dirs = new File[0];154}155156boolean result = true;157for (int i = 0; i < dirs.length; i++) {158String[] files = dirs[i].list();159if (files != null) {160for (int j = 0; j < files.length; j++) {161try {162File f = new File(dirs[i],files[j]);163File canon = new File(f.getCanonicalPath());164URL url = ParseUtil.fileToEncodedURL(canon);165if (url != null){166result = result && checkURLRecursively(1,url);167}168} catch (MalformedURLException e){169error("Malformed URL");170} catch (IOException e) {171error("IO Exception");172}173}174}175}176if (result) {177generalMessage("No conflicting installed jar found.");178} else {179generalMessage("Conflicting installed jar found. "180+ " Use -verbose for more information.");181}182return result;183}184185/**186* Recursively verify that a jar file, and any urls mentioned187* in its class path, do not conflict with the target jar file.188*189* @param indent is the current nesting level190* @param url is the path to the jar file being checked.191* @return true if there is no newer URL, otherwise false192*/193private boolean checkURLRecursively(int indent, URL url)194throws IOException195{196verboseMessage("Comparing with " + url);197JarLoader jarloader = new JarLoader(url);198JarFile j = jarloader.getJarFile();199Manifest man = j.getManifest();200if (man != null) {201Attributes attr = man.getMainAttributes();202if (attr != null){203String title = attr.getValue(Name.SPECIFICATION_TITLE);204String version = attr.getValue(Name.SPECIFICATION_VERSION);205String vendor = attr.getValue(Name.SPECIFICATION_VENDOR);206String implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE);207String implVersion208= attr.getValue(Name.IMPLEMENTATION_VERSION);209String implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR);210String sealed = attr.getValue(Name.SEALED);211if (title != null){212if (title.equals(targetSpecTitle)){213if (version != null){214if (version.equals(targetSpecVersion) ||215isNotOlderThan(version,targetSpecVersion)){216verboseMessage("");217verboseMessage("CONFLICT DETECTED ");218verboseMessage("Conflicting file:"+ url);219verboseMessage("Installed Version:" +220version);221if (implTitle != null)222verboseMessage("Implementation Title:"+223implTitle);224if (implVersion != null)225verboseMessage("Implementation Version:"+226implVersion);227if (implVendor != null)228verboseMessage("Implementation Vendor:"+229implVendor);230return false;231}232}233}234}235}236}237boolean result = true;238URL[] loaderList = jarloader.getClassPath();239if (loaderList != null) {240for(int i=0; i < loaderList.length; i++){241if (url != null){242boolean res = checkURLRecursively(indent+1,loaderList[i]);243result = res && result;244}245}246}247return result;248}249250/**251* See comment in method java.lang.Package.isCompatibleWith.252* Return true if already is not older than target. i.e. the253* target file may be superseded by a file already installed254*/255private boolean isNotOlderThan(String already,String target)256throws NumberFormatException257{258if (already == null || already.length() < 1) {259throw new NumberFormatException("Empty version string");260}261262// Until it matches scan and compare numbers263StringTokenizer dtok = new StringTokenizer(target, ".", true);264StringTokenizer stok = new StringTokenizer(already, ".", true);265while (dtok.hasMoreTokens() || stok.hasMoreTokens()) {266int dver;267int sver;268if (dtok.hasMoreTokens()) {269dver = Integer.parseInt(dtok.nextToken());270} else271dver = 0;272273if (stok.hasMoreTokens()) {274sver = Integer.parseInt(stok.nextToken());275} else276sver = 0;277278if (sver < dver)279return false; // Known to be incompatible280if (sver > dver)281return true; // Known to be compatible282283// Check for and absorb separators284if (dtok.hasMoreTokens())285dtok.nextToken();286if (stok.hasMoreTokens())287stok.nextToken();288// Compare next component289}290// All components numerically equal291return true;292}293294295/**296* Prints out message if the verboseFlag is set297*/298void verboseMessage(String message){299if (verboseFlag) {300System.err.println(message);301}302}303304void generalMessage(String message){305System.err.println(message);306}307308/**309* Throws a RuntimeException with a message describing the error.310*/311static void error(String message) throws RuntimeException {312throw new RuntimeException(message);313}314315316/**317* Inner class used to represent a loader of resources and classes318* from a base URL. Somewhat modified version of code in319* sun.misc.URLClassPath.JarLoader320*/321private static class JarLoader {322private final URL base;323private JarFile jar;324private URL csu;325326/*327* Creates a new Loader for the specified URL.328*/329JarLoader(URL url) {330String urlName = url + "!/";331URL tmpBaseURL = null;332try {333tmpBaseURL = new URL("jar","",urlName);334jar = findJarFile(url);335csu = url;336} catch (MalformedURLException e) {337ExtCheck.error("Malformed url "+urlName);338} catch (IOException e) {339ExtCheck.error("IO Exception occurred");340}341base = tmpBaseURL;342343}344345/*346* Returns the base URL for this Loader.347*/348URL getBaseURL() {349return base;350}351352JarFile getJarFile() {353return jar;354}355356private JarFile findJarFile(URL url) throws IOException {357// Optimize case where url refers to a local jar file358if ("file".equals(url.getProtocol())) {359String path = url.getFile().replace('/', File.separatorChar);360File file = new File(path);361if (!file.exists()) {362throw new FileNotFoundException(path);363}364return new JarFile(path);365}366URLConnection uc = getBaseURL().openConnection();367//uc.setRequestProperty(USER_AGENT_JAVA_VERSION, JAVA_VERSION);368return ((JarURLConnection)uc).getJarFile();369}370371372/*373* Returns the JAR file local class path, or null if none.374*/375URL[] getClassPath() throws IOException {376Manifest man = jar.getManifest();377if (man != null) {378Attributes attr = man.getMainAttributes();379if (attr != null) {380String value = attr.getValue(Name.CLASS_PATH);381if (value != null) {382return parseClassPath(csu, value);383}384}385}386return null;387}388389/*390* Parses value of the Class-Path manifest attribute and returns391* an array of URLs relative to the specified base URL.392*/393private URL[] parseClassPath(URL base, String value)394throws MalformedURLException395{396StringTokenizer st = new StringTokenizer(value);397URL[] urls = new URL[st.countTokens()];398int i = 0;399while (st.hasMoreTokens()) {400String path = st.nextToken();401urls[i] = new URL(base, path);402i++;403}404return urls;405}406}407408409}410411412