8302819: Remove JAR Index
Reviewed-by: mchung, alanb, lancea, jpai
This commit is contained in:
parent
0243da2e4a
commit
0d45a524b3
@ -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() {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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) {
|
||||
|
@ -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=\
|
||||
|
@ -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(" +"));
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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.
|
@ -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");
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
@ -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.
|
@ -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.
|
@ -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");
|
||||
}
|
||||
}
|
@ -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
|
@ -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.
|
@ -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.
|
@ -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
|
@ -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";
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user