8064925: URLConnection::getContent needs to be updated to work with modules
Reviewed-by: chegar, alanb
This commit is contained in:
parent
7c256783a5
commit
91a4a6b0ce
@ -44,14 +44,14 @@ import java.io.IOException;
|
||||
* instance of a subclass of {@code ContentHandler}, and its
|
||||
* {@code getContent} method is called to create the object.
|
||||
* <p>
|
||||
* If no content handler could be found, URLConnection will
|
||||
* look for a content handler in a user-defineable set of places.
|
||||
* If no content handler could be {@linkplain URLConnection#getContent() found},
|
||||
* URLConnection will look for a content handler in a user-definable set of places.
|
||||
* Users can define a vertical-bar delimited set of class prefixes
|
||||
* to search through by defining the <i>java.content.handler.pkgs</i>
|
||||
* to search through by defining the <i>{@value java.net.URLConnection#contentPathProp}</i>
|
||||
* property. The class name must be of the form:
|
||||
* <blockquote>
|
||||
* <i>{package-prefix}.{major}.{minor}</i>
|
||||
* <P>
|
||||
* <p>
|
||||
* where <i>{major}.{minor}</i> is formed by taking the
|
||||
* content-type string, replacing all slash characters with a
|
||||
* {@code period} ('.'), and all other non-alphanumeric characters
|
||||
@ -82,6 +82,7 @@ import java.io.IOException;
|
||||
* @since 1.0
|
||||
*/
|
||||
abstract public class ContentHandler {
|
||||
|
||||
/**
|
||||
* Given a URL connect stream positioned at the beginning of the
|
||||
* representation of an object, this method reads that stream and
|
||||
@ -104,8 +105,8 @@ abstract public class ContentHandler {
|
||||
* @param urlc a URL connection.
|
||||
* @param classes an array of types requested
|
||||
* @return the object read by the {@code ContentHandler} that is
|
||||
* the first match of the suggested types.
|
||||
* null if none of the requested are supported.
|
||||
* the first match of the suggested types or
|
||||
* {@code null} if none of the requested are supported.
|
||||
* @exception IOException if an I/O error occurs while reading the object.
|
||||
* @since 1.3
|
||||
*/
|
||||
@ -113,12 +114,11 @@ abstract public class ContentHandler {
|
||||
public Object getContent(URLConnection urlc, Class[] classes) throws IOException {
|
||||
Object obj = getContent(urlc);
|
||||
|
||||
for (int i = 0; i < classes.length; i++) {
|
||||
if (classes[i].isInstance(obj)) {
|
||||
for (Class<?> c : classes) {
|
||||
if (c.isInstance(obj)) {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -39,12 +39,13 @@ package java.net;
|
||||
* @since 1.0
|
||||
*/
|
||||
public interface ContentHandlerFactory {
|
||||
|
||||
/**
|
||||
* Creates a new {@code ContentHandler} to read an object from
|
||||
* a {@code URLStreamHandler}.
|
||||
*
|
||||
* @param mimetype the MIME type for which a content handler is desired.
|
||||
|
||||
*
|
||||
* @return a new {@code ContentHandler} to read an object from a
|
||||
* {@code URLStreamHandler}.
|
||||
* @see java.net.ContentHandler
|
||||
|
@ -28,8 +28,12 @@ package java.net;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.ServiceConfigurationError;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
@ -107,7 +111,7 @@ import sun.net.www.MessageHeader;
|
||||
* <li>{@code getContentType}
|
||||
* <li>{@code getDate}
|
||||
* <li>{@code getExpiration}
|
||||
* <li>{@code getLastModifed}
|
||||
* <li>{@code getLastModified}
|
||||
* </ul>
|
||||
* <p>
|
||||
* provide convenient access to these fields. The
|
||||
@ -695,16 +699,30 @@ public abstract class URLConnection {
|
||||
* This method first determines the content type of the object by
|
||||
* calling the {@code getContentType} method. If this is
|
||||
* the first time that the application has seen that specific content
|
||||
* type, a content handler for that content type is created:
|
||||
* type, a content handler for that content type is created.
|
||||
* <p> This is done as follows:
|
||||
* <ol>
|
||||
* <li>If the application has set up a content handler factory instance
|
||||
* using the {@code setContentHandlerFactory} method, the
|
||||
* {@code createContentHandler} method of that instance is called
|
||||
* with the content type as an argument; the result is a content
|
||||
* handler for that content type.
|
||||
* <li>If no content handler factory has yet been set up, or if the
|
||||
* factory's {@code createContentHandler} method returns
|
||||
* {@code null}, then this method tries to load a content handler
|
||||
* <li>If no {@code ContentHandlerFactory} has yet been set up,
|
||||
* or if the factory's {@code createContentHandler} method
|
||||
* returns {@code null}, then the {@linkplain java.util.ServiceLoader
|
||||
* ServiceLoader} mechanism is used to locate {@linkplain
|
||||
* java.net.ContentHandlerFactory ContentHandlerFactory}
|
||||
* implementations using the system class
|
||||
* loader. The order that factories are located is implementation
|
||||
* specific, and an implementation is free to cache the located
|
||||
* factories. A {@linkplain java.util.ServiceConfigurationError
|
||||
* ServiceConfigurationError}, {@code Error} or {@code RuntimeException}
|
||||
* thrown from the {@code createContentHandler}, if encountered, will
|
||||
* be propagated to the calling thread. The {@code
|
||||
* createContentHandler} method of each factory, if instantiated, is
|
||||
* invoked, with the content type, until a factory returns non-null,
|
||||
* or all factories have been exhausted.
|
||||
* <li>Failing that, this method tries to load a content handler
|
||||
* class as defined by {@link java.net.ContentHandler ContentHandler}.
|
||||
* If the class does not exist, or is not a subclass of {@code
|
||||
* ContentHandler}, then an {@code UnknownServiceException} is thrown.
|
||||
@ -855,8 +873,7 @@ public abstract class URLConnection {
|
||||
* @see #getDoInput()
|
||||
*/
|
||||
public void setDoInput(boolean doinput) {
|
||||
if (connected)
|
||||
throw new IllegalStateException("Already connected");
|
||||
checkConnected();
|
||||
doInput = doinput;
|
||||
}
|
||||
|
||||
@ -885,8 +902,7 @@ public abstract class URLConnection {
|
||||
* @see #getDoOutput()
|
||||
*/
|
||||
public void setDoOutput(boolean dooutput) {
|
||||
if (connected)
|
||||
throw new IllegalStateException("Already connected");
|
||||
checkConnected();
|
||||
doOutput = dooutput;
|
||||
}
|
||||
|
||||
@ -911,8 +927,7 @@ public abstract class URLConnection {
|
||||
* @see #getAllowUserInteraction()
|
||||
*/
|
||||
public void setAllowUserInteraction(boolean allowuserinteraction) {
|
||||
if (connected)
|
||||
throw new IllegalStateException("Already connected");
|
||||
checkConnected();
|
||||
allowUserInteraction = allowuserinteraction;
|
||||
}
|
||||
|
||||
@ -974,8 +989,7 @@ public abstract class URLConnection {
|
||||
* @see #getUseCaches()
|
||||
*/
|
||||
public void setUseCaches(boolean usecaches) {
|
||||
if (connected)
|
||||
throw new IllegalStateException("Already connected");
|
||||
checkConnected();
|
||||
useCaches = usecaches;
|
||||
}
|
||||
|
||||
@ -1000,8 +1014,7 @@ public abstract class URLConnection {
|
||||
* @see #getIfModifiedSince()
|
||||
*/
|
||||
public void setIfModifiedSince(long ifmodifiedsince) {
|
||||
if (connected)
|
||||
throw new IllegalStateException("Already connected");
|
||||
checkConnected();
|
||||
ifModifiedSince = ifmodifiedsince;
|
||||
}
|
||||
|
||||
@ -1055,12 +1068,11 @@ public abstract class URLConnection {
|
||||
* (e.g., "{@code Accept}").
|
||||
* @param value the value associated with it.
|
||||
* @throws IllegalStateException if already connected
|
||||
* @throws NullPointerException if key is <CODE>null</CODE>
|
||||
* @throws NullPointerException if key is {@code null}
|
||||
* @see #getRequestProperty(java.lang.String)
|
||||
*/
|
||||
public void setRequestProperty(String key, String value) {
|
||||
if (connected)
|
||||
throw new IllegalStateException("Already connected");
|
||||
checkConnected();
|
||||
if (key == null)
|
||||
throw new NullPointerException ("key is null");
|
||||
|
||||
@ -1084,8 +1096,7 @@ public abstract class URLConnection {
|
||||
* @since 1.4
|
||||
*/
|
||||
public void addRequestProperty(String key, String value) {
|
||||
if (connected)
|
||||
throw new IllegalStateException("Already connected");
|
||||
checkConnected();
|
||||
if (key == null)
|
||||
throw new NullPointerException ("key is null");
|
||||
|
||||
@ -1107,8 +1118,7 @@ public abstract class URLConnection {
|
||||
* @see #setRequestProperty(java.lang.String, java.lang.String)
|
||||
*/
|
||||
public String getRequestProperty(String key) {
|
||||
if (connected)
|
||||
throw new IllegalStateException("Already connected");
|
||||
checkConnected();
|
||||
|
||||
if (requests == null)
|
||||
return null;
|
||||
@ -1129,8 +1139,7 @@ public abstract class URLConnection {
|
||||
* @since 1.4
|
||||
*/
|
||||
public Map<String,List<String>> getRequestProperties() {
|
||||
if (connected)
|
||||
throw new IllegalStateException("Already connected");
|
||||
checkConnected();
|
||||
|
||||
if (requests == null)
|
||||
return Collections.emptyMap();
|
||||
@ -1183,7 +1192,7 @@ public abstract class URLConnection {
|
||||
/**
|
||||
* The ContentHandler factory.
|
||||
*/
|
||||
static ContentHandlerFactory factory;
|
||||
private static volatile ContentHandlerFactory factory;
|
||||
|
||||
/**
|
||||
* Sets the {@code ContentHandlerFactory} of an
|
||||
@ -1216,37 +1225,45 @@ public abstract class URLConnection {
|
||||
factory = fac;
|
||||
}
|
||||
|
||||
private static Hashtable<String, ContentHandler> handlers = new Hashtable<>();
|
||||
private static final Hashtable<String, ContentHandler> handlers = new Hashtable<>();
|
||||
|
||||
/**
|
||||
* Gets the Content Handler appropriate for this connection.
|
||||
*/
|
||||
synchronized ContentHandler getContentHandler()
|
||||
throws UnknownServiceException
|
||||
{
|
||||
private ContentHandler getContentHandler() throws UnknownServiceException {
|
||||
String contentType = stripOffParameters(getContentType());
|
||||
ContentHandler handler = null;
|
||||
if (contentType == null)
|
||||
if (contentType == null) {
|
||||
throw new UnknownServiceException("no content-type");
|
||||
try {
|
||||
handler = handlers.get(contentType);
|
||||
if (handler != null)
|
||||
return handler;
|
||||
} catch(Exception e) {
|
||||
}
|
||||
|
||||
if (factory != null)
|
||||
ContentHandler handler = handlers.get(contentType);
|
||||
if (handler != null)
|
||||
return handler;
|
||||
|
||||
if (factory != null) {
|
||||
handler = factory.createContentHandler(contentType);
|
||||
if (handler == null) {
|
||||
try {
|
||||
handler = lookupContentHandlerClassFor(contentType);
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
handler = UnknownContentHandler.INSTANCE;
|
||||
}
|
||||
handlers.put(contentType, handler);
|
||||
if (handler != null)
|
||||
return handler;
|
||||
}
|
||||
return handler;
|
||||
|
||||
handler = lookupContentHandlerViaProvider(contentType);
|
||||
|
||||
if (handler != null) {
|
||||
ContentHandler h = handlers.putIfAbsent(contentType, handler);
|
||||
return h != null ? h : handler;
|
||||
}
|
||||
|
||||
try {
|
||||
handler = lookupContentHandlerClassFor(contentType);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
handler = UnknownContentHandler.INSTANCE;
|
||||
}
|
||||
|
||||
assert handler != null;
|
||||
|
||||
ContentHandler h = handlers.putIfAbsent(contentType, handler);
|
||||
return h != null ? h : handler;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1270,10 +1287,10 @@ public abstract class URLConnection {
|
||||
private static final String contentPathProp = "java.content.handler.pkgs";
|
||||
|
||||
/**
|
||||
* Looks for a content handler in a user-defineable set of places.
|
||||
* By default it looks in sun.net.www.content, but users can define a
|
||||
* vertical-bar delimited set of class prefixes to search through in
|
||||
* addition by defining the java.content.handler.pkgs property.
|
||||
* Looks for a content handler in a user-definable set of places.
|
||||
* By default it looks in {@value #contentClassPrefix}, but users can define
|
||||
* a vertical-bar delimited set of class prefixes to search through in
|
||||
* addition by defining the {@value #contentPathProp} property.
|
||||
* The class name must be of the form:
|
||||
* <pre>
|
||||
* {package-prefix}.{major}.{minor}
|
||||
@ -1281,11 +1298,10 @@ public abstract class URLConnection {
|
||||
* YoyoDyne.experimental.text.plain
|
||||
* </pre>
|
||||
*/
|
||||
private ContentHandler lookupContentHandlerClassFor(String contentType)
|
||||
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
|
||||
private ContentHandler lookupContentHandlerClassFor(String contentType) {
|
||||
String contentHandlerClassName = typeToPackageName(contentType);
|
||||
|
||||
String contentHandlerPkgPrefixes =getContentHandlerPkgPrefixes();
|
||||
String contentHandlerPkgPrefixes = getContentHandlerPkgPrefixes();
|
||||
|
||||
StringTokenizer packagePrefixIter =
|
||||
new StringTokenizer(contentHandlerPkgPrefixes, "|");
|
||||
@ -1305,17 +1321,46 @@ public abstract class URLConnection {
|
||||
}
|
||||
}
|
||||
if (cls != null) {
|
||||
ContentHandler handler =
|
||||
(ContentHandler)cls.newInstance();
|
||||
return handler;
|
||||
return (ContentHandler) cls.newInstance();
|
||||
}
|
||||
} catch(Exception e) {
|
||||
}
|
||||
} catch(Exception ignored) { }
|
||||
}
|
||||
|
||||
return UnknownContentHandler.INSTANCE;
|
||||
}
|
||||
|
||||
private ContentHandler lookupContentHandlerViaProvider(String contentType) {
|
||||
return AccessController.doPrivileged(
|
||||
new PrivilegedAction<>() {
|
||||
@Override
|
||||
public ContentHandler run() {
|
||||
ClassLoader cl = ClassLoader.getSystemClassLoader();
|
||||
ServiceLoader<ContentHandlerFactory> sl =
|
||||
ServiceLoader.load(ContentHandlerFactory.class, cl);
|
||||
|
||||
Iterator<ContentHandlerFactory> iterator = sl.iterator();
|
||||
|
||||
ContentHandler handler = null;
|
||||
while (iterator.hasNext()) {
|
||||
ContentHandlerFactory f;
|
||||
try {
|
||||
f = iterator.next();
|
||||
} catch (ServiceConfigurationError e) {
|
||||
if (e.getCause() instanceof SecurityException) {
|
||||
continue;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
handler = f.createContentHandler(contentType);
|
||||
if (handler != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return handler;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function to map a MIME content type into an equivalent
|
||||
* pair of class name components. For example: "text/html" would
|
||||
@ -1345,8 +1390,8 @@ public abstract class URLConnection {
|
||||
* Returns a vertical bar separated list of package prefixes for potential
|
||||
* content handlers. Tries to get the java.content.handler.pkgs property
|
||||
* to use as a set of package prefixes to search. Whether or not
|
||||
* that property has been defined, the sun.net.www.content is always
|
||||
* the last one on the returned package list.
|
||||
* that property has been defined, the {@value #contentClassPrefix}
|
||||
* is always the last one on the returned package list.
|
||||
*/
|
||||
private String getContentHandlerPkgPrefixes() {
|
||||
String packagePrefixList = AccessController.doPrivileged(
|
||||
@ -1764,9 +1809,12 @@ public abstract class URLConnection {
|
||||
return skipped;
|
||||
}
|
||||
|
||||
private void checkConnected() {
|
||||
if (connected)
|
||||
throw new IllegalStateException("Already connected");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class UnknownContentHandler extends ContentHandler {
|
||||
static final ContentHandler INSTANCE = new UnknownContentHandler();
|
||||
|
||||
|
@ -0,0 +1,27 @@
|
||||
#
|
||||
# Copyright (c) 2015, 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.
|
||||
#
|
||||
|
||||
# Provider for content handlers
|
||||
sun.awt.www.content.MultimediaContentHandlers
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 sun.awt.www.content;
|
||||
|
||||
import sun.awt.www.content.audio.wav;
|
||||
import sun.awt.www.content.audio.x_aiff;
|
||||
import sun.awt.www.content.image.gif;
|
||||
import sun.awt.www.content.audio.aiff;
|
||||
import sun.awt.www.content.audio.basic;
|
||||
import sun.awt.www.content.audio.x_wav;
|
||||
import sun.awt.www.content.image.jpeg;
|
||||
import sun.awt.www.content.image.png;
|
||||
import sun.awt.www.content.image.x_xbitmap;
|
||||
import sun.awt.www.content.image.x_xpixmap;
|
||||
|
||||
import java.net.ContentHandler;
|
||||
import java.net.ContentHandlerFactory;
|
||||
|
||||
public final class MultimediaContentHandlers implements ContentHandlerFactory {
|
||||
|
||||
@Override
|
||||
public ContentHandler createContentHandler(String mimetype) {
|
||||
switch (mimetype) {
|
||||
case "audio/aiff": return new aiff();
|
||||
case "audio/basic": return new basic();
|
||||
case "audio/wav": return new wav();
|
||||
case "audio/x-aiff": return new x_aiff();
|
||||
case "audio/x-wav": return new x_wav();
|
||||
case "image/gif": return new gif();
|
||||
case "image/jpeg": return new jpeg();
|
||||
case "image/png": return new png();
|
||||
case "image/x-xbitmap": return new x_xbitmap();
|
||||
case "image/x-xpixmap": return new x_xpixmap();
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -27,7 +27,7 @@
|
||||
* Basic .aiff audio handler.
|
||||
* @author Jeff Nisewanger
|
||||
*/
|
||||
package sun.net.www.content.audio;
|
||||
package sun.awt.www.content.audio;
|
||||
|
||||
import java.net.*;
|
||||
import java.io.IOException;
|
@ -27,7 +27,7 @@
|
||||
* Basic .au and .snd audio handler.
|
||||
* @author Jeff Nisewanger
|
||||
*/
|
||||
package sun.net.www.content.audio;
|
||||
package sun.awt.www.content.audio;
|
||||
|
||||
import java.net.*;
|
||||
import java.io.IOException;
|
@ -27,7 +27,7 @@
|
||||
* Basic .wav audio handler.
|
||||
* @author Jeff Nisewanger
|
||||
*/
|
||||
package sun.net.www.content.audio;
|
||||
package sun.awt.www.content.audio;
|
||||
|
||||
import java.net.*;
|
||||
import java.io.IOException;
|
@ -27,7 +27,7 @@
|
||||
* Basic .aiff audio handler.
|
||||
* @author Jeff Nisewanger
|
||||
*/
|
||||
package sun.net.www.content.audio;
|
||||
package sun.awt.www.content.audio;
|
||||
|
||||
import java.net.*;
|
||||
import java.io.IOException;
|
@ -27,7 +27,7 @@
|
||||
* Basic .wav audio handler.
|
||||
* @author Jeff Nisewanger
|
||||
*/
|
||||
package sun.net.www.content.audio;
|
||||
package sun.awt.www.content.audio;
|
||||
|
||||
import java.net.*;
|
||||
import java.io.IOException;
|
@ -23,7 +23,7 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.www.content.image;
|
||||
package sun.awt.www.content.image;
|
||||
|
||||
import java.net.*;
|
||||
import sun.awt.image.*;
|
@ -23,7 +23,7 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.www.content.image;
|
||||
package sun.awt.www.content.image;
|
||||
|
||||
import java.net.*;
|
||||
import sun.awt.image.*;
|
@ -23,7 +23,7 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.www.content.image;
|
||||
package sun.awt.www.content.image;
|
||||
|
||||
import java.net.*;
|
||||
import java.io.IOException;
|
@ -23,7 +23,7 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.www.content.image;
|
||||
package sun.awt.www.content.image;
|
||||
|
||||
import java.net.*;
|
||||
import sun.awt.image.*;
|
@ -23,7 +23,7 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.www.content.image;
|
||||
package sun.awt.www.content.image;
|
||||
|
||||
import java.net.*;
|
||||
import sun.awt.image.*;
|
@ -0,0 +1,371 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.io.SequenceInputStream;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Collections.emptyMap;
|
||||
import static java.util.Collections.singleton;
|
||||
import static java.util.Collections.singletonMap;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8064925
|
||||
* @summary Basic test for ContentHandler. Ensures discovery paths for content
|
||||
* handlers follow a particular order.
|
||||
*/
|
||||
public class ContentHandlersTest {
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
step1_ContentHandlerFactory();
|
||||
step2_ServiceLoader();
|
||||
step3_UserDefined();
|
||||
step4_BuiltIn();
|
||||
}
|
||||
|
||||
private static void step1_ContentHandlerFactory() throws IOException {
|
||||
String factoryClassFqn = "net.java.openjdk.test.TestContentHandlerFactory";
|
||||
|
||||
Path tmp = Files.createDirectory(Paths.get("ContentHandlersTest-1"));
|
||||
|
||||
Path src = templatesHome().resolve("test.template");
|
||||
Path dst = tmp.resolve("Test.java");
|
||||
Files.copy(src, dst);
|
||||
|
||||
Path build = Files.createDirectory(tmp.resolve("build"));
|
||||
|
||||
Path dst1 = fromTemplate(templatesHome().resolve("broken_factory.template"),
|
||||
factoryClassFqn, tmp);
|
||||
|
||||
javac(build, dst, dst1);
|
||||
|
||||
Result r = java(emptyMap(), singleton(build), "Test", factoryClassFqn);
|
||||
|
||||
if (r.exitValue == 0 || !r.output.startsWith(
|
||||
stackTraceStringForBrokenFactory(factoryClassFqn))) {
|
||||
throw new RuntimeException(
|
||||
"Expected a different kind of failure: " + r.output);
|
||||
}
|
||||
}
|
||||
|
||||
private static void step2_ServiceLoader() throws IOException {
|
||||
String factoryClassFqn = "net.java.openjdk.test.TestContentHandlerFactory";
|
||||
|
||||
Path tmp = Files.createDirectory(Paths.get("ContentHandlersTest-2"));
|
||||
|
||||
Path src = templatesHome().resolve("test.template");
|
||||
Path dst = tmp.resolve("Test.java");
|
||||
Files.copy(src, dst);
|
||||
|
||||
Path dst1 = fromTemplate(templatesHome().resolve("broken_constructor_factory.template"),
|
||||
factoryClassFqn, tmp);
|
||||
|
||||
Path build = Files.createDirectory(tmp.resolve("build"));
|
||||
|
||||
javac(build, dst);
|
||||
|
||||
Path explodedJar = Files.createDirectory(tmp.resolve("exploded-jar"));
|
||||
Path services = Files.createDirectories(explodedJar.resolve("META-INF")
|
||||
.resolve("services"));
|
||||
|
||||
Path s = services.resolve("java.net.ContentHandlerFactory");
|
||||
|
||||
try (FileWriter fw = new FileWriter(s.toFile())) {
|
||||
fw.write(factoryClassFqn);
|
||||
}
|
||||
|
||||
javac(explodedJar, dst1);
|
||||
jar(tmp.resolve("test.jar"), explodedJar);
|
||||
|
||||
Files.copy(tmp.resolve("test.jar"), build.resolve("test.jar"));
|
||||
|
||||
Result r = java(emptyMap(), asList(build.resolve("test.jar"), build), "Test");
|
||||
|
||||
if (r.exitValue == 0 || !verifyOutput(r.output, factoryClassFqn))
|
||||
throw new RuntimeException(r.output);
|
||||
}
|
||||
|
||||
private static void step3_UserDefined() throws IOException {
|
||||
String packagePrefix = "net.java.openjdk.test";
|
||||
String fqn = packagePrefix + ".text.plain";
|
||||
|
||||
Path tmp = Files.createDirectory(Paths.get("ContentHandlersTest-3"));
|
||||
|
||||
Path src = templatesHome().resolve("test.template");
|
||||
Path dst = tmp.resolve("Test.java");
|
||||
Files.copy(src, dst);
|
||||
|
||||
Path dst1 = fromTemplate(templatesHome().resolve("plain.template"),
|
||||
fqn, tmp);
|
||||
|
||||
Path build = Files.createDirectory(tmp.resolve("build"));
|
||||
|
||||
javac(build, dst);
|
||||
|
||||
Path classes = Files.createDirectory(tmp.resolve("classes"));
|
||||
|
||||
javac(classes, dst1);
|
||||
|
||||
Map<String, String> m = singletonMap("java.content.handler.pkgs", packagePrefix);
|
||||
Result r = java(m, asList(build, classes), "Test");
|
||||
|
||||
if (r.exitValue != 0 || !r.output.contains(fqn))
|
||||
throw new RuntimeException(r.output);
|
||||
}
|
||||
|
||||
private static void step4_BuiltIn() throws IOException {
|
||||
Path tmp = Files.createDirectory(Paths.get("ContentHandlersTest-4"));
|
||||
|
||||
Path src = templatesHome().resolve("test.template");
|
||||
Path dst = tmp.resolve("Test.java");
|
||||
Files.copy(src, dst);
|
||||
|
||||
Path build = Files.createDirectory(tmp.resolve("build"));
|
||||
|
||||
javac(build, dst);
|
||||
|
||||
Result r = java(emptyMap(), singleton(build), "Test");
|
||||
|
||||
if (r.exitValue != 0 || !r.output.contains("sun.net.www.content.text.PlainTextInputStream"))
|
||||
throw new RuntimeException(r.output);
|
||||
}
|
||||
|
||||
private static String stackTraceStringForBrokenFactory(String fqn) {
|
||||
return "Exception in thread \"main\" java.lang.RuntimeException: " +
|
||||
"This is a broken factory. It is supposed to throw this exception.";
|
||||
}
|
||||
|
||||
private static Path fromTemplate(Path srcTemplate,
|
||||
String factoryFqn,
|
||||
Path dstFolder) throws IOException {
|
||||
|
||||
String factorySimpleName, packageName;
|
||||
int i = factoryFqn.lastIndexOf('.');
|
||||
if (i < 0) {
|
||||
packageName = "";
|
||||
factorySimpleName = factoryFqn;
|
||||
} else {
|
||||
packageName = factoryFqn.substring(0, i);
|
||||
factorySimpleName = factoryFqn.substring(i + 1);
|
||||
}
|
||||
|
||||
Path result = dstFolder.resolve(factorySimpleName + ".java");
|
||||
File dst = result.toFile();
|
||||
File src = srcTemplate.toFile();
|
||||
try (BufferedReader r = new BufferedReader(new FileReader(src));
|
||||
BufferedWriter w = new BufferedWriter(new FileWriter(dst))) {
|
||||
|
||||
List<String> lines = processTemplate(packageName, factorySimpleName,
|
||||
r.lines()).collect(Collectors.toList());
|
||||
|
||||
Iterator<String> it = lines.iterator();
|
||||
if (it.hasNext())
|
||||
w.write(it.next());
|
||||
while (it.hasNext()) {
|
||||
w.newLine();
|
||||
w.write(it.next());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Stream<String> processTemplate(String packageName,
|
||||
String factorySimpleName,
|
||||
Stream<String> lines) {
|
||||
Function<String, String> pckg;
|
||||
|
||||
if (packageName.isEmpty()) {
|
||||
pckg = s -> s.contains("$package") ? "" : s;
|
||||
} else {
|
||||
pckg = s -> s.replaceAll("\\$package", packageName);
|
||||
}
|
||||
|
||||
Function<String, String> factory
|
||||
= s -> s.replaceAll("\\$className", factorySimpleName);
|
||||
|
||||
return lines.map(pckg).map(factory);
|
||||
}
|
||||
|
||||
// IMO, that's the easiest way that gives you a fair amount of confidence in
|
||||
// that j.u.ServiceLoader is loading a factory rather than Class.forName
|
||||
private static boolean verifyOutput(String output, String fqn) {
|
||||
String s1 = String.format("java.util.ServiceConfigurationError: " +
|
||||
"java.net.ContentHandlerFactory: " +
|
||||
"Provider %s could not be instantiated", fqn);
|
||||
|
||||
return output.contains(s1);
|
||||
}
|
||||
|
||||
private static void jar(Path jarName, Path jarRoot) {
|
||||
String jar = getJDKTool("jar");
|
||||
ProcessBuilder p = new ProcessBuilder(jar, "cf", jarName.toString(),
|
||||
"-C", jarRoot.toString(), ".");
|
||||
quickFail(run(p));
|
||||
}
|
||||
|
||||
private static void javac(Path compilationOutput, Path... sourceFiles) {
|
||||
String javac = getJDKTool("javac");
|
||||
List<String> commands = new ArrayList<>();
|
||||
commands.addAll(asList(javac, "-d", compilationOutput.toString()));
|
||||
List<Path> paths = asList(sourceFiles);
|
||||
commands.addAll(paths.stream()
|
||||
.map(Path::toString)
|
||||
.collect(Collectors.toList()));
|
||||
quickFail(run(new ProcessBuilder(commands)));
|
||||
}
|
||||
|
||||
private static void quickFail(Result r) {
|
||||
if (r.exitValue != 0)
|
||||
throw new RuntimeException(r.output);
|
||||
}
|
||||
|
||||
private static Result java(Map<String, String> properties,
|
||||
Collection<Path> classpath,
|
||||
String classname, String... args) {
|
||||
|
||||
String java = getJDKTool("java");
|
||||
|
||||
List<String> commands = new ArrayList<>();
|
||||
commands.add(java);
|
||||
commands.addAll(properties.entrySet()
|
||||
.stream()
|
||||
.map(e -> "-D" + e.getKey() + "=" + e.getValue())
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
String cp = classpath.stream()
|
||||
.map(Path::toString)
|
||||
.collect(Collectors.joining(File.pathSeparator));
|
||||
commands.add("-cp");
|
||||
commands.add(cp);
|
||||
commands.add(classname);
|
||||
commands.addAll(Arrays.asList(args));
|
||||
|
||||
return run(new ProcessBuilder(commands));
|
||||
}
|
||||
|
||||
private static Result run(ProcessBuilder b) {
|
||||
Process p;
|
||||
try {
|
||||
p = b.start();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(
|
||||
format("Couldn't start process '%s'", b.command()), e);
|
||||
}
|
||||
|
||||
String output;
|
||||
try {
|
||||
output = toString(p.getInputStream(), p.getErrorStream());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(
|
||||
format("Couldn't read process output '%s'", b.command()), e);
|
||||
}
|
||||
|
||||
try {
|
||||
p.waitFor();
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(
|
||||
format("Process hasn't finished '%s'", b.command()), e);
|
||||
}
|
||||
|
||||
return new Result(p.exitValue(), output);
|
||||
}
|
||||
|
||||
private static String getJDKTool(String name) {
|
||||
String testJdk = System.getProperty("test.jdk");
|
||||
if (testJdk == null)
|
||||
throw new RuntimeException("Please provide test.jdk property at a startup");
|
||||
return testJdk + File.separator + "bin" + File.separator + name;
|
||||
}
|
||||
|
||||
private static Path templatesHome() {
|
||||
String testSrc = System.getProperty("test.src");
|
||||
if (testSrc == null)
|
||||
throw new RuntimeException("Please provide test.src property at a startup");
|
||||
return Paths.get(testSrc);
|
||||
}
|
||||
|
||||
private static String toString(InputStream... src) throws IOException {
|
||||
StringWriter dst = new StringWriter();
|
||||
Reader concatenated =
|
||||
new InputStreamReader(
|
||||
new SequenceInputStream(
|
||||
Collections.enumeration(asList(src))));
|
||||
copy(concatenated, dst);
|
||||
return dst.toString();
|
||||
}
|
||||
|
||||
private static void copy(Reader src, Writer dst) throws IOException {
|
||||
int len;
|
||||
char[] buf = new char[1024];
|
||||
try {
|
||||
while ((len = src.read(buf)) != -1)
|
||||
dst.write(buf, 0, len);
|
||||
} finally {
|
||||
try {
|
||||
src.close();
|
||||
} catch (IOException ignored1) {
|
||||
} finally {
|
||||
try {
|
||||
dst.close();
|
||||
} catch (IOException ignored2) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class Result {
|
||||
|
||||
final int exitValue;
|
||||
final String output;
|
||||
|
||||
private Result(int exitValue, String output) {
|
||||
this.exitValue = exitValue;
|
||||
this.output = output;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 $package;
|
||||
|
||||
import java.net.ContentHandler;
|
||||
import java.net.ContentHandlerFactory;
|
||||
|
||||
public class $className implements ContentHandlerFactory {
|
||||
|
||||
public $className() {
|
||||
throw new RuntimeException(
|
||||
"This is a broken factory. It is supposed to throw this exception.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentHandler createContentHandler(String mimetype) {
|
||||
throw new RuntimeException( "This method is not supposed to be called.");
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 $package;
|
||||
|
||||
import java.net.ContentHandler;
|
||||
import java.net.ContentHandlerFactory;
|
||||
|
||||
public class $className implements ContentHandlerFactory {
|
||||
|
||||
@Override
|
||||
public ContentHandler createContentHandler(String mimetype) {
|
||||
throw new RuntimeException(
|
||||
"This is a broken factory. It is supposed to throw this exception.");
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 $package;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ContentHandler;
|
||||
import java.net.URLConnection;
|
||||
|
||||
public final class $className extends ContentHandler {
|
||||
|
||||
@Override
|
||||
public Object getContent(URLConnection urlc) throws IOException {
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.net.ContentHandlerFactory;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.URLStreamHandler;
|
||||
import java.net.URLStreamHandlerFactory;
|
||||
|
||||
public class Test {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (args.length > 0) {
|
||||
String fqn = args[0];
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends ContentHandlerFactory> c =
|
||||
(Class<? extends ContentHandlerFactory>) Class.forName(fqn);
|
||||
|
||||
ContentHandlerFactory f = c.newInstance();
|
||||
|
||||
URLConnection.setContentHandlerFactory(f);
|
||||
}
|
||||
|
||||
// One does not simply use a ContentHandler...
|
||||
// From an end user perspective ContentHandler is used indirectly
|
||||
// and it's more like SPI rather than API. So there's a certain amount
|
||||
// of preparations needs to be done beforehand.
|
||||
|
||||
URLStreamHandlerFactory streamHandlerFactory =
|
||||
(protocol) ->
|
||||
new URLStreamHandler() {
|
||||
@Override
|
||||
protected URLConnection openConnection(URL u) {
|
||||
return newUrlConnection(u);
|
||||
}
|
||||
};
|
||||
|
||||
URL.setURLStreamHandlerFactory(streamHandlerFactory);
|
||||
|
||||
// Finally
|
||||
Object content = new URL("whatever:").getContent();
|
||||
|
||||
System.out.println("Content class is: " + content.getClass());
|
||||
}
|
||||
|
||||
private static URLConnection newUrlConnection(URL u) {
|
||||
return new URLConnection(u) {
|
||||
@Override public void connect() { }
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() { return null; }
|
||||
|
||||
@Override public String getContentType() { return "text/plain"; }
|
||||
};
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user