8302819: Remove JAR Index

Reviewed-by: mchung, alanb, lancea, jpai
This commit is contained in:
Eirik Bjorsnos 2023-04-10 11:23:21 +00:00 committed by Lance Andersen
parent 0243da2e4a
commit 0d45a524b3
24 changed files with 45 additions and 1394 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2023, 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
@ -207,12 +207,18 @@ public class JarFile extends ZipFile {
*/
public static final String MANIFEST_NAME = META_INF + "MANIFEST.MF";
/**
* The 'JAR index' feature has been removed, but JarInputStream and
* JarVerifier's verification of signed jars still need to be
* able to skip this entry.
*/
static final String INDEX_NAME = "META-INF/INDEX.LIST";
/**
* Returns the version that represents the unversioned configuration of a
* multi-release jar file.
*
* @return the version that represents the unversioned configuration
*
* @since 9
*/
public static Runtime.Version baseVersion() {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2023, 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
@ -28,7 +28,6 @@ package java.util.jar;
import java.util.zip.*;
import java.io.*;
import sun.security.util.ManifestEntryVerifier;
import jdk.internal.util.jar.JarIndex;
/**
* The {@code JarInputStream} class, which extends {@link ZipInputStream},
@ -185,7 +184,7 @@ public class JarInputStream extends ZipInputStream {
}
} else {
e = first;
if (first.getName().equalsIgnoreCase(JarIndex.INDEX_NAME))
if (first.getName().equalsIgnoreCase(JarFile.INDEX_NAME))
tryManifest = true;
first = null;
}

View File

@ -33,7 +33,6 @@ import java.security.SignatureException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import jdk.internal.util.jar.JarIndex;
import sun.security.util.ManifestDigester;
import sun.security.util.ManifestEntryVerifier;
import sun.security.util.SignatureFileVerifier;
@ -146,7 +145,7 @@ class JarVerifier {
}
String uname = name.toUpperCase(Locale.ENGLISH);
if (uname.equals(JarFile.MANIFEST_NAME) ||
uname.equals(JarIndex.INDEX_NAME)) {
uname.equals(JarFile.INDEX_NAME)) {
return;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2023, 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
@ -71,8 +71,6 @@ import java.util.zip.ZipFile;
import jdk.internal.access.JavaNetURLAccess;
import jdk.internal.access.JavaUtilZipFileAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.util.jar.InvalidJarIndexError;
import jdk.internal.util.jar.JarIndex;
import sun.net.util.URLUtil;
import sun.net.www.ParseUtil;
import sun.security.action.GetPropertyAction;
@ -91,7 +89,6 @@ public class URLClassPath {
private static final boolean DISABLE_ACC_CHECKING;
private static final boolean DISABLE_CP_URL_CHECK;
private static final boolean DEBUG_CP_URL_CHECK;
private static final boolean ENABLE_JAR_INDEX;
static {
Properties props = GetPropertyAction.privilegedGetProperties();
@ -111,9 +108,6 @@ public class URLClassPath {
// the check is not disabled).
p = props.getProperty("jdk.net.URLClassPath.showIgnoredClassPathEntries");
DEBUG_CP_URL_CHECK = p != null ? p.equals("true") || p.isEmpty() : false;
p = props.getProperty("jdk.net.URLClassPath.enableJarIndex");
ENABLE_JAR_INDEX = p != null ? p.equals("true") || p.isEmpty() : false;
}
/* The original search path of URLs. */
@ -714,7 +708,6 @@ public class URLClassPath {
private static class JarLoader extends Loader {
private JarFile jar;
private final URL csu;
private JarIndex index;
private URLStreamHandler handler;
private final HashMap<String, Loader> lmap;
@SuppressWarnings("removal")
@ -779,31 +772,6 @@ public class URLClassPath {
Thread.dumpStack();
}
jar = getJarFile(csu);
if (!ENABLE_JAR_INDEX) {
return null;
}
index = JarIndex.getJarIndex(jar);
if (index != null) {
String[] jarfiles = index.getJarFiles();
// Add all the dependent URLs to the lmap so that loaders
// will not be created for them by URLClassPath.getLoader(int)
// if the same URL occurs later on the main class path. We set
// Loader to null here to avoid creating a Loader for each
// URL until we actually need to try to load something from them.
for (int i = 0; i < jarfiles.length; i++) {
try {
@SuppressWarnings("deprecation")
URL jarURL = new URL(csu, jarfiles[i]);
// If a non-null loader already exists, leave it alone.
String urlNoFragString = URLUtil.urlNoFragString(jarURL);
if (!lmap.containsKey(urlNoFragString)) {
lmap.put(urlNoFragString, null);
}
} catch (MalformedURLException e) {
continue;
}
}
}
return null;
}
}, acc);
@ -847,18 +815,6 @@ public class URLClassPath {
return checkJar(jarFile);
}
/*
* Returns the index of this JarLoader if it exists.
*/
JarIndex getIndex() {
try {
ensureOpen();
} catch (IOException e) {
throw new InternalError(e);
}
return index;
}
/*
* Creates the resource and if the check flag is set to true, checks if
* is its okay to return the resource.
@ -968,138 +924,15 @@ public class URLClassPath {
if (entry != null)
return checkResource(name, check, entry);
if (index == null)
return null;
HashSet<String> visited = new HashSet<>();
return getResource(name, check, visited);
}
/*
* Version of getResource() that tracks the jar files that have been
* visited by linking through the index files. This helper method uses
* a HashSet to store the URLs of jar files that have been searched and
* uses it to avoid going into an infinite loop, looking for a
* non-existent resource.
*/
@SuppressWarnings("removal")
Resource getResource(final String name, boolean check,
Set<String> visited) {
Resource res;
String[] jarFiles;
int count = 0;
List<String> jarFilesList;
/* If there no jar files in the index that can potential contain
* this resource then return immediately.
*/
if ((jarFilesList = index.get(name)) == null)
return null;
do {
int size = jarFilesList.size();
jarFiles = jarFilesList.toArray(new String[size]);
/* loop through the mapped jar file list */
while (count < size) {
String jarName = jarFiles[count++];
JarLoader newLoader;
final URL url;
try{
@SuppressWarnings("deprecation")
var _unused = url = new URL(csu, jarName);
String urlNoFragString = URLUtil.urlNoFragString(url);
if ((newLoader = (JarLoader)lmap.get(urlNoFragString)) == null) {
/* no loader has been set up for this jar file
* before
*/
newLoader = AccessController.doPrivileged(
new PrivilegedExceptionAction<>() {
public JarLoader run() throws IOException {
return new JarLoader(url, handler,
lmap, acc);
}
}, acc);
/* this newly opened jar file has its own index,
* merge it into the parent's index, taking into
* account the relative path.
*/
JarIndex newIndex = newLoader.getIndex();
if (newIndex != null) {
int pos = jarName.lastIndexOf('/');
newIndex.merge(this.index, (pos == -1 ?
null : jarName.substring(0, pos + 1)));
}
/* put it in the global hashtable */
lmap.put(urlNoFragString, newLoader);
}
} catch (PrivilegedActionException | MalformedURLException e) {
continue;
}
/* Note that the addition of the url to the list of visited
* jars incorporates a check for presence in the hashmap
*/
boolean visitedURL = !visited.add(URLUtil.urlNoFragString(url));
if (!visitedURL) {
try {
newLoader.ensureOpen();
} catch (IOException e) {
throw new InternalError(e);
}
final JarEntry entry = newLoader.jar.getJarEntry(name);
if (entry != null) {
return newLoader.checkResource(name, check, entry);
}
/* Verify that at least one other resource with the
* same package name as the lookedup resource is
* present in the new jar
*/
if (!newLoader.validIndex(name)) {
/* the mapping is wrong */
throw new InvalidJarIndexError("Invalid index");
}
}
/* If newLoader is the current loader or if it is a
* loader that has already been searched or if the new
* loader does not have an index then skip it
* and move on to the next loader.
*/
if (visitedURL || newLoader == this ||
newLoader.getIndex() == null) {
continue;
}
/* Process the index of the new loader
*/
if ((res = newLoader.getResource(name, check, visited))
!= null) {
return res;
}
}
// Get the list of jar files again as the list could have grown
// due to merging of index files.
jarFilesList = index.get(name);
// If the count is unchanged, we are done.
} while (count < jarFilesList.size());
return null;
}
/*
* Returns the JAR file local class path, or null if none.
*/
@Override
URL[] getClassPath() throws IOException {
if (index != null) {
return null;
}
ensureOpen();
// Only get manifest when necessary

View File

@ -1,55 +0,0 @@
/*
* Copyright (c) 1999, 2019, 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 jdk.internal.util.jar;
/**
* Thrown if the URLClassLoader finds the INDEX.LIST file of
* a jar file contains incorrect information.
*
* @since 9
*/
public class InvalidJarIndexError extends Error {
@java.io.Serial
static final long serialVersionUID = 0L;
/**
* Constructs an {@code InvalidJarIndexError} with no detail message.
*/
public InvalidJarIndexError() {
super();
}
/**
* Constructs an {@code InvalidJarIndexError} with the specified detail message.
*
* @param s the detail message.
*/
public InvalidJarIndexError(String s) {
super(s);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2023, 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
@ -274,8 +274,6 @@ module java.base {
jdk.unsupported;
exports jdk.internal.vm.vector to
jdk.incubator.vector;
exports jdk.internal.util.jar to
jdk.jartool;
exports jdk.internal.util.xml to
jdk.jfr;
exports jdk.internal.util.xml.impl to

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2023, 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
@ -23,30 +23,27 @@
* questions.
*/
package jdk.internal.util.jar;
package sun.tools.jar;
import sun.nio.cs.UTF_8;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.jar.*;
import java.util.zip.*;
import static sun.security.action.GetPropertyAction.privilegedGetProperty;
/**
* This class is used to maintain mappings from packages, classes
* and resources to their enclosing JAR files. Mappings are kept
* at the package level except for class or resource files that
* are located at the root directory. URLClassLoader uses the mapping
* information to determine where to fetch an extension class or
* resource from.
* are located at the root directory.
*
* @author Zhenghua Li
* @since 1.3
* @author Zhenghua Li
* @since 1.3
*/
public class JarIndex {
class JarIndex {
/**
* The hash map that maintains mappings from
@ -68,7 +65,7 @@ public class JarIndex {
/**
* The index file name.
*/
public static final String INDEX_NAME = "META-INF/INDEX.LIST";
static final String INDEX_NAME = "META-INF/INDEX.LIST";
/**
* true if, and only if, sun.misc.JarIndex.metaInfFilenames is set to true.
@ -76,25 +73,7 @@ public class JarIndex {
* be added to the index. Otherwise, just the directory names are added.
*/
private static final boolean metaInfFilenames =
"true".equals(privilegedGetProperty("sun.misc.JarIndex.metaInfFilenames"));
/**
* Constructs a new, empty jar index.
*/
public JarIndex() {
indexMap = new HashMap<>();
jarMap = new HashMap<>();
}
/**
* Constructs a new index from the specified input stream.
*
* @param is the input stream containing the index data
*/
public JarIndex(InputStream is) throws IOException {
this();
read(is);
}
"true".equals(System.getProperty("sun.misc.JarIndex.metaInfFilenames"));
/**
* Constructs a new index for the specified list of jar files.
@ -102,34 +81,12 @@ public class JarIndex {
* @param files the list of jar files to construct the index from.
*/
public JarIndex(String[] files) throws IOException {
this();
this.indexMap = new HashMap<>();
this.jarMap = new HashMap<>();
this.jarFiles = files;
parseJars(files);
}
/**
* Returns the jar index, or <code>null</code> if none.
*
* @param jar the JAR file to get the index from.
* @exception IOException if an I/O error has occurred.
*/
public static JarIndex getJarIndex(JarFile jar) throws IOException {
JarIndex index = null;
JarEntry e = jar.getJarEntry(INDEX_NAME);
// if found, then load the index
if (e != null) {
index = new JarIndex(jar.getInputStream(e));
}
return index;
}
/**
* Returns the jar files that are defined in this index.
*/
public String[] getJarFiles() {
return jarFiles;
}
/*
* Add the key, value pair to the hashmap, the value will
* be put in a list which is created if necessary.
@ -146,23 +103,6 @@ public class JarIndex {
}
}
/**
* Returns the list of jar files that are mapped to the file.
*
* @param fileName the key of the mapping
*/
public List<String> get(String fileName) {
List<String> jarFiles;
if ((jarFiles = indexMap.get(fileName)) == null) {
/* try the package name again */
int pos;
if((pos = fileName.lastIndexOf('/')) != -1) {
jarFiles = indexMap.get(fileName.substring(0, pos));
}
}
return jarFiles;
}
/**
* Add the mapping from the specified file to the specified
* jar file. If there were no mapping for the package of the
@ -176,10 +116,10 @@ public class JarIndex {
* @param jarName the jar file that the file is mapped to
*
*/
public void add(String fileName, String jarName) {
private void add(String fileName, String jarName) {
String packageName;
int pos;
if((pos = fileName.lastIndexOf('/')) != -1) {
if ((pos = fileName.lastIndexOf('/')) != -1) {
packageName = fileName.substring(0, pos);
} else {
packageName = fileName;
@ -253,7 +193,7 @@ public class JarIndex {
*/
public void write(OutputStream out) throws IOException {
BufferedWriter bw = new BufferedWriter
(new OutputStreamWriter(out, UTF_8.INSTANCE));
(new OutputStreamWriter(out, StandardCharsets.UTF_8));
bw.write("JarIndex-Version: 1.0\n\n");
if (jarFiles != null) {
@ -272,62 +212,4 @@ public class JarIndex {
bw.flush();
}
}
/**
* Reads the index from the specified InputStream.
*
* @param is the input stream
* @exception IOException if an I/O error has occurred
*/
public void read(InputStream is) throws IOException {
BufferedReader br = new BufferedReader
(new InputStreamReader(is, UTF_8.INSTANCE));
String line;
String currentJar = null;
/* an ordered list of jar file names */
ArrayList<String> jars = new ArrayList<>();
/* read until we see a .jar line */
while((line = br.readLine()) != null && !line.endsWith(".jar"));
for(;line != null; line = br.readLine()) {
if (line.isEmpty())
continue;
if (line.endsWith(".jar")) {
currentJar = line;
jars.add(currentJar);
} else {
String name = line;
addMapping(name, currentJar);
}
}
jarFiles = jars.toArray(new String[jars.size()]);
}
/**
* Merges the current index into another index, taking into account
* the relative path of the current index.
*
* @param toIndex The destination index which the current index will
* merge into.
* @param path The relative path of the this index to the destination
* index.
*
*/
public void merge(JarIndex toIndex, String path) {
for (Map.Entry<String, List<String>> e : indexMap.entrySet()) {
String packageName = e.getKey();
List<String> from_list = e.getValue();
for (String jarName : from_list) {
if (path != null) {
jarName = path.concat(jarName);
}
toIndex.addMapping(packageName, jarName);
}
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2023, 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
@ -46,6 +46,7 @@ import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.FileTime;
import java.text.MessageFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Consumer;
import java.util.jar.Attributes;
@ -60,7 +61,7 @@ import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import java.util.concurrent.TimeUnit;
import jdk.internal.module.Checks;
import jdk.internal.module.ModuleHashes;
import jdk.internal.module.ModuleHashesBuilder;
@ -69,14 +70,11 @@ import jdk.internal.module.ModuleInfoExtender;
import jdk.internal.module.ModuleResolution;
import jdk.internal.module.ModuleTarget;
import jdk.internal.opt.CommandLine;
import jdk.internal.util.jar.JarIndex;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
import static java.util.jar.JarFile.MANIFEST_NAME;
import static java.util.stream.Collectors.joining;
import static jdk.internal.util.jar.JarIndex.INDEX_NAME;
import static sun.tools.jar.JarIndex.INDEX_NAME;
/**
* This class implements a simple utility for creating files in the JAR
@ -397,6 +395,10 @@ public class Main {
}
}
} else if (iflag) {
if (!suppressDeprecateMsg) {
warn(getMsg("warn.index.is.ignored"));
warn(formatMsg("warn.flag.is.deprecated", "--generate-index/-i"));
}
String[] files = filesMap.get(BASE_VERSION); // base entries only, can be null
genIndex(rootjar, files);
} else if (dflag) {

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 1999, 2023, 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
@ -139,8 +139,10 @@ warn.validator.concealed.public.class=\
in incompatible public interfaces
warn.release.unexpected.versioned.entry=\
unexpected versioned entry {0}
warn.index.is.ignored=\
The JAR index (META-INF/INDEX.LIST) is ignored at run-time since JDK 18
warn.flag.is.deprecated=\
Warning: The {0} option is deprecated, and is planned for removal in a future JDK release\n
Warning: The {0} option is deprecated, and may be ignored or removed in a future release\n
out.added.manifest=\
added manifest
out.added.module-info=\
@ -236,7 +238,8 @@ main.help.opt.main.create=\
\ will also be created
main.help.opt.main.generate-index=\
\ -i, --generate-index=FILE Generate index information for the specified jar\n\
\ archives
\ archives. This option is deprecated and may be \n\
\ removed in a future release.
main.help.opt.main.list=\
\ -t, --list List the table of contents for the archive
main.help.opt.main.update=\

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2023, 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
@ -26,7 +26,6 @@
* @bug 8163798 8189611 8211728
* @summary basic tests for multi-release jar versioned streams
* @library /test/lib
* @modules jdk.jartool/sun.tools.jar java.base/jdk.internal.util.jar
* @build jdk.test.lib.Platform
* jdk.test.lib.util.FileUtils
* @run testng TestVersionedStream
@ -49,6 +48,7 @@ import java.util.Map;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.spi.ToolProvider;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.zip.ZipFile;
@ -249,7 +249,7 @@ public class TestVersionedStream {
}
private void jar(String args) {
new sun.tools.jar.Main(System.out, System.err, "jar")
.run(args.split(" +"));
ToolProvider jar = ToolProvider.findFirst("jar").orElseThrow();
jar.run(System.out, System.err, args.split(" +"));
}
}

View File

@ -1,216 +0,0 @@
/*
* Copyright (c) 2012, 2021, 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.
*
* 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.
*/
/*
* @test
* @bug 6901992
* @summary InvalidJarIndexException due to bug in sun.misc.JarIndex.merge()
* Test URLClassLoader usage of the merge method when using indexes
* @author Diego Belfer
* @run main/othervm -Djdk.net.URLClassPath.enableJarIndex=true JarIndexMergeForClassLoaderTest
*/
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
public class JarIndexMergeForClassLoaderTest {
static final String slash = File.separator;
static final String testClassesDir = System.getProperty("test.classes", ".");
static final String jar;
static final boolean debug = true;
static final File tmpFolder = new File(testClassesDir);
static {
jar = System.getProperty("java.home") + slash + "bin" + slash + "jar";
}
public static void main(String[] args) throws Exception {
// Create the jars file
File jar1 = buildJar1();
File jar2 = buildJar2();
File jar3 = buildJar3();
// Index jar files in two levels: jar1 -> jar2 -> jar3
createIndex(jar2.getName(), jar3.getName());
createIndex(jar1.getName(), jar2.getName());
// Get root jar of the URLClassLoader
URL url = jar1.toURI().toURL();
URLClassLoader classLoader = new URLClassLoader(new URL[] { url });
assertResource(classLoader, "com/jar1/resource.file", "jar1");
assertResource(classLoader, "com/test/resource1.file", "resource1");
assertResource(classLoader, "com/jar2/resource.file", "jar2");
assertResource(classLoader, "com/test/resource2.file", "resource2");
assertResource(classLoader, "com/test/resource3.file", "resource3");
/*
* The following two asserts failed before the fix of the bug 6901992
*/
// Check that an existing file is found using the merged index
assertResource(classLoader, "com/missing/jar3/resource.file", "jar3");
// Check that a non existent file in directory which does not contain
// any file is not found and it does not throw InvalidJarIndexException
assertResource(classLoader, "com/missing/nofile", null);
}
private static File buildJar3() throws FileNotFoundException, IOException {
JarBuilder jar3Builder = new JarBuilder(tmpFolder, "jar3.jar");
jar3Builder.addResourceFile("com/test/resource3.file", "resource3");
jar3Builder.addResourceFile("com/missing/jar3/resource.file", "jar3");
return jar3Builder.build();
}
private static File buildJar2() throws FileNotFoundException, IOException {
JarBuilder jar2Builder = new JarBuilder(tmpFolder, "jar2.jar");
jar2Builder.addResourceFile("com/jar2/resource.file", "jar2");
jar2Builder.addResourceFile("com/test/resource2.file", "resource2");
return jar2Builder.build();
}
private static File buildJar1() throws FileNotFoundException, IOException {
JarBuilder jar1Builder = new JarBuilder(tmpFolder, "jar1.jar");
jar1Builder.addResourceFile("com/jar1/resource.file", "jar1");
jar1Builder.addResourceFile("com/test/resource1.file", "resource1");
return jar1Builder.build();
}
/* create the index */
static void createIndex(String parentJar, String childJar) {
// ProcessBuilder is used so that the current directory can be set
// to the directory that directly contains the jars.
debug("Running jar to create the index for: " + parentJar + " and "
+ childJar);
ProcessBuilder pb = new ProcessBuilder(jar, "-i", parentJar, childJar);
pb.directory(tmpFolder);
// pd.inheritIO();
try {
Process p = pb.start();
if (p.waitFor() != 0)
throw new RuntimeException("jar indexing failed");
if (debug && p != null) {
debugStream(p.getInputStream());
debugStream(p.getErrorStream());
}
} catch (InterruptedException | IOException x) {
throw new RuntimeException(x);
}
}
private static void debugStream(InputStream is) throws IOException {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) {
String line;
while ((line = reader.readLine()) != null) {
debug(line);
}
}
}
private static void assertResource(URLClassLoader classLoader, String file,
String expectedContent) throws IOException {
InputStream fileStream = classLoader.getResourceAsStream(file);
if (fileStream == null && expectedContent == null) {
return;
}
if (fileStream == null && expectedContent != null) {
throw new RuntimeException(
buildMessage(file, expectedContent, null));
}
try {
String actualContent = readAsString(fileStream);
if (fileStream != null && expectedContent == null) {
throw new RuntimeException(buildMessage(file, null,
actualContent));
}
if (!expectedContent.equals(actualContent)) {
throw new RuntimeException(buildMessage(file, expectedContent,
actualContent));
}
} finally {
fileStream.close();
}
}
private static String buildMessage(String file, String expectedContent,
String actualContent) {
return "Expected: " + expectedContent + " for: " + file + " was: "
+ actualContent;
}
private static String readAsString(InputStream fileStream)
throws IOException {
byte[] buffer = new byte[1024];
int count, len = 0;
while ((count = fileStream.read(buffer, len, buffer.length-len)) != -1)
len += count;
return new String(buffer, 0, len, "ASCII");
}
static void debug(Object message) {
if (debug)
System.out.println(message);
}
/*
* Helper class for building jar files
*/
public static class JarBuilder {
private JarOutputStream os;
private File jarFile;
public JarBuilder(File tmpFolder, String jarName)
throws FileNotFoundException, IOException
{
this.jarFile = new File(tmpFolder, jarName);
this.os = new JarOutputStream(new FileOutputStream(jarFile));
}
public void addResourceFile(String pathFromRoot, String content)
throws IOException
{
JarEntry entry = new JarEntry(pathFromRoot);
os.putNextEntry(entry);
os.write(content.getBytes("ASCII"));
os.closeEntry();
}
public File build() throws IOException {
os.close();
return jarFile;
}
}
}

View File

@ -1,117 +0,0 @@
/*
* Copyright (c) 2012, 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.
*
* 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.
*/
/*
* @test
* @bug 6901992
* @summary InvalidJarIndexException due to bug in sun.misc.JarIndex.merge()
* @modules java.base/jdk.internal.util.jar
* @compile -XDignore.symbol.file JarIndexMergeTest.java
* @run main JarIndexMergeTest
* @author Diego Belfer
*/
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
// implementation specific API
import jdk.internal.util.jar.JarIndex;
public class JarIndexMergeTest {
static final String slash = File.separator;
static final String testClassesDir = System.getProperty("test.classes", ".");
static final File tmpFolder = new File(testClassesDir);
public static void main(String[] args) throws Exception {
File jar1 = buildJar1();
File jar2 = buildJar2();
JarIndex jarIndex1 = new JarIndex(new String[] { jar1.getAbsolutePath() });
JarIndex jarIndex2 = new JarIndex(new String[] { jar2.getAbsolutePath() });
jarIndex1.merge(jarIndex2, null);
assertFileResolved(jarIndex2, "com/test1/resource1.file",
jar1.getAbsolutePath());
assertFileResolved(jarIndex2, "com/test2/resource2.file",
jar2.getAbsolutePath());
}
static void assertFileResolved(JarIndex jarIndex2, String file,
String jarName) {
@SuppressWarnings("unchecked")
List<String> jarLists = (List<String>)jarIndex2.get(file);
if (jarLists == null || jarLists.size() == 0 ||
!jarName.equals(jarLists.get(0))) {
throw new RuntimeException(
"Unexpected result: the merged index must resolve file: "
+ file);
}
}
private static File buildJar1() throws FileNotFoundException, IOException {
JarBuilder jar1Builder = new JarBuilder(tmpFolder, "jar1-merge.jar");
jar1Builder.addResourceFile("com/test1/resource1.file", "resource1");
return jar1Builder.build();
}
private static File buildJar2() throws FileNotFoundException, IOException {
JarBuilder jar2Builder = new JarBuilder(tmpFolder, "jar2-merge.jar");
jar2Builder.addResourceFile("com/test2/resource2.file", "resource2");
return jar2Builder.build();
}
/*
* Helper class for building jar files
*/
public static class JarBuilder {
private JarOutputStream os;
private File jarFile;
public JarBuilder(File tmpFolder, String jarName)
throws FileNotFoundException, IOException
{
this.jarFile = new File(tmpFolder, jarName);
this.os = new JarOutputStream(new FileOutputStream(jarFile));
}
public void addResourceFile(String pathFromRoot, String content)
throws IOException
{
JarEntry entry = new JarEntry(pathFromRoot);
os.putNextEntry(entry);
os.write(content.getBytes("ASCII"));
os.closeEntry();
}
public File build() throws IOException {
os.close();
return jarFile;
}
}
}

View File

@ -1,406 +0,0 @@
/*
* Copyright (c) 2011, 2022, 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.
*
* 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.
*/
/*
* @test
* @bug 6887710
* @summary Verify the impact of sun.misc.JarIndex.metaInfFilenames on ServiceLoader
* @modules jdk.jartool/sun.tools.jar
* jdk.httpserver
* jdk.compiler
* jdk.zipfs
* @run main/othervm -Djdk.net.URLClassPath.enableJarIndex=true Basic
*/
import java.io.IOException;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.Iterator;
import java.util.ServiceLoader;
import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
/**
* Verifies the impact of sun.misc.JarIndex.metaInfFilenames on ServiceLoader
* and on finding resources via Class.getResource.
*
* 1) Compile the test sources:
* jarA:
* META-INF/services/my.happy.land
* com/message/spi/MessageService.java
* a/A.java
* jarB:
* META-INF/JAVA2.DS
* META-INF/services/no.name.service
* b/B.java
* jarC:
* META-INF/fonts.mf
* META-INF/fonts/Company-corporate.ttf
* META-INF/fonts/kidpr.ttf
* META-INF/services/com.message.spi.MessageService
* my/impl/StandardMessageService.java
*
* 2) Build three jar files a.jar, b.jar, c.jar
*
* 3) Create an index in a.jar (jar -i a.jar b.jar c.jar)
* with sun.misc.JarIndex.metaInfFilenames=true
*
* 4) Start a HTTP server serving out the three jars.
*
* The test then tries to locate services/resources within the jars using
* URLClassLoader. Each request to the HTTP server is recorded to ensure
* only the correct amount of requests are being made.
*
*/
public class Basic {
static final String slash = File.separator;
static final String[] testSources = {
"jarA" + slash + "a" + slash + "A.java",
"jarA" + slash + "com" + slash + "message" + slash + "spi" + slash + "MessageService.java",
"jarB" + slash + "b" + slash + "B.java",
"jarC" + slash + "my" + slash + "impl" + slash + "StandardMessageService.java"};
static final String testSrc = System.getProperty("test.src");
static final String testSrcDir = testSrc != null ? testSrc : ".";
static final String testClasses = System.getProperty("test.classes");
static final String testClassesDir = testClasses != null ? testClasses : ".";
static JarHttpServer httpServer;
public static void main(String[] args) throws Exception {
// Set global url cache to false so that we can track every jar request.
(new URL("http://localhost/")).openConnection().setDefaultUseCaches(false);
buildTest();
try {
httpServer = new JarHttpServer(testClassesDir);
httpServer.start();
doTest(httpServer.getAddress());
} catch (IOException ioe) {
ioe.printStackTrace();
} finally {
if (httpServer != null) { httpServer.stop(2); }
}
}
static void buildTest() {
/* compile the source that will be used to generate the jars */
for (int i=0; i<testSources.length; i++)
testSources[i] = testSrcDir + slash + testSources[i];
compile("-d" , testClassesDir,
"-sourcepath", testSrcDir,
testSources[0], testSources[1], testSources[2], testSources[3]);
/* build the 3 jar files */
jar("-cf", testClassesDir + slash + "a.jar",
"-C", testClassesDir, "a",
"-C", testClassesDir, "com",
"-C", testSrcDir + slash + "jarA", "META-INF");
jar("-cf", testClassesDir + slash + "b.jar",
"-C", testClassesDir, "b",
"-C", testSrcDir + slash + "jarB", "META-INF");
jar("-cf", testClassesDir + slash + "c.jar",
"-C", testClassesDir, "my",
"-C", testSrcDir + slash + "jarC", "META-INF");
/* Create an index in a.jar for b.jar and c.jar */
createIndex(testClassesDir);
}
/* run jar <args> */
static void jar(String... args) {
debug("Running: jar " + Arrays.toString(args));
sun.tools.jar.Main jar = new sun.tools.jar.Main(System.out, System.err, "jar");
if (!jar.run(args)) {
throw new RuntimeException("jar failed: args=" + Arrays.toString(args));
}
}
/* run javac <args> */
static void compile(String... args) {
debug("Running: javac " + Arrays.toString(args));
if (com.sun.tools.javac.Main.compile(args) != 0) {
throw new RuntimeException("javac failed: args=" + Arrays.toString(args));
}
}
static String jar;
static {
jar = System.getProperty("java.home") + slash+ "bin" + slash + "jar";
}
/* create the index */
static void createIndex(String workingDir) {
// ProcessBuilder is used so that the current directory can be set
// to the directory that directly contains the jars.
debug("Running jar to create the index");
ProcessBuilder pb = new ProcessBuilder(
jar, "-J-Dsun.misc.JarIndex.metaInfFilenames=true", "-i", "a.jar", "b.jar", "c.jar");
pb.directory(new File(workingDir));
//pd.inheritIO();
try {
Process p = pb.start();
if(p.waitFor() != 0)
throw new RuntimeException("jar indexing failed");
if(debug && p != null) {
String line = null;
BufferedReader reader =
new BufferedReader(new InputStreamReader(p.getInputStream()));
while((line = reader.readLine()) != null)
debug(line);
reader = new BufferedReader(new InputStreamReader(p.getErrorStream()));
while((line = reader.readLine()) != null)
debug(line);
}
} catch(InterruptedException ie) { throw new RuntimeException(ie);
} catch(IOException e) { throw new RuntimeException(e); }
}
static final boolean debug = true;
static void debug(Object message) { if (debug) System.out.println(message); }
/* service define in c.jar */
static final String messageService = "com.message.spi.MessageService";
/* a service that is not defined in any of the jars */
static final String unknownService = "java.lang.Object";
static void doTest(InetSocketAddress serverAddress) throws IOException {
URL baseURL = new URL("http://localhost:" + serverAddress.getPort() + "/");
int failed = 0;
// Tests using java.util.SerivceLoader
if (!javaUtilServiceLoaderTest(baseURL, messageService, true, false, true)) {
System.out.println("Test: ServiceLoader looking for " + messageService + ", failed");
failed++;
}
if (!javaUtilServiceLoaderTest(baseURL, unknownService, false, false, false)) {
System.out.println("Test: ServiceLoader looking for " + unknownService + " failed");
failed++;
}
// Tests using java.lang.Class (similar to the FontManager in javafx)
if (!klassLoader(baseURL, "/META-INF/fonts.mf", true, false, true)) {
System.out.println("Test: klassLoader looking for /META-INF/fonts.mf failed");
failed++;
}
if (!klassLoader(baseURL, "/META-INF/unknown.mf", false, false, false)) {
System.out.println("Test: klassLoader looking for /META-INF/unknown.mf failed");
failed++;
}
if (failed > 0)
throw new RuntimeException("Failed: " + failed + " tests");
}
static boolean javaUtilServiceLoaderTest(URL baseURL,
String serviceClass,
boolean expectToFind,
boolean expectbDotJar,
boolean expectcDotJar) throws IOException {
debug("----------------------------------");
debug("Running test with java.util.ServiceLoader looking for " + serviceClass);
URLClassLoader loader = getLoader(baseURL);
httpServer.reset();
Class<?> messageServiceClass = null;
try {
messageServiceClass = loader.loadClass(serviceClass);
} catch (ClassNotFoundException cnfe) {
System.err.println(cnfe);
throw new RuntimeException("Error in test: " + cnfe);
}
Iterator<?> iterator = (ServiceLoader.load(messageServiceClass, loader)).iterator();
if (expectToFind && !iterator.hasNext()) {
debug(messageServiceClass + " NOT found.");
return false;
}
while (iterator.hasNext()) {
debug("found " + iterator.next() + " " + messageService);
}
debug("HttpServer: " + httpServer);
if (!expectbDotJar && httpServer.bDotJar > 0) {
debug("Unexpected request sent to the httpserver for b.jar");
return false;
}
if (!expectcDotJar && httpServer.cDotJar > 0) {
debug("Unexpected request sent to the httpserver for c.jar");
return false;
}
return true;
}
/* Tries to find a resource in a similar way to the font manager in javafx
* com.sun.javafx.scene.text.FontManager */
static boolean klassLoader(URL baseURL,
String resource,
boolean expectToFind,
boolean expectbDotJar,
boolean expectcDotJar) throws IOException {
debug("----------------------------------");
debug("Running test looking for " + resource);
URLClassLoader loader = getLoader(baseURL);
httpServer.reset();
Class<?> ADotAKlass = null;
try {
ADotAKlass = loader.loadClass("a.A");
} catch (ClassNotFoundException cnfe) {
System.err.println(cnfe);
throw new RuntimeException("Error in test: " + cnfe);
}
URL u = ADotAKlass.getResource(resource);
if (expectToFind && u == null) {
System.out.println("Expected to find " + resource + " but didn't");
return false;
}
debug("HttpServer: " + httpServer);
if (!expectbDotJar && httpServer.bDotJar > 0) {
debug("Unexpected request sent to the httpserver for b.jar");
return false;
}
if (!expectcDotJar && httpServer.cDotJar > 0) {
debug("Unexpected request sent to the httpserver for c.jar");
return false;
}
return true;
}
static URLClassLoader getLoader(URL baseURL) throws IOException {
ClassLoader loader = Basic.class.getClassLoader();
while (loader.getParent() != null)
loader = loader.getParent();
return new URLClassLoader( new URL[]{
new URL(baseURL, "a.jar"),
new URL(baseURL, "b.jar"),
new URL(baseURL, "c.jar")}, loader );
}
/**
* HTTP Server to server the jar files.
*/
static class JarHttpServer implements HttpHandler {
final String docsDir;
final HttpServer httpServer;
int aDotJar, bDotJar, cDotJar;
JarHttpServer(String docsDir) throws IOException {
this.docsDir = docsDir;
httpServer = HttpServer.create(new InetSocketAddress(0), 0);
httpServer.createContext("/", this);
}
void start() throws IOException {
httpServer.start();
}
void stop(int delay) {
httpServer.stop(delay);
}
InetSocketAddress getAddress() {
return httpServer.getAddress();
}
void reset() {
aDotJar = bDotJar = cDotJar = 0;
}
@Override
public String toString() {
return "aDotJar=" + aDotJar + ", bDotJar=" + bDotJar + ", cDotJar=" + cDotJar;
}
public void handle(HttpExchange t) throws IOException {
InputStream is = t.getRequestBody();
Headers map = t.getRequestHeaders();
Headers rmap = t.getResponseHeaders();
URI uri = t.getRequestURI();
debug("Server: received request for " + uri);
String path = uri.getPath();
if (path.endsWith("a.jar"))
aDotJar++;
else if (path.endsWith("b.jar"))
bDotJar++;
else if (path.endsWith("c.jar"))
cDotJar++;
else
System.out.println("Unexpected resource request" + path);
while (is.read() != -1);
is.close();
File file = new File(docsDir, path);
if (!file.exists())
throw new RuntimeException("Error: request for " + file);
long clen = file.length();
t.sendResponseHeaders (200, clen);
OutputStream os = t.getResponseBody();
FileInputStream fis = new FileInputStream(file);
try {
byte[] buf = new byte [16 * 1024];
int len;
while ((len=fis.read(buf)) != -1) {
os.write (buf, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
fis.close();
os.close();
}
}
}

View File

@ -1,23 +0,0 @@
# Copyright (c) 2011, 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.
#
# 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.
# The contents of this file do not matter. It exists
# simply to have a service defined in META-INF/services.

View File

@ -1,30 +0,0 @@
/*
* Copyright (c) 2011, 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.
*
* 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 a;
public class A {
public static void hello() throws Exception {
System.out.println("Hello from a.A");
}
}

View File

@ -1,28 +0,0 @@
/*
* Copyright (c) 2011, 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.
*
* 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.message.spi;
public interface MessageService {
String message();
}

View File

@ -1,23 +0,0 @@
# Copyright (c) 2011, 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.
#
# 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.
# The contents of this file do not matter. It exists
# simply to have a file under META-INF.

View File

@ -1,23 +0,0 @@
# Copyright (c) 2011, 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.
#
# 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.
# The contents of this file do not matter. It exists
# simply to have a service defined in META-INF/services.

View File

@ -1,30 +0,0 @@
/*
* Copyright (c) 2011, 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.
*
* 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 b;
public class B {
public static void hello() {
System.out.println("Hello from b.B");
}
}

View File

@ -1,23 +0,0 @@
# Copyright (c) 2011, 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.
#
# 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.
corporate=/fonts/Company-corporate.ttf
crazy-looking=/fonts/kidpr.ttf

View File

@ -1,22 +0,0 @@
# Copyright (c) 2011, 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.
#
# 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.
This is not a real font.

View File

@ -1,22 +0,0 @@
# Copyright (c) 2011, 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.
#
# 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.
This is not a real font.

View File

@ -1,22 +0,0 @@
# Copyright (c) 2011, 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.
#
# 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.
my.impl.StandardMessageService

View File

@ -1,31 +0,0 @@
/*
* Copyright (c) 2011, 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.
*
* 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 my.impl;
public class StandardMessageService implements com.message.spi.MessageService {
@Override
public String message() {
return "This is a message from the standard message service";
}
}