mirror of
https://github.com/openjdk/jdk.git
synced 2026-04-14 00:49:42 +00:00
Merge
This commit is contained in:
commit
1edfabb9b0
@ -428,3 +428,5 @@ b94be69cbb1d2943b886bf2d458745756df146e4 jdk-10+9
|
||||
2c25fc24103251f9711a1c280c31e1e41016d90f jdk-9+172
|
||||
6b750cdb823a029a25ff2e560302cc2d28a86cb6 jdk-10+11
|
||||
88d7fd969e7df0e07a53b201cfd29393ca33ede9 jdk-9+173
|
||||
5466f409346e0446ee9a6daeb7f5d75c8fc76823 jdk-9+174
|
||||
8d4ed1e06fe184c9cb08c5b708e7d6f5c066644f jdk-10+12
|
||||
|
||||
@ -688,6 +688,7 @@ LIBFFI_LIBS
|
||||
LIBFFI_CFLAGS
|
||||
ALSA_LIBS
|
||||
ALSA_CFLAGS
|
||||
FREETYPE_LICENSE
|
||||
FREETYPE_BUNDLE_LIB_PATH
|
||||
FREETYPE_LIBS
|
||||
FREETYPE_CFLAGS
|
||||
@ -1200,6 +1201,7 @@ with_freetype_include
|
||||
with_freetype_lib
|
||||
with_freetype_src
|
||||
enable_freetype_bundling
|
||||
with_freetype_license
|
||||
with_alsa
|
||||
with_alsa_include
|
||||
with_alsa_lib
|
||||
@ -2153,6 +2155,7 @@ Optional Packages:
|
||||
--with-freetype-src specify directory with freetype sources to
|
||||
automatically build the library (experimental,
|
||||
Windows-only)
|
||||
--with-freetype-license if bundling freetype, also bundle this license file
|
||||
--with-alsa specify prefix directory for the alsa package
|
||||
(expecting the libraries under PATH/lib and the
|
||||
headers under PATH/include)
|
||||
@ -5186,7 +5189,7 @@ VS_SDK_PLATFORM_NAME_2013=
|
||||
#CUSTOM_AUTOCONF_INCLUDE
|
||||
|
||||
# Do not change or remove the following line, it is needed for consistency checks:
|
||||
DATE_WHEN_GENERATED=1494858828
|
||||
DATE_WHEN_GENERATED=1496926402
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
@ -57906,6 +57909,12 @@ if test "${enable_freetype_bundling+set}" = set; then :
|
||||
fi
|
||||
|
||||
|
||||
# Check whether --with-freetype-license was given.
|
||||
if test "${with_freetype_license+set}" = set; then :
|
||||
withval=$with_freetype_license;
|
||||
fi
|
||||
|
||||
|
||||
# Need to specify explicitly since it needs to be overridden on some versions of macosx
|
||||
FREETYPE_BASE_NAME=freetype
|
||||
FREETYPE_CFLAGS=
|
||||
@ -63852,6 +63861,153 @@ $as_echo "$BUNDLE_FREETYPE" >&6; }
|
||||
|
||||
fi # end freetype needed
|
||||
|
||||
FREETYPE_LICENSE=""
|
||||
if test "x$with_freetype_license" = "xyes"; then
|
||||
as_fn_error $? "--with-freetype-license must have a value" "$LINENO" 5
|
||||
elif test "x$with_freetype_license" != "x"; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for freetype license" >&5
|
||||
$as_echo_n "checking for freetype license... " >&6; }
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_freetype_license" >&5
|
||||
$as_echo "$with_freetype_license" >&6; }
|
||||
FREETYPE_LICENSE="$with_freetype_license"
|
||||
|
||||
# Only process if variable expands to non-empty
|
||||
|
||||
if test "x$FREETYPE_LICENSE" != x; then
|
||||
if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
|
||||
|
||||
# Input might be given as Windows format, start by converting to
|
||||
# unix format.
|
||||
path="$FREETYPE_LICENSE"
|
||||
new_path=`$CYGPATH -u "$path"`
|
||||
|
||||
# Cygwin tries to hide some aspects of the Windows file system, such that binaries are
|
||||
# named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered
|
||||
# the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
|
||||
# "foo.exe" is OK but "foo" is an error.
|
||||
#
|
||||
# This test is therefore slightly more accurate than "test -f" to check for file precense.
|
||||
# It is also a way to make sure we got the proper file name for the real test later on.
|
||||
test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
|
||||
if test "x$test_shortpath" = x; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: The path of FREETYPE_LICENSE, which resolves as \"$path\", is invalid." >&5
|
||||
$as_echo "$as_me: The path of FREETYPE_LICENSE, which resolves as \"$path\", is invalid." >&6;}
|
||||
as_fn_error $? "Cannot locate the the path of FREETYPE_LICENSE" "$LINENO" 5
|
||||
fi
|
||||
|
||||
# Call helper function which possibly converts this using DOS-style short mode.
|
||||
# If so, the updated path is stored in $new_path.
|
||||
|
||||
input_path="$new_path"
|
||||
# Check if we need to convert this using DOS-style short mode. If the path
|
||||
# contains just simple characters, use it. Otherwise (spaces, weird characters),
|
||||
# take no chances and rewrite it.
|
||||
# Note: m4 eats our [], so we need to use [ and ] instead.
|
||||
has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]`
|
||||
if test "x$has_forbidden_chars" != x; then
|
||||
# Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
|
||||
shortmode_path=`$CYGPATH -s -m -a "$input_path"`
|
||||
path_after_shortmode=`$CYGPATH -u "$shortmode_path"`
|
||||
if test "x$path_after_shortmode" != "x$input_to_shortpath"; then
|
||||
# Going to short mode and back again did indeed matter. Since short mode is
|
||||
# case insensitive, let's make it lowercase to improve readability.
|
||||
shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
|
||||
# Now convert it back to Unix-style (cygpath)
|
||||
input_path=`$CYGPATH -u "$shortmode_path"`
|
||||
new_path="$input_path"
|
||||
fi
|
||||
fi
|
||||
|
||||
test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/`
|
||||
if test "x$test_cygdrive_prefix" = x; then
|
||||
# As a simple fix, exclude /usr/bin since it's not a real path.
|
||||
if test "x`$ECHO $new_path | $GREP ^/usr/bin/`" = x; then
|
||||
# The path is in a Cygwin special directory (e.g. /home). We need this converted to
|
||||
# a path prefixed by /cygdrive for fixpath to work.
|
||||
new_path="$CYGWIN_ROOT_PATH$input_path"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
if test "x$path" != "x$new_path"; then
|
||||
FREETYPE_LICENSE="$new_path"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting FREETYPE_LICENSE to \"$new_path\"" >&5
|
||||
$as_echo "$as_me: Rewriting FREETYPE_LICENSE to \"$new_path\"" >&6;}
|
||||
fi
|
||||
|
||||
elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
|
||||
|
||||
path="$FREETYPE_LICENSE"
|
||||
has_colon=`$ECHO $path | $GREP ^.:`
|
||||
new_path="$path"
|
||||
if test "x$has_colon" = x; then
|
||||
# Not in mixed or Windows style, start by that.
|
||||
new_path=`cmd //c echo $path`
|
||||
fi
|
||||
|
||||
|
||||
input_path="$new_path"
|
||||
# Check if we need to convert this using DOS-style short mode. If the path
|
||||
# contains just simple characters, use it. Otherwise (spaces, weird characters),
|
||||
# take no chances and rewrite it.
|
||||
# Note: m4 eats our [], so we need to use [ and ] instead.
|
||||
has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]`
|
||||
if test "x$has_forbidden_chars" != x; then
|
||||
# Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
|
||||
new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
|
||||
fi
|
||||
|
||||
|
||||
windows_path="$new_path"
|
||||
if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
|
||||
unix_path=`$CYGPATH -u "$windows_path"`
|
||||
new_path="$unix_path"
|
||||
elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
|
||||
unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'`
|
||||
new_path="$unix_path"
|
||||
fi
|
||||
|
||||
if test "x$path" != "x$new_path"; then
|
||||
FREETYPE_LICENSE="$new_path"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting FREETYPE_LICENSE to \"$new_path\"" >&5
|
||||
$as_echo "$as_me: Rewriting FREETYPE_LICENSE to \"$new_path\"" >&6;}
|
||||
fi
|
||||
|
||||
# Save the first 10 bytes of this path to the storage, so fixpath can work.
|
||||
all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}")
|
||||
|
||||
else
|
||||
# We're on a unix platform. Hooray! :)
|
||||
path="$FREETYPE_LICENSE"
|
||||
has_space=`$ECHO "$path" | $GREP " "`
|
||||
if test "x$has_space" != x; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: The path of FREETYPE_LICENSE, which resolves as \"$path\", is invalid." >&5
|
||||
$as_echo "$as_me: The path of FREETYPE_LICENSE, which resolves as \"$path\", is invalid." >&6;}
|
||||
as_fn_error $? "Spaces are not allowed in this path." "$LINENO" 5
|
||||
fi
|
||||
|
||||
# Use eval to expand a potential ~
|
||||
eval path="$path"
|
||||
if test ! -f "$path" && test ! -d "$path"; then
|
||||
as_fn_error $? "The path of FREETYPE_LICENSE, which resolves as \"$path\", is not found." "$LINENO" 5
|
||||
fi
|
||||
|
||||
if test -d "$path"; then
|
||||
FREETYPE_LICENSE="`cd "$path"; $THEPWDCMD -L`"
|
||||
else
|
||||
dir="`$DIRNAME "$path"`"
|
||||
base="`$BASENAME "$path"`"
|
||||
FREETYPE_LICENSE="`cd "$dir"; $THEPWDCMD -L`/$base"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test ! -f "$FREETYPE_LICENSE"; then
|
||||
as_fn_error $? "$FREETYPE_LICENSE cannot be found" "$LINENO" 5
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -194,6 +194,8 @@ AC_DEFUN_ONCE([LIB_SETUP_FREETYPE],
|
||||
[specify directory with freetype sources to automatically build the library (experimental, Windows-only)])])
|
||||
AC_ARG_ENABLE(freetype-bundling, [AS_HELP_STRING([--disable-freetype-bundling],
|
||||
[disable bundling of the freetype library with the build result @<:@enabled on Windows or when using --with-freetype, disabled otherwise@:>@])])
|
||||
AC_ARG_WITH(freetype-license, [AS_HELP_STRING([--with-freetype-license],
|
||||
[if bundling freetype, also bundle this license file])])
|
||||
|
||||
# Need to specify explicitly since it needs to be overridden on some versions of macosx
|
||||
FREETYPE_BASE_NAME=freetype
|
||||
@ -443,7 +445,21 @@ AC_DEFUN_ONCE([LIB_SETUP_FREETYPE],
|
||||
|
||||
fi # end freetype needed
|
||||
|
||||
FREETYPE_LICENSE=""
|
||||
if test "x$with_freetype_license" = "xyes"; then
|
||||
AC_MSG_ERROR([--with-freetype-license must have a value])
|
||||
elif test "x$with_freetype_license" != "x"; then
|
||||
AC_MSG_CHECKING([for freetype license])
|
||||
AC_MSG_RESULT([$with_freetype_license])
|
||||
FREETYPE_LICENSE="$with_freetype_license"
|
||||
BASIC_FIXUP_PATH(FREETYPE_LICENSE)
|
||||
if test ! -f "$FREETYPE_LICENSE"; then
|
||||
AC_MSG_ERROR([$FREETYPE_LICENSE cannot be found])
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_SUBST(FREETYPE_BUNDLE_LIB_PATH)
|
||||
AC_SUBST(FREETYPE_CFLAGS)
|
||||
AC_SUBST(FREETYPE_LIBS)
|
||||
AC_SUBST(FREETYPE_LICENSE)
|
||||
])
|
||||
|
||||
@ -312,6 +312,7 @@ DEFAULT_MAKE_TARGET:=@DEFAULT_MAKE_TARGET@
|
||||
FREETYPE_LIBS:=@FREETYPE_LIBS@
|
||||
FREETYPE_CFLAGS:=@FREETYPE_CFLAGS@
|
||||
FREETYPE_BUNDLE_LIB_PATH=@FREETYPE_BUNDLE_LIB_PATH@
|
||||
FREETYPE_LICENSE=@FREETYPE_LICENSE@
|
||||
CUPS_CFLAGS:=@CUPS_CFLAGS@
|
||||
ALSA_LIBS:=@ALSA_LIBS@
|
||||
ALSA_CFLAGS:=@ALSA_CFLAGS@
|
||||
|
||||
@ -893,6 +893,16 @@ var getJibProfilesProfiles = function (input, common, data) {
|
||||
}
|
||||
});
|
||||
|
||||
// The windows ri profile needs to add the freetype license file
|
||||
profilesRiFreetype = {
|
||||
"windows-x86-ri": {
|
||||
configure_args: "--with-freetype-license="
|
||||
+ input.get("freetype", "install_path")
|
||||
+ "/freetype-2.7.1-v120-x86/freetype.md"
|
||||
}
|
||||
};
|
||||
profiles = concatObjects(profiles, profilesRiFreetype);
|
||||
|
||||
// Generate the missing platform attributes
|
||||
profiles = generatePlatformAttributes(profiles);
|
||||
profiles = generateDefaultMakeTargetsConfigureArg(common, profiles);
|
||||
|
||||
@ -428,3 +428,5 @@ c62e5964cfcf144d8f72e9ba69757897785349a9 jdk-9+171
|
||||
95ed14547ca9246baed34f90ef3ca13217538a8c jdk-9+172
|
||||
8ef8a0f1c4dfea17e10125e1f885920538e63085 jdk-10+11
|
||||
534ba4f8cfcf12accc5b9adb943103f2ff79fe16 jdk-9+173
|
||||
3615768c12904e29bb2ec1b506cd4633cd8a9ced jdk-9+174
|
||||
00ae6307d78bac49883ddc85d687aa88c49f3971 jdk-10+12
|
||||
|
||||
@ -588,3 +588,5 @@ c6cd3ec8d46b034e57c86399380ffcf7f25706e4 jdk-10+10
|
||||
1ae9e84f68b359420d2d153ecfe5ee2903e33a2e jdk-9+172
|
||||
7f14e550f1e8abea41c223e5fdad2261e99ba929 jdk-10+11
|
||||
e64b1cb48d6e7703928a9d1da106fc27f8cb65fd jdk-9+173
|
||||
944791f8160185bffa13fbb821fc09b6198f1f25 jdk-9+174
|
||||
070aa7a2eb14c4645f7eb31384cba0a2ba72a4b5 jdk-10+12
|
||||
|
||||
@ -26,6 +26,15 @@
|
||||
/**
|
||||
* Defines the implementation of the HotSpot Serviceability Agent.
|
||||
*
|
||||
* <p> This module includes the <em>{@index jhsdb jhsdb tool}</em> tool to
|
||||
* attach to a running Java Virtual Machine (JVM) or launch a postmortem
|
||||
* debugger to analyze the content of a core-dump from a crashed JVM.
|
||||
*
|
||||
* <dl style="font-family:'DejaVu Sans', Arial, Helvetica, sans serif">
|
||||
* <dt class="simpleTagLabel">Tool Guides:</dt>
|
||||
* <dd> {@extLink jhsdb_tool_reference jhsdb}</dd>
|
||||
* </dl>
|
||||
*
|
||||
* @moduleGraph
|
||||
* @since 9
|
||||
*/
|
||||
|
||||
@ -251,7 +251,13 @@ public class StandardGraphBuilderPlugins {
|
||||
|
||||
for (JavaKind kind : new JavaKind[]{JavaKind.Int, JavaKind.Long, JavaKind.Object}) {
|
||||
Class<?> javaClass = kind == JavaKind.Object ? Object.class : kind.toJavaClass();
|
||||
r.register5("compareAndSwap" + kind.name(), Receiver.class, Object.class, long.class, javaClass, javaClass, new InvocationPlugin() {
|
||||
String casName;
|
||||
if (Java8OrEarlier) {
|
||||
casName = "compareAndSwap";
|
||||
} else {
|
||||
casName = "compareAndSet";
|
||||
}
|
||||
r.register5(casName + kind.name(), Receiver.class, Object.class, long.class, javaClass, javaClass, new InvocationPlugin() {
|
||||
@Override
|
||||
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode expected, ValueNode x) {
|
||||
// Emits a null-check for the otherwise unused receiver
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2017, 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
|
||||
@ -1095,8 +1095,11 @@ inline intptr_t bitfield(intptr_t x, int start_bit_no, int field_length) {
|
||||
#undef min
|
||||
#endif
|
||||
|
||||
#define max(a,b) Do_not_use_max_use_MAX2_instead
|
||||
#define min(a,b) Do_not_use_min_use_MIN2_instead
|
||||
// The following defines serve the purpose of preventing use of accidentally
|
||||
// included min max macros from compiling, while continuing to allow innocent
|
||||
// min and max identifiers in the code to compile as intended.
|
||||
#define max max
|
||||
#define min min
|
||||
|
||||
// It is necessary to use templates here. Having normal overloaded
|
||||
// functions does not work because it is necessary to provide both 32-
|
||||
|
||||
@ -773,221 +773,221 @@ public class TestIntUnsafeCAS {
|
||||
|
||||
static void test_ci(int[] a) {
|
||||
for (int i = 0; i < ARRLEN; i+=1) {
|
||||
unsafe.compareAndSwapInt(a, byte_offset(i), -1, -123);
|
||||
unsafe.compareAndSetInt(a, byte_offset(i), -1, -123);
|
||||
}
|
||||
}
|
||||
static void test_vi(int[] a, int b, int old) {
|
||||
for (int i = 0; i < ARRLEN; i+=1) {
|
||||
unsafe.compareAndSwapInt(a, byte_offset(i), old, b);
|
||||
unsafe.compareAndSetInt(a, byte_offset(i), old, b);
|
||||
}
|
||||
}
|
||||
static void test_cp(int[] a, int[] b) {
|
||||
for (int i = 0; i < ARRLEN; i+=1) {
|
||||
unsafe.compareAndSwapInt(a, byte_offset(i), -123, b[i]);
|
||||
unsafe.compareAndSetInt(a, byte_offset(i), -123, b[i]);
|
||||
}
|
||||
}
|
||||
static void test_2ci(int[] a, int[] b) {
|
||||
for (int i = 0; i < ARRLEN; i+=1) {
|
||||
unsafe.compareAndSwapInt(a, byte_offset(i), 123, -123);
|
||||
unsafe.compareAndSwapInt(b, byte_offset(i), 123, -103);
|
||||
unsafe.compareAndSetInt(a, byte_offset(i), 123, -123);
|
||||
unsafe.compareAndSetInt(b, byte_offset(i), 123, -103);
|
||||
}
|
||||
}
|
||||
static void test_2vi(int[] a, int[] b, int c, int d) {
|
||||
for (int i = 0; i < ARRLEN; i+=1) {
|
||||
unsafe.compareAndSwapInt(a, byte_offset(i), -123, c);
|
||||
unsafe.compareAndSwapInt(b, byte_offset(i), -103, d);
|
||||
unsafe.compareAndSetInt(a, byte_offset(i), -123, c);
|
||||
unsafe.compareAndSetInt(b, byte_offset(i), -103, d);
|
||||
}
|
||||
}
|
||||
static void test_ci_neg(int[] a, int old) {
|
||||
for (int i = ARRLEN-1; i >= 0; i-=1) {
|
||||
unsafe.compareAndSwapInt(a, byte_offset(i), old, -123);
|
||||
unsafe.compareAndSetInt(a, byte_offset(i), old, -123);
|
||||
}
|
||||
}
|
||||
static void test_vi_neg(int[] a, int b, int old) {
|
||||
for (int i = ARRLEN-1; i >= 0; i-=1) {
|
||||
unsafe.compareAndSwapInt(a, byte_offset(i), old, b);
|
||||
unsafe.compareAndSetInt(a, byte_offset(i), old, b);
|
||||
}
|
||||
}
|
||||
static void test_cp_neg(int[] a, int[] b) {
|
||||
for (int i = ARRLEN-1; i >= 0; i-=1) {
|
||||
unsafe.compareAndSwapInt(a, byte_offset(i), -123, b[i]);
|
||||
unsafe.compareAndSetInt(a, byte_offset(i), -123, b[i]);
|
||||
}
|
||||
}
|
||||
static void test_2ci_neg(int[] a, int[] b) {
|
||||
for (int i = ARRLEN-1; i >= 0; i-=1) {
|
||||
unsafe.compareAndSwapInt(a, byte_offset(i), 123, -123);
|
||||
unsafe.compareAndSwapInt(b, byte_offset(i), 123, -103);
|
||||
unsafe.compareAndSetInt(a, byte_offset(i), 123, -123);
|
||||
unsafe.compareAndSetInt(b, byte_offset(i), 123, -103);
|
||||
}
|
||||
}
|
||||
static void test_2vi_neg(int[] a, int[] b, int c, int d) {
|
||||
for (int i = ARRLEN-1; i >= 0; i-=1) {
|
||||
unsafe.compareAndSwapInt(a, byte_offset(i), -123, c);
|
||||
unsafe.compareAndSwapInt(b, byte_offset(i), -103, d);
|
||||
unsafe.compareAndSetInt(a, byte_offset(i), -123, c);
|
||||
unsafe.compareAndSetInt(b, byte_offset(i), -103, d);
|
||||
}
|
||||
}
|
||||
static void test_ci_oppos(int[] a, int old) {
|
||||
int limit = ARRLEN-1;
|
||||
for (int i = 0; i < ARRLEN; i+=1) {
|
||||
unsafe.compareAndSwapInt(a, byte_offset(limit-i), old, -123);
|
||||
unsafe.compareAndSetInt(a, byte_offset(limit-i), old, -123);
|
||||
}
|
||||
}
|
||||
static void test_vi_oppos(int[] a, int b, int old) {
|
||||
int limit = ARRLEN-1;
|
||||
for (int i = limit; i >= 0; i-=1) {
|
||||
unsafe.compareAndSwapInt(a, byte_offset(limit-i), old, b);
|
||||
unsafe.compareAndSetInt(a, byte_offset(limit-i), old, b);
|
||||
}
|
||||
}
|
||||
static void test_cp_oppos(int[] a, int[] b) {
|
||||
int limit = ARRLEN-1;
|
||||
for (int i = 0; i < ARRLEN; i+=1) {
|
||||
unsafe.compareAndSwapInt(a, byte_offset(i), -123, b[limit-i]);
|
||||
unsafe.compareAndSetInt(a, byte_offset(i), -123, b[limit-i]);
|
||||
}
|
||||
}
|
||||
static void test_2ci_oppos(int[] a, int[] b) {
|
||||
int limit = ARRLEN-1;
|
||||
for (int i = 0; i < ARRLEN; i+=1) {
|
||||
unsafe.compareAndSwapInt(a, byte_offset(limit-i), 123, -123);
|
||||
unsafe.compareAndSwapInt(b, byte_offset(i), 123, -103);
|
||||
unsafe.compareAndSetInt(a, byte_offset(limit-i), 123, -123);
|
||||
unsafe.compareAndSetInt(b, byte_offset(i), 123, -103);
|
||||
}
|
||||
}
|
||||
static void test_2vi_oppos(int[] a, int[] b, int c, int d) {
|
||||
int limit = ARRLEN-1;
|
||||
for (int i = limit; i >= 0; i-=1) {
|
||||
unsafe.compareAndSwapInt(a, byte_offset(i), -123, c);
|
||||
unsafe.compareAndSwapInt(b, byte_offset(limit-i), -103, d);
|
||||
unsafe.compareAndSetInt(a, byte_offset(i), -123, c);
|
||||
unsafe.compareAndSetInt(b, byte_offset(limit-i), -103, d);
|
||||
}
|
||||
}
|
||||
static void test_ci_off(int[] a, int old) {
|
||||
for (int i = 0; i < ARRLEN-OFFSET; i+=1) {
|
||||
unsafe.compareAndSwapInt(a, byte_offset(i+OFFSET), old, -123);
|
||||
unsafe.compareAndSetInt(a, byte_offset(i+OFFSET), old, -123);
|
||||
}
|
||||
}
|
||||
static void test_vi_off(int[] a, int b, int old) {
|
||||
for (int i = 0; i < ARRLEN-OFFSET; i+=1) {
|
||||
unsafe.compareAndSwapInt(a, byte_offset(i+OFFSET), old, b);
|
||||
unsafe.compareAndSetInt(a, byte_offset(i+OFFSET), old, b);
|
||||
}
|
||||
}
|
||||
static void test_cp_off(int[] a, int[] b) {
|
||||
for (int i = 0; i < ARRLEN-OFFSET; i+=1) {
|
||||
unsafe.compareAndSwapInt(a, byte_offset(i+OFFSET), -123, b[i+OFFSET]);
|
||||
unsafe.compareAndSetInt(a, byte_offset(i+OFFSET), -123, b[i+OFFSET]);
|
||||
}
|
||||
}
|
||||
static void test_2ci_off(int[] a, int[] b) {
|
||||
for (int i = 0; i < ARRLEN-OFFSET; i+=1) {
|
||||
unsafe.compareAndSwapInt(a, byte_offset(i+OFFSET), 123, -123);
|
||||
unsafe.compareAndSwapInt(b, byte_offset(i+OFFSET), 123, -103);
|
||||
unsafe.compareAndSetInt(a, byte_offset(i+OFFSET), 123, -123);
|
||||
unsafe.compareAndSetInt(b, byte_offset(i+OFFSET), 123, -103);
|
||||
}
|
||||
}
|
||||
static void test_2vi_off(int[] a, int[] b, int c, int d) {
|
||||
for (int i = 0; i < ARRLEN-OFFSET; i+=1) {
|
||||
unsafe.compareAndSwapInt(a, byte_offset(i+OFFSET), -123, c);
|
||||
unsafe.compareAndSwapInt(b, byte_offset(i+OFFSET), -103, d);
|
||||
unsafe.compareAndSetInt(a, byte_offset(i+OFFSET), -123, c);
|
||||
unsafe.compareAndSetInt(b, byte_offset(i+OFFSET), -103, d);
|
||||
}
|
||||
}
|
||||
static void test_ci_inv(int[] a, int k, int old) {
|
||||
for (int i = 0; i < ARRLEN-k; i+=1) {
|
||||
unsafe.compareAndSwapInt(a, byte_offset(i+k), old, -123);
|
||||
unsafe.compareAndSetInt(a, byte_offset(i+k), old, -123);
|
||||
}
|
||||
}
|
||||
static void test_vi_inv(int[] a, int b, int k, int old) {
|
||||
for (int i = 0; i < ARRLEN-k; i+=1) {
|
||||
unsafe.compareAndSwapInt(a, byte_offset(i+k), old, b);
|
||||
unsafe.compareAndSetInt(a, byte_offset(i+k), old, b);
|
||||
}
|
||||
}
|
||||
static void test_cp_inv(int[] a, int[] b, int k) {
|
||||
for (int i = 0; i < ARRLEN-k; i+=1) {
|
||||
unsafe.compareAndSwapInt(a, byte_offset(i+k), -123, b[i+k]);
|
||||
unsafe.compareAndSetInt(a, byte_offset(i+k), -123, b[i+k]);
|
||||
}
|
||||
}
|
||||
static void test_2ci_inv(int[] a, int[] b, int k) {
|
||||
for (int i = 0; i < ARRLEN-k; i+=1) {
|
||||
unsafe.compareAndSwapInt(a, byte_offset(i+k), 123, -123);
|
||||
unsafe.compareAndSwapInt(b, byte_offset(i+k), 123, -103);
|
||||
unsafe.compareAndSetInt(a, byte_offset(i+k), 123, -123);
|
||||
unsafe.compareAndSetInt(b, byte_offset(i+k), 123, -103);
|
||||
}
|
||||
}
|
||||
static void test_2vi_inv(int[] a, int[] b, int c, int d, int k) {
|
||||
for (int i = 0; i < ARRLEN-k; i+=1) {
|
||||
unsafe.compareAndSwapInt(a, byte_offset(i+k), -123, c);
|
||||
unsafe.compareAndSwapInt(b, byte_offset(i+k), -103, d);
|
||||
unsafe.compareAndSetInt(a, byte_offset(i+k), -123, c);
|
||||
unsafe.compareAndSetInt(b, byte_offset(i+k), -103, d);
|
||||
}
|
||||
}
|
||||
static void test_ci_scl(int[] a, int old) {
|
||||
for (int i = 0; i*SCALE < ARRLEN; i+=1) {
|
||||
unsafe.compareAndSwapInt(a, byte_offset(i*SCALE), old, -123);
|
||||
unsafe.compareAndSetInt(a, byte_offset(i*SCALE), old, -123);
|
||||
}
|
||||
}
|
||||
static void test_vi_scl(int[] a, int b, int old) {
|
||||
for (int i = 0; i*SCALE < ARRLEN; i+=1) {
|
||||
unsafe.compareAndSwapInt(a, byte_offset(i*SCALE), old, b);
|
||||
unsafe.compareAndSetInt(a, byte_offset(i*SCALE), old, b);
|
||||
}
|
||||
}
|
||||
static void test_cp_scl(int[] a, int[] b) {
|
||||
for (int i = 0; i*SCALE < ARRLEN; i+=1) {
|
||||
unsafe.compareAndSwapInt(a, byte_offset(i*SCALE), -123, b[i*SCALE]);
|
||||
unsafe.compareAndSetInt(a, byte_offset(i*SCALE), -123, b[i*SCALE]);
|
||||
}
|
||||
}
|
||||
static void test_2ci_scl(int[] a, int[] b) {
|
||||
for (int i = 0; i*SCALE < ARRLEN; i+=1) {
|
||||
unsafe.compareAndSwapInt(a, byte_offset(i*SCALE), 123, -123);
|
||||
unsafe.compareAndSwapInt(b, byte_offset(i*SCALE), 123, -103);
|
||||
unsafe.compareAndSetInt(a, byte_offset(i*SCALE), 123, -123);
|
||||
unsafe.compareAndSetInt(b, byte_offset(i*SCALE), 123, -103);
|
||||
}
|
||||
}
|
||||
static void test_2vi_scl(int[] a, int[] b, int c, int d) {
|
||||
for (int i = 0; i*SCALE < ARRLEN; i+=1) {
|
||||
unsafe.compareAndSwapInt(a, byte_offset(i*SCALE), -123, c);
|
||||
unsafe.compareAndSwapInt(b, byte_offset(i*SCALE), -103, d);
|
||||
unsafe.compareAndSetInt(a, byte_offset(i*SCALE), -123, c);
|
||||
unsafe.compareAndSetInt(b, byte_offset(i*SCALE), -103, d);
|
||||
}
|
||||
}
|
||||
static void test_cp_alndst(int[] a, int[] b) {
|
||||
for (int i = 0; i < ARRLEN-ALIGN_OFF; i+=1) {
|
||||
unsafe.compareAndSwapInt(a, byte_offset(i+ALIGN_OFF), -1, b[i]);
|
||||
unsafe.compareAndSetInt(a, byte_offset(i+ALIGN_OFF), -1, b[i]);
|
||||
}
|
||||
}
|
||||
static void test_cp_alnsrc(int[] a, int[] b) {
|
||||
for (int i = 0; i < ARRLEN-ALIGN_OFF; i+=1) {
|
||||
int old = unsafe.getIntVolatile(a, byte_offset(i));
|
||||
unsafe.compareAndSwapInt(a, byte_offset(i), old, b[i+ALIGN_OFF]);
|
||||
unsafe.compareAndSetInt(a, byte_offset(i), old, b[i+ALIGN_OFF]);
|
||||
}
|
||||
}
|
||||
static void test_2ci_aln(int[] a, int[] b) {
|
||||
for (int i = 0; i < ARRLEN-ALIGN_OFF; i+=1) {
|
||||
unsafe.compareAndSwapInt(a, byte_offset(i+ALIGN_OFF), -1, -123);
|
||||
unsafe.compareAndSetInt(a, byte_offset(i+ALIGN_OFF), -1, -123);
|
||||
int old = unsafe.getIntVolatile(b, byte_offset(i));
|
||||
unsafe.compareAndSwapInt(b, byte_offset(i), old, -103);
|
||||
unsafe.compareAndSetInt(b, byte_offset(i), old, -103);
|
||||
}
|
||||
}
|
||||
static void test_2vi_aln(int[] a, int[] b, int c, int d) {
|
||||
for (int i = 0; i < ARRLEN-ALIGN_OFF; i+=1) {
|
||||
int old = unsafe.getIntVolatile(a, byte_offset(i));
|
||||
unsafe.compareAndSwapInt(a, byte_offset(i), old, c);
|
||||
unsafe.compareAndSetInt(a, byte_offset(i), old, c);
|
||||
old = unsafe.getIntVolatile(b, byte_offset(i+ALIGN_OFF));
|
||||
unsafe.compareAndSwapInt(b, byte_offset(i+ALIGN_OFF), old, d);
|
||||
unsafe.compareAndSetInt(b, byte_offset(i+ALIGN_OFF), old, d);
|
||||
}
|
||||
}
|
||||
static void test_cp_unalndst(int[] a, int[] b) {
|
||||
for (int i = 0; i < ARRLEN-UNALIGN_OFF; i+=1) {
|
||||
unsafe.compareAndSwapInt(a, byte_offset(i+UNALIGN_OFF), -1, b[i]);
|
||||
unsafe.compareAndSetInt(a, byte_offset(i+UNALIGN_OFF), -1, b[i]);
|
||||
}
|
||||
}
|
||||
static void test_cp_unalnsrc(int[] a, int[] b) {
|
||||
for (int i = 0; i < ARRLEN-UNALIGN_OFF; i+=1) {
|
||||
int old = unsafe.getIntVolatile(a, byte_offset(i));
|
||||
unsafe.compareAndSwapInt(a, byte_offset(i), old, b[i+UNALIGN_OFF]);
|
||||
unsafe.compareAndSetInt(a, byte_offset(i), old, b[i+UNALIGN_OFF]);
|
||||
}
|
||||
}
|
||||
static void test_2ci_unaln(int[] a, int[] b) {
|
||||
for (int i = 0; i < ARRLEN-UNALIGN_OFF; i+=1) {
|
||||
unsafe.compareAndSwapInt(a, byte_offset(i+UNALIGN_OFF), -1, -123);
|
||||
unsafe.compareAndSetInt(a, byte_offset(i+UNALIGN_OFF), -1, -123);
|
||||
int old = unsafe.getIntVolatile(b, byte_offset(i));
|
||||
unsafe.compareAndSwapInt(b, byte_offset(i), old, -103);
|
||||
unsafe.compareAndSetInt(b, byte_offset(i), old, -103);
|
||||
}
|
||||
}
|
||||
static void test_2vi_unaln(int[] a, int[] b, int c, int d) {
|
||||
for (int i = 0; i < ARRLEN-UNALIGN_OFF; i+=1) {
|
||||
int old = unsafe.getIntVolatile(a, byte_offset(i));
|
||||
unsafe.compareAndSwapInt(a, byte_offset(i), old, c);
|
||||
unsafe.compareAndSetInt(a, byte_offset(i), old, c);
|
||||
old = unsafe.getIntVolatile(b, byte_offset(i+UNALIGN_OFF));
|
||||
unsafe.compareAndSwapInt(b, byte_offset(i+UNALIGN_OFF), old, d);
|
||||
unsafe.compareAndSetInt(b, byte_offset(i+UNALIGN_OFF), old, d);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -64,7 +64,7 @@ public class UnsafeAccess {
|
||||
static Object helperUnsafeLoadStore(Object o, boolean isObjArray) {
|
||||
if (isObjArray) {
|
||||
Object o1 = U.getObject(o, off);
|
||||
U.compareAndSwapObject(o, off, o1, new Object());
|
||||
U.compareAndSetObject(o, off, o1, new Object());
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
@ -428,3 +428,5 @@ bd4b2c8835f35760a51c1475b03a16cc20c62973 jdk-10+10
|
||||
eedb6e54c8bd6197ecba5fc0d8568bac8ae852dd jdk-9+172
|
||||
95bab8bf9201ae8bfdf28e164bf33b78e49477e7 jdk-10+11
|
||||
9788347e0629d0cb3a0e55a903494ff741d4fa15 jdk-9+173
|
||||
b9c0b105002272d7414c8b34af9aded151f9cad6 jdk-9+174
|
||||
ff293e39e83366c40a5687dacd1ccb2305ed2c1e jdk-10+12
|
||||
|
||||
@ -1,596 +0,0 @@
|
||||
/*
|
||||
* reserved comment block
|
||||
* DO NOT REMOVE OR ALTER!
|
||||
*/
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.sun.org.apache.xerces.internal.util;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.ext.EntityResolver2;
|
||||
|
||||
import org.w3c.dom.ls.LSInput;
|
||||
import org.w3c.dom.ls.LSResourceResolver;
|
||||
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
|
||||
import com.sun.org.apache.xerces.internal.dom.DOMInputImpl;
|
||||
import com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl;
|
||||
|
||||
import com.sun.org.apache.xerces.internal.xni.XNIException;
|
||||
import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier;
|
||||
|
||||
import com.sun.org.apache.xerces.internal.xni.parser.XMLEntityResolver;
|
||||
import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
|
||||
|
||||
import com.sun.org.apache.xml.internal.resolver.Catalog;
|
||||
import com.sun.org.apache.xml.internal.resolver.CatalogManager;
|
||||
import com.sun.org.apache.xml.internal.resolver.readers.OASISXMLCatalogReader;
|
||||
import com.sun.org.apache.xml.internal.resolver.readers.SAXCatalogReader;
|
||||
|
||||
/**
|
||||
* <p>The catalog resolver handles the resolution of external
|
||||
* identifiers and URI references through XML catalogs. This
|
||||
* component supports XML catalogs defined by the
|
||||
* <a href="http://www.oasis-open.org/committees/entity/spec.html">
|
||||
* OASIS XML Catalogs Specification</a>. It encapsulates the
|
||||
* <a href="http://xml.apache.org/commons/">XML Commons</a> resolver.
|
||||
* An instance of this class may be registered on the parser
|
||||
* as a SAX entity resolver, as a DOM LSResourceResolver or
|
||||
* as an XNI entity resolver by setting the property
|
||||
* (http://apache.org/xml/properties/internal/entity-resolver).</p>
|
||||
*
|
||||
* <p>It is intended that this class may be used standalone to perform
|
||||
* catalog resolution outside of a parsing context. It may be shared
|
||||
* between several parsers and the application.</p>
|
||||
*
|
||||
* @deprecated This class and the JDK internal Catalog API in package
|
||||
* {@code com.sun.org.apache.xml.internal.resolver}
|
||||
* is encapsulated in JDK 9. The entire implementation under the package is now
|
||||
* deprecated and subject to removal in a future release. Users of the API should
|
||||
* migrate to the {@linkplain javax.xml.catalog new public API}.
|
||||
* <p>
|
||||
* The new Catalog API is supported throughout the JDK XML Processors, which allows
|
||||
* the use of Catalog by simply setting a path to a Catalog file as a property.
|
||||
*
|
||||
* @author Michael Glavassevich, IBM
|
||||
*
|
||||
*/
|
||||
@Deprecated(since="9", forRemoval=true)
|
||||
public class XMLCatalogResolver
|
||||
implements XMLEntityResolver, EntityResolver2, LSResourceResolver {
|
||||
|
||||
/** Internal catalog manager for Apache catalogs. **/
|
||||
private CatalogManager fResolverCatalogManager = null;
|
||||
|
||||
/** Internal catalog structure. **/
|
||||
private Catalog fCatalog = null;
|
||||
|
||||
/** An array of catalog URIs. **/
|
||||
private String [] fCatalogsList = null;
|
||||
|
||||
/**
|
||||
* Indicates whether the list of catalogs has
|
||||
* changed since it was processed.
|
||||
*/
|
||||
private boolean fCatalogsChanged = true;
|
||||
|
||||
/** Application specified prefer public setting. **/
|
||||
private boolean fPreferPublic = true;
|
||||
|
||||
/**
|
||||
* Indicates whether the application desires that
|
||||
* the parser or some other component performing catalog
|
||||
* resolution should use the literal system identifier
|
||||
* instead of the expanded system identifier.
|
||||
*/
|
||||
private boolean fUseLiteralSystemId = true;
|
||||
|
||||
/**
|
||||
* <p>Constructs a catalog resolver with a default configuration.</p>
|
||||
*/
|
||||
public XMLCatalogResolver () {
|
||||
this(null, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Constructs a catalog resolver with the given
|
||||
* list of entry files.</p>
|
||||
*
|
||||
* @param catalogs an ordered array list of absolute URIs
|
||||
*/
|
||||
public XMLCatalogResolver (String [] catalogs) {
|
||||
this(catalogs, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Constructs a catalog resolver with the given
|
||||
* list of entry files and the preference for whether
|
||||
* system or public matches are preferred.</p>
|
||||
*
|
||||
* @param catalogs an ordered array list of absolute URIs
|
||||
* @param preferPublic the prefer public setting
|
||||
*/
|
||||
public XMLCatalogResolver (String [] catalogs, boolean preferPublic) {
|
||||
init(catalogs, preferPublic);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the initial list of catalog entry files.</p>
|
||||
*
|
||||
* @return the initial list of catalog entry files
|
||||
*/
|
||||
public final synchronized String [] getCatalogList () {
|
||||
return (fCatalogsList != null)
|
||||
? (String[]) fCatalogsList.clone() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Sets the initial list of catalog entry files.
|
||||
* If there were any catalog mappings cached from
|
||||
* the previous list they will be replaced by catalog
|
||||
* mappings from the new list the next time the catalog
|
||||
* is queried.</p>
|
||||
*
|
||||
* @param catalogs an ordered array list of absolute URIs
|
||||
*/
|
||||
public final synchronized void setCatalogList (String [] catalogs) {
|
||||
fCatalogsChanged = true;
|
||||
fCatalogsList = (catalogs != null)
|
||||
? (String[]) catalogs.clone() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Forces the cache of catalog mappings to be cleared.</p>
|
||||
*/
|
||||
public final synchronized void clear () {
|
||||
fCatalog = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the preference for whether system or public
|
||||
* matches are preferred. This is used in the absence
|
||||
* of any occurence of the <code>prefer</code> attribute
|
||||
* on the <code>catalog</code> entry of a catalog. If this
|
||||
* property has not yet been explicitly set its value is
|
||||
* <code>true</code>.</p>
|
||||
*
|
||||
* @return the prefer public setting
|
||||
*/
|
||||
public final boolean getPreferPublic () {
|
||||
return fPreferPublic;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Sets the preference for whether system or public
|
||||
* matches are preferred. This is used in the absence
|
||||
* of any occurence of the <code>prefer</code> attribute
|
||||
* on the <code>catalog</code> entry of a catalog.</p>
|
||||
*
|
||||
* @param preferPublic the prefer public setting
|
||||
*/
|
||||
public final void setPreferPublic (boolean preferPublic) {
|
||||
fPreferPublic = preferPublic;
|
||||
fResolverCatalogManager.setPreferPublic(preferPublic);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the preference for whether the literal system
|
||||
* identifier should be used when resolving system
|
||||
* identifiers when both it and the expanded system
|
||||
* identifier are available. If this property has not yet
|
||||
* been explicitly set its value is <code>true</code>.</p>
|
||||
*
|
||||
* @return the preference for using literal system identifers
|
||||
* for catalog resolution
|
||||
*
|
||||
* @see #setUseLiteralSystemId
|
||||
*/
|
||||
public final boolean getUseLiteralSystemId () {
|
||||
return fUseLiteralSystemId;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Sets the preference for whether the literal system
|
||||
* identifier should be used when resolving system
|
||||
* identifiers when both it and the expanded system
|
||||
* identifier are available.</p>
|
||||
*
|
||||
* <p>The literal system identifier is the URI as it was
|
||||
* provided before absolutization. It may be embedded within
|
||||
* an entity. It may be provided externally or it may be the
|
||||
* result of redirection. For example, redirection may
|
||||
* have come from the protocol level through HTTP or from
|
||||
* an application's entity resolver.</p>
|
||||
*
|
||||
* <p>The expanded system identifier is an absolute URI
|
||||
* which is the result of resolving the literal system
|
||||
* identifier against a base URI.</p>
|
||||
*
|
||||
* @param useLiteralSystemId the preference for using
|
||||
* literal system identifers for catalog resolution
|
||||
*/
|
||||
public final void setUseLiteralSystemId (boolean useLiteralSystemId) {
|
||||
fUseLiteralSystemId = useLiteralSystemId;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Resolves an external entity. If the entity cannot be
|
||||
* resolved, this method should return <code>null</code>. This
|
||||
* method returns an input source if an entry was found in the
|
||||
* catalog for the given external identifier. It should be
|
||||
* overrided if other behaviour is required.</p>
|
||||
*
|
||||
* @param publicId the public identifier, or <code>null</code> if none was supplied
|
||||
* @param systemId the system identifier
|
||||
*
|
||||
* @throws SAXException any SAX exception, possibly wrapping another exception
|
||||
* @throws IOException thrown if some i/o error occurs
|
||||
*/
|
||||
public InputSource resolveEntity(String publicId, String systemId)
|
||||
throws SAXException, IOException {
|
||||
|
||||
String resolvedId = null;
|
||||
if (publicId != null && systemId != null) {
|
||||
resolvedId = resolvePublic(publicId, systemId);
|
||||
}
|
||||
else if (systemId != null) {
|
||||
resolvedId = resolveSystem(systemId);
|
||||
}
|
||||
|
||||
if (resolvedId != null) {
|
||||
InputSource source = new InputSource(resolvedId);
|
||||
source.setPublicId(publicId);
|
||||
return source;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Resolves an external entity. If the entity cannot be
|
||||
* resolved, this method should return <code>null</code>. This
|
||||
* method returns an input source if an entry was found in the
|
||||
* catalog for the given external identifier. It should be
|
||||
* overrided if other behaviour is required.</p>
|
||||
*
|
||||
* @param name the identifier of the external entity
|
||||
* @param publicId the public identifier, or <code>null</code> if none was supplied
|
||||
* @param baseURI the URI with respect to which relative systemIDs are interpreted.
|
||||
* @param systemId the system identifier
|
||||
*
|
||||
* @throws SAXException any SAX exception, possibly wrapping another exception
|
||||
* @throws IOException thrown if some i/o error occurs
|
||||
*/
|
||||
public InputSource resolveEntity(String name, String publicId,
|
||||
String baseURI, String systemId) throws SAXException, IOException {
|
||||
|
||||
String resolvedId = null;
|
||||
|
||||
if (!getUseLiteralSystemId() && baseURI != null) {
|
||||
// Attempt to resolve the system identifier against the base URI.
|
||||
try {
|
||||
URI uri = new URI(new URI(baseURI), systemId);
|
||||
systemId = uri.toString();
|
||||
}
|
||||
// Ignore the exception. Fallback to the literal system identifier.
|
||||
catch (URI.MalformedURIException ex) {}
|
||||
}
|
||||
|
||||
if (publicId != null && systemId != null) {
|
||||
resolvedId = resolvePublic(publicId, systemId);
|
||||
}
|
||||
else if (systemId != null) {
|
||||
resolvedId = resolveSystem(systemId);
|
||||
}
|
||||
|
||||
if (resolvedId != null) {
|
||||
InputSource source = new InputSource(resolvedId);
|
||||
source.setPublicId(publicId);
|
||||
return source;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Locates an external subset for documents which do not explicitly
|
||||
* provide one. This method always returns <code>null</code>. It
|
||||
* should be overrided if other behaviour is required.</p>
|
||||
*
|
||||
* @param name the identifier of the document root element
|
||||
* @param baseURI the document's base URI
|
||||
*
|
||||
* @throws SAXException any SAX exception, possibly wrapping another exception
|
||||
* @throws IOException thrown if some i/o error occurs
|
||||
*/
|
||||
public InputSource getExternalSubset(String name, String baseURI)
|
||||
throws SAXException, IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Resolves a resource using the catalog. This method interprets that
|
||||
* the namespace URI corresponds to uri entries in the catalog.
|
||||
* Where both a namespace and an external identifier exist, the namespace
|
||||
* takes precedence.</p>
|
||||
*
|
||||
* @param type the type of the resource being resolved
|
||||
* @param namespaceURI the namespace of the resource being resolved,
|
||||
* or <code>null</code> if none was supplied
|
||||
* @param publicId the public identifier of the resource being resolved,
|
||||
* or <code>null</code> if none was supplied
|
||||
* @param systemId the system identifier of the resource being resolved,
|
||||
* or <code>null</code> if none was supplied
|
||||
* @param baseURI the absolute base URI of the resource being parsed,
|
||||
* or <code>null</code> if there is no base URI
|
||||
*/
|
||||
public LSInput resolveResource(String type, String namespaceURI,
|
||||
String publicId, String systemId, String baseURI) {
|
||||
|
||||
String resolvedId = null;
|
||||
|
||||
try {
|
||||
// The namespace is useful for resolving namespace aware
|
||||
// grammars such as XML schema. Let it take precedence over
|
||||
// the external identifier if one exists.
|
||||
if (namespaceURI != null) {
|
||||
resolvedId = resolveURI(namespaceURI);
|
||||
}
|
||||
|
||||
if (!getUseLiteralSystemId() && baseURI != null) {
|
||||
// Attempt to resolve the system identifier against the base URI.
|
||||
try {
|
||||
URI uri = new URI(new URI(baseURI), systemId);
|
||||
systemId = uri.toString();
|
||||
}
|
||||
// Ignore the exception. Fallback to the literal system identifier.
|
||||
catch (URI.MalformedURIException ex) {}
|
||||
}
|
||||
|
||||
// Resolve against an external identifier if one exists. This
|
||||
// is useful for resolving DTD external subsets and other
|
||||
// external entities. For XML schemas if there was no namespace
|
||||
// mapping we might be able to resolve a system identifier
|
||||
// specified as a location hint.
|
||||
if (resolvedId == null) {
|
||||
if (publicId != null && systemId != null) {
|
||||
resolvedId = resolvePublic(publicId, systemId);
|
||||
}
|
||||
else if (systemId != null) {
|
||||
resolvedId = resolveSystem(systemId);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Ignore IOException. It cannot be thrown from this method.
|
||||
catch (IOException ex) {}
|
||||
|
||||
if (resolvedId != null) {
|
||||
return new DOMInputImpl(publicId, resolvedId, baseURI);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>Resolves an external entity. If the entity cannot be
|
||||
* resolved, this method should return <code>null</code>. This
|
||||
* method only calls <code>resolveIdentifier</code> and returns
|
||||
* an input source if an entry was found in the catalog. It
|
||||
* should be overrided if other behaviour is required.</p>
|
||||
*
|
||||
* @param resourceIdentifier location of the XML resource to resolve
|
||||
*
|
||||
* @throws XNIException thrown on general error
|
||||
* @throws IOException thrown if some i/o error occurs
|
||||
*/
|
||||
public XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier)
|
||||
throws XNIException, IOException {
|
||||
|
||||
String resolvedId = resolveIdentifier(resourceIdentifier);
|
||||
if (resolvedId != null) {
|
||||
return new XMLInputSource(resourceIdentifier.getPublicId(),
|
||||
resolvedId, resourceIdentifier.getBaseSystemId(), false);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Resolves an identifier using the catalog. This method interprets that
|
||||
* the namespace of the identifier corresponds to uri entries in the catalog.
|
||||
* Where both a namespace and an external identifier exist, the namespace
|
||||
* takes precedence.</p>
|
||||
*
|
||||
* @param resourceIdentifier the identifier to resolve
|
||||
*
|
||||
* @throws XNIException thrown on general error
|
||||
* @throws IOException thrown if some i/o error occurs
|
||||
*/
|
||||
public String resolveIdentifier(XMLResourceIdentifier resourceIdentifier)
|
||||
throws IOException, XNIException {
|
||||
|
||||
String resolvedId = null;
|
||||
|
||||
// The namespace is useful for resolving namespace aware
|
||||
// grammars such as XML schema. Let it take precedence over
|
||||
// the external identifier if one exists.
|
||||
String namespace = resourceIdentifier.getNamespace();
|
||||
if (namespace != null) {
|
||||
resolvedId = resolveURI(namespace);
|
||||
}
|
||||
|
||||
// Resolve against an external identifier if one exists. This
|
||||
// is useful for resolving DTD external subsets and other
|
||||
// external entities. For XML schemas if there was no namespace
|
||||
// mapping we might be able to resolve a system identifier
|
||||
// specified as a location hint.
|
||||
if (resolvedId == null) {
|
||||
String publicId = resourceIdentifier.getPublicId();
|
||||
String systemId = getUseLiteralSystemId()
|
||||
? resourceIdentifier.getLiteralSystemId()
|
||||
: resourceIdentifier.getExpandedSystemId();
|
||||
if (publicId != null && systemId != null) {
|
||||
resolvedId = resolvePublic(publicId, systemId);
|
||||
}
|
||||
else if (systemId != null) {
|
||||
resolvedId = resolveSystem(systemId);
|
||||
}
|
||||
}
|
||||
return resolvedId;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the URI mapping in the catalog for the given
|
||||
* external identifier or <code>null</code> if no mapping
|
||||
* exists. If the system identifier is an URN in the
|
||||
* <code>publicid</code> namespace it is converted into
|
||||
* a public identifier by URN "unwrapping" as specified
|
||||
* in the XML Catalogs specification.</p>
|
||||
*
|
||||
* @param systemId the system identifier to locate in the catalog
|
||||
*
|
||||
* @return the mapped URI or <code>null</code> if no mapping
|
||||
* was found in the catalog
|
||||
*
|
||||
* @throws IOException if an i/o error occurred while reading
|
||||
* the catalog
|
||||
*/
|
||||
public final synchronized String resolveSystem (String systemId)
|
||||
throws IOException {
|
||||
|
||||
if (fCatalogsChanged) {
|
||||
parseCatalogs();
|
||||
fCatalogsChanged = false;
|
||||
}
|
||||
return (fCatalog != null)
|
||||
? fCatalog.resolveSystem(systemId) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the URI mapping in the catalog for the given
|
||||
* external identifier or <code>null</code> if no mapping
|
||||
* exists. Public identifiers are normalized before
|
||||
* comparison.</p>
|
||||
*
|
||||
* @param publicId the public identifier to locate in the catalog
|
||||
* @param systemId the system identifier to locate in the catalog
|
||||
*
|
||||
* @return the mapped URI or <code>null</code> if no mapping
|
||||
* was found in the catalog
|
||||
*
|
||||
* @throws IOException if an i/o error occurred while reading
|
||||
* the catalog
|
||||
*/
|
||||
public final synchronized String resolvePublic (String publicId, String systemId)
|
||||
throws IOException {
|
||||
|
||||
if (fCatalogsChanged) {
|
||||
parseCatalogs();
|
||||
fCatalogsChanged = false;
|
||||
}
|
||||
return (fCatalog != null)
|
||||
? fCatalog.resolvePublic(publicId, systemId) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the URI mapping in the catalog for the given URI
|
||||
* reference or <code>null</code> if no mapping exists.
|
||||
* URI comparison is case sensitive. If the URI reference
|
||||
* is an URN in the <code>publicid</code> namespace
|
||||
* it is converted into a public identifier by URN "unwrapping"
|
||||
* as specified in the XML Catalogs specification and then
|
||||
* resolution is performed following the semantics of
|
||||
* external identifier resolution.</p>
|
||||
*
|
||||
* @param uri the URI to locate in the catalog
|
||||
*
|
||||
* @return the mapped URI or <code>null</code> if no mapping
|
||||
* was found in the catalog
|
||||
*
|
||||
* @throws IOException if an i/o error occurred while reading
|
||||
* the catalog
|
||||
*/
|
||||
public final synchronized String resolveURI (String uri)
|
||||
throws IOException {
|
||||
|
||||
if (fCatalogsChanged) {
|
||||
parseCatalogs();
|
||||
fCatalogsChanged = false;
|
||||
}
|
||||
return (fCatalog != null)
|
||||
? fCatalog.resolveURI(uri) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialization. Create a CatalogManager and set all
|
||||
* the properties upfront. This prevents JVM wide system properties
|
||||
* or a property file somewhere in the environment from affecting
|
||||
* the behaviour of this catalog resolver.
|
||||
*/
|
||||
private void init (String [] catalogs, boolean preferPublic) {
|
||||
fCatalogsList = (catalogs != null) ? (String[]) catalogs.clone() : null;
|
||||
fPreferPublic = preferPublic;
|
||||
fResolverCatalogManager = new CatalogManager();
|
||||
fResolverCatalogManager.setAllowOasisXMLCatalogPI(false);
|
||||
fResolverCatalogManager.setCatalogClassName("com.sun.org.apache.xml.internal.resolver.Catalog");
|
||||
fResolverCatalogManager.setCatalogFiles("");
|
||||
fResolverCatalogManager.setIgnoreMissingProperties(true);
|
||||
fResolverCatalogManager.setPreferPublic(fPreferPublic);
|
||||
fResolverCatalogManager.setRelativeCatalogs(false);
|
||||
fResolverCatalogManager.setUseStaticCatalog(false);
|
||||
fResolverCatalogManager.setVerbosity(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instruct the <code>Catalog</code> to parse each of the
|
||||
* catalogs in the list. Only the first catalog will actually be
|
||||
* parsed immediately. The others will be queued and read if
|
||||
* they are needed later.
|
||||
*/
|
||||
private void parseCatalogs () throws IOException {
|
||||
if (fCatalogsList != null) {
|
||||
fCatalog = new Catalog(fResolverCatalogManager);
|
||||
attachReaderToCatalog(fCatalog);
|
||||
for (int i = 0; i < fCatalogsList.length; ++i) {
|
||||
String catalog = fCatalogsList[i];
|
||||
if (catalog != null && catalog.length() > 0) {
|
||||
fCatalog.parseCatalog(catalog);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
fCatalog = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches the reader to the catalog.
|
||||
*/
|
||||
private void attachReaderToCatalog (Catalog catalog) {
|
||||
|
||||
SAXParserFactory spf = new SAXParserFactoryImpl();
|
||||
spf.setNamespaceAware(true);
|
||||
spf.setValidating(false);
|
||||
|
||||
SAXCatalogReader saxReader = new SAXCatalogReader(spf);
|
||||
saxReader.setCatalogParser(OASISXMLCatalogReader.namespaceName, "catalog",
|
||||
"com.sun.org.apache.xml.internal.resolver.readers.OASISXMLCatalogReader");
|
||||
catalog.addReader("application/xml", saxReader);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,251 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
*/
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.sun.org.apache.xml.internal.resolver;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Vector;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* Represents a Catalog entry.
|
||||
*
|
||||
* <p>Instances of this class represent individual entries
|
||||
* in a Catalog.</p>
|
||||
*
|
||||
* <p>Each catalog entry has a unique name and is associated with
|
||||
* an arbitrary number of arguments (all strings). For example, the
|
||||
* TR9401 catalog entry "PUBLIC" has two arguments, a public identifier
|
||||
* and a system identifier. Each entry has a unique numeric type,
|
||||
* assigned automatically when the entry type is created.</p>
|
||||
*
|
||||
* <p>The number and type of catalog entries is maintained
|
||||
* <em>statically</em>. Catalog classes, or their subclasses, can add
|
||||
* new entry types, but all Catalog objects share the same global pool
|
||||
* of types.</p>
|
||||
*
|
||||
* <p>Initially there are no valid entries.</p>
|
||||
*
|
||||
* @see Catalog
|
||||
*
|
||||
* @author Norman Walsh
|
||||
* <a href="mailto:Norman.Walsh@Sun.COM">Norman.Walsh@Sun.COM</a>
|
||||
*
|
||||
*/
|
||||
public class CatalogEntry {
|
||||
/** The nextEntry is the ordinal number of the next entry type. */
|
||||
static AtomicInteger nextEntry = new AtomicInteger(0);
|
||||
|
||||
/**
|
||||
* The entryTypes vector maps catalog entry names
|
||||
* (e.g., 'BASE' or 'SYSTEM') to their type (1, 2, etc.).
|
||||
* Names are case sensitive.
|
||||
*/
|
||||
static final Map<String, Integer> entryTypes = new ConcurrentHashMap<>();
|
||||
|
||||
/** The entryTypes vector maps catalog entry types to the
|
||||
number of arguments they're required to have. */
|
||||
static final Vector entryArgs = new Vector();
|
||||
|
||||
/**
|
||||
* Adds a new catalog entry type.
|
||||
*
|
||||
* @param name The name of the catalog entry type. This must be
|
||||
* unique among all types and is case-sensitive. (Adding a duplicate
|
||||
* name effectively replaces the old type with the new type.)
|
||||
* @param numArgs The number of arguments that this entry type
|
||||
* is required to have. There is no provision for variable numbers
|
||||
* of arguments.
|
||||
* @return The type for the new entry.
|
||||
*/
|
||||
static int addEntryType(String name, int numArgs) {
|
||||
final int index = nextEntry.getAndIncrement();
|
||||
entryTypes.put(name, index);
|
||||
entryArgs.add(index, numArgs);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup an entry type
|
||||
*
|
||||
* @param name The name of the catalog entry type.
|
||||
* @return The type of the catalog entry with the specified name.
|
||||
* @throws InvalidCatalogEntryTypeException if no entry has the
|
||||
* specified name.
|
||||
*/
|
||||
public static int getEntryType(String name)
|
||||
throws CatalogException {
|
||||
if (!entryTypes.containsKey(name)) {
|
||||
throw new CatalogException(CatalogException.INVALID_ENTRY_TYPE);
|
||||
}
|
||||
|
||||
Integer iType = entryTypes.get(name);
|
||||
|
||||
if (iType == null) {
|
||||
throw new CatalogException(CatalogException.INVALID_ENTRY_TYPE);
|
||||
}
|
||||
|
||||
return iType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find out how many arguments an entry is required to have.
|
||||
*
|
||||
* @param name The name of the catalog entry type.
|
||||
* @return The number of arguments that entry type is required to have.
|
||||
* @throws InvalidCatalogEntryTypeException if no entry has the
|
||||
* specified name.
|
||||
*/
|
||||
public static int getEntryArgCount(String name)
|
||||
throws CatalogException {
|
||||
return getEntryArgCount(getEntryType(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find out how many arguments an entry is required to have.
|
||||
*
|
||||
* @param type A valid catalog entry type.
|
||||
* @return The number of arguments that entry type is required to have.
|
||||
* @throws InvalidCatalogEntryTypeException if the type is invalid.
|
||||
*/
|
||||
public static int getEntryArgCount(int type)
|
||||
throws CatalogException {
|
||||
try {
|
||||
Integer iArgs = (Integer) entryArgs.get(type);
|
||||
return iArgs.intValue();
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
throw new CatalogException(CatalogException.INVALID_ENTRY_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
/** The entry type of this entry */
|
||||
protected int entryType = 0;
|
||||
|
||||
/** The arguments associated with this entry */
|
||||
protected Vector args = null;
|
||||
|
||||
/**
|
||||
* Null constructor; something for subclasses to call.
|
||||
*/
|
||||
public CatalogEntry() {}
|
||||
|
||||
/**
|
||||
* Construct a catalog entry of the specified type.
|
||||
*
|
||||
* @param name The name of the entry type
|
||||
* @param args A String Vector of arguments
|
||||
* @throws InvalidCatalogEntryTypeException if no such entry type
|
||||
* exists.
|
||||
* @throws InvalidCatalogEntryException if the wrong number of arguments
|
||||
* is passed.
|
||||
*/
|
||||
public CatalogEntry(String name, Vector args)
|
||||
throws CatalogException {
|
||||
Integer iType = entryTypes.get(name);
|
||||
|
||||
if (iType == null) {
|
||||
throw new CatalogException(CatalogException.INVALID_ENTRY_TYPE);
|
||||
}
|
||||
|
||||
int type = iType;
|
||||
|
||||
try {
|
||||
Integer iArgs = (Integer) entryArgs.get(type);
|
||||
if (iArgs.intValue() != args.size()) {
|
||||
throw new CatalogException(CatalogException.INVALID_ENTRY);
|
||||
}
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
throw new CatalogException(CatalogException.INVALID_ENTRY_TYPE);
|
||||
}
|
||||
|
||||
entryType = type;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a catalog entry of the specified type.
|
||||
*
|
||||
* @param type The entry type
|
||||
* @param args A String Vector of arguments
|
||||
* @throws InvalidCatalogEntryTypeException if no such entry type
|
||||
* exists.
|
||||
* @throws InvalidCatalogEntryException if the wrong number of arguments
|
||||
* is passed.
|
||||
*/
|
||||
public CatalogEntry(int type, Vector args)
|
||||
throws CatalogException {
|
||||
try {
|
||||
Integer iArgs = (Integer) entryArgs.get(type);
|
||||
if (iArgs.intValue() != args.size()) {
|
||||
throw new CatalogException(CatalogException.INVALID_ENTRY);
|
||||
}
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
throw new CatalogException(CatalogException.INVALID_ENTRY_TYPE);
|
||||
}
|
||||
|
||||
entryType = type;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the entry type.
|
||||
*
|
||||
* @return The entry type of the CatalogEntry
|
||||
*/
|
||||
public int getEntryType() {
|
||||
return entryType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an entry argument.
|
||||
*
|
||||
* @param argNum The argument number (arguments are numbered from 0).
|
||||
* @return The specified argument or null if an invalid argNum is
|
||||
* provided.
|
||||
*/
|
||||
public String getEntryArg(int argNum) {
|
||||
try {
|
||||
String arg = (String) args.get(argNum);
|
||||
return arg;
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an entry argument.
|
||||
*
|
||||
* <p>Catalogs sometimes need to adjust the catlog entry parameters,
|
||||
* for example to make a relative URI absolute with respect to the
|
||||
* current base URI. But in general, this function should only be
|
||||
* called shortly after object creation to do some sort of cleanup.
|
||||
* Catalog entries should not mutate over time.</p>
|
||||
*
|
||||
* @param argNum The argument number (arguments are numbered from 0).
|
||||
* @throws ArrayIndexOutOfBoundsException if an invalid argument
|
||||
* number is provided.
|
||||
*/
|
||||
public void setEntryArg(int argNum, String newspec)
|
||||
throws ArrayIndexOutOfBoundsException {
|
||||
args.set(argNum, newspec);
|
||||
}
|
||||
}
|
||||
@ -1,165 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.sun.org.apache.xml.internal.resolver;
|
||||
|
||||
/**
|
||||
* Signal Catalog exception.
|
||||
*
|
||||
* <p>This exception is thrown if an error occurs loading a
|
||||
* catalog file.</p>
|
||||
*
|
||||
* @see Catalog
|
||||
*
|
||||
* @author Norman Walsh
|
||||
* <a href="mailto:Norman.Walsh@Sun.COM">Norman.Walsh@Sun.COM</a>
|
||||
*
|
||||
*/
|
||||
public class CatalogException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 4007157171817798450L;
|
||||
|
||||
/** A wrapper around another exception */
|
||||
public static final int WRAPPER = 1;
|
||||
/** An invalid entry */
|
||||
public static final int INVALID_ENTRY = 2;
|
||||
/** An invalid entry type */
|
||||
public static final int INVALID_ENTRY_TYPE = 3;
|
||||
/** Could not instantiate an XML parser */
|
||||
public static final int NO_XML_PARSER = 4;
|
||||
/** Unknown XML format */
|
||||
public static final int UNKNOWN_FORMAT = 5;
|
||||
/** Unparseable XML catalog (not XML)*/
|
||||
public static final int UNPARSEABLE = 6;
|
||||
/** XML but parse failed */
|
||||
public static final int PARSE_FAILED = 7;
|
||||
/** Text catalog ended in mid-comment */
|
||||
public static final int UNENDED_COMMENT = 8;
|
||||
|
||||
/**
|
||||
* The embedded exception if tunnelling, or null.
|
||||
*/
|
||||
private final Exception exception;
|
||||
private final int exceptionType;
|
||||
|
||||
/**
|
||||
* Create a new CatalogException.
|
||||
*
|
||||
* @param type The exception type
|
||||
* @param message The error or warning message.
|
||||
*/
|
||||
public CatalogException (int type, String message) {
|
||||
super(message);
|
||||
this.exceptionType = type;
|
||||
this.exception = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new CatalogException.
|
||||
*
|
||||
* @param type The exception type
|
||||
*/
|
||||
public CatalogException (int type) {
|
||||
super("Catalog Exception " + type);
|
||||
this.exceptionType = type;
|
||||
this.exception = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new CatalogException wrapping an existing exception.
|
||||
*
|
||||
* <p>The existing exception will be embedded in the new
|
||||
* one, and its message will become the default message for
|
||||
* the CatalogException.</p>
|
||||
*
|
||||
* @param e The exception to be wrapped in a CatalogException.
|
||||
*/
|
||||
public CatalogException (Exception e) {
|
||||
super();
|
||||
this.exceptionType = WRAPPER;
|
||||
this.exception = e;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new CatalogException from an existing exception.
|
||||
*
|
||||
* <p>The existing exception will be embedded in the new
|
||||
* one, but the new exception will have its own message.</p>
|
||||
*
|
||||
* @param message The detail message.
|
||||
* @param e The exception to be wrapped in a CatalogException.
|
||||
*/
|
||||
public CatalogException (String message, Exception e) {
|
||||
super(message);
|
||||
this.exceptionType = WRAPPER;
|
||||
this.exception = e;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a detail message for this exception.
|
||||
*
|
||||
* <p>If there is an embedded exception, and if the CatalogException
|
||||
* has no detail message of its own, this method will return
|
||||
* the detail message from the embedded exception.</p>
|
||||
*
|
||||
* @return The error or warning message.
|
||||
*/
|
||||
public String getMessage ()
|
||||
{
|
||||
String message = super.getMessage();
|
||||
|
||||
if (message == null && exception != null) {
|
||||
return exception.getMessage();
|
||||
} else {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the embedded exception, if any.
|
||||
*
|
||||
* @return The embedded exception, or null if there is none.
|
||||
*/
|
||||
public Exception getException ()
|
||||
{
|
||||
return exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the exception type
|
||||
*
|
||||
* @return The exception type
|
||||
*/
|
||||
public int getExceptionType ()
|
||||
{
|
||||
return exceptionType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override toString to pick up any embedded exception.
|
||||
*
|
||||
* @return A string representation of this exception.
|
||||
*/
|
||||
public String toString ()
|
||||
{
|
||||
if (exception != null) {
|
||||
return exception.toString();
|
||||
} else {
|
||||
return super.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,870 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.sun.org.apache.xml.internal.resolver;
|
||||
|
||||
import com.sun.org.apache.xerces.internal.utils.SecuritySupport;
|
||||
import com.sun.org.apache.xml.internal.resolver.helpers.BootstrapResolver;
|
||||
import com.sun.org.apache.xml.internal.resolver.helpers.Debug;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.PropertyResourceBundle;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.Vector;
|
||||
import sun.reflect.misc.ReflectUtil;
|
||||
|
||||
/**
|
||||
* CatalogManager provides an interface to the catalog properties.
|
||||
*
|
||||
* <p>Properties can come from two places: from system properties or
|
||||
* from a <i>CatalogManager.properties</i> file. This class provides a transparent
|
||||
* interface to both, with system properties preferred over property file values.</p>
|
||||
*
|
||||
* <p>The following table summarizes the properties:</p>
|
||||
*
|
||||
* <table border="1">
|
||||
* <thead>
|
||||
* <tr>
|
||||
* <td>System Property</td>
|
||||
* <td>CatalogManager.properties<br/>Property</td>
|
||||
* <td>Description</td>
|
||||
* </tr>
|
||||
* </thead>
|
||||
* <tbody>
|
||||
* <tr>
|
||||
* <td>xml.catalog.ignoreMissing</td>
|
||||
* <td> </td>
|
||||
* <td>If true, a missing <i>CatalogManager.properties</i> file or missing properties
|
||||
* within that file will not generate warning messages. See also the
|
||||
* <i>ignoreMissingProperties</i> method.</td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>xml.catalog.files</td>
|
||||
* <td>catalogs</td>
|
||||
* <td>The <emph>semicolon-delimited</emph> list of catalog files.</td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td> </td>
|
||||
* <td>relative-catalogs</td>
|
||||
* <td>If false, relative catalog URIs are made absolute with respect to the base URI of
|
||||
* the <i>CatalogManager.properties</i> file. This setting only applies to catalog
|
||||
* URIs obtained from the <i>catalogs</i> property <emph>in the</emph>
|
||||
* <i>CatalogManager.properties</i> file</td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>xml.catalog.verbosity</td>
|
||||
* <td>verbosity</td>
|
||||
* <td>If non-zero, the Catalog classes will print informative and debugging messages.
|
||||
* The higher the number, the more messages.</td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>xml.catalog.prefer</td>
|
||||
* <td>prefer</td>
|
||||
* <td>Which identifier is preferred, "public" or "system"?</td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>xml.catalog.staticCatalog</td>
|
||||
* <td>static-catalog</td>
|
||||
* <td>Should a single catalog be constructed for all parsing, or should a different
|
||||
* catalog be created for each parser?</td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>xml.catalog.allowPI</td>
|
||||
* <td>allow-oasis-xml-catalog-pi</td>
|
||||
* <td>If the source document contains "oasis-xml-catalog" processing instructions,
|
||||
* should they be used?</td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>xml.catalog.className</td>
|
||||
* <td>catalog-class-name</td>
|
||||
* <td>If you're using the convenience classes
|
||||
* <tt>com.sun.org.apache.xml.internal.resolver.tools.*</tt>), this setting
|
||||
* allows you to specify an alternate class name to use for the underlying
|
||||
* catalog.</td>
|
||||
* </tr>
|
||||
* </tbody>
|
||||
* </table>
|
||||
*
|
||||
* @see Catalog
|
||||
* @deprecated The JDK internal Catalog API in package
|
||||
* {@code com.sun.org.apache.xml.internal.resolver}
|
||||
* is encapsulated in JDK 9. The entire implementation under the package is now
|
||||
* deprecated and subject to removal in a future release. Users of the API
|
||||
* should migrate to the {@linkplain javax.xml.catalog new public API}.
|
||||
* <p>
|
||||
* The new Catalog API is supported throughout the JDK XML Processors, which allows
|
||||
* the use of Catalog by simply setting a path to a Catalog file as a property.
|
||||
*
|
||||
* @author Norman Walsh
|
||||
* <a href="mailto:Norman.Walsh@Sun.COM">Norman.Walsh@Sun.COM</a>
|
||||
*
|
||||
* @version 1.0
|
||||
*/
|
||||
@Deprecated(since="9", forRemoval=true)
|
||||
public class CatalogManager {
|
||||
private static final String pFiles = "xml.catalog.files";
|
||||
private static final String pVerbosity = "xml.catalog.verbosity";
|
||||
private static final String pPrefer = "xml.catalog.prefer";
|
||||
private static final String pStatic = "xml.catalog.staticCatalog";
|
||||
private static final String pAllowPI = "xml.catalog.allowPI";
|
||||
private static final String pClassname = "xml.catalog.className";
|
||||
private static final String pIgnoreMissing = "xml.catalog.ignoreMissing";
|
||||
|
||||
/** A static CatalogManager instance for sharing */
|
||||
private static final CatalogManager staticManager = new CatalogManager();
|
||||
|
||||
/** The bootstrap resolver to use when loading XML Catalogs. */
|
||||
private BootstrapResolver bResolver = new BootstrapResolver();
|
||||
|
||||
/** Flag to ignore missing property files and/or properties */
|
||||
private boolean ignoreMissingProperties
|
||||
= (SecuritySupport.getSystemProperty(pIgnoreMissing) != null
|
||||
|| SecuritySupport.getSystemProperty(pFiles) != null);
|
||||
|
||||
/** Holds the resources after they are loaded from the file. */
|
||||
private ResourceBundle resources;
|
||||
|
||||
/** The name of the CatalogManager properties file. */
|
||||
private String propertyFile = "CatalogManager.properties";
|
||||
|
||||
/** The location of the propertyFile */
|
||||
private URL propertyFileURI = null;
|
||||
|
||||
/** Default catalog files list. */
|
||||
private String defaultCatalogFiles = "./xcatalog";
|
||||
|
||||
/** Current catalog files list. */
|
||||
private String catalogFiles = null;
|
||||
|
||||
/** Did the catalogFiles come from the properties file? */
|
||||
private boolean fromPropertiesFile = false;
|
||||
|
||||
/** Default verbosity level if there is no property setting for it. */
|
||||
private int defaultVerbosity = 1;
|
||||
|
||||
/** Current verbosity level. */
|
||||
private Integer verbosity = null;
|
||||
|
||||
/** Default preference setting. */
|
||||
private boolean defaultPreferPublic = true;
|
||||
|
||||
/** Current preference setting. */
|
||||
private Boolean preferPublic = null;
|
||||
|
||||
/** Default setting of the static catalog flag. */
|
||||
private boolean defaultUseStaticCatalog = true;
|
||||
|
||||
/** Current setting of the static catalog flag. */
|
||||
private Boolean useStaticCatalog = null;
|
||||
|
||||
/** The static catalog used by this manager. */
|
||||
private static volatile Catalog staticCatalog = null;
|
||||
|
||||
/** Default setting of the oasisXMLCatalogPI flag. */
|
||||
private boolean defaultOasisXMLCatalogPI = true;
|
||||
|
||||
/** Current setting of the oasisXMLCatalogPI flag. */
|
||||
private Boolean oasisXMLCatalogPI = null;
|
||||
|
||||
/** Default setting of the relativeCatalogs flag. */
|
||||
private boolean defaultRelativeCatalogs = true;
|
||||
|
||||
/** Current setting of the relativeCatalogs flag. */
|
||||
private Boolean relativeCatalogs = null;
|
||||
|
||||
/** Current catalog class name. */
|
||||
private String catalogClassName = null;
|
||||
/**
|
||||
* Indicates whether implementation parts should use
|
||||
* service loader (or similar).
|
||||
* Note the default value (false) is the safe option..
|
||||
*/
|
||||
private boolean useServicesMechanism;
|
||||
|
||||
/** The manager's debug object. Used for printing debugging messages.
|
||||
*
|
||||
* <p>This field is public so that objects that have access to this
|
||||
* CatalogManager can use this debug object.</p>
|
||||
*/
|
||||
public Debug debug = null;
|
||||
|
||||
/** Constructor. */
|
||||
public CatalogManager() {
|
||||
init();
|
||||
}
|
||||
|
||||
/** Constructor that specifies an explicit property file. */
|
||||
public CatalogManager(String propertyFile) {
|
||||
this.propertyFile = propertyFile;
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
debug = new Debug();
|
||||
// Note that we don't setDebug() here; we do that lazily. Either the
|
||||
// user will set it explicitly, or we'll do it automagically if they
|
||||
// read from the propertyFile for some other reason. That way, there's
|
||||
// no attempt to read from the file before the caller has had a chance
|
||||
// to avoid it.
|
||||
if (System.getSecurityManager() == null) {
|
||||
useServicesMechanism = true;
|
||||
}
|
||||
// Make sure verbosity is set by xml.catalog.verbosity sysprop
|
||||
// setting, if defined.
|
||||
queryVerbosityFromSysProp();
|
||||
}
|
||||
|
||||
/** Set the bootstrap resolver
|
||||
* @param resolver the bootstrap resolver
|
||||
*/
|
||||
public void setBootstrapResolver(BootstrapResolver resolver) {
|
||||
bResolver = resolver;
|
||||
}
|
||||
|
||||
/** Get the bootstrap resolver
|
||||
* @return the bootstrap resolver
|
||||
*/
|
||||
public BootstrapResolver getBootstrapResolver() {
|
||||
return bResolver;
|
||||
}
|
||||
|
||||
/** Query system property for verbosity level. */
|
||||
private void queryVerbosityFromSysProp() {
|
||||
String verbStr = SecuritySupport.getSystemProperty(pVerbosity);
|
||||
if (verbStr != null) {
|
||||
try {
|
||||
int verb = Integer.parseInt(verbStr.trim());
|
||||
verbosity = new Integer(verb);
|
||||
debug.setDebug(verb);
|
||||
} catch (Exception e) {
|
||||
System.err.println("Cannot parse verbosity: \"" + verbStr + "\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the properties from the propertyFile and build the
|
||||
* resources from it.
|
||||
*/
|
||||
private synchronized void readProperties() {
|
||||
try {
|
||||
propertyFileURI = CatalogManager.class.getResource("/"+propertyFile);
|
||||
InputStream in =
|
||||
CatalogManager.class.getResourceAsStream("/"+propertyFile);
|
||||
if (in==null) {
|
||||
if (!ignoreMissingProperties) {
|
||||
System.err.println("Cannot find "+propertyFile);
|
||||
// there's no reason to give this warning more than once
|
||||
ignoreMissingProperties = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
resources = new PropertyResourceBundle(in);
|
||||
} catch (MissingResourceException mre) {
|
||||
if (!ignoreMissingProperties) {
|
||||
System.err.println("Cannot read "+propertyFile);
|
||||
}
|
||||
} catch (java.io.IOException e) {
|
||||
if (!ignoreMissingProperties) {
|
||||
System.err.println("Failure trying to read "+propertyFile);
|
||||
}
|
||||
}
|
||||
|
||||
// This is a bit of a hack. After we've successfully read the properties,
|
||||
// use them to set the default debug level, if the user hasn't already set
|
||||
// the default debug level.
|
||||
if (verbosity == null) {
|
||||
try {
|
||||
String verbStr = resources.getString("verbosity");
|
||||
int verb = Integer.parseInt(verbStr.trim());
|
||||
debug.setDebug(verb);
|
||||
verbosity = new Integer(verb);
|
||||
} catch (Exception e) {
|
||||
// nop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow access to the static CatalogManager
|
||||
*/
|
||||
public static CatalogManager getStaticManager() {
|
||||
return staticManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* How are missing properties handled?
|
||||
*
|
||||
* <p>If true, missing or unreadable property files will
|
||||
* not be reported. Otherwise, a message will be sent to System.err.
|
||||
* </p>
|
||||
*/
|
||||
public boolean getIgnoreMissingProperties() {
|
||||
return ignoreMissingProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* How should missing properties be handled?
|
||||
*
|
||||
* <p>If ignore is true, missing or unreadable property files will
|
||||
* not be reported. Otherwise, a message will be sent to System.err.
|
||||
* </p>
|
||||
*/
|
||||
public void setIgnoreMissingProperties(boolean ignore) {
|
||||
ignoreMissingProperties = ignore;
|
||||
}
|
||||
|
||||
/**
|
||||
* How are missing properties handled?
|
||||
*
|
||||
* <p>If ignore is true, missing or unreadable property files will
|
||||
* not be reported. Otherwise, a message will be sent to System.err.
|
||||
* </p>
|
||||
*
|
||||
* @deprecated No longer static; use get/set methods.
|
||||
*/
|
||||
public void ignoreMissingProperties(boolean ignore) {
|
||||
setIgnoreMissingProperties(ignore);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the verbosity setting from the properties.
|
||||
*
|
||||
* @return The verbosity level from the propertyFile or the
|
||||
* defaultVerbosity.
|
||||
*/
|
||||
private int queryVerbosity () {
|
||||
String defaultVerbStr = Integer.toString(defaultVerbosity);
|
||||
|
||||
String verbStr = SecuritySupport.getSystemProperty(pVerbosity);
|
||||
|
||||
if (verbStr == null) {
|
||||
if (resources==null) readProperties();
|
||||
if (resources != null) {
|
||||
try {
|
||||
verbStr = resources.getString("verbosity");
|
||||
} catch (MissingResourceException e) {
|
||||
verbStr = defaultVerbStr;
|
||||
}
|
||||
} else {
|
||||
verbStr = defaultVerbStr;
|
||||
}
|
||||
}
|
||||
|
||||
int verb = defaultVerbosity;
|
||||
|
||||
try {
|
||||
verb = Integer.parseInt(verbStr.trim());
|
||||
} catch (Exception e) {
|
||||
System.err.println("Cannot parse verbosity: \"" + verbStr + "\"");
|
||||
}
|
||||
|
||||
// This is a bit of a hack. After we've successfully got the verbosity,
|
||||
// we have to use it to set the default debug level,
|
||||
// if the user hasn't already set the default debug level.
|
||||
if (verbosity == null) {
|
||||
debug.setDebug(verb);
|
||||
verbosity = new Integer(verb);
|
||||
}
|
||||
|
||||
return verb;
|
||||
}
|
||||
|
||||
/**
|
||||
* What is the current verbosity?
|
||||
*/
|
||||
public int getVerbosity() {
|
||||
if (verbosity == null) {
|
||||
verbosity = new Integer(queryVerbosity());
|
||||
}
|
||||
|
||||
return verbosity.intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current verbosity.
|
||||
*/
|
||||
public void setVerbosity (int verbosity) {
|
||||
this.verbosity = new Integer(verbosity);
|
||||
debug.setDebug(verbosity);
|
||||
}
|
||||
|
||||
/**
|
||||
* What is the current verbosity?
|
||||
*
|
||||
* @deprecated No longer static; use get/set methods.
|
||||
*/
|
||||
public int verbosity () {
|
||||
return getVerbosity();
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the relativeCatalogs setting from the properties.
|
||||
*
|
||||
* @return The relativeCatalogs setting from the propertyFile or the
|
||||
* defaultRelativeCatalogs.
|
||||
*/
|
||||
private boolean queryRelativeCatalogs () {
|
||||
if (resources==null) readProperties();
|
||||
|
||||
if (resources==null) return defaultRelativeCatalogs;
|
||||
|
||||
try {
|
||||
String allow = resources.getString("relative-catalogs");
|
||||
return (allow.equalsIgnoreCase("true")
|
||||
|| allow.equalsIgnoreCase("yes")
|
||||
|| allow.equalsIgnoreCase("1"));
|
||||
} catch (MissingResourceException e) {
|
||||
return defaultRelativeCatalogs;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the relativeCatalogs setting.
|
||||
*
|
||||
* <p>This property is used when the catalogFiles property is
|
||||
* interrogated. If true, then relative catalog entry file names
|
||||
* are returned. If false, relative catalog entry file names are
|
||||
* made absolute with respect to the properties file before returning
|
||||
* them.</p>
|
||||
*
|
||||
* <p>This property <emph>only applies</emph> when the catalog files
|
||||
* come from a properties file. If they come from a system property or
|
||||
* the default list, they are never considered relative. (What would
|
||||
* they be relative to?)</p>
|
||||
*
|
||||
* <p>In the properties, a value of 'yes', 'true', or '1' is considered
|
||||
* true, anything else is false.</p>
|
||||
*
|
||||
* @return The relativeCatalogs setting from the propertyFile or the
|
||||
* defaultRelativeCatalogs.
|
||||
*/
|
||||
public boolean getRelativeCatalogs () {
|
||||
if (relativeCatalogs == null) {
|
||||
relativeCatalogs = queryRelativeCatalogs() ? Boolean.TRUE : Boolean.FALSE;
|
||||
}
|
||||
|
||||
return relativeCatalogs.booleanValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the relativeCatalogs setting.
|
||||
*
|
||||
* @see #getRelativeCatalogs()
|
||||
*/
|
||||
public void setRelativeCatalogs (boolean relative) {
|
||||
relativeCatalogs = relative ? Boolean.TRUE : Boolean.FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the relativeCatalogs setting.
|
||||
*
|
||||
* @deprecated No longer static; use get/set methods.
|
||||
*/
|
||||
public boolean relativeCatalogs () {
|
||||
return getRelativeCatalogs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the list of catalog files from the properties.
|
||||
*
|
||||
* @return A semicolon delimited list of catlog file URIs
|
||||
*/
|
||||
private String queryCatalogFiles () {
|
||||
String catalogList = SecuritySupport.getSystemProperty(pFiles);
|
||||
fromPropertiesFile = false;
|
||||
|
||||
if (catalogList == null) {
|
||||
if (resources == null) readProperties();
|
||||
if (resources != null) {
|
||||
try {
|
||||
catalogList = resources.getString("catalogs");
|
||||
fromPropertiesFile = true;
|
||||
} catch (MissingResourceException e) {
|
||||
System.err.println(propertyFile + ": catalogs not found.");
|
||||
catalogList = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (catalogList == null) {
|
||||
catalogList = defaultCatalogFiles;
|
||||
}
|
||||
|
||||
return catalogList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current list of catalog files.
|
||||
*
|
||||
* @return A vector of the catalog file names or null if no catalogs
|
||||
* are available in the properties.
|
||||
*/
|
||||
public Vector getCatalogFiles() {
|
||||
if (catalogFiles == null) {
|
||||
catalogFiles = queryCatalogFiles();
|
||||
}
|
||||
|
||||
StringTokenizer files = new StringTokenizer(catalogFiles, ";");
|
||||
Vector catalogs = new Vector();
|
||||
while (files.hasMoreTokens()) {
|
||||
String catalogFile = files.nextToken();
|
||||
URL absURI = null;
|
||||
|
||||
if (fromPropertiesFile && !relativeCatalogs()) {
|
||||
try {
|
||||
absURI = new URL(propertyFileURI, catalogFile);
|
||||
catalogFile = absURI.toString();
|
||||
} catch (MalformedURLException mue) {
|
||||
absURI = null;
|
||||
}
|
||||
}
|
||||
|
||||
catalogs.add(catalogFile);
|
||||
}
|
||||
|
||||
return catalogs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the list of catalog files.
|
||||
*/
|
||||
public void setCatalogFiles(String fileList) {
|
||||
catalogFiles = fileList;
|
||||
fromPropertiesFile = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current list of catalog files.
|
||||
*
|
||||
* @return A vector of the catalog file names or null if no catalogs
|
||||
* are available in the properties.
|
||||
*
|
||||
* @deprecated No longer static; use get/set methods.
|
||||
*/
|
||||
public Vector catalogFiles() {
|
||||
return getCatalogFiles();
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the preferPublic setting from the properties.
|
||||
*
|
||||
* <p>In the properties, a value of 'public' is true,
|
||||
* anything else is false.</p>
|
||||
*
|
||||
* @return True if prefer is public or the
|
||||
* defaultPreferSetting.
|
||||
*/
|
||||
private boolean queryPreferPublic () {
|
||||
String prefer = SecuritySupport.getSystemProperty(pPrefer);
|
||||
|
||||
if (prefer == null) {
|
||||
if (resources==null) readProperties();
|
||||
if (resources==null) return defaultPreferPublic;
|
||||
try {
|
||||
prefer = resources.getString("prefer");
|
||||
} catch (MissingResourceException e) {
|
||||
return defaultPreferPublic;
|
||||
}
|
||||
}
|
||||
|
||||
if (prefer == null) {
|
||||
return defaultPreferPublic;
|
||||
}
|
||||
|
||||
return (prefer.equalsIgnoreCase("public"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current prefer public setting.
|
||||
*
|
||||
* @return True if public identifiers are preferred.
|
||||
*/
|
||||
public boolean getPreferPublic () {
|
||||
if (preferPublic == null) {
|
||||
preferPublic = queryPreferPublic() ? Boolean.TRUE : Boolean.FALSE;
|
||||
}
|
||||
return preferPublic.booleanValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the prefer public setting.
|
||||
*/
|
||||
public void setPreferPublic (boolean preferPublic) {
|
||||
this.preferPublic = preferPublic ? Boolean.TRUE : Boolean.FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current prefer public setting.
|
||||
*
|
||||
* @return True if public identifiers are preferred.
|
||||
*
|
||||
* @deprecated No longer static; use get/set methods.
|
||||
*/
|
||||
public boolean preferPublic () {
|
||||
return getPreferPublic();
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the static-catalog setting from the properties.
|
||||
*
|
||||
* <p>In the properties, a value of 'yes', 'true', or '1' is considered
|
||||
* true, anything else is false.</p>
|
||||
*
|
||||
* @return The static-catalog setting from the propertyFile or the
|
||||
* defaultUseStaticCatalog.
|
||||
*/
|
||||
private boolean queryUseStaticCatalog () {
|
||||
String staticCatalog = SecuritySupport.getSystemProperty(pStatic);
|
||||
|
||||
if (staticCatalog == null) {
|
||||
if (resources==null) readProperties();
|
||||
if (resources==null) return defaultUseStaticCatalog;
|
||||
try {
|
||||
staticCatalog = resources.getString("static-catalog");
|
||||
} catch (MissingResourceException e) {
|
||||
return defaultUseStaticCatalog;
|
||||
}
|
||||
}
|
||||
|
||||
if (staticCatalog == null) {
|
||||
return defaultUseStaticCatalog;
|
||||
}
|
||||
|
||||
return (staticCatalog.equalsIgnoreCase("true")
|
||||
|| staticCatalog.equalsIgnoreCase("yes")
|
||||
|| staticCatalog.equalsIgnoreCase("1"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current use static catalog setting.
|
||||
*/
|
||||
public boolean getUseStaticCatalog() {
|
||||
if (useStaticCatalog == null) {
|
||||
useStaticCatalog = queryUseStaticCatalog() ? Boolean.TRUE : Boolean.FALSE;
|
||||
}
|
||||
|
||||
return useStaticCatalog.booleanValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the use static catalog setting.
|
||||
*/
|
||||
public void setUseStaticCatalog(boolean useStatic) {
|
||||
useStaticCatalog = useStatic ? Boolean.TRUE : Boolean.FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current use static catalog setting.
|
||||
*
|
||||
* @deprecated No longer static; use get/set methods.
|
||||
*/
|
||||
public boolean staticCatalog() {
|
||||
return getUseStaticCatalog();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a new catalog instance.
|
||||
*
|
||||
* This method always returns a new instance of the underlying catalog class.
|
||||
*/
|
||||
public Catalog getPrivateCatalog() {
|
||||
Catalog catalog = staticCatalog;
|
||||
|
||||
if (useStaticCatalog == null) {
|
||||
useStaticCatalog = getUseStaticCatalog() ? Boolean.TRUE : Boolean.FALSE;
|
||||
}
|
||||
|
||||
if (catalog == null || !useStaticCatalog.booleanValue()) {
|
||||
|
||||
try {
|
||||
String catalogClassName = getCatalogClassName();
|
||||
|
||||
if (catalogClassName == null) {
|
||||
catalog = new Catalog();
|
||||
} else {
|
||||
try {
|
||||
catalog = (Catalog) ReflectUtil.forName(catalogClassName).newInstance();
|
||||
} catch (ClassNotFoundException cnfe) {
|
||||
debug.message(1,"Catalog class named '"
|
||||
+ catalogClassName
|
||||
+ "' could not be found. Using default.");
|
||||
catalog = new Catalog();
|
||||
} catch (ClassCastException cnfe) {
|
||||
debug.message(1,"Class named '"
|
||||
+ catalogClassName
|
||||
+ "' is not a Catalog. Using default.");
|
||||
catalog = new Catalog();
|
||||
}
|
||||
}
|
||||
|
||||
catalog.setCatalogManager(this);
|
||||
catalog.setupReaders();
|
||||
catalog.loadSystemCatalogs();
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
if (useStaticCatalog.booleanValue()) {
|
||||
staticCatalog = catalog;
|
||||
}
|
||||
}
|
||||
|
||||
return catalog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a catalog instance.
|
||||
*
|
||||
* If this manager uses static catalogs, the same static catalog will
|
||||
* always be returned. Otherwise a new catalog will be returned.
|
||||
*/
|
||||
public Catalog getCatalog() {
|
||||
Catalog catalog = staticCatalog;
|
||||
|
||||
if (useStaticCatalog == null) {
|
||||
useStaticCatalog = getUseStaticCatalog() ? Boolean.TRUE : Boolean.FALSE;
|
||||
}
|
||||
|
||||
if (catalog == null || !useStaticCatalog.booleanValue()) {
|
||||
catalog = getPrivateCatalog();
|
||||
if (useStaticCatalog.booleanValue()) {
|
||||
staticCatalog = catalog;
|
||||
}
|
||||
}
|
||||
|
||||
return catalog;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Obtain the oasisXMLCatalogPI setting from the properties.</p>
|
||||
*
|
||||
* <p>In the properties, a value of 'yes', 'true', or '1' is considered
|
||||
* true, anything else is false.</p>
|
||||
*
|
||||
* @return The oasisXMLCatalogPI setting from the propertyFile or the
|
||||
* defaultOasisXMLCatalogPI.
|
||||
*/
|
||||
public boolean queryAllowOasisXMLCatalogPI () {
|
||||
String allow = SecuritySupport.getSystemProperty(pAllowPI);
|
||||
|
||||
if (allow == null) {
|
||||
if (resources==null) readProperties();
|
||||
if (resources==null) return defaultOasisXMLCatalogPI;
|
||||
try {
|
||||
allow = resources.getString("allow-oasis-xml-catalog-pi");
|
||||
} catch (MissingResourceException e) {
|
||||
return defaultOasisXMLCatalogPI;
|
||||
}
|
||||
}
|
||||
|
||||
if (allow == null) {
|
||||
return defaultOasisXMLCatalogPI;
|
||||
}
|
||||
|
||||
return (allow.equalsIgnoreCase("true")
|
||||
|| allow.equalsIgnoreCase("yes")
|
||||
|| allow.equalsIgnoreCase("1"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current XML Catalog PI setting.
|
||||
*/
|
||||
public boolean getAllowOasisXMLCatalogPI () {
|
||||
if (oasisXMLCatalogPI == null) {
|
||||
oasisXMLCatalogPI = queryAllowOasisXMLCatalogPI() ? Boolean.TRUE : Boolean.FALSE;
|
||||
}
|
||||
|
||||
return oasisXMLCatalogPI.booleanValue();
|
||||
}
|
||||
|
||||
public boolean useServicesMechanism() {
|
||||
return useServicesMechanism;
|
||||
}
|
||||
/**
|
||||
* Set the XML Catalog PI setting
|
||||
*/
|
||||
public void setAllowOasisXMLCatalogPI(boolean allowPI) {
|
||||
oasisXMLCatalogPI = allowPI ? Boolean.TRUE : Boolean.FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current XML Catalog PI setting.
|
||||
*
|
||||
* @deprecated No longer static; use get/set methods.
|
||||
*/
|
||||
public boolean allowOasisXMLCatalogPI() {
|
||||
return getAllowOasisXMLCatalogPI();
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the Catalog class name setting from the properties.
|
||||
*
|
||||
*/
|
||||
public String queryCatalogClassName () {
|
||||
String className = SecuritySupport.getSystemProperty(pClassname);
|
||||
|
||||
if (className == null) {
|
||||
if (resources==null) readProperties();
|
||||
if (resources==null) return null;
|
||||
try {
|
||||
return resources.getString("catalog-class-name");
|
||||
} catch (MissingResourceException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return className;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current Catalog class name.
|
||||
*/
|
||||
public String getCatalogClassName() {
|
||||
if (catalogClassName == null) {
|
||||
catalogClassName = queryCatalogClassName();
|
||||
}
|
||||
|
||||
return catalogClassName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Catalog class name.
|
||||
*/
|
||||
public void setCatalogClassName(String className) {
|
||||
catalogClassName = className;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current Catalog class name.
|
||||
*
|
||||
* @deprecated No longer static; use get/set methods.
|
||||
*/
|
||||
public String catalogClassName() {
|
||||
return getCatalogClassName();
|
||||
}
|
||||
}
|
||||
@ -1,697 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.sun.org.apache.xml.internal.resolver;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Vector;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
import com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl;
|
||||
import com.sun.org.apache.xerces.internal.utils.SecuritySupport;
|
||||
import com.sun.org.apache.xml.internal.resolver.readers.SAXCatalogReader;
|
||||
import com.sun.org.apache.xml.internal.resolver.readers.OASISXMLCatalogReader;
|
||||
import com.sun.org.apache.xml.internal.resolver.readers.TR9401CatalogReader;
|
||||
|
||||
/**
|
||||
* An extension to OASIS Open Catalog files, this class supports
|
||||
* suffix-based matching and an external RFC2483 resolver.
|
||||
*
|
||||
* @see Catalog
|
||||
* @deprecated The JDK internal Catalog API in package
|
||||
* {@code com.sun.org.apache.xml.internal.resolver}
|
||||
* is encapsulated in JDK 9. The entire implementation under the package is now
|
||||
* deprecated and subject to removal in a future release. Users of the API
|
||||
* should migrate to the {@linkplain javax.xml.catalog new public API}.
|
||||
* <p>
|
||||
* The new Catalog API is supported throughout the JDK XML Processors, which allows
|
||||
* the use of Catalog by simply setting a path to a Catalog file as a property.
|
||||
*
|
||||
* @author Norman Walsh
|
||||
* <a href="mailto:Norman.Walsh@Sun.COM">Norman.Walsh@Sun.COM</a>
|
||||
*
|
||||
* @version 1.0
|
||||
*/
|
||||
@Deprecated(since="9", forRemoval=true)
|
||||
public class Resolver extends Catalog {
|
||||
/**
|
||||
* The URISUFFIX Catalog Entry type.
|
||||
*
|
||||
* <p>URI suffix entries match URIs that end in a specified suffix.</p>
|
||||
*/
|
||||
public static final int URISUFFIX = CatalogEntry.addEntryType("URISUFFIX", 2);
|
||||
|
||||
/**
|
||||
* The SYSTEMSUFFIX Catalog Entry type.
|
||||
*
|
||||
* <p>System suffix entries match system identifiers that end in a
|
||||
* specified suffix.</p>
|
||||
*/
|
||||
public static final int SYSTEMSUFFIX = CatalogEntry.addEntryType("SYSTEMSUFFIX", 2);
|
||||
|
||||
/**
|
||||
* The RESOLVER Catalog Entry type.
|
||||
*
|
||||
* <p>A hook for providing support for web-based backup resolvers.</p>
|
||||
*/
|
||||
public static final int RESOLVER = CatalogEntry.addEntryType("RESOLVER", 1);
|
||||
|
||||
/**
|
||||
* The SYSTEMREVERSE Catalog Entry type.
|
||||
*
|
||||
* <p>This is a bit of a hack. There's no actual SYSTEMREVERSE entry,
|
||||
* but this entry type is used to indicate that a reverse lookup is
|
||||
* being performed. (This allows the Resolver to implement
|
||||
* RFC2483 I2N and I2NS.)
|
||||
*/
|
||||
public static final int SYSTEMREVERSE
|
||||
= CatalogEntry.addEntryType("SYSTEMREVERSE", 1);
|
||||
|
||||
/**
|
||||
* Setup readers.
|
||||
*/
|
||||
public void setupReaders() {
|
||||
SAXParserFactory spf = catalogManager.useServicesMechanism() ?
|
||||
SAXParserFactory.newInstance() : new SAXParserFactoryImpl();
|
||||
spf.setNamespaceAware(true);
|
||||
spf.setValidating(false);
|
||||
|
||||
SAXCatalogReader saxReader = new SAXCatalogReader(spf);
|
||||
|
||||
saxReader.setCatalogParser(null, "XCatalog",
|
||||
"com.sun.org.apache.xml.internal.resolver.readers.XCatalogReader");
|
||||
|
||||
saxReader.setCatalogParser(OASISXMLCatalogReader.namespaceName,
|
||||
"catalog",
|
||||
"com.sun.org.apache.xml.internal.resolver.readers.ExtendedXMLCatalogReader");
|
||||
|
||||
addReader("application/xml", saxReader);
|
||||
|
||||
TR9401CatalogReader textReader = new TR9401CatalogReader();
|
||||
addReader("text/plain", textReader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup and process a Catalog entry.
|
||||
*
|
||||
* <p>This method processes each Catalog entry, changing mapped
|
||||
* relative system identifiers into absolute ones (based on the current
|
||||
* base URI), and maintaining other information about the current
|
||||
* catalog.</p>
|
||||
*
|
||||
* @param entry The CatalogEntry to process.
|
||||
*/
|
||||
public void addEntry(CatalogEntry entry) {
|
||||
int type = entry.getEntryType();
|
||||
|
||||
if (type == URISUFFIX) {
|
||||
String suffix = normalizeURI(entry.getEntryArg(0));
|
||||
String fsi = makeAbsolute(normalizeURI(entry.getEntryArg(1)));
|
||||
|
||||
entry.setEntryArg(1, fsi);
|
||||
|
||||
catalogManager.debug.message(4, "URISUFFIX", suffix, fsi);
|
||||
} else if (type == SYSTEMSUFFIX) {
|
||||
String suffix = normalizeURI(entry.getEntryArg(0));
|
||||
String fsi = makeAbsolute(normalizeURI(entry.getEntryArg(1)));
|
||||
|
||||
entry.setEntryArg(1, fsi);
|
||||
|
||||
catalogManager.debug.message(4, "SYSTEMSUFFIX", suffix, fsi);
|
||||
}
|
||||
|
||||
super.addEntry(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the applicable URI.
|
||||
*
|
||||
* <p>If a URI entry exists in the Catalog
|
||||
* for the URI specified, return the mapped value.</p>
|
||||
*
|
||||
* <p>In the Resolver (as opposed to the Catalog) class, if the
|
||||
* URI isn't found by the usual algorithm, URISUFFIX entries are
|
||||
* considered.</p>
|
||||
*
|
||||
* <p>URI comparison is case sensitive.</p>
|
||||
*
|
||||
* @param uri The URI to locate in the catalog.
|
||||
*
|
||||
* @return The resolved URI.
|
||||
*
|
||||
* @throws MalformedURLException The system identifier of a
|
||||
* subordinate catalog cannot be turned into a valid URL.
|
||||
* @throws IOException Error reading subordinate catalog file.
|
||||
*/
|
||||
public String resolveURI(String uri)
|
||||
throws MalformedURLException, IOException {
|
||||
|
||||
String resolved = super.resolveURI(uri);
|
||||
if (resolved != null) {
|
||||
return resolved;
|
||||
}
|
||||
|
||||
Enumeration en = catalogEntries.elements();
|
||||
while (en.hasMoreElements()) {
|
||||
CatalogEntry e = (CatalogEntry) en.nextElement();
|
||||
if (e.getEntryType() == RESOLVER) {
|
||||
resolved = resolveExternalSystem(uri, e.getEntryArg(0));
|
||||
if (resolved != null) {
|
||||
return resolved;
|
||||
}
|
||||
} else if (e.getEntryType() == URISUFFIX) {
|
||||
String suffix = e.getEntryArg(0);
|
||||
String result = e.getEntryArg(1);
|
||||
|
||||
if (suffix.length() <= uri.length()
|
||||
&& uri.substring(uri.length()-suffix.length()).equals(suffix)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, look in the subordinate catalogs
|
||||
return resolveSubordinateCatalogs(Catalog.URI,
|
||||
null,
|
||||
null,
|
||||
uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the applicable SYSTEM system identifier, resorting
|
||||
* to external RESOLVERs if necessary.
|
||||
*
|
||||
* <p>If a SYSTEM entry exists in the Catalog
|
||||
* for the system ID specified, return the mapped value.</p>
|
||||
*
|
||||
* <p>In the Resolver (as opposed to the Catalog) class, if the
|
||||
* URI isn't found by the usual algorithm, SYSTEMSUFFIX entries are
|
||||
* considered.</p>
|
||||
*
|
||||
* <p>On Windows-based operating systems, the comparison between
|
||||
* the system identifier provided and the SYSTEM entries in the
|
||||
* Catalog is case-insensitive.</p>
|
||||
*
|
||||
* @param systemId The system ID to locate in the catalog.
|
||||
*
|
||||
* @return The system identifier to use for systemId.
|
||||
*
|
||||
* @throws MalformedURLException The formal system identifier of a
|
||||
* subordinate catalog cannot be turned into a valid URL.
|
||||
* @throws IOException Error reading subordinate catalog file.
|
||||
*/
|
||||
public String resolveSystem(String systemId)
|
||||
throws MalformedURLException, IOException {
|
||||
|
||||
String resolved = super.resolveSystem(systemId);
|
||||
if (resolved != null) {
|
||||
return resolved;
|
||||
}
|
||||
|
||||
Enumeration en = catalogEntries.elements();
|
||||
while (en.hasMoreElements()) {
|
||||
CatalogEntry e = (CatalogEntry) en.nextElement();
|
||||
if (e.getEntryType() == RESOLVER) {
|
||||
resolved = resolveExternalSystem(systemId, e.getEntryArg(0));
|
||||
if (resolved != null) {
|
||||
return resolved;
|
||||
}
|
||||
} else if (e.getEntryType() == SYSTEMSUFFIX) {
|
||||
String suffix = e.getEntryArg(0);
|
||||
String result = e.getEntryArg(1);
|
||||
|
||||
if (suffix.length() <= systemId.length()
|
||||
&& systemId.substring(systemId.length()-suffix.length()).equals(suffix)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return resolveSubordinateCatalogs(Catalog.SYSTEM,
|
||||
null,
|
||||
null,
|
||||
systemId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the applicable PUBLIC or SYSTEM identifier, resorting
|
||||
* to external resolvers if necessary.
|
||||
*
|
||||
* <p>This method searches the Catalog and returns the system
|
||||
* identifier specified for the given system or
|
||||
* public identifiers. If
|
||||
* no appropriate PUBLIC or SYSTEM entry is found in the Catalog,
|
||||
* null is returned.</p>
|
||||
*
|
||||
* <p>Note that a system or public identifier in the current catalog
|
||||
* (or subordinate catalogs) will be used in preference to an
|
||||
* external resolver. Further, if a systemId is present, the external
|
||||
* resolver(s) will be queried for that before the publicId.</p>
|
||||
*
|
||||
* @param publicId The public identifier to locate in the catalog.
|
||||
* Public identifiers are normalized before comparison.
|
||||
* @param systemId The nominal system identifier for the entity
|
||||
* in question (as provided in the source document).
|
||||
*
|
||||
* @throws MalformedURLException The formal system identifier of a
|
||||
* subordinate catalog cannot be turned into a valid URL.
|
||||
* @throws IOException Error reading subordinate catalog file.
|
||||
*
|
||||
* @return The system identifier to use.
|
||||
* Note that the nominal system identifier is not returned if a
|
||||
* match is not found in the catalog, instead null is returned
|
||||
* to indicate that no match was found.
|
||||
*/
|
||||
public String resolvePublic(String publicId, String systemId)
|
||||
throws MalformedURLException, IOException {
|
||||
|
||||
String resolved = super.resolvePublic(publicId, systemId);
|
||||
if (resolved != null) {
|
||||
return resolved;
|
||||
}
|
||||
|
||||
Enumeration en = catalogEntries.elements();
|
||||
while (en.hasMoreElements()) {
|
||||
CatalogEntry e = (CatalogEntry) en.nextElement();
|
||||
if (e.getEntryType() == RESOLVER) {
|
||||
if (systemId != null) {
|
||||
resolved = resolveExternalSystem(systemId,
|
||||
e.getEntryArg(0));
|
||||
if (resolved != null) {
|
||||
return resolved;
|
||||
}
|
||||
}
|
||||
resolved = resolveExternalPublic(publicId, e.getEntryArg(0));
|
||||
if (resolved != null) {
|
||||
return resolved;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return resolveSubordinateCatalogs(Catalog.PUBLIC,
|
||||
null,
|
||||
publicId,
|
||||
systemId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query an external RFC2483 resolver for a system identifier.
|
||||
*
|
||||
* @param systemId The system ID to locate.
|
||||
* @param resolver The name of the resolver to use.
|
||||
*
|
||||
* @return The system identifier to use for the systemId.
|
||||
*/
|
||||
protected String resolveExternalSystem(String systemId, String resolver)
|
||||
throws MalformedURLException, IOException {
|
||||
Resolver r = queryResolver(resolver, "i2l", systemId, null);
|
||||
if (r != null) {
|
||||
return r.resolveSystem(systemId);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Query an external RFC2483 resolver for a public identifier.
|
||||
*
|
||||
* @param publicId The system ID to locate.
|
||||
* @param resolver The name of the resolver to use.
|
||||
*
|
||||
* @return The system identifier to use for the systemId.
|
||||
*/
|
||||
protected String resolveExternalPublic(String publicId, String resolver)
|
||||
throws MalformedURLException, IOException {
|
||||
Resolver r = queryResolver(resolver, "fpi2l", publicId, null);
|
||||
if (r != null) {
|
||||
return r.resolvePublic(publicId, null);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Query an external RFC2483 resolver.
|
||||
*
|
||||
* @param resolver The URL of the RFC2483 resolver.
|
||||
* @param command The command to send the resolver.
|
||||
* @param arg1 The first argument to the resolver.
|
||||
* @param arg2 The second argument to the resolver, usually null.
|
||||
*
|
||||
* @return The Resolver constructed.
|
||||
*/
|
||||
protected Resolver queryResolver(String resolver,
|
||||
String command,
|
||||
String arg1,
|
||||
String arg2) {
|
||||
InputStream iStream = null;
|
||||
String RFC2483 = resolver + "?command=" + command
|
||||
+ "&format=tr9401&uri=" + arg1
|
||||
+ "&uri2=" + arg2;
|
||||
String line = null;
|
||||
|
||||
try {
|
||||
URL url = new URL(RFC2483);
|
||||
|
||||
URLConnection urlCon = url.openConnection();
|
||||
|
||||
urlCon.setUseCaches(false);
|
||||
|
||||
Resolver r = (Resolver) newCatalog();
|
||||
|
||||
String cType = urlCon.getContentType();
|
||||
|
||||
// I don't care about the character set or subtype
|
||||
if (cType.indexOf(";") > 0) {
|
||||
cType = cType.substring(0, cType.indexOf(";"));
|
||||
}
|
||||
|
||||
r.parseCatalog(cType, urlCon.getInputStream());
|
||||
|
||||
return r;
|
||||
} catch (CatalogException cex) {
|
||||
if (cex.getExceptionType() == CatalogException.UNPARSEABLE) {
|
||||
catalogManager.debug.message(1, "Unparseable catalog: " + RFC2483);
|
||||
} else if (cex.getExceptionType()
|
||||
== CatalogException.UNKNOWN_FORMAT) {
|
||||
catalogManager.debug.message(1, "Unknown catalog format: " + RFC2483);
|
||||
}
|
||||
return null;
|
||||
} catch (MalformedURLException mue) {
|
||||
catalogManager.debug.message(1, "Malformed resolver URL: " + RFC2483);
|
||||
return null;
|
||||
} catch (IOException ie) {
|
||||
catalogManager.debug.message(1, "I/O Exception opening resolver: " + RFC2483);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Append two vectors, returning the result.
|
||||
*
|
||||
* @param vec The first vector
|
||||
* @param appvec The vector to be appended
|
||||
* @return The vector vec, with appvec's elements appended to it
|
||||
*/
|
||||
private Vector appendVector(Vector vec, Vector appvec) {
|
||||
if (appvec != null) {
|
||||
for (int count = 0; count < appvec.size(); count++) {
|
||||
vec.addElement(appvec.elementAt(count));
|
||||
}
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the URNs for a given system identifier in all catalogs.
|
||||
*
|
||||
* @param systemId The system ID to locate.
|
||||
*
|
||||
* @return A vector of URNs that map to the systemId.
|
||||
*/
|
||||
public Vector resolveAllSystemReverse(String systemId)
|
||||
throws MalformedURLException, IOException {
|
||||
Vector resolved = new Vector();
|
||||
|
||||
// If there's a SYSTEM entry in this catalog, use it
|
||||
if (systemId != null) {
|
||||
Vector localResolved = resolveLocalSystemReverse(systemId);
|
||||
resolved = appendVector(resolved, localResolved);
|
||||
}
|
||||
|
||||
// Otherwise, look in the subordinate catalogs
|
||||
Vector subResolved = resolveAllSubordinateCatalogs(SYSTEMREVERSE,
|
||||
null,
|
||||
null,
|
||||
systemId);
|
||||
|
||||
return appendVector(resolved, subResolved);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the URN for a given system identifier.
|
||||
*
|
||||
* @param systemId The system ID to locate.
|
||||
*
|
||||
* @return A (single) URN that maps to the systemId.
|
||||
*/
|
||||
public String resolveSystemReverse(String systemId)
|
||||
throws MalformedURLException, IOException {
|
||||
Vector resolved = resolveAllSystemReverse(systemId);
|
||||
if (resolved != null && resolved.size() > 0) {
|
||||
return (String) resolved.elementAt(0);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the applicable SYSTEM system identifiers.
|
||||
*
|
||||
* <p>If one or more SYSTEM entries exists in the Catalog
|
||||
* for the system ID specified, return the mapped values.</p>
|
||||
*
|
||||
* <p>The caller is responsible for doing any necessary
|
||||
* normalization of the system identifier before calling
|
||||
* this method. For example, a relative system identifier in
|
||||
* a document might be converted to an absolute system identifier
|
||||
* before attempting to resolve it.</p>
|
||||
*
|
||||
* <p>Note that this function will force all subordinate catalogs
|
||||
* to be loaded.</p>
|
||||
*
|
||||
* <p>On Windows-based operating systems, the comparison between
|
||||
* the system identifier provided and the SYSTEM entries in the
|
||||
* Catalog is case-insensitive.</p>
|
||||
*
|
||||
* @param systemId The system ID to locate in the catalog.
|
||||
*
|
||||
* @return The system identifier to use for the notation.
|
||||
*
|
||||
* @throws MalformedURLException The formal system identifier of a
|
||||
* subordinate catalog cannot be turned into a valid URL.
|
||||
* @throws IOException Error reading subordinate catalog file.
|
||||
*/
|
||||
public Vector resolveAllSystem(String systemId)
|
||||
throws MalformedURLException, IOException {
|
||||
Vector resolutions = new Vector();
|
||||
|
||||
// If there are SYSTEM entries in this catalog, start with them
|
||||
if (systemId != null) {
|
||||
Vector localResolutions = resolveAllLocalSystem(systemId);
|
||||
resolutions = appendVector(resolutions, localResolutions);
|
||||
}
|
||||
|
||||
// Then look in the subordinate catalogs
|
||||
Vector subResolutions = resolveAllSubordinateCatalogs(SYSTEM,
|
||||
null,
|
||||
null,
|
||||
systemId);
|
||||
resolutions = appendVector(resolutions, subResolutions);
|
||||
|
||||
if (resolutions.size() > 0) {
|
||||
return resolutions;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all applicable SYSTEM system identifiers in this
|
||||
* catalog.
|
||||
*
|
||||
* <p>If one or more SYSTEM entries exists in the catalog file
|
||||
* for the system ID specified, return the mapped values.</p>
|
||||
*
|
||||
* @param systemId The system ID to locate in the catalog
|
||||
*
|
||||
* @return A vector of the mapped system identifiers or null
|
||||
*/
|
||||
private Vector resolveAllLocalSystem(String systemId) {
|
||||
Vector map = new Vector();
|
||||
String osname = SecuritySupport.getSystemProperty("os.name");
|
||||
boolean windows = (osname.indexOf("Windows") >= 0);
|
||||
Enumeration en = catalogEntries.elements();
|
||||
while (en.hasMoreElements()) {
|
||||
CatalogEntry e = (CatalogEntry) en.nextElement();
|
||||
if (e.getEntryType() == SYSTEM
|
||||
&& (e.getEntryArg(0).equals(systemId)
|
||||
|| (windows
|
||||
&& e.getEntryArg(0).equalsIgnoreCase(systemId)))) {
|
||||
map.addElement(e.getEntryArg(1));
|
||||
}
|
||||
}
|
||||
if (map.size() == 0) {
|
||||
return null;
|
||||
} else {
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the URNs for a given system identifier in the current catalog.
|
||||
*
|
||||
* @param systemId The system ID to locate.
|
||||
*
|
||||
* @return A vector of URNs that map to the systemId.
|
||||
*/
|
||||
private Vector resolveLocalSystemReverse(String systemId) {
|
||||
Vector map = new Vector();
|
||||
String osname = SecuritySupport.getSystemProperty("os.name");
|
||||
boolean windows = (osname.indexOf("Windows") >= 0);
|
||||
Enumeration en = catalogEntries.elements();
|
||||
while (en.hasMoreElements()) {
|
||||
CatalogEntry e = (CatalogEntry) en.nextElement();
|
||||
if (e.getEntryType() == SYSTEM
|
||||
&& (e.getEntryArg(1).equals(systemId)
|
||||
|| (windows
|
||||
&& e.getEntryArg(1).equalsIgnoreCase(systemId)))) {
|
||||
map.addElement(e.getEntryArg(0));
|
||||
}
|
||||
}
|
||||
if (map.size() == 0) {
|
||||
return null;
|
||||
} else {
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Search the subordinate catalogs, in order, looking for all
|
||||
* match.
|
||||
*
|
||||
* <p>This method searches the Catalog and returns all of the system
|
||||
* identifiers specified for the given entity type with the given
|
||||
* name, public, and system identifiers. In some contexts, these
|
||||
* may be null.</p>
|
||||
*
|
||||
* @param entityType The CatalogEntry type for which this query is
|
||||
* being conducted. This is necessary in order to do the approprate
|
||||
* query on a subordinate catalog.
|
||||
* @param entityName The name of the entity being searched for, if
|
||||
* appropriate.
|
||||
* @param publicId The public identifier of the entity in question
|
||||
* (as provided in the source document).
|
||||
* @param systemId The nominal system identifier for the entity
|
||||
* in question (as provided in the source document).
|
||||
*
|
||||
* @throws MalformedURLException The formal system identifier of a
|
||||
* delegated catalog cannot be turned into a valid URL.
|
||||
* @throws IOException Error reading delegated catalog file.
|
||||
*
|
||||
* @return The system identifier to use.
|
||||
* Note that the nominal system identifier is not returned if a
|
||||
* match is not found in the catalog, instead null is returned
|
||||
* to indicate that no match was found.
|
||||
*/
|
||||
private synchronized Vector resolveAllSubordinateCatalogs(int entityType,
|
||||
String entityName,
|
||||
String publicId,
|
||||
String systemId)
|
||||
throws MalformedURLException, IOException {
|
||||
|
||||
Vector resolutions = new Vector();
|
||||
|
||||
for (int catPos = 0; catPos < catalogs.size(); catPos++) {
|
||||
Resolver c = null;
|
||||
|
||||
try {
|
||||
c = (Resolver) catalogs.elementAt(catPos);
|
||||
} catch (ClassCastException e) {
|
||||
String catfile = (String) catalogs.elementAt(catPos);
|
||||
c = (Resolver) newCatalog();
|
||||
|
||||
try {
|
||||
c.parseCatalog(catfile);
|
||||
} catch (MalformedURLException mue) {
|
||||
catalogManager.debug.message(1, "Malformed Catalog URL", catfile);
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
catalogManager.debug.message(1, "Failed to load catalog, file not found",
|
||||
catfile);
|
||||
} catch (IOException ioe) {
|
||||
catalogManager.debug.message(1, "Failed to load catalog, I/O error", catfile);
|
||||
}
|
||||
|
||||
catalogs.setElementAt(c, catPos);
|
||||
}
|
||||
|
||||
String resolved = null;
|
||||
|
||||
// Ok, now what are we supposed to call here?
|
||||
if (entityType == DOCTYPE) {
|
||||
resolved = c.resolveDoctype(entityName,
|
||||
publicId,
|
||||
systemId);
|
||||
if (resolved != null) {
|
||||
// Only find one DOCTYPE resolution
|
||||
resolutions.addElement(resolved);
|
||||
return resolutions;
|
||||
}
|
||||
} else if (entityType == DOCUMENT) {
|
||||
resolved = c.resolveDocument();
|
||||
if (resolved != null) {
|
||||
// Only find one DOCUMENT resolution
|
||||
resolutions.addElement(resolved);
|
||||
return resolutions;
|
||||
}
|
||||
} else if (entityType == ENTITY) {
|
||||
resolved = c.resolveEntity(entityName,
|
||||
publicId,
|
||||
systemId);
|
||||
if (resolved != null) {
|
||||
// Only find one ENTITY resolution
|
||||
resolutions.addElement(resolved);
|
||||
return resolutions;
|
||||
}
|
||||
} else if (entityType == NOTATION) {
|
||||
resolved = c.resolveNotation(entityName,
|
||||
publicId,
|
||||
systemId);
|
||||
if (resolved != null) {
|
||||
// Only find one NOTATION resolution
|
||||
resolutions.addElement(resolved);
|
||||
return resolutions;
|
||||
}
|
||||
} else if (entityType == PUBLIC) {
|
||||
resolved = c.resolvePublic(publicId, systemId);
|
||||
if (resolved != null) {
|
||||
// Only find one PUBLIC resolution
|
||||
resolutions.addElement(resolved);
|
||||
return resolutions;
|
||||
}
|
||||
} else if (entityType == SYSTEM) {
|
||||
Vector localResolutions = c.resolveAllSystem(systemId);
|
||||
resolutions = appendVector(resolutions, localResolutions);
|
||||
break;
|
||||
} else if (entityType == SYSTEMREVERSE) {
|
||||
Vector localResolutions = c.resolveAllSystemReverse(systemId);
|
||||
resolutions = appendVector(resolutions, localResolutions);
|
||||
}
|
||||
}
|
||||
|
||||
if (resolutions != null) {
|
||||
return resolutions;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,207 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
*/
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.sun.org.apache.xml.internal.resolver.helpers;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.URIResolver;
|
||||
import javax.xml.transform.sax.SAXSource;
|
||||
import org.xml.sax.EntityResolver;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
/**
|
||||
* A simple bootstrapping resolver.
|
||||
*
|
||||
* <p>This class is used as the entity resolver when reading XML Catalogs.
|
||||
* It searches for the OASIS XML Catalog DTD, Relax NG Grammar and W3C XML Schema
|
||||
* as resources (e.g., in the resolver jar file).</p>
|
||||
*
|
||||
* <p>If you have your own DTDs or schemas, you can extend this class and
|
||||
* set the BootstrapResolver in your CatalogManager.</p>
|
||||
*
|
||||
* @see com.sun.org.apache.xml.internal.resolver.CatalogManager
|
||||
*
|
||||
* @author Norman Walsh
|
||||
* <a href="mailto:Norman.Walsh@Sun.COM">Norman.Walsh@Sun.COM</a>
|
||||
*
|
||||
*/
|
||||
public class BootstrapResolver implements EntityResolver, URIResolver {
|
||||
/** URI of the W3C XML Schema for OASIS XML Catalog files. */
|
||||
public static final String xmlCatalogXSD = "http://www.oasis-open.org/committees/entity/release/1.0/catalog.xsd";
|
||||
|
||||
/** URI of the RELAX NG Grammar for OASIS XML Catalog files. */
|
||||
public static final String xmlCatalogRNG = "http://www.oasis-open.org/committees/entity/release/1.0/catalog.rng";
|
||||
|
||||
/** Public identifier for OASIS XML Catalog files. */
|
||||
public static final String xmlCatalogPubId = "-//OASIS//DTD XML Catalogs V1.0//EN";
|
||||
|
||||
/** System identifier for OASIS XML Catalog files. */
|
||||
public static final String xmlCatalogSysId = "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd";
|
||||
|
||||
/** Public identifier for legacy Apache XCatalog files. There is no official system identifier for XCatalog files. */
|
||||
public static final String xCatalogPubId = "-//DTD XCatalog//EN";
|
||||
|
||||
/** Private hash used for public identifiers. */
|
||||
private final Map<String, String> publicMap = new HashMap<>();
|
||||
|
||||
/** Private hash used for system identifiers. */
|
||||
private final Map<String, String> systemMap = new HashMap<>();
|
||||
|
||||
/** Private hash used for URIs. */
|
||||
private final Map<String, String> uriMap = new HashMap<>();
|
||||
|
||||
/** Constructor. */
|
||||
public BootstrapResolver() {
|
||||
URL url = this.getClass().getResource("/com/sun/org/apache/xml/internal/resolver/etc/catalog.dtd");
|
||||
if (url != null) {
|
||||
publicMap.put(xmlCatalogPubId, url.toString());
|
||||
systemMap.put(xmlCatalogSysId, url.toString());
|
||||
}
|
||||
|
||||
url = this.getClass().getResource("/com/sun/org/apache/xml/internal/resolver/etc/catalog.rng");
|
||||
if (url != null) {
|
||||
uriMap.put(xmlCatalogRNG, url.toString());
|
||||
}
|
||||
|
||||
url = this.getClass().getResource("/com/sun/org/apache/xml/internal/resolver/etc/catalog.xsd");
|
||||
if (url != null) {
|
||||
uriMap.put(xmlCatalogXSD, url.toString());
|
||||
}
|
||||
|
||||
url = this.getClass().getResource("/com/sun/org/apache/xml/internal/resolver/etc/xcatalog.dtd");
|
||||
if (url != null) {
|
||||
publicMap.put(xCatalogPubId, url.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/** SAX resolveEntity API. */
|
||||
public InputSource resolveEntity (String publicId, String systemId) {
|
||||
String resolved = null;
|
||||
|
||||
if (systemId != null && systemMap.containsKey(systemId)) {
|
||||
resolved = systemMap.get(systemId);
|
||||
} else if (publicId != null && publicMap.containsKey(publicId)) {
|
||||
resolved = publicMap.get(publicId);
|
||||
}
|
||||
|
||||
if (resolved != null) {
|
||||
try {
|
||||
InputSource iSource = new InputSource(resolved);
|
||||
iSource.setPublicId(publicId);
|
||||
|
||||
// Ideally this method would not attempt to open the
|
||||
// InputStream, but there is a bug (in Xerces, at least)
|
||||
// that causes the parser to mistakenly open the wrong
|
||||
// system identifier if the returned InputSource does
|
||||
// not have a byteStream.
|
||||
//
|
||||
// It could be argued that we still shouldn't do this here,
|
||||
// but since the purpose of calling the entityResolver is
|
||||
// almost certainly to open the input stream, it seems to
|
||||
// do little harm.
|
||||
//
|
||||
URL url = new URL(resolved);
|
||||
InputStream iStream = url.openStream();
|
||||
iSource.setByteStream(iStream);
|
||||
|
||||
return iSource;
|
||||
} catch (Exception e) {
|
||||
// FIXME: silently fail?
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Transformer resolve API. */
|
||||
public Source resolve(String href, String base)
|
||||
throws TransformerException {
|
||||
|
||||
String uri = href;
|
||||
String fragment = null;
|
||||
int hashPos = href.indexOf("#");
|
||||
if (hashPos >= 0) {
|
||||
uri = href.substring(0, hashPos);
|
||||
fragment = href.substring(hashPos+1);
|
||||
}
|
||||
|
||||
String result = null;
|
||||
if (href != null && uriMap.containsKey(href)) {
|
||||
result = uriMap.get(href);
|
||||
}
|
||||
|
||||
if (result == null) {
|
||||
try {
|
||||
URL url = null;
|
||||
|
||||
if (base==null) {
|
||||
url = new URL(uri);
|
||||
result = url.toString();
|
||||
} else {
|
||||
URL baseURL = new URL(base);
|
||||
url = (href.length()==0 ? baseURL : new URL(baseURL, uri));
|
||||
result = url.toString();
|
||||
}
|
||||
} catch (java.net.MalformedURLException mue) {
|
||||
// try to make an absolute URI from the current base
|
||||
String absBase = makeAbsolute(base);
|
||||
if (!absBase.equals(base)) {
|
||||
// don't bother if the absBase isn't different!
|
||||
return resolve(href, absBase);
|
||||
} else {
|
||||
throw new TransformerException("Malformed URL "
|
||||
+ href + "(base " + base + ")",
|
||||
mue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SAXSource source = new SAXSource();
|
||||
source.setInputSource(new InputSource(result));
|
||||
return source;
|
||||
}
|
||||
|
||||
/** Attempt to construct an absolute URI */
|
||||
private String makeAbsolute(String uri) {
|
||||
if (uri == null) {
|
||||
uri = "";
|
||||
}
|
||||
|
||||
try {
|
||||
URL url = new URL(uri);
|
||||
return url.toString();
|
||||
} catch (MalformedURLException mue) {
|
||||
try {
|
||||
URL fileURL = FileURL.makeURL(uri);
|
||||
return fileURL.toString();
|
||||
} catch (MalformedURLException mue2) {
|
||||
// bail
|
||||
return uri;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,105 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.sun.org.apache.xml.internal.resolver.helpers;
|
||||
|
||||
/**
|
||||
* Static debugging/messaging class for Catalogs.
|
||||
*
|
||||
* <p>This class defines a set of static methods that can be called
|
||||
* to produce debugging messages. Messages have an associated "debug
|
||||
* level" and messages below the current setting are not displayed.</p>
|
||||
*
|
||||
* @author Norman Walsh
|
||||
* <a href="mailto:Norman.Walsh@Sun.COM">Norman.Walsh@Sun.COM</a>
|
||||
*
|
||||
*/
|
||||
public class Debug {
|
||||
/** The internal debug level. */
|
||||
protected int debug = 0;
|
||||
|
||||
/** Constructor */
|
||||
public Debug() {
|
||||
// nop
|
||||
}
|
||||
|
||||
/** Set the debug level for future messages. */
|
||||
public void setDebug(int newDebug) {
|
||||
debug = newDebug;
|
||||
}
|
||||
|
||||
/** Get the current debug level. */
|
||||
public int getDebug() {
|
||||
return debug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print debug message (if the debug level is high enough).
|
||||
*
|
||||
* <p>Prints "the message"</p>
|
||||
*
|
||||
* @param level The debug level of this message. This message
|
||||
* will only be
|
||||
* displayed if the current debug level is at least equal to this
|
||||
* value.
|
||||
* @param message The text of the message.
|
||||
*/
|
||||
public void message(int level, String message) {
|
||||
if (debug >= level) {
|
||||
System.out.println(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print debug message (if the debug level is high enough).
|
||||
*
|
||||
* <p>Prints "the message: spec"</p>
|
||||
*
|
||||
* @param level The debug level of this message. This message
|
||||
* will only be
|
||||
* displayed if the current debug level is at least equal to this
|
||||
* value.
|
||||
* @param message The text of the message.
|
||||
* @param spec An argument to the message.
|
||||
*/
|
||||
public void message(int level, String message, String spec) {
|
||||
if (debug >= level) {
|
||||
System.out.println(message + ": " + spec);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print debug message (if the debug level is high enough).
|
||||
*
|
||||
* <p>Prints "the message: spec1" and "spec2" indented on the next line.</p>
|
||||
*
|
||||
* @param level The debug level of this message. This message
|
||||
* will only be
|
||||
* displayed if the current debug level is at least equal to this
|
||||
* value.
|
||||
* @param message The text of the message.
|
||||
* @param spec1 An argument to the message.
|
||||
* @param spec2 Another argument to the message.
|
||||
*/
|
||||
public void message(int level, String message,
|
||||
String spec1, String spec2) {
|
||||
if (debug >= level) {
|
||||
System.out.println(message + ": " + spec1);
|
||||
System.out.println("\t" + spec2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,87 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.sun.org.apache.xml.internal.resolver.helpers;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.MalformedURLException;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Static method for dealing with file: URLs.
|
||||
*
|
||||
* <p>This class defines a static method that can be used to construct
|
||||
* an appropriate file: URL from parts. It's defined here so that it
|
||||
* can be reused throught the resolver.</p>
|
||||
*
|
||||
* <p>(Yes, I'd rather have called this class FileUR<b>I</b>, but
|
||||
* given that a jave.net.URL is returned, it seemed...even more
|
||||
* confusing.)</p>
|
||||
*
|
||||
* @author Norman Walsh
|
||||
* <a href="mailto:Norman.Walsh@Sun.COM">Norman.Walsh@Sun.COM</a>
|
||||
*
|
||||
* @version 1.0
|
||||
*/
|
||||
public abstract class FileURL {
|
||||
protected FileURL() { }
|
||||
|
||||
/**
|
||||
* Construct a file: URL for a path name.
|
||||
*
|
||||
* <p>URLs in the file: scheme can be constructed for paths on
|
||||
* the local file system. Several possibilities need to be considered:
|
||||
* </p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>If the path does not begin with a slash, then it is assumed
|
||||
* to reside in the users current working directory
|
||||
* (System.getProperty("user.dir")).</li>
|
||||
* <li>On Windows machines, the current working directory uses
|
||||
* backslashes (\\, instead of /).</li>
|
||||
* <li>If the current working directory is "/", don't add an extra
|
||||
* slash before the base name.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>This method is declared static so that other classes
|
||||
* can use it directly.</p>
|
||||
*
|
||||
* @param pathname The path name component for which to construct a URL.
|
||||
*
|
||||
* @return The appropriate file: URL.
|
||||
*
|
||||
* @throws MalformedURLException if the pathname can't be turned into
|
||||
* a proper URL.
|
||||
*/
|
||||
public static URL makeURL(String pathname) throws MalformedURLException {
|
||||
/*if (pathname.startsWith("/")) {
|
||||
return new URL("file://" + pathname);
|
||||
}
|
||||
|
||||
String userdir = System.getProperty("user.dir");
|
||||
userdir.replace('\\', '/');
|
||||
|
||||
if (userdir.endsWith("/")) {
|
||||
return new URL("file:///" + userdir + pathname);
|
||||
} else {
|
||||
return new URL("file:///" + userdir + "/" + pathname);
|
||||
}
|
||||
*/
|
||||
File file = new File(pathname);
|
||||
return file.toURI().toURL();
|
||||
}
|
||||
}
|
||||
@ -1,110 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.sun.org.apache.xml.internal.resolver.helpers;
|
||||
|
||||
import org.w3c.dom.*;
|
||||
|
||||
/**
|
||||
* Static Namespace query methods.
|
||||
*
|
||||
* <p>This class defines a set of static methods that can be called
|
||||
* to analyze the namespace properties of DOM nodes.</p>
|
||||
*
|
||||
* @author Norman Walsh
|
||||
* <a href="mailto:Norman.Walsh@Sun.COM">Norman.Walsh@Sun.COM</a>
|
||||
*
|
||||
*/
|
||||
public class Namespaces {
|
||||
/**
|
||||
* Returns the "prefix" part of a QName or the empty string (not
|
||||
* null) if the name has no prefix.
|
||||
*
|
||||
* @param element The QName of an element.
|
||||
* @return The prefix part of the element name.
|
||||
*/
|
||||
public static String getPrefix(Element element) {
|
||||
String name = element.getTagName();
|
||||
String prefix = "";
|
||||
|
||||
final int indexOfColon = name.indexOf(':');
|
||||
if (indexOfColon > 0) {
|
||||
prefix = name.substring(0, indexOfColon);
|
||||
}
|
||||
|
||||
return prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the "localname" part of a QName, which is the whole
|
||||
* name if it has no prefix.
|
||||
*
|
||||
* @param element The QName of an element.
|
||||
* @return The local part of a QName.
|
||||
*/
|
||||
public static String getLocalName(Element element) {
|
||||
String name = element.getTagName();
|
||||
|
||||
final int indexOfColon = name.indexOf(':');
|
||||
if (indexOfColon > 0) {
|
||||
name = name.substring(indexOfColon + 1);
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the namespace URI for the specified prefix at the
|
||||
* specified context node.
|
||||
*
|
||||
* @param node The context node.
|
||||
* @param prefix The prefix.
|
||||
* @return The namespace URI associated with the prefix, or
|
||||
* null if no namespace declaration exists for the prefix.
|
||||
*/
|
||||
public static String getNamespaceURI(Node node, String prefix) {
|
||||
if (node == null || node.getNodeType() != Node.ELEMENT_NODE) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (prefix.length() == 0) {
|
||||
if (((Element) node).hasAttribute("xmlns")) {
|
||||
return ((Element) node).getAttribute("xmlns");
|
||||
}
|
||||
} else {
|
||||
String nsattr = "xmlns:" + prefix;
|
||||
if (((Element) node).hasAttribute(nsattr)) {
|
||||
return ((Element) node).getAttribute(nsattr);
|
||||
}
|
||||
}
|
||||
|
||||
return getNamespaceURI(node.getParentNode(), prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the namespace URI for the namespace to which the
|
||||
* element belongs.
|
||||
*
|
||||
* @param element The element.
|
||||
* @return The namespace URI associated with the namespace of the
|
||||
* element, or null if no namespace declaration exists for it.
|
||||
*/
|
||||
public static String getNamespaceURI(Element element) {
|
||||
String prefix = getPrefix(element);
|
||||
return getNamespaceURI(element, prefix);
|
||||
}
|
||||
}
|
||||
@ -1,169 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.sun.org.apache.xml.internal.resolver.helpers;
|
||||
|
||||
/**
|
||||
* Static methods for dealing with public identifiers.
|
||||
*
|
||||
* <p>This class defines a set of static methods that can be called
|
||||
* to handle public identifiers.</p>
|
||||
*
|
||||
* @author Norman Walsh
|
||||
* <a href="mailto:Norman.Walsh@Sun.COM">Norman.Walsh@Sun.COM</a>
|
||||
*
|
||||
*/
|
||||
public abstract class PublicId {
|
||||
|
||||
protected PublicId() {}
|
||||
|
||||
/**
|
||||
* Normalize a public identifier.
|
||||
*
|
||||
* <p>Public identifiers must be normalized according to the following
|
||||
* rules before comparisons between them can be made:</p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>Whitespace characters are normalized to spaces (e.g., line feeds,
|
||||
* tabs, etc. become spaces).</li>
|
||||
* <li>Leading and trailing whitespace is removed.</li>
|
||||
* <li>Multiple internal whitespaces are normalized to a single
|
||||
* space.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>This method is declared static so that other classes
|
||||
* can use it directly.</p>
|
||||
*
|
||||
* @param publicId The unnormalized public identifier.
|
||||
*
|
||||
* @return The normalized identifier.
|
||||
*/
|
||||
public static String normalize(String publicId) {
|
||||
String normal = publicId.replace('\t', ' ');
|
||||
normal = normal.replace('\r', ' ');
|
||||
normal = normal.replace('\n', ' ');
|
||||
normal = normal.trim();
|
||||
|
||||
int pos;
|
||||
|
||||
while ((pos = normal.indexOf(" ")) >= 0) {
|
||||
normal = normal.substring(0, pos) + normal.substring(pos+1);
|
||||
}
|
||||
return normal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a public identifier as a "publicid" URN.
|
||||
*
|
||||
* <p>This method is declared static so that other classes
|
||||
* can use it directly.</p>
|
||||
*
|
||||
* @param publicId The unnormalized public identifier.
|
||||
*
|
||||
* @return The normalized identifier.
|
||||
*/
|
||||
public static String encodeURN(String publicId) {
|
||||
String urn = PublicId.normalize(publicId);
|
||||
|
||||
urn = PublicId.stringReplace(urn, "%", "%25");
|
||||
urn = PublicId.stringReplace(urn, ";", "%3B");
|
||||
urn = PublicId.stringReplace(urn, "'", "%27");
|
||||
urn = PublicId.stringReplace(urn, "?", "%3F");
|
||||
urn = PublicId.stringReplace(urn, "#", "%23");
|
||||
urn = PublicId.stringReplace(urn, "+", "%2B");
|
||||
urn = PublicId.stringReplace(urn, " ", "+");
|
||||
urn = PublicId.stringReplace(urn, "::", ";");
|
||||
urn = PublicId.stringReplace(urn, ":", "%3A");
|
||||
urn = PublicId.stringReplace(urn, "//", ":");
|
||||
urn = PublicId.stringReplace(urn, "/", "%2F");
|
||||
|
||||
StringBuilder buffer = new StringBuilder(13 + urn.length());
|
||||
buffer.append("urn:publicid:");
|
||||
buffer.append(urn);
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a "publicid" URN into a public identifier.
|
||||
*
|
||||
* <p>This method is declared static so that other classes
|
||||
* can use it directly.</p>
|
||||
*
|
||||
* @param urn The urn:publicid: URN
|
||||
*
|
||||
* @return The normalized identifier.
|
||||
*/
|
||||
public static String decodeURN(String urn) {
|
||||
String publicId;
|
||||
if (urn.startsWith("urn:publicid:")) {
|
||||
publicId = urn.substring(13);
|
||||
}
|
||||
else {
|
||||
return urn;
|
||||
}
|
||||
|
||||
final boolean hasEscape = (publicId.indexOf('%') >= 0);
|
||||
if (hasEscape) {
|
||||
publicId = PublicId.stringReplace(publicId, "%2F", "/");
|
||||
}
|
||||
publicId = PublicId.stringReplace(publicId, ":", "//");
|
||||
if (hasEscape) {
|
||||
publicId = PublicId.stringReplace(publicId, "%3A", ":");
|
||||
}
|
||||
publicId = PublicId.stringReplace(publicId, ";", "::");
|
||||
publicId = PublicId.stringReplace(publicId, "+", " ");
|
||||
if (hasEscape) {
|
||||
publicId = PublicId.stringReplace(publicId, "%2B", "+");
|
||||
publicId = PublicId.stringReplace(publicId, "%23", "#");
|
||||
publicId = PublicId.stringReplace(publicId, "%3F", "?");
|
||||
publicId = PublicId.stringReplace(publicId, "%27", "'");
|
||||
publicId = PublicId.stringReplace(publicId, "%3B", ";");
|
||||
publicId = PublicId.stringReplace(publicId, "%25", "%");
|
||||
}
|
||||
|
||||
return publicId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace one string with another.
|
||||
*/
|
||||
private static String stringReplace(String str,
|
||||
String oldStr,
|
||||
String newStr) {
|
||||
int pos = str.indexOf(oldStr);
|
||||
if (pos >= 0) {
|
||||
final StringBuilder buffer = new StringBuilder();
|
||||
final int oldStrLength = oldStr.length();
|
||||
int start = 0;
|
||||
do {
|
||||
for (int i = start; i < pos; ++i) {
|
||||
buffer.append(str.charAt(i));
|
||||
}
|
||||
buffer.append(newStr);
|
||||
start = pos + oldStrLength;
|
||||
pos = str.indexOf(oldStr, start);
|
||||
}
|
||||
while (pos >= 0);
|
||||
final int strLength = str.length();
|
||||
for (int i = start; i < strLength; ++i) {
|
||||
buffer.append(str.charAt(i));
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
return str;
|
||||
}
|
||||
}
|
||||
@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.sun.org.apache.xml.internal.resolver.readers;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import com.sun.org.apache.xml.internal.resolver.CatalogException;
|
||||
|
||||
import java.io.InputStream;
|
||||
import com.sun.org.apache.xml.internal.resolver.Catalog;
|
||||
|
||||
/**
|
||||
* The CatalogReader interface.
|
||||
*
|
||||
* <p>The Catalog class requires that classes implement this interface
|
||||
* in order to be used to read catalogs. Examples of CatalogReaders
|
||||
* include the TextCatalogReader, the SAXCatalogReader, and the
|
||||
* DOMCatalogReader.</p>
|
||||
*
|
||||
* @see Catalog
|
||||
*
|
||||
* @author Norman Walsh
|
||||
* <a href="mailto:Norman.Walsh@Sun.COM">Norman.Walsh@Sun.COM</a>
|
||||
*
|
||||
*/
|
||||
public interface CatalogReader {
|
||||
/**
|
||||
* Read a catalog from a file.
|
||||
*
|
||||
* <p>This class reads a catalog from a URL.</p>
|
||||
*
|
||||
* @param catalog The catalog for which this reader is called.
|
||||
* @param fileUrl The URL of a document to be read.
|
||||
* @throws MalformedURLException if the specified URL cannot be
|
||||
* turned into a URL object.
|
||||
* @throws IOException if the URL cannot be read.
|
||||
* @throws UnknownCatalogFormatException if the catalog format is
|
||||
* not recognized.
|
||||
* @throws UnparseableCatalogException if the catalog cannot be parsed.
|
||||
* (For example, if it is supposed to be XML and isn't well-formed.)
|
||||
*/
|
||||
public void readCatalog(Catalog catalog, String fileUrl)
|
||||
throws MalformedURLException, IOException, CatalogException;
|
||||
|
||||
/**
|
||||
* Read a catalog from an input stream.
|
||||
*
|
||||
* <p>This class reads a catalog from an input stream.</p>
|
||||
*
|
||||
* @param catalog The catalog for which this reader is called.
|
||||
* @param is The input stream that is to be read.
|
||||
* @throws IOException if the URL cannot be read.
|
||||
* @throws UnknownCatalogFormatException if the catalog format is
|
||||
* not recognized.
|
||||
* @throws UnparseableCatalogException if the catalog cannot be parsed.
|
||||
* (For example, if it is supposed to be XML and isn't well-formed.)
|
||||
*/
|
||||
public void readCatalog(Catalog catalog, InputStream is)
|
||||
throws IOException, CatalogException;
|
||||
}
|
||||
@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.sun.org.apache.xml.internal.resolver.readers;
|
||||
|
||||
import com.sun.org.apache.xml.internal.resolver.Catalog;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
/**
|
||||
* The DOMCatalogParser interface.
|
||||
*
|
||||
* <p>This interface must be implemented in order for a class to
|
||||
* participate as a parser for the DOMCatalogReader.
|
||||
*
|
||||
* @see Catalog
|
||||
* @see DOMCatalogReader
|
||||
*
|
||||
* @author Norman Walsh
|
||||
* <a href="mailto:Norman.Walsh@Sun.COM">Norman.Walsh@Sun.COM</a>
|
||||
*
|
||||
*/
|
||||
public interface DOMCatalogParser {
|
||||
/**
|
||||
* Parse a DOM node as a catalog entry.
|
||||
*
|
||||
* <p>This method is expected to analyze the specified node and
|
||||
* construct appropriate catalog entry(ies) from it.</p>
|
||||
*
|
||||
* @param catalog The catalog for which this node is being considered.
|
||||
* @param node The DOM Node from the catalog.
|
||||
*/
|
||||
public void parseCatalogEntry(Catalog catalog, Node node);
|
||||
}
|
||||
@ -1,240 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
*/
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.sun.org.apache.xml.internal.resolver.readers;
|
||||
|
||||
import com.sun.org.apache.xml.internal.resolver.Catalog;
|
||||
import com.sun.org.apache.xml.internal.resolver.CatalogException;
|
||||
import com.sun.org.apache.xml.internal.resolver.helpers.Namespaces;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import org.w3c.dom.*;
|
||||
import org.xml.sax.SAXException;
|
||||
import sun.reflect.misc.ReflectUtil;
|
||||
|
||||
/**
|
||||
* A DOM-based CatalogReader.
|
||||
*
|
||||
* <p>This class is used to read XML Catalogs using the DOM. This reader
|
||||
* has an advantage over the SAX-based reader that it can analyze the
|
||||
* DOM tree rather than simply a series of SAX events. It has the disadvantage
|
||||
* that it requires all of the code necessary to build and walk a DOM
|
||||
* tree.</p>
|
||||
*
|
||||
* <p>Since the choice of CatalogReaders (in the InputStream case) can only
|
||||
* be made on the basis of MIME type, the following problem occurs: only
|
||||
* one CatalogReader can exist for all XML mime types. In order to get
|
||||
* around this problem, the DOMCatalogReader relies on a set of external
|
||||
* CatalogParsers to actually build the catalog.</p>
|
||||
*
|
||||
* <p>The selection of CatalogParsers is made on the basis of the QName
|
||||
* of the root element of the document.</p>
|
||||
*
|
||||
*
|
||||
* @see Catalog
|
||||
* @see CatalogReader
|
||||
* @see SAXCatalogReader
|
||||
* @see TextCatalogReader
|
||||
* @see DOMCatalogParser
|
||||
*
|
||||
* @author Norman Walsh
|
||||
* <a href="mailto:Norman.Walsh@Sun.COM">Norman.Walsh@Sun.COM</a>
|
||||
*
|
||||
*/
|
||||
public class DOMCatalogReader implements CatalogReader {
|
||||
/**
|
||||
* Mapping table from QNames to CatalogParser classes.
|
||||
*
|
||||
* <p>Each key in this hash table has the form "elementname"
|
||||
* or "{namespaceuri}elementname". The former is used if the
|
||||
* namespace URI is null.</p>
|
||||
*/
|
||||
protected Map<String, String> namespaceMap = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Add a new parser to the reader.
|
||||
*
|
||||
* <p>This method associates the specified parserClass with the
|
||||
* namespaceURI/rootElement names specified.</p>
|
||||
*
|
||||
* @param namespaceURI The namespace URI. <em>Not</em> the prefix.
|
||||
* @param rootElement The name of the root element.
|
||||
* @param parserClass The name of the parserClass to instantiate
|
||||
* for this kind of catalog.
|
||||
*/
|
||||
public void setCatalogParser(String namespaceURI,
|
||||
String rootElement,
|
||||
String parserClass) {
|
||||
if (namespaceURI == null) {
|
||||
namespaceMap.put(rootElement, parserClass);
|
||||
} else {
|
||||
namespaceMap.put("{"+namespaceURI+"}"+rootElement, parserClass);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the parser class for a given catalog type.
|
||||
*
|
||||
* <p>This method returns the parserClass associated with the
|
||||
* namespaceURI/rootElement names specified.</p>
|
||||
*
|
||||
* @param namespaceURI The namespace URI. <em>Not</em> the prefix.
|
||||
* @param rootElement The name of the root element.
|
||||
* @return The parser class.
|
||||
*/
|
||||
public String getCatalogParser(String namespaceURI,
|
||||
String rootElement) {
|
||||
if (namespaceURI == null) {
|
||||
return namespaceMap.get(rootElement);
|
||||
} else {
|
||||
return namespaceMap.get("{"+namespaceURI+"}"+rootElement);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Null constructor; something for subclasses to call.
|
||||
*/
|
||||
public DOMCatalogReader() { }
|
||||
|
||||
/**
|
||||
* Read a catalog from an input stream.
|
||||
*
|
||||
* <p>This class reads a catalog from an input stream:</p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>Based on the QName of the root element, it determines which
|
||||
* parser to instantiate for this catalog.</li>
|
||||
* <li>It constructs a DOM Document from the catalog and</li>
|
||||
* <li>For each child of the root node, it calls the parser's
|
||||
* parseCatalogEntry method. This method is expected to make
|
||||
* appropriate calls back into the catalog to add entries for the
|
||||
* entries in the catalog. It is free to do this in whatever manner
|
||||
* is appropriate (perhaps using just the node passed in, perhaps
|
||||
* wandering arbitrarily throughout the tree).</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param catalog The catalog for which this reader is called.
|
||||
* @param is The input stream that is to be read.
|
||||
* @throws IOException if the URL cannot be read.
|
||||
* @throws UnknownCatalogFormatException if the catalog format is
|
||||
* not recognized.
|
||||
* @throws UnparseableCatalogException if the catalog cannot be parsed.
|
||||
* (For example, if it is supposed to be XML and isn't well-formed or
|
||||
* if the parser class cannot be instantiated.)
|
||||
*/
|
||||
public void readCatalog(Catalog catalog, InputStream is)
|
||||
throws IOException, CatalogException {
|
||||
|
||||
DocumentBuilderFactory factory = null;
|
||||
DocumentBuilder builder = null;
|
||||
|
||||
factory = DocumentBuilderFactory.newInstance();
|
||||
factory.setNamespaceAware(false);
|
||||
factory.setValidating(false);
|
||||
try {
|
||||
builder = factory.newDocumentBuilder();
|
||||
} catch (ParserConfigurationException pce) {
|
||||
throw new CatalogException(CatalogException.UNPARSEABLE);
|
||||
}
|
||||
|
||||
Document doc = null;
|
||||
|
||||
try {
|
||||
doc = builder.parse(is);
|
||||
} catch (SAXException se) {
|
||||
throw new CatalogException(CatalogException.UNKNOWN_FORMAT);
|
||||
}
|
||||
|
||||
Element root = doc.getDocumentElement();
|
||||
|
||||
String namespaceURI = Namespaces.getNamespaceURI(root);
|
||||
String localName = Namespaces.getLocalName(root);
|
||||
|
||||
String domParserClass = getCatalogParser(namespaceURI,
|
||||
localName);
|
||||
|
||||
if (domParserClass == null) {
|
||||
if (namespaceURI == null) {
|
||||
catalog.getCatalogManager().debug.message(1, "No Catalog parser for "
|
||||
+ localName);
|
||||
} else {
|
||||
catalog.getCatalogManager().debug.message(1, "No Catalog parser for "
|
||||
+ "{" + namespaceURI + "}"
|
||||
+ localName);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
DOMCatalogParser domParser = null;
|
||||
|
||||
try {
|
||||
domParser = (DOMCatalogParser) ReflectUtil.forName(domParserClass).newInstance();
|
||||
} catch (ClassNotFoundException cnfe) {
|
||||
catalog.getCatalogManager().debug.message(1, "Cannot load XML Catalog Parser class", domParserClass);
|
||||
throw new CatalogException(CatalogException.UNPARSEABLE);
|
||||
} catch (InstantiationException ie) {
|
||||
catalog.getCatalogManager().debug.message(1, "Cannot instantiate XML Catalog Parser class", domParserClass);
|
||||
throw new CatalogException(CatalogException.UNPARSEABLE);
|
||||
} catch (IllegalAccessException iae) {
|
||||
catalog.getCatalogManager().debug.message(1, "Cannot access XML Catalog Parser class", domParserClass);
|
||||
throw new CatalogException(CatalogException.UNPARSEABLE);
|
||||
} catch (ClassCastException cce ) {
|
||||
catalog.getCatalogManager().debug.message(1, "Cannot cast XML Catalog Parser class", domParserClass);
|
||||
throw new CatalogException(CatalogException.UNPARSEABLE);
|
||||
}
|
||||
|
||||
Node node = root.getFirstChild();
|
||||
while (node != null) {
|
||||
domParser.parseCatalogEntry(catalog, node);
|
||||
node = node.getNextSibling();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the catalog behind the specified URL.
|
||||
*
|
||||
* @see #readCatalog(Catalog, InputStream)
|
||||
*
|
||||
* @param catalog The catalog for which we are reading.
|
||||
* @param fileUrl The URL of the document that should be read.
|
||||
*
|
||||
* @throws MalformedURLException if the specified URL cannot be
|
||||
* turned into a URL object.
|
||||
* @throws IOException if the URL cannot be read.
|
||||
* @throws UnknownCatalogFormatException if the catalog format is
|
||||
* not recognized.
|
||||
* @throws UnparseableCatalogException if the catalog cannot be parsed.
|
||||
* (For example, if it is supposed to be XML and isn't well-formed.)
|
||||
*/
|
||||
public void readCatalog(Catalog catalog, String fileUrl)
|
||||
throws MalformedURLException, IOException, CatalogException {
|
||||
URL url = new URL(fileUrl);
|
||||
URLConnection urlCon = url.openConnection();
|
||||
readCatalog(catalog, urlCon.getInputStream());
|
||||
}
|
||||
}
|
||||
@ -1,181 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.sun.org.apache.xml.internal.resolver.readers;
|
||||
|
||||
import java.util.Vector;
|
||||
import com.sun.org.apache.xml.internal.resolver.Catalog;
|
||||
import com.sun.org.apache.xml.internal.resolver.Resolver;
|
||||
import com.sun.org.apache.xml.internal.resolver.CatalogEntry;
|
||||
import com.sun.org.apache.xml.internal.resolver.CatalogException;
|
||||
|
||||
import org.xml.sax.*;
|
||||
import org.w3c.dom.*;
|
||||
|
||||
/**
|
||||
* Parse Extended OASIS Entity Resolution Technical Committee
|
||||
* XML Catalog files.
|
||||
*
|
||||
* @see Catalog
|
||||
*
|
||||
* @author Norman Walsh
|
||||
* <a href="mailto:Norman.Walsh@Sun.COM">Norman.Walsh@Sun.COM</a>
|
||||
*
|
||||
*/
|
||||
public class ExtendedXMLCatalogReader extends OASISXMLCatalogReader {
|
||||
/** The namespace name of extended catalog elements */
|
||||
public static final String extendedNamespaceName = "http://nwalsh.com/xcatalog/1.0";
|
||||
|
||||
/**
|
||||
* The SAX <code>startElement</code> method recognizes elements
|
||||
* from the plain catalog format and instantiates CatalogEntry
|
||||
* objects for them.
|
||||
*
|
||||
* @param namespaceURI The namespace name of the element.
|
||||
* @param localName The local name of the element.
|
||||
* @param qName The QName of the element.
|
||||
* @param atts The list of attributes on the element.
|
||||
*
|
||||
* @see CatalogEntry
|
||||
*/
|
||||
public void startElement (String namespaceURI,
|
||||
String localName,
|
||||
String qName,
|
||||
Attributes atts)
|
||||
throws SAXException {
|
||||
|
||||
// Check before calling the super because super will report our
|
||||
// namespace as an extension namespace, but that doesn't count
|
||||
// for this element.
|
||||
boolean inExtension = inExtensionNamespace();
|
||||
|
||||
super.startElement(namespaceURI, localName, qName, atts);
|
||||
|
||||
int entryType = -1;
|
||||
Vector entryArgs = new Vector();
|
||||
|
||||
if (namespaceURI != null && extendedNamespaceName.equals(namespaceURI)
|
||||
&& !inExtension) {
|
||||
// This is an Extended XML Catalog entry
|
||||
|
||||
if (atts.getValue("xml:base") != null) {
|
||||
String baseURI = atts.getValue("xml:base");
|
||||
entryType = Catalog.BASE;
|
||||
entryArgs.add(baseURI);
|
||||
baseURIStack.push(baseURI);
|
||||
|
||||
debug.message(4, "xml:base", baseURI);
|
||||
|
||||
try {
|
||||
CatalogEntry ce = new CatalogEntry(entryType, entryArgs);
|
||||
catalog.addEntry(ce);
|
||||
} catch (CatalogException cex) {
|
||||
if (cex.getExceptionType() == CatalogException.INVALID_ENTRY_TYPE) {
|
||||
debug.message(1, "Invalid catalog entry type", localName);
|
||||
} else if (cex.getExceptionType() == CatalogException.INVALID_ENTRY) {
|
||||
debug.message(1, "Invalid catalog entry (base)", localName);
|
||||
}
|
||||
}
|
||||
|
||||
entryType = -1;
|
||||
entryArgs = new Vector();
|
||||
} else {
|
||||
baseURIStack.push(baseURIStack.peek());
|
||||
}
|
||||
|
||||
if (localName.equals("uriSuffix")) {
|
||||
if (checkAttributes(atts, "suffix", "uri")) {
|
||||
entryType = Resolver.URISUFFIX;
|
||||
entryArgs.add(atts.getValue("suffix"));
|
||||
entryArgs.add(atts.getValue("uri"));
|
||||
|
||||
debug.message(4, "uriSuffix",
|
||||
atts.getValue("suffix"),
|
||||
atts.getValue("uri"));
|
||||
}
|
||||
} else if (localName.equals("systemSuffix")) {
|
||||
if (checkAttributes(atts, "suffix", "uri")) {
|
||||
entryType = Resolver.SYSTEMSUFFIX;
|
||||
entryArgs.add(atts.getValue("suffix"));
|
||||
entryArgs.add(atts.getValue("uri"));
|
||||
|
||||
debug.message(4, "systemSuffix",
|
||||
atts.getValue("suffix"),
|
||||
atts.getValue("uri"));
|
||||
}
|
||||
} else {
|
||||
// This is equivalent to an invalid catalog entry type
|
||||
debug.message(1, "Invalid catalog entry type", localName);
|
||||
}
|
||||
|
||||
if (entryType >= 0) {
|
||||
try {
|
||||
CatalogEntry ce = new CatalogEntry(entryType, entryArgs);
|
||||
catalog.addEntry(ce);
|
||||
} catch (CatalogException cex) {
|
||||
if (cex.getExceptionType() == CatalogException.INVALID_ENTRY_TYPE) {
|
||||
debug.message(1, "Invalid catalog entry type", localName);
|
||||
} else if (cex.getExceptionType() == CatalogException.INVALID_ENTRY) {
|
||||
debug.message(1, "Invalid catalog entry", localName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** The SAX <code>endElement</code> method does nothing. */
|
||||
public void endElement (String namespaceURI,
|
||||
String localName,
|
||||
String qName)
|
||||
throws SAXException {
|
||||
|
||||
super.endElement(namespaceURI, localName, qName);
|
||||
|
||||
// Check after popping the stack so we don't erroneously think we
|
||||
// are our own extension namespace...
|
||||
boolean inExtension = inExtensionNamespace();
|
||||
|
||||
int entryType = -1;
|
||||
Vector entryArgs = new Vector();
|
||||
|
||||
if (namespaceURI != null
|
||||
&& (extendedNamespaceName.equals(namespaceURI))
|
||||
&& !inExtension) {
|
||||
|
||||
String popURI = (String) baseURIStack.pop();
|
||||
String baseURI = (String) baseURIStack.peek();
|
||||
|
||||
if (!baseURI.equals(popURI)) {
|
||||
entryType = Catalog.BASE;
|
||||
entryArgs.add(baseURI);
|
||||
|
||||
debug.message(4, "(reset) xml:base", baseURI);
|
||||
|
||||
try {
|
||||
CatalogEntry ce = new CatalogEntry(entryType, entryArgs);
|
||||
catalog.addEntry(ce);
|
||||
} catch (CatalogException cex) {
|
||||
if (cex.getExceptionType() == CatalogException.INVALID_ENTRY_TYPE) {
|
||||
debug.message(1, "Invalid catalog entry type", localName);
|
||||
} else if (cex.getExceptionType() == CatalogException.INVALID_ENTRY) {
|
||||
debug.message(1, "Invalid catalog entry (rbase)", localName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,546 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.sun.org.apache.xml.internal.resolver.readers;
|
||||
|
||||
import com.sun.org.apache.xml.internal.resolver.Catalog;
|
||||
import com.sun.org.apache.xml.internal.resolver.CatalogEntry;
|
||||
import com.sun.org.apache.xml.internal.resolver.CatalogException;
|
||||
import com.sun.org.apache.xml.internal.resolver.helpers.PublicId;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Stack;
|
||||
import java.util.Vector;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
import org.w3c.dom.*;
|
||||
import org.xml.sax.*;
|
||||
|
||||
/**
|
||||
* Parse OASIS Entity Resolution Technical Committee
|
||||
* XML Catalog files.
|
||||
*
|
||||
* @see Catalog
|
||||
*
|
||||
* @author Norman Walsh
|
||||
* <a href="mailto:Norman.Walsh@Sun.COM">Norman.Walsh@Sun.COM</a>
|
||||
*
|
||||
*/
|
||||
public class OASISXMLCatalogReader extends SAXCatalogReader implements SAXCatalogParser {
|
||||
/** The catalog object needs to be stored by the object so that
|
||||
* SAX callbacks can use it.
|
||||
*/
|
||||
protected Catalog catalog = null;
|
||||
|
||||
/** The namespace name of OASIS ERTC catalogs */
|
||||
public static final String namespaceName = "urn:oasis:names:tc:entity:xmlns:xml:catalog";
|
||||
|
||||
/** The namespace name of OASIS ERTC TR9401 catalog extension */
|
||||
public static final String tr9401NamespaceName = "urn:oasis:names:tc:entity:xmlns:tr9401:catalog";
|
||||
|
||||
protected Stack baseURIStack = new Stack();
|
||||
protected Stack overrideStack = new Stack();
|
||||
protected Stack namespaceStack = new Stack();
|
||||
|
||||
/** Set the current catalog. */
|
||||
public void setCatalog (Catalog catalog) {
|
||||
this.catalog = catalog;
|
||||
debug = catalog.getCatalogManager().debug;
|
||||
}
|
||||
|
||||
/** Get the current catalog. */
|
||||
public Catalog getCatalog () {
|
||||
return catalog;
|
||||
}
|
||||
|
||||
/** Default constructor */
|
||||
public OASISXMLCatalogReader() {
|
||||
super();
|
||||
}
|
||||
|
||||
/** Constructor allowing for providing custom SAX parser factory */
|
||||
public OASISXMLCatalogReader(SAXParserFactory parserFactory, Catalog catalog) {
|
||||
super(parserFactory);
|
||||
setCatalog(catalog);
|
||||
}
|
||||
|
||||
/**
|
||||
* Are we in an extension namespace?
|
||||
*
|
||||
* @return true if the current stack of open namespaces includes
|
||||
* an extension namespace.
|
||||
*/
|
||||
protected boolean inExtensionNamespace() {
|
||||
boolean inExtension = false;
|
||||
|
||||
Enumeration elements = namespaceStack.elements();
|
||||
while (!inExtension && elements.hasMoreElements()) {
|
||||
String ns = (String) elements.nextElement();
|
||||
if (ns == null) {
|
||||
inExtension = true;
|
||||
} else {
|
||||
inExtension = (!ns.equals(tr9401NamespaceName)
|
||||
&& !ns.equals(namespaceName));
|
||||
}
|
||||
}
|
||||
|
||||
return inExtension;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Implement the SAX ContentHandler interface
|
||||
|
||||
/** The SAX <code>setDocumentLocator</code> method does nothing. */
|
||||
public void setDocumentLocator (Locator locator) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** The SAX <code>startDocument</code> */
|
||||
public void startDocument ()
|
||||
throws SAXException {
|
||||
baseURIStack.push(catalog.getCurrentBase());
|
||||
overrideStack.push(catalog.getDefaultOverride());
|
||||
return;
|
||||
}
|
||||
|
||||
/** The SAX <code>endDocument</code> method does nothing. */
|
||||
public void endDocument ()
|
||||
throws SAXException {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* The SAX <code>startElement</code> method recognizes elements
|
||||
* from the plain catalog format and instantiates CatalogEntry
|
||||
* objects for them.
|
||||
*
|
||||
* @param namespaceURI The namespace name of the element.
|
||||
* @param localName The local name of the element.
|
||||
* @param qName The QName of the element.
|
||||
* @param atts The list of attributes on the element.
|
||||
*
|
||||
* @see CatalogEntry
|
||||
*/
|
||||
public void startElement (String namespaceURI,
|
||||
String localName,
|
||||
String qName,
|
||||
Attributes atts)
|
||||
throws SAXException {
|
||||
|
||||
int entryType = -1;
|
||||
Vector entryArgs = new Vector();
|
||||
|
||||
namespaceStack.push(namespaceURI);
|
||||
|
||||
boolean inExtension = inExtensionNamespace();
|
||||
|
||||
if (namespaceURI != null && namespaceName.equals(namespaceURI)
|
||||
&& !inExtension) {
|
||||
// This is an XML Catalog entry
|
||||
|
||||
if (atts.getValue("xml:base") != null) {
|
||||
String baseURI = atts.getValue("xml:base");
|
||||
entryType = Catalog.BASE;
|
||||
entryArgs.add(baseURI);
|
||||
baseURIStack.push(baseURI);
|
||||
|
||||
debug.message(4, "xml:base", baseURI);
|
||||
|
||||
try {
|
||||
CatalogEntry ce = new CatalogEntry(entryType, entryArgs);
|
||||
catalog.addEntry(ce);
|
||||
} catch (CatalogException cex) {
|
||||
if (cex.getExceptionType() == CatalogException.INVALID_ENTRY_TYPE) {
|
||||
debug.message(1, "Invalid catalog entry type", localName);
|
||||
} else if (cex.getExceptionType() == CatalogException.INVALID_ENTRY) {
|
||||
debug.message(1, "Invalid catalog entry (base)", localName);
|
||||
}
|
||||
}
|
||||
|
||||
entryType = -1;
|
||||
entryArgs = new Vector();
|
||||
|
||||
} else {
|
||||
baseURIStack.push(baseURIStack.peek());
|
||||
}
|
||||
|
||||
if ((localName.equals("catalog") || localName.equals("group"))
|
||||
&& atts.getValue("prefer") != null) {
|
||||
String override = atts.getValue("prefer");
|
||||
|
||||
if (override.equals("public")) {
|
||||
override = "yes";
|
||||
} else if (override.equals("system")) {
|
||||
override = "no";
|
||||
} else {
|
||||
debug.message(1,
|
||||
"Invalid prefer: must be 'system' or 'public'",
|
||||
localName);
|
||||
override = catalog.getDefaultOverride();
|
||||
}
|
||||
|
||||
entryType = Catalog.OVERRIDE;
|
||||
entryArgs.add(override);
|
||||
overrideStack.push(override);
|
||||
|
||||
debug.message(4, "override", override);
|
||||
|
||||
try {
|
||||
CatalogEntry ce = new CatalogEntry(entryType, entryArgs);
|
||||
catalog.addEntry(ce);
|
||||
} catch (CatalogException cex) {
|
||||
if (cex.getExceptionType() == CatalogException.INVALID_ENTRY_TYPE) {
|
||||
debug.message(1, "Invalid catalog entry type", localName);
|
||||
} else if (cex.getExceptionType() == CatalogException.INVALID_ENTRY) {
|
||||
debug.message(1, "Invalid catalog entry (override)", localName);
|
||||
}
|
||||
}
|
||||
|
||||
entryType = -1;
|
||||
entryArgs = new Vector();
|
||||
|
||||
} else {
|
||||
overrideStack.push(overrideStack.peek());
|
||||
}
|
||||
|
||||
if (localName.equals("delegatePublic")) {
|
||||
if (checkAttributes(atts, "publicIdStartString", "catalog")) {
|
||||
entryType = Catalog.DELEGATE_PUBLIC;
|
||||
entryArgs.add(atts.getValue("publicIdStartString"));
|
||||
entryArgs.add(atts.getValue("catalog"));
|
||||
|
||||
debug.message(4, "delegatePublic",
|
||||
PublicId.normalize(atts.getValue("publicIdStartString")),
|
||||
atts.getValue("catalog"));
|
||||
}
|
||||
} else if (localName.equals("delegateSystem")) {
|
||||
if (checkAttributes(atts, "systemIdStartString", "catalog")) {
|
||||
entryType = Catalog.DELEGATE_SYSTEM;
|
||||
entryArgs.add(atts.getValue("systemIdStartString"));
|
||||
entryArgs.add(atts.getValue("catalog"));
|
||||
|
||||
debug.message(4, "delegateSystem",
|
||||
atts.getValue("systemIdStartString"),
|
||||
atts.getValue("catalog"));
|
||||
}
|
||||
} else if (localName.equals("delegateURI")) {
|
||||
if (checkAttributes(atts, "uriStartString", "catalog")) {
|
||||
entryType = Catalog.DELEGATE_URI;
|
||||
entryArgs.add(atts.getValue("uriStartString"));
|
||||
entryArgs.add(atts.getValue("catalog"));
|
||||
|
||||
debug.message(4, "delegateURI",
|
||||
atts.getValue("uriStartString"),
|
||||
atts.getValue("catalog"));
|
||||
}
|
||||
} else if (localName.equals("rewriteSystem")) {
|
||||
if (checkAttributes(atts, "systemIdStartString", "rewritePrefix")) {
|
||||
entryType = Catalog.REWRITE_SYSTEM;
|
||||
entryArgs.add(atts.getValue("systemIdStartString"));
|
||||
entryArgs.add(atts.getValue("rewritePrefix"));
|
||||
|
||||
debug.message(4, "rewriteSystem",
|
||||
atts.getValue("systemIdStartString"),
|
||||
atts.getValue("rewritePrefix"));
|
||||
}
|
||||
} else if (localName.equals("systemSuffix")) {
|
||||
if (checkAttributes(atts, "systemIdSuffix", "uri")) {
|
||||
entryType = Catalog.SYSTEM_SUFFIX;
|
||||
entryArgs.add(atts.getValue("systemIdSuffix"));
|
||||
entryArgs.add(atts.getValue("uri"));
|
||||
|
||||
debug.message(4, "systemSuffix",
|
||||
atts.getValue("systemIdSuffix"),
|
||||
atts.getValue("uri"));
|
||||
}
|
||||
} else if (localName.equals("rewriteURI")) {
|
||||
if (checkAttributes(atts, "uriStartString", "rewritePrefix")) {
|
||||
entryType = Catalog.REWRITE_URI;
|
||||
entryArgs.add(atts.getValue("uriStartString"));
|
||||
entryArgs.add(atts.getValue("rewritePrefix"));
|
||||
|
||||
debug.message(4, "rewriteURI",
|
||||
atts.getValue("uriStartString"),
|
||||
atts.getValue("rewritePrefix"));
|
||||
}
|
||||
} else if (localName.equals("uriSuffix")) {
|
||||
if (checkAttributes(atts, "uriSuffix", "uri")) {
|
||||
entryType = Catalog.URI_SUFFIX;
|
||||
entryArgs.add(atts.getValue("uriSuffix"));
|
||||
entryArgs.add(atts.getValue("uri"));
|
||||
|
||||
debug.message(4, "uriSuffix",
|
||||
atts.getValue("uriSuffix"),
|
||||
atts.getValue("uri"));
|
||||
}
|
||||
} else if (localName.equals("nextCatalog")) {
|
||||
if (checkAttributes(atts, "catalog")) {
|
||||
entryType = Catalog.CATALOG;
|
||||
entryArgs.add(atts.getValue("catalog"));
|
||||
|
||||
debug.message(4, "nextCatalog", atts.getValue("catalog"));
|
||||
}
|
||||
} else if (localName.equals("public")) {
|
||||
if (checkAttributes(atts, "publicId", "uri")) {
|
||||
entryType = Catalog.PUBLIC;
|
||||
entryArgs.add(atts.getValue("publicId"));
|
||||
entryArgs.add(atts.getValue("uri"));
|
||||
|
||||
debug.message(4, "public",
|
||||
PublicId.normalize(atts.getValue("publicId")),
|
||||
atts.getValue("uri"));
|
||||
}
|
||||
} else if (localName.equals("system")) {
|
||||
if (checkAttributes(atts, "systemId", "uri")) {
|
||||
entryType = Catalog.SYSTEM;
|
||||
entryArgs.add(atts.getValue("systemId"));
|
||||
entryArgs.add(atts.getValue("uri"));
|
||||
|
||||
debug.message(4, "system",
|
||||
atts.getValue("systemId"),
|
||||
atts.getValue("uri"));
|
||||
}
|
||||
} else if (localName.equals("uri")) {
|
||||
if (checkAttributes(atts, "name", "uri")) {
|
||||
entryType = Catalog.URI;
|
||||
entryArgs.add(atts.getValue("name"));
|
||||
entryArgs.add(atts.getValue("uri"));
|
||||
|
||||
debug.message(4, "uri",
|
||||
atts.getValue("name"),
|
||||
atts.getValue("uri"));
|
||||
}
|
||||
} else if (localName.equals("catalog")) {
|
||||
// nop, start of catalog
|
||||
} else if (localName.equals("group")) {
|
||||
// nop, a group
|
||||
} else {
|
||||
// This is equivalent to an invalid catalog entry type
|
||||
debug.message(1, "Invalid catalog entry type", localName);
|
||||
}
|
||||
|
||||
if (entryType >= 0) {
|
||||
try {
|
||||
CatalogEntry ce = new CatalogEntry(entryType, entryArgs);
|
||||
catalog.addEntry(ce);
|
||||
} catch (CatalogException cex) {
|
||||
if (cex.getExceptionType() == CatalogException.INVALID_ENTRY_TYPE) {
|
||||
debug.message(1, "Invalid catalog entry type", localName);
|
||||
} else if (cex.getExceptionType() == CatalogException.INVALID_ENTRY) {
|
||||
debug.message(1, "Invalid catalog entry", localName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (namespaceURI != null && tr9401NamespaceName.equals(namespaceURI)
|
||||
&& !inExtension) {
|
||||
// This is a TR9401 Catalog entry
|
||||
|
||||
if (atts.getValue("xml:base") != null) {
|
||||
String baseURI = atts.getValue("xml:base");
|
||||
entryType = Catalog.BASE;
|
||||
entryArgs.add(baseURI);
|
||||
baseURIStack.push(baseURI);
|
||||
|
||||
debug.message(4, "xml:base", baseURI);
|
||||
|
||||
try {
|
||||
CatalogEntry ce = new CatalogEntry(entryType, entryArgs);
|
||||
catalog.addEntry(ce);
|
||||
} catch (CatalogException cex) {
|
||||
if (cex.getExceptionType() == CatalogException.INVALID_ENTRY_TYPE) {
|
||||
debug.message(1, "Invalid catalog entry type", localName);
|
||||
} else if (cex.getExceptionType() == CatalogException.INVALID_ENTRY) {
|
||||
debug.message(1, "Invalid catalog entry (base)", localName);
|
||||
}
|
||||
}
|
||||
|
||||
entryType = -1;
|
||||
entryArgs = new Vector();
|
||||
|
||||
} else {
|
||||
baseURIStack.push(baseURIStack.peek());
|
||||
}
|
||||
|
||||
if (localName.equals("doctype")) {
|
||||
entryType = Catalog.DOCTYPE;
|
||||
entryArgs.add(atts.getValue("name"));
|
||||
entryArgs.add(atts.getValue("uri"));
|
||||
} else if (localName.equals("document")) {
|
||||
entryType = Catalog.DOCUMENT;
|
||||
entryArgs.add(atts.getValue("uri"));
|
||||
} else if (localName.equals("dtddecl")) {
|
||||
entryType = Catalog.DTDDECL;
|
||||
entryArgs.add(atts.getValue("publicId"));
|
||||
entryArgs.add(atts.getValue("uri"));
|
||||
} else if (localName.equals("entity")) {
|
||||
entryType = Catalog.ENTITY;
|
||||
entryArgs.add(atts.getValue("name"));
|
||||
entryArgs.add(atts.getValue("uri"));
|
||||
} else if (localName.equals("linktype")) {
|
||||
entryType = Catalog.LINKTYPE;
|
||||
entryArgs.add(atts.getValue("name"));
|
||||
entryArgs.add(atts.getValue("uri"));
|
||||
} else if (localName.equals("notation")) {
|
||||
entryType = Catalog.NOTATION;
|
||||
entryArgs.add(atts.getValue("name"));
|
||||
entryArgs.add(atts.getValue("uri"));
|
||||
} else if (localName.equals("sgmldecl")) {
|
||||
entryType = Catalog.SGMLDECL;
|
||||
entryArgs.add(atts.getValue("uri"));
|
||||
} else {
|
||||
// This is equivalent to an invalid catalog entry type
|
||||
debug.message(1, "Invalid catalog entry type", localName);
|
||||
}
|
||||
|
||||
if (entryType >= 0) {
|
||||
try {
|
||||
CatalogEntry ce = new CatalogEntry(entryType, entryArgs);
|
||||
catalog.addEntry(ce);
|
||||
} catch (CatalogException cex) {
|
||||
if (cex.getExceptionType() == CatalogException.INVALID_ENTRY_TYPE) {
|
||||
debug.message(1, "Invalid catalog entry type", localName);
|
||||
} else if (cex.getExceptionType() == CatalogException.INVALID_ENTRY) {
|
||||
debug.message(1, "Invalid catalog entry", localName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean checkAttributes (Attributes atts, String attName) {
|
||||
if (atts.getValue(attName) == null) {
|
||||
debug.message(1, "Error: required attribute " + attName + " missing.");
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean checkAttributes (Attributes atts,
|
||||
String attName1,
|
||||
String attName2) {
|
||||
return checkAttributes(atts, attName1)
|
||||
&& checkAttributes(atts, attName2);
|
||||
}
|
||||
|
||||
/** The SAX <code>endElement</code> */
|
||||
public void endElement (String namespaceURI,
|
||||
String localName,
|
||||
String qName)
|
||||
throws SAXException {
|
||||
|
||||
int entryType = -1;
|
||||
Vector entryArgs = new Vector();
|
||||
|
||||
boolean inExtension = inExtensionNamespace();
|
||||
|
||||
if (namespaceURI != null
|
||||
&& !inExtension
|
||||
&& (namespaceName.equals(namespaceURI)
|
||||
|| tr9401NamespaceName.equals(namespaceURI))) {
|
||||
|
||||
String popURI = (String) baseURIStack.pop();
|
||||
String baseURI = (String) baseURIStack.peek();
|
||||
|
||||
if (!baseURI.equals(popURI)) {
|
||||
entryType = Catalog.BASE;
|
||||
entryArgs.add(baseURI);
|
||||
|
||||
debug.message(4, "(reset) xml:base", baseURI);
|
||||
|
||||
try {
|
||||
CatalogEntry ce = new CatalogEntry(entryType, entryArgs);
|
||||
catalog.addEntry(ce);
|
||||
} catch (CatalogException cex) {
|
||||
if (cex.getExceptionType() == CatalogException.INVALID_ENTRY_TYPE) {
|
||||
debug.message(1, "Invalid catalog entry type", localName);
|
||||
} else if (cex.getExceptionType() == CatalogException.INVALID_ENTRY) {
|
||||
debug.message(1, "Invalid catalog entry (rbase)", localName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (namespaceURI != null && namespaceName.equals(namespaceURI)
|
||||
&& !inExtension) {
|
||||
if (localName.equals("catalog") || localName.equals("group")) {
|
||||
String popOverride = (String) overrideStack.pop();
|
||||
String override = (String) overrideStack.peek();
|
||||
|
||||
if (!override.equals(popOverride)) {
|
||||
entryType = Catalog.OVERRIDE;
|
||||
entryArgs.add(override);
|
||||
overrideStack.push(override);
|
||||
|
||||
debug.message(4, "(reset) override", override);
|
||||
|
||||
try {
|
||||
CatalogEntry ce = new CatalogEntry(entryType, entryArgs);
|
||||
catalog.addEntry(ce);
|
||||
} catch (CatalogException cex) {
|
||||
if (cex.getExceptionType() == CatalogException.INVALID_ENTRY_TYPE) {
|
||||
debug.message(1, "Invalid catalog entry type", localName);
|
||||
} else if (cex.getExceptionType() == CatalogException.INVALID_ENTRY) {
|
||||
debug.message(1, "Invalid catalog entry (roverride)", localName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespaceStack.pop();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/** The SAX <code>characters</code> method does nothing. */
|
||||
public void characters (char ch[], int start, int length)
|
||||
throws SAXException {
|
||||
return;
|
||||
}
|
||||
|
||||
/** The SAX <code>ignorableWhitespace</code> method does nothing. */
|
||||
public void ignorableWhitespace (char ch[], int start, int length)
|
||||
throws SAXException {
|
||||
return;
|
||||
}
|
||||
|
||||
/** The SAX <code>processingInstruction</code> method does nothing. */
|
||||
public void processingInstruction (String target, String data)
|
||||
throws SAXException {
|
||||
return;
|
||||
}
|
||||
|
||||
/** The SAX <code>skippedEntity</code> method does nothing. */
|
||||
public void skippedEntity (String name)
|
||||
throws SAXException {
|
||||
return;
|
||||
}
|
||||
|
||||
/** The SAX <code>startPrefixMapping</code> method does nothing. */
|
||||
public void startPrefixMapping(String prefix, String uri)
|
||||
throws SAXException {
|
||||
return;
|
||||
}
|
||||
|
||||
/** The SAX <code>endPrefixMapping</code> method does nothing. */
|
||||
public void endPrefixMapping(String prefix)
|
||||
throws SAXException {
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.sun.org.apache.xml.internal.resolver.readers;
|
||||
|
||||
import com.sun.org.apache.xml.internal.resolver.Catalog;
|
||||
import org.xml.sax.*;
|
||||
|
||||
/**
|
||||
* The SAXCatalogParser interface.
|
||||
*
|
||||
* <p>This interface must be implemented in order for a class to
|
||||
* participate as a parser for the SAXCatalogReader.
|
||||
*
|
||||
* @see Catalog
|
||||
* @see SAXCatalogReader
|
||||
*
|
||||
* @author Norman Walsh
|
||||
* <a href="mailto:Norman.Walsh@Sun.COM">Norman.Walsh@Sun.COM</a>
|
||||
*
|
||||
*/
|
||||
public interface SAXCatalogParser extends ContentHandler, DocumentHandler {
|
||||
/** Set the Catalog for which parsing is being performed. */
|
||||
public void setCatalog(Catalog catalog);
|
||||
}
|
||||
@ -1,503 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
*/
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.sun.org.apache.xml.internal.resolver.readers;
|
||||
|
||||
import com.sun.org.apache.xml.internal.resolver.Catalog;
|
||||
import com.sun.org.apache.xml.internal.resolver.CatalogException;
|
||||
import com.sun.org.apache.xml.internal.resolver.CatalogManager;
|
||||
import com.sun.org.apache.xml.internal.resolver.helpers.Debug;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
import org.xml.sax.AttributeList;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.ContentHandler;
|
||||
import org.xml.sax.DocumentHandler;
|
||||
import org.xml.sax.EntityResolver;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.Locator;
|
||||
import org.xml.sax.Parser;
|
||||
import org.xml.sax.SAXException;
|
||||
import sun.reflect.misc.ReflectUtil;
|
||||
|
||||
/**
|
||||
* A SAX-based CatalogReader.
|
||||
*
|
||||
* <p>This class is used to read XML Catalogs using the SAX. This reader
|
||||
* has an advantage over the DOM-based reader in that it functions on
|
||||
* the stream of SAX events. It has the disadvantage
|
||||
* that it cannot look around in the tree.</p>
|
||||
*
|
||||
* <p>Since the choice of CatalogReaders (in the InputStream case) can only
|
||||
* be made on the basis of MIME type, the following problem occurs: only
|
||||
* one CatalogReader can exist for all XML mime types. In order to get
|
||||
* around this problem, the SAXCatalogReader relies on a set of external
|
||||
* CatalogParsers to actually build the catalog.</p>
|
||||
*
|
||||
* <p>The selection of CatalogParsers is made on the basis of the QName
|
||||
* of the root element of the document.</p>
|
||||
*
|
||||
* @see Catalog
|
||||
* @see CatalogReader
|
||||
* @see SAXCatalogReader
|
||||
* @see TextCatalogReader
|
||||
* @see DOMCatalogParser
|
||||
*
|
||||
* @author Norman Walsh
|
||||
* <a href="mailto:Norman.Walsh@Sun.COM">Norman.Walsh@Sun.COM</a>
|
||||
*
|
||||
*/
|
||||
public class SAXCatalogReader implements CatalogReader, ContentHandler, DocumentHandler {
|
||||
/** The SAX Parser Factory */
|
||||
protected SAXParserFactory parserFactory = null;
|
||||
|
||||
/** The SAX Parser Class */
|
||||
protected String parserClass = null;
|
||||
|
||||
/**
|
||||
* Mapping table from QNames to CatalogParser classes.
|
||||
*
|
||||
* <p>Each key in this hash table has the form "elementname"
|
||||
* or "{namespaceuri}elementname". The former is used if the
|
||||
* namespace URI is null.</p>
|
||||
*/
|
||||
protected Map<String, String> namespaceMap = new HashMap<>();
|
||||
|
||||
/** The parser in use for the current catalog. */
|
||||
private SAXCatalogParser saxParser = null;
|
||||
|
||||
/** Set if something goes horribly wrong. It allows the class to
|
||||
* ignore the rest of the events that are received.
|
||||
*/
|
||||
private boolean abandonHope = false;
|
||||
|
||||
/** The Catalog that we're working for. */
|
||||
private Catalog catalog;
|
||||
|
||||
/** Set the XML SAX Parser Factory.
|
||||
*/
|
||||
public void setParserFactory(SAXParserFactory parserFactory) {
|
||||
this.parserFactory = parserFactory;
|
||||
}
|
||||
|
||||
/** Set the XML SAX Parser Class
|
||||
*/
|
||||
public void setParserClass(String parserClass) {
|
||||
this.parserClass = parserClass;
|
||||
}
|
||||
|
||||
/** Get the parser factory currently in use. */
|
||||
public SAXParserFactory getParserFactory() {
|
||||
return parserFactory;
|
||||
}
|
||||
|
||||
/** Get the parser class currently in use. */
|
||||
public String getParserClass() {
|
||||
return parserClass;
|
||||
}
|
||||
|
||||
/** The debug class to use for this reader.
|
||||
*
|
||||
* This is a bit of a hack. Anyway, whenever we read for a catalog,
|
||||
* we extract the debug object
|
||||
* from the catalog's manager so that we can use it to print messages.
|
||||
*
|
||||
* In production, we don't really expect any messages so it doesn't
|
||||
* really matter. But it's still a bit of a hack.
|
||||
*/
|
||||
protected Debug debug = CatalogManager.getStaticManager().debug;
|
||||
|
||||
/** The constructor */
|
||||
public SAXCatalogReader() {
|
||||
parserFactory = null;
|
||||
parserClass = null;
|
||||
}
|
||||
|
||||
/** The constructor */
|
||||
public SAXCatalogReader(SAXParserFactory parserFactory) {
|
||||
this.parserFactory = parserFactory;
|
||||
}
|
||||
|
||||
/** The constructor */
|
||||
public SAXCatalogReader(String parserClass) {
|
||||
this.parserClass = parserClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the SAXCatalogParser class for the given namespace/root
|
||||
* element type.
|
||||
*/
|
||||
public void setCatalogParser(String namespaceURI,
|
||||
String rootElement,
|
||||
String parserClass) {
|
||||
namespaceURI = namespaceURI != null ? namespaceURI.trim() : "";
|
||||
namespaceMap.put("{"+namespaceURI+"}"+rootElement, parserClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SAXCatalogParser class for the given namespace/root
|
||||
* element type.
|
||||
*/
|
||||
public String getCatalogParser(String namespaceURI,
|
||||
String rootElement) {
|
||||
namespaceURI = namespaceURI != null ? namespaceURI.trim() : "";
|
||||
return namespaceMap.get("{"+namespaceURI+"}"+rootElement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an XML Catalog file.
|
||||
*
|
||||
* @param catalog The catalog to which this catalog file belongs
|
||||
* @param fileUrl The URL or filename of the catalog file to process
|
||||
*
|
||||
* @throws MalformedURLException Improper fileUrl
|
||||
* @throws IOException Error reading catalog file
|
||||
*/
|
||||
public void readCatalog(Catalog catalog, String fileUrl)
|
||||
throws MalformedURLException, IOException,
|
||||
CatalogException {
|
||||
|
||||
URL url = null;
|
||||
|
||||
try {
|
||||
url = new URL(fileUrl);
|
||||
} catch (MalformedURLException e) {
|
||||
url = new URL("file:///" + fileUrl);
|
||||
}
|
||||
|
||||
debug = catalog.getCatalogManager().debug;
|
||||
|
||||
try {
|
||||
URLConnection urlCon = url.openConnection();
|
||||
readCatalog(catalog, urlCon.getInputStream());
|
||||
} catch (FileNotFoundException e) {
|
||||
catalog.getCatalogManager().debug.message(1, "Failed to load catalog, file not found",
|
||||
url.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an XML Catalog stream.
|
||||
*
|
||||
* @param catalog The catalog to which this catalog file belongs
|
||||
* @param is The input stream from which the catalog will be read
|
||||
*
|
||||
* @throws MalformedURLException Improper fileUrl
|
||||
* @throws IOException Error reading catalog file
|
||||
* @throws CatalogException A Catalog exception
|
||||
*/
|
||||
public void readCatalog(Catalog catalog, InputStream is)
|
||||
throws IOException, CatalogException {
|
||||
|
||||
// Create an instance of the parser
|
||||
if (parserFactory == null && parserClass == null) {
|
||||
debug.message(1, "Cannot read SAX catalog without a parser");
|
||||
throw new CatalogException(CatalogException.UNPARSEABLE);
|
||||
}
|
||||
|
||||
debug = catalog.getCatalogManager().debug;
|
||||
EntityResolver bResolver = catalog.getCatalogManager().getBootstrapResolver();
|
||||
|
||||
this.catalog = catalog;
|
||||
|
||||
try {
|
||||
if (parserFactory != null) {
|
||||
SAXParser parser = parserFactory.newSAXParser();
|
||||
SAXParserHandler spHandler = new SAXParserHandler();
|
||||
spHandler.setContentHandler(this);
|
||||
if (bResolver != null) {
|
||||
spHandler.setEntityResolver(bResolver);
|
||||
}
|
||||
parser.parse(new InputSource(is), spHandler);
|
||||
} else {
|
||||
Class<?> c = ReflectUtil.forName(parserClass);
|
||||
if (!Parser.class.isAssignableFrom(c)) {
|
||||
throw new ClassCastException(parserClass
|
||||
+ " cannot be cast to "
|
||||
+ Parser.class.getName());
|
||||
}
|
||||
Parser parser = (Parser) c.newInstance();
|
||||
parser.setDocumentHandler(this);
|
||||
if (bResolver != null) {
|
||||
parser.setEntityResolver(bResolver);
|
||||
}
|
||||
parser.parse(new InputSource(is));
|
||||
}
|
||||
} catch (ClassNotFoundException cnfe) {
|
||||
throw new CatalogException(CatalogException.UNPARSEABLE);
|
||||
} catch (IllegalAccessException iae) {
|
||||
throw new CatalogException(CatalogException.UNPARSEABLE);
|
||||
} catch (InstantiationException ie) {
|
||||
throw new CatalogException(CatalogException.UNPARSEABLE);
|
||||
} catch (ParserConfigurationException pce) {
|
||||
throw new CatalogException(CatalogException.UNKNOWN_FORMAT);
|
||||
} catch (SAXException se) {
|
||||
Exception e = se.getException();
|
||||
// FIXME: there must be a better way
|
||||
UnknownHostException uhe = new UnknownHostException();
|
||||
FileNotFoundException fnfe = new FileNotFoundException();
|
||||
if (e != null) {
|
||||
if (e.getClass() == uhe.getClass()) {
|
||||
throw new CatalogException(CatalogException.PARSE_FAILED,
|
||||
e.toString());
|
||||
} else if (e.getClass() == fnfe.getClass()) {
|
||||
throw new CatalogException(CatalogException.PARSE_FAILED,
|
||||
e.toString());
|
||||
}
|
||||
}
|
||||
throw new CatalogException(se);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Implement the SAX ContentHandler interface
|
||||
|
||||
/** The SAX <code>setDocumentLocator</code> method. Does nothing. */
|
||||
public void setDocumentLocator (Locator locator) {
|
||||
if (saxParser != null) {
|
||||
saxParser.setDocumentLocator(locator);
|
||||
}
|
||||
}
|
||||
|
||||
/** The SAX <code>startDocument</code> method. Does nothing. */
|
||||
public void startDocument () throws SAXException {
|
||||
saxParser = null;
|
||||
abandonHope = false;
|
||||
return;
|
||||
}
|
||||
|
||||
/** The SAX <code>endDocument</code> method. Does nothing. */
|
||||
public void endDocument ()throws SAXException {
|
||||
if (saxParser != null) {
|
||||
saxParser.endDocument();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The SAX <code>startElement</code> method.
|
||||
*
|
||||
* <p>The catalog parser is selected based on the namespace of the
|
||||
* first element encountered in the catalog.</p>
|
||||
*/
|
||||
public void startElement (String name,
|
||||
AttributeList atts)
|
||||
throws SAXException {
|
||||
|
||||
if (abandonHope) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (saxParser == null) {
|
||||
String prefix = "";
|
||||
if (name.indexOf(':') > 0) {
|
||||
prefix = name.substring(0, name.indexOf(':'));
|
||||
}
|
||||
|
||||
String localName = name;
|
||||
if (localName.indexOf(':') > 0) {
|
||||
localName = localName.substring(localName.indexOf(':')+1);
|
||||
}
|
||||
|
||||
String namespaceURI = null;
|
||||
if (prefix.length() == 0) {
|
||||
namespaceURI = atts.getValue("xmlns");
|
||||
} else {
|
||||
namespaceURI = atts.getValue("xmlns:" + prefix);
|
||||
}
|
||||
|
||||
String saxParserClass = getCatalogParser(namespaceURI,
|
||||
localName);
|
||||
|
||||
if (saxParserClass == null) {
|
||||
abandonHope = true;
|
||||
if (namespaceURI == null) {
|
||||
debug.message(2, "No Catalog parser for " + name);
|
||||
} else {
|
||||
debug.message(2, "No Catalog parser for "
|
||||
+ "{" + namespaceURI + "}"
|
||||
+ name);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
saxParser = (SAXCatalogParser)
|
||||
ReflectUtil.forName(saxParserClass).newInstance();
|
||||
|
||||
saxParser.setCatalog(catalog);
|
||||
saxParser.startDocument();
|
||||
saxParser.startElement(name, atts);
|
||||
} catch (ClassNotFoundException cnfe) {
|
||||
saxParser = null;
|
||||
abandonHope = true;
|
||||
debug.message(2, cnfe.toString());
|
||||
} catch (InstantiationException ie) {
|
||||
saxParser = null;
|
||||
abandonHope = true;
|
||||
debug.message(2, ie.toString());
|
||||
} catch (IllegalAccessException iae) {
|
||||
saxParser = null;
|
||||
abandonHope = true;
|
||||
debug.message(2, iae.toString());
|
||||
} catch (ClassCastException cce ) {
|
||||
saxParser = null;
|
||||
abandonHope = true;
|
||||
debug.message(2, cce.toString());
|
||||
}
|
||||
} else {
|
||||
saxParser.startElement(name, atts);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The SAX2 <code>startElement</code> method.
|
||||
*
|
||||
* <p>The catalog parser is selected based on the namespace of the
|
||||
* first element encountered in the catalog.</p>
|
||||
*/
|
||||
public void startElement (String namespaceURI,
|
||||
String localName,
|
||||
String qName,
|
||||
Attributes atts)
|
||||
throws SAXException {
|
||||
|
||||
if (abandonHope) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (saxParser == null) {
|
||||
String saxParserClass = getCatalogParser(namespaceURI,
|
||||
localName);
|
||||
|
||||
if (saxParserClass == null) {
|
||||
abandonHope = true;
|
||||
if (namespaceURI == null) {
|
||||
debug.message(2, "No Catalog parser for " + localName);
|
||||
} else {
|
||||
debug.message(2, "No Catalog parser for "
|
||||
+ "{" + namespaceURI + "}"
|
||||
+ localName);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
saxParser = (SAXCatalogParser)
|
||||
ReflectUtil.forName(saxParserClass).newInstance();
|
||||
|
||||
saxParser.setCatalog(catalog);
|
||||
saxParser.startDocument();
|
||||
saxParser.startElement(namespaceURI, localName, qName, atts);
|
||||
} catch (ClassNotFoundException cnfe) {
|
||||
saxParser = null;
|
||||
abandonHope = true;
|
||||
debug.message(2, cnfe.toString());
|
||||
} catch (InstantiationException ie) {
|
||||
saxParser = null;
|
||||
abandonHope = true;
|
||||
debug.message(2, ie.toString());
|
||||
} catch (IllegalAccessException iae) {
|
||||
saxParser = null;
|
||||
abandonHope = true;
|
||||
debug.message(2, iae.toString());
|
||||
} catch (ClassCastException cce ) {
|
||||
saxParser = null;
|
||||
abandonHope = true;
|
||||
debug.message(2, cce.toString());
|
||||
}
|
||||
} else {
|
||||
saxParser.startElement(namespaceURI, localName, qName, atts);
|
||||
}
|
||||
}
|
||||
|
||||
/** The SAX <code>endElement</code> method. Does nothing. */
|
||||
public void endElement (String name) throws SAXException {
|
||||
if (saxParser != null) {
|
||||
saxParser.endElement(name);
|
||||
}
|
||||
}
|
||||
|
||||
/** The SAX2 <code>endElement</code> method. Does nothing. */
|
||||
public void endElement (String namespaceURI,
|
||||
String localName,
|
||||
String qName) throws SAXException {
|
||||
if (saxParser != null) {
|
||||
saxParser.endElement(namespaceURI, localName, qName);
|
||||
}
|
||||
}
|
||||
|
||||
/** The SAX <code>characters</code> method. Does nothing. */
|
||||
public void characters (char ch[], int start, int length)
|
||||
throws SAXException {
|
||||
if (saxParser != null) {
|
||||
saxParser.characters(ch, start, length);
|
||||
}
|
||||
}
|
||||
|
||||
/** The SAX <code>ignorableWhitespace</code> method. Does nothing. */
|
||||
public void ignorableWhitespace (char ch[], int start, int length)
|
||||
throws SAXException {
|
||||
if (saxParser != null) {
|
||||
saxParser.ignorableWhitespace(ch, start, length);
|
||||
}
|
||||
}
|
||||
|
||||
/** The SAX <code>processingInstruction</code> method. Does nothing. */
|
||||
public void processingInstruction (String target, String data)
|
||||
throws SAXException {
|
||||
if (saxParser != null) {
|
||||
saxParser.processingInstruction(target, data);
|
||||
}
|
||||
}
|
||||
|
||||
/** The SAX <code>startPrefixMapping</code> method. Does nothing. */
|
||||
public void startPrefixMapping (String prefix, String uri)
|
||||
throws SAXException {
|
||||
if (saxParser != null) {
|
||||
saxParser.startPrefixMapping (prefix, uri);
|
||||
}
|
||||
}
|
||||
|
||||
/** The SAX <code>endPrefixMapping</code> method. Does nothing. */
|
||||
public void endPrefixMapping (String prefix)
|
||||
throws SAXException {
|
||||
if (saxParser != null) {
|
||||
saxParser.endPrefixMapping (prefix);
|
||||
}
|
||||
}
|
||||
|
||||
/** The SAX <code>skippedentity</code> method. Does nothing. */
|
||||
public void skippedEntity (String name)
|
||||
throws SAXException {
|
||||
if (saxParser != null) {
|
||||
saxParser.skippedEntity(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,144 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.sun.org.apache.xml.internal.resolver.readers;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.xml.sax.*;
|
||||
import org.xml.sax.helpers.*;
|
||||
|
||||
/**
|
||||
* An entity-resolving DefaultHandler.
|
||||
*
|
||||
* <p>This class provides a SAXParser DefaultHandler that performs
|
||||
* entity resolution.
|
||||
* </p>
|
||||
*
|
||||
* @author Norman Walsh
|
||||
* <a href="mailto:Norman.Walsh@Sun.COM">Norman.Walsh@Sun.COM</a>
|
||||
*/
|
||||
public class SAXParserHandler extends DefaultHandler {
|
||||
private EntityResolver er = null;
|
||||
private ContentHandler ch = null;
|
||||
|
||||
public SAXParserHandler() {
|
||||
super();
|
||||
}
|
||||
|
||||
public void setEntityResolver(EntityResolver er) {
|
||||
this.er = er;
|
||||
}
|
||||
|
||||
public void setContentHandler(ContentHandler ch) {
|
||||
this.ch = ch;
|
||||
}
|
||||
|
||||
// Entity Resolver
|
||||
public InputSource resolveEntity(String publicId, String systemId)
|
||||
throws SAXException {
|
||||
|
||||
if (er != null) {
|
||||
try {
|
||||
return er.resolveEntity(publicId, systemId);
|
||||
} catch (IOException e) {
|
||||
System.out.println("resolveEntity threw IOException!");
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Content Handler
|
||||
public void characters(char[] ch, int start, int length)
|
||||
throws SAXException {
|
||||
if (this.ch != null) {
|
||||
this.ch.characters(ch, start, length);
|
||||
}
|
||||
}
|
||||
|
||||
public void endDocument()
|
||||
throws SAXException {
|
||||
if (ch != null) {
|
||||
ch.endDocument();
|
||||
}
|
||||
}
|
||||
|
||||
public void endElement(String namespaceURI, String localName, String qName)
|
||||
throws SAXException {
|
||||
if (ch != null) {
|
||||
ch.endElement(namespaceURI, localName, qName);
|
||||
}
|
||||
}
|
||||
|
||||
public void endPrefixMapping(String prefix)
|
||||
throws SAXException {
|
||||
if (ch != null) {
|
||||
ch.endPrefixMapping(prefix);
|
||||
}
|
||||
}
|
||||
|
||||
public void ignorableWhitespace(char[] ch, int start, int length)
|
||||
throws SAXException {
|
||||
if (this.ch != null) {
|
||||
this.ch.ignorableWhitespace(ch, start, length);
|
||||
}
|
||||
}
|
||||
|
||||
public void processingInstruction(String target, String data)
|
||||
throws SAXException {
|
||||
if (ch != null) {
|
||||
ch.processingInstruction(target, data);
|
||||
}
|
||||
}
|
||||
|
||||
public void setDocumentLocator(Locator locator) {
|
||||
if (ch != null) {
|
||||
ch.setDocumentLocator(locator);
|
||||
}
|
||||
}
|
||||
|
||||
public void skippedEntity(String name)
|
||||
throws SAXException {
|
||||
if (ch != null) {
|
||||
ch.skippedEntity(name);
|
||||
}
|
||||
}
|
||||
|
||||
public void startDocument()
|
||||
throws SAXException {
|
||||
if (ch != null) {
|
||||
ch.startDocument();
|
||||
}
|
||||
}
|
||||
|
||||
public void startElement(String namespaceURI, String localName,
|
||||
String qName, Attributes atts)
|
||||
throws SAXException {
|
||||
if (ch != null) {
|
||||
ch.startElement(namespaceURI, localName, qName, atts);
|
||||
}
|
||||
}
|
||||
|
||||
public void startPrefixMapping(String prefix, String uri)
|
||||
throws SAXException {
|
||||
if (ch != null) {
|
||||
ch.startPrefixMapping(prefix, uri);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,138 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.sun.org.apache.xml.internal.resolver.readers;
|
||||
|
||||
import com.sun.org.apache.xml.internal.resolver.Catalog;
|
||||
import com.sun.org.apache.xml.internal.resolver.CatalogEntry;
|
||||
import com.sun.org.apache.xml.internal.resolver.CatalogException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.Locale;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* Parses OASIS Open Catalog files.
|
||||
*
|
||||
* <p>This class reads OASIS Open Catalog files, returning a stream
|
||||
* of tokens.</p>
|
||||
*
|
||||
* <p>This code interrogates the following non-standard system properties:</p>
|
||||
*
|
||||
* <dl>
|
||||
* <dt><b>xml.catalog.debug</b></dt>
|
||||
* <dd><p>Sets the debug level. A value of 0 is assumed if the
|
||||
* property is not set or is not a number.</p></dd>
|
||||
* </dl>
|
||||
*
|
||||
* @see Catalog
|
||||
*
|
||||
* @author Norman Walsh
|
||||
* <a href="mailto:Norman.Walsh@Sun.COM">Norman.Walsh@Sun.COM</a>
|
||||
*
|
||||
*/
|
||||
public class TR9401CatalogReader extends TextCatalogReader {
|
||||
|
||||
/**
|
||||
* Start parsing an OASIS TR9401 Open Catalog file. The file is
|
||||
* actually read and parsed
|
||||
* as needed by <code>nextEntry</code>.
|
||||
*
|
||||
* <p>In a TR9401 Catalog the 'DELEGATE' entry delegates public
|
||||
* identifiers. There is no delegate entry for system identifiers
|
||||
* or URIs.</p>
|
||||
*
|
||||
* @param catalog The Catalog to populate
|
||||
* @param is The input stream from which to read the TR9401 Catalog
|
||||
*
|
||||
* @throws MalformedURLException Improper fileUrl
|
||||
* @throws IOException Error reading catalog file
|
||||
*/
|
||||
public void readCatalog(Catalog catalog, InputStream is)
|
||||
throws MalformedURLException, IOException {
|
||||
|
||||
catfile = is;
|
||||
|
||||
if (catfile == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Vector unknownEntry = null;
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
String token = nextToken();
|
||||
|
||||
if (token == null) {
|
||||
if (unknownEntry != null) {
|
||||
catalog.unknownEntry(unknownEntry);
|
||||
unknownEntry = null;
|
||||
}
|
||||
catfile.close();
|
||||
catfile = null;
|
||||
return;
|
||||
}
|
||||
|
||||
String entryToken = null;
|
||||
if (caseSensitive) {
|
||||
entryToken = token;
|
||||
} else {
|
||||
entryToken = token.toUpperCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
if (entryToken.equals("DELEGATE")) {
|
||||
entryToken = "DELEGATE_PUBLIC";
|
||||
}
|
||||
|
||||
try {
|
||||
int type = CatalogEntry.getEntryType(entryToken);
|
||||
int numArgs = CatalogEntry.getEntryArgCount(type);
|
||||
Vector args = new Vector();
|
||||
|
||||
if (unknownEntry != null) {
|
||||
catalog.unknownEntry(unknownEntry);
|
||||
unknownEntry = null;
|
||||
}
|
||||
|
||||
for (int count = 0; count < numArgs; count++) {
|
||||
args.addElement(nextToken());
|
||||
}
|
||||
|
||||
catalog.addEntry(new CatalogEntry(entryToken, args));
|
||||
} catch (CatalogException cex) {
|
||||
if (cex.getExceptionType() == CatalogException.INVALID_ENTRY_TYPE) {
|
||||
if (unknownEntry == null) {
|
||||
unknownEntry = new Vector();
|
||||
}
|
||||
unknownEntry.addElement(token);
|
||||
} else if (cex.getExceptionType() == CatalogException.INVALID_ENTRY) {
|
||||
catalog.getCatalogManager().debug.message(1, "Invalid catalog entry", token);
|
||||
unknownEntry = null;
|
||||
} else if (cex.getExceptionType() == CatalogException.UNENDED_COMMENT) {
|
||||
catalog.getCatalogManager().debug.message(1, cex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (CatalogException cex2) {
|
||||
if (cex2.getExceptionType() == CatalogException.UNENDED_COMMENT) {
|
||||
catalog.getCatalogManager().debug.message(1, cex2.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,298 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.sun.org.apache.xml.internal.resolver.readers;
|
||||
|
||||
import com.sun.org.apache.xml.internal.resolver.Catalog;
|
||||
import com.sun.org.apache.xml.internal.resolver.CatalogEntry;
|
||||
import com.sun.org.apache.xml.internal.resolver.CatalogException;
|
||||
import com.sun.org.apache.xml.internal.resolver.readers.CatalogReader;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.Locale;
|
||||
import java.util.Stack;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* Parses plain text Catalog files.
|
||||
*
|
||||
* <p>This class reads plain text Open Catalog files.</p>
|
||||
*
|
||||
* @see Catalog
|
||||
*
|
||||
* @author Norman Walsh
|
||||
* <a href="mailto:Norman.Walsh@Sun.COM">Norman.Walsh@Sun.COM</a>
|
||||
*
|
||||
*/
|
||||
public class TextCatalogReader implements CatalogReader {
|
||||
/** The input stream used to read the catalog */
|
||||
protected InputStream catfile = null;
|
||||
|
||||
/**
|
||||
* Character lookahead stack. Reading a catalog sometimes requires
|
||||
* up to two characters of lookahead.
|
||||
*/
|
||||
protected int[] stack = new int[3];
|
||||
|
||||
/**
|
||||
* Token stack. Recognizing an unexpected catalog entry requires
|
||||
* the ability to "push back" a token.
|
||||
*/
|
||||
protected Stack tokenStack = new Stack();
|
||||
|
||||
/** The current position on the lookahead stack */
|
||||
protected int top = -1;
|
||||
|
||||
/** Are keywords in the catalog case sensitive? */
|
||||
protected boolean caseSensitive = false;
|
||||
|
||||
/**
|
||||
* Construct a CatalogReader object.
|
||||
*/
|
||||
public TextCatalogReader() { }
|
||||
|
||||
public void setCaseSensitive(boolean isCaseSensitive) {
|
||||
caseSensitive = isCaseSensitive;
|
||||
}
|
||||
|
||||
public boolean getCaseSensitive() {
|
||||
return caseSensitive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start parsing a text catalog file. The file is
|
||||
* actually read and parsed
|
||||
* as needed by <code>nextEntry</code>.</p>
|
||||
*
|
||||
* @param fileUrl The URL or filename of the catalog file to process
|
||||
*
|
||||
* @throws MalformedURLException Improper fileUrl
|
||||
* @throws IOException Error reading catalog file
|
||||
*/
|
||||
public void readCatalog(Catalog catalog, String fileUrl)
|
||||
throws MalformedURLException, IOException {
|
||||
URL catURL = null;
|
||||
|
||||
try {
|
||||
catURL = new URL(fileUrl);
|
||||
} catch (MalformedURLException e) {
|
||||
catURL = new URL("file:///" + fileUrl);
|
||||
}
|
||||
|
||||
URLConnection urlCon = catURL.openConnection();
|
||||
try {
|
||||
readCatalog(catalog, urlCon.getInputStream());
|
||||
} catch (FileNotFoundException e) {
|
||||
catalog.getCatalogManager().debug.message(1, "Failed to load catalog, file not found",
|
||||
catURL.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public void readCatalog(Catalog catalog, InputStream is)
|
||||
throws MalformedURLException, IOException {
|
||||
|
||||
catfile = is;
|
||||
|
||||
if (catfile == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Vector unknownEntry = null;
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
String token = nextToken();
|
||||
|
||||
if (token == null) {
|
||||
if (unknownEntry != null) {
|
||||
catalog.unknownEntry(unknownEntry);
|
||||
unknownEntry = null;
|
||||
}
|
||||
catfile.close();
|
||||
catfile = null;
|
||||
return;
|
||||
}
|
||||
|
||||
String entryToken = null;
|
||||
if (caseSensitive) {
|
||||
entryToken = token;
|
||||
} else {
|
||||
entryToken = token.toUpperCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
try {
|
||||
int type = CatalogEntry.getEntryType(entryToken);
|
||||
int numArgs = CatalogEntry.getEntryArgCount(type);
|
||||
Vector args = new Vector();
|
||||
|
||||
if (unknownEntry != null) {
|
||||
catalog.unknownEntry(unknownEntry);
|
||||
unknownEntry = null;
|
||||
}
|
||||
|
||||
for (int count = 0; count < numArgs; count++) {
|
||||
args.addElement(nextToken());
|
||||
}
|
||||
|
||||
catalog.addEntry(new CatalogEntry(entryToken, args));
|
||||
} catch (CatalogException cex) {
|
||||
if (cex.getExceptionType() == CatalogException.INVALID_ENTRY_TYPE) {
|
||||
if (unknownEntry == null) {
|
||||
unknownEntry = new Vector();
|
||||
}
|
||||
unknownEntry.addElement(token);
|
||||
} else if (cex.getExceptionType() == CatalogException.INVALID_ENTRY) {
|
||||
catalog.getCatalogManager().debug.message(1, "Invalid catalog entry", token);
|
||||
unknownEntry = null;
|
||||
} else if (cex.getExceptionType() == CatalogException.UNENDED_COMMENT) {
|
||||
catalog.getCatalogManager().debug.message(1, cex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (CatalogException cex2) {
|
||||
if (cex2.getExceptionType() == CatalogException.UNENDED_COMMENT) {
|
||||
catalog.getCatalogManager().debug.message(1, cex2.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The destructor.
|
||||
*
|
||||
* <p>Makes sure the catalog file is closed.</p>
|
||||
*/
|
||||
protected void finalize() {
|
||||
if (catfile != null) {
|
||||
try {
|
||||
catfile.close();
|
||||
} catch (IOException e) {
|
||||
// whatever...
|
||||
}
|
||||
}
|
||||
catfile = null;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Return the next token in the catalog file.
|
||||
*
|
||||
* <p>FYI: This code does not throw any sort of exception for
|
||||
* a file that contains an n
|
||||
*
|
||||
* @return The Catalog file token from the input stream.
|
||||
* @throws IOException If an error occurs reading from the stream.
|
||||
*/
|
||||
protected String nextToken() throws IOException, CatalogException {
|
||||
String token = "";
|
||||
int ch, nextch;
|
||||
|
||||
if (!tokenStack.empty()) {
|
||||
return (String) tokenStack.pop();
|
||||
}
|
||||
|
||||
// Skip over leading whitespace and comments
|
||||
while (true) {
|
||||
// skip leading whitespace
|
||||
ch = catfile.read();
|
||||
while (ch <= ' ') { // all ctrls are whitespace
|
||||
ch = catfile.read();
|
||||
if (ch < 0) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// now 'ch' is the current char from the file
|
||||
nextch = catfile.read();
|
||||
if (nextch < 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (ch == '-' && nextch == '-') {
|
||||
// we've found a comment, skip it...
|
||||
ch = ' ';
|
||||
nextch = nextChar();
|
||||
while ((ch != '-' || nextch != '-') && nextch > 0) {
|
||||
ch = nextch;
|
||||
nextch = nextChar();
|
||||
}
|
||||
|
||||
if (nextch < 0) {
|
||||
throw new CatalogException(CatalogException.UNENDED_COMMENT,
|
||||
"Unterminated comment in catalog file; EOF treated as end-of-comment.");
|
||||
}
|
||||
|
||||
// Ok, we've found the end of the comment,
|
||||
// loop back to the top and start again...
|
||||
} else {
|
||||
stack[++top] = nextch;
|
||||
stack[++top] = ch;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ch = nextChar();
|
||||
if (ch == '"' || ch == '\'') {
|
||||
int quote = ch;
|
||||
while ((ch = nextChar()) != quote) {
|
||||
char[] chararr = new char[1];
|
||||
chararr[0] = (char) ch;
|
||||
String s = new String(chararr);
|
||||
token = token.concat(s);
|
||||
}
|
||||
return token;
|
||||
} else {
|
||||
// return the next whitespace or comment delimited
|
||||
// string
|
||||
while (ch > ' ') {
|
||||
nextch = nextChar();
|
||||
if (ch == '-' && nextch == '-') {
|
||||
stack[++top] = ch;
|
||||
stack[++top] = nextch;
|
||||
return token;
|
||||
} else {
|
||||
char[] chararr = new char[1];
|
||||
chararr[0] = (char) ch;
|
||||
String s = new String(chararr);
|
||||
token = token.concat(s);
|
||||
ch = nextch;
|
||||
}
|
||||
}
|
||||
return token;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the next logical character from the input stream.
|
||||
*
|
||||
* @return The next (logical) character from the input stream. The
|
||||
* character may be buffered from a previous lookahead.
|
||||
*
|
||||
* @throws IOException If an error occurs reading from the stream.
|
||||
*/
|
||||
protected int nextChar() throws IOException {
|
||||
if (top < 0) {
|
||||
return catfile.read();
|
||||
} else {
|
||||
return stack[top--];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,208 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.sun.org.apache.xml.internal.resolver.readers;
|
||||
|
||||
import java.util.Vector;
|
||||
import com.sun.org.apache.xml.internal.resolver.Catalog;
|
||||
import com.sun.org.apache.xml.internal.resolver.CatalogEntry;
|
||||
import com.sun.org.apache.xml.internal.resolver.CatalogException;
|
||||
import com.sun.org.apache.xml.internal.resolver.helpers.PublicId;
|
||||
|
||||
import org.xml.sax.*;
|
||||
|
||||
import javax.xml.parsers.*;
|
||||
|
||||
/**
|
||||
* Parse "XCatalog" XML Catalog files, this is the XML Catalog format
|
||||
* developed by John Cowan and supported by Apache.
|
||||
*
|
||||
* @see Catalog
|
||||
*
|
||||
* @author Norman Walsh
|
||||
* <a href="mailto:Norman.Walsh@Sun.COM">Norman.Walsh@Sun.COM</a>
|
||||
*
|
||||
*/
|
||||
public class XCatalogReader extends SAXCatalogReader implements SAXCatalogParser {
|
||||
/** The catalog object needs to be stored by the object so that
|
||||
* SAX callbacks can use it.
|
||||
*/
|
||||
protected Catalog catalog = null;
|
||||
|
||||
/** Set the current catalog. */
|
||||
public void setCatalog (Catalog catalog) {
|
||||
this.catalog = catalog;
|
||||
debug = catalog.getCatalogManager().debug;
|
||||
}
|
||||
|
||||
/** Get the current catalog. */
|
||||
public Catalog getCatalog () {
|
||||
return catalog;
|
||||
}
|
||||
|
||||
/** Default constructor */
|
||||
public XCatalogReader() {
|
||||
super();
|
||||
}
|
||||
|
||||
/** Constructor allowing for providing custom SAX parser factory */
|
||||
public XCatalogReader(SAXParserFactory parserFactory, Catalog catalog) {
|
||||
super(parserFactory);
|
||||
setCatalog(catalog);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Implement the SAX ContentHandler interface
|
||||
|
||||
/** The SAX <code>setDocumentLocator</code> method does nothing. */
|
||||
public void setDocumentLocator (Locator locator) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** The SAX <code>startDocument</code> method does nothing. */
|
||||
public void startDocument ()
|
||||
throws SAXException {
|
||||
return;
|
||||
}
|
||||
|
||||
/** The SAX <code>endDocument</code> method does nothing. */
|
||||
public void endDocument ()
|
||||
throws SAXException {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* The SAX <code>startElement</code> method recognizes elements
|
||||
* from the plain catalog format and instantiates CatalogEntry
|
||||
* objects for them.
|
||||
*
|
||||
* @param namespaceURI The namespace name of the element.
|
||||
* @param localName The local name of the element.
|
||||
* @param qName The QName of the element.
|
||||
* @param atts The list of attributes on the element.
|
||||
*
|
||||
* @see CatalogEntry
|
||||
*/
|
||||
public void startElement (String namespaceURI,
|
||||
String localName,
|
||||
String qName,
|
||||
Attributes atts)
|
||||
throws SAXException {
|
||||
|
||||
int entryType = -1;
|
||||
Vector entryArgs = new Vector();
|
||||
|
||||
if (localName.equals("Base")) {
|
||||
entryType = Catalog.BASE;
|
||||
entryArgs.add(atts.getValue("HRef"));
|
||||
|
||||
debug.message(4, "Base", atts.getValue("HRef"));
|
||||
} else if (localName.equals("Delegate")) {
|
||||
entryType = Catalog.DELEGATE_PUBLIC;
|
||||
entryArgs.add(atts.getValue("PublicID"));
|
||||
entryArgs.add(atts.getValue("HRef"));
|
||||
|
||||
debug.message(4, "Delegate",
|
||||
PublicId.normalize(atts.getValue("PublicID")),
|
||||
atts.getValue("HRef"));
|
||||
} else if (localName.equals("Extend")) {
|
||||
entryType = Catalog.CATALOG;
|
||||
entryArgs.add(atts.getValue("HRef"));
|
||||
|
||||
debug.message(4, "Extend", atts.getValue("HRef"));
|
||||
} else if (localName.equals("Map")) {
|
||||
entryType = Catalog.PUBLIC;
|
||||
entryArgs.add(atts.getValue("PublicID"));
|
||||
entryArgs.add(atts.getValue("HRef"));
|
||||
|
||||
debug.message(4, "Map",
|
||||
PublicId.normalize(atts.getValue("PublicID")),
|
||||
atts.getValue("HRef"));
|
||||
} else if (localName.equals("Remap")) {
|
||||
entryType = Catalog.SYSTEM;
|
||||
entryArgs.add(atts.getValue("SystemID"));
|
||||
entryArgs.add(atts.getValue("HRef"));
|
||||
|
||||
debug.message(4, "Remap",
|
||||
atts.getValue("SystemID"),
|
||||
atts.getValue("HRef"));
|
||||
} else if (localName.equals("XCatalog")) {
|
||||
// nop, start of catalog
|
||||
} else {
|
||||
// This is equivalent to an invalid catalog entry type
|
||||
debug.message(1, "Invalid catalog entry type", localName);
|
||||
}
|
||||
|
||||
if (entryType >= 0) {
|
||||
try {
|
||||
CatalogEntry ce = new CatalogEntry(entryType, entryArgs);
|
||||
catalog.addEntry(ce);
|
||||
} catch (CatalogException cex) {
|
||||
if (cex.getExceptionType() == CatalogException.INVALID_ENTRY_TYPE) {
|
||||
debug.message(1, "Invalid catalog entry type", localName);
|
||||
} else if (cex.getExceptionType() == CatalogException.INVALID_ENTRY) {
|
||||
debug.message(1, "Invalid catalog entry", localName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** The SAX <code>endElement</code> method does nothing. */
|
||||
public void endElement (String namespaceURI,
|
||||
String localName,
|
||||
String qName)
|
||||
throws SAXException {
|
||||
return;
|
||||
}
|
||||
|
||||
/** The SAX <code>characters</code> method does nothing. */
|
||||
public void characters (char ch[], int start, int length)
|
||||
throws SAXException {
|
||||
return;
|
||||
}
|
||||
|
||||
/** The SAX <code>ignorableWhitespace</code> method does nothing. */
|
||||
public void ignorableWhitespace (char ch[], int start, int length)
|
||||
throws SAXException {
|
||||
return;
|
||||
}
|
||||
|
||||
/** The SAX <code>processingInstruction</code> method does nothing. */
|
||||
public void processingInstruction (String target, String data)
|
||||
throws SAXException {
|
||||
return;
|
||||
}
|
||||
|
||||
/** The SAX <code>skippedEntity</code> method does nothing. */
|
||||
public void skippedEntity (String name)
|
||||
throws SAXException {
|
||||
return;
|
||||
}
|
||||
|
||||
/** The SAX <code>startPrefixMapping</code> method does nothing. */
|
||||
public void startPrefixMapping(String prefix, String uri)
|
||||
throws SAXException {
|
||||
return;
|
||||
}
|
||||
|
||||
/** The SAX <code>endPrefixMapping</code> method does nothing. */
|
||||
public void endPrefixMapping(String prefix)
|
||||
throws SAXException {
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,349 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.sun.org.apache.xml.internal.resolver.tools;
|
||||
|
||||
import com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.MalformedURLException;
|
||||
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.XMLReader;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.EntityResolver;
|
||||
|
||||
import javax.xml.transform.sax.SAXSource;
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.URIResolver;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
|
||||
import com.sun.org.apache.xml.internal.resolver.Catalog;
|
||||
import com.sun.org.apache.xml.internal.resolver.CatalogManager;
|
||||
import com.sun.org.apache.xml.internal.resolver.helpers.FileURL;
|
||||
|
||||
/**
|
||||
* A SAX EntityResolver/JAXP URIResolver that uses catalogs.
|
||||
*
|
||||
* <p>This class implements both a SAX EntityResolver and a JAXP URIResolver.
|
||||
* </p>
|
||||
*
|
||||
* <p>This resolver understands OASIS TR9401 catalogs, XCatalogs, and the
|
||||
* current working draft of the OASIS Entity Resolution Technical
|
||||
* Committee specification.</p>
|
||||
*
|
||||
* @see Catalog
|
||||
* @see org.xml.sax.EntityResolver
|
||||
* @see javax.xml.transform.URIResolver
|
||||
* @deprecated The JDK internal Catalog API in package
|
||||
* {@code com.sun.org.apache.xml.internal.resolver}
|
||||
* is encapsulated in JDK 9. The entire implementation under the package is now
|
||||
* deprecated and subject to removal in a future release. Users of the API
|
||||
* should migrate to the {@linkplain javax.xml.catalog new public API}.
|
||||
* <p>
|
||||
* The new Catalog API is supported throughout the JDK XML Processors, which allows
|
||||
* the use of Catalog by simply setting a path to a Catalog file as a property.
|
||||
*
|
||||
* @author Norman Walsh
|
||||
* <a href="mailto:Norman.Walsh@Sun.COM">Norman.Walsh@Sun.COM</a>
|
||||
*
|
||||
* @version 1.0
|
||||
*/
|
||||
@Deprecated(since="9", forRemoval=true)
|
||||
public class CatalogResolver implements EntityResolver, URIResolver {
|
||||
/** Make the parser Namespace aware? */
|
||||
public boolean namespaceAware = true;
|
||||
|
||||
/** Make the parser validating? */
|
||||
public boolean validating = false;
|
||||
|
||||
/** The underlying catalog */
|
||||
private Catalog catalog = null;
|
||||
|
||||
/** The catalog manager */
|
||||
private CatalogManager catalogManager = CatalogManager.getStaticManager();
|
||||
|
||||
/** Constructor */
|
||||
public CatalogResolver() {
|
||||
initializeCatalogs(false);
|
||||
}
|
||||
|
||||
/** Constructor */
|
||||
public CatalogResolver(boolean privateCatalog) {
|
||||
initializeCatalogs(privateCatalog);
|
||||
}
|
||||
|
||||
/** Constructor */
|
||||
public CatalogResolver(CatalogManager manager) {
|
||||
catalogManager = manager;
|
||||
initializeCatalogs(!catalogManager.getUseStaticCatalog());
|
||||
}
|
||||
|
||||
/** Initialize catalog */
|
||||
private void initializeCatalogs(boolean privateCatalog) {
|
||||
catalog = catalogManager.getCatalog();
|
||||
}
|
||||
|
||||
/** Return the underlying catalog */
|
||||
public Catalog getCatalog() {
|
||||
return catalog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the guts of the <code>resolveEntity</code> method
|
||||
* for the SAX interface.
|
||||
*
|
||||
* <p>Presented with an optional public identifier and a system
|
||||
* identifier, this function attempts to locate a mapping in the
|
||||
* catalogs.</p>
|
||||
*
|
||||
* <p>If such a mapping is found, it is returned. If no mapping is
|
||||
* found, null is returned.</p>
|
||||
*
|
||||
* @param publicId The public identifier for the entity in question.
|
||||
* This may be null.
|
||||
*
|
||||
* @param systemId The system identifier for the entity in question.
|
||||
* XML requires a system identifier on all external entities, so this
|
||||
* value is always specified.
|
||||
*
|
||||
* @return The resolved identifier (a URI reference).
|
||||
*/
|
||||
public String getResolvedEntity (String publicId, String systemId) {
|
||||
String resolved = null;
|
||||
|
||||
if (catalog == null) {
|
||||
catalogManager.debug.message(1, "Catalog resolution attempted with null catalog; ignored");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (systemId != null) {
|
||||
try {
|
||||
resolved = catalog.resolveSystem(systemId);
|
||||
} catch (MalformedURLException me) {
|
||||
catalogManager.debug.message(1, "Malformed URL exception trying to resolve",
|
||||
publicId);
|
||||
resolved = null;
|
||||
} catch (IOException ie) {
|
||||
catalogManager.debug.message(1, "I/O exception trying to resolve", publicId);
|
||||
resolved = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (resolved == null) {
|
||||
if (publicId != null) {
|
||||
try {
|
||||
resolved = catalog.resolvePublic(publicId, systemId);
|
||||
} catch (MalformedURLException me) {
|
||||
catalogManager.debug.message(1, "Malformed URL exception trying to resolve",
|
||||
publicId);
|
||||
} catch (IOException ie) {
|
||||
catalogManager.debug.message(1, "I/O exception trying to resolve", publicId);
|
||||
}
|
||||
}
|
||||
|
||||
if (resolved != null) {
|
||||
catalogManager.debug.message(2, "Resolved public", publicId, resolved);
|
||||
}
|
||||
} else {
|
||||
catalogManager.debug.message(2, "Resolved system", systemId, resolved);
|
||||
}
|
||||
|
||||
return resolved;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the <code>resolveEntity</code> method
|
||||
* for the SAX interface.
|
||||
*
|
||||
* <p>Presented with an optional public identifier and a system
|
||||
* identifier, this function attempts to locate a mapping in the
|
||||
* catalogs.</p>
|
||||
*
|
||||
* <p>If such a mapping is found, the resolver attempts to open
|
||||
* the mapped value as an InputSource and return it. Exceptions are
|
||||
* ignored and null is returned if the mapped value cannot be opened
|
||||
* as an input source.</p>
|
||||
*
|
||||
* <p>If no mapping is found (or an error occurs attempting to open
|
||||
* the mapped value as an input source), null is returned and the system
|
||||
* will use the specified system identifier as if no entityResolver
|
||||
* was specified.</p>
|
||||
*
|
||||
* @param publicId The public identifier for the entity in question.
|
||||
* This may be null.
|
||||
*
|
||||
* @param systemId The system identifier for the entity in question.
|
||||
* XML requires a system identifier on all external entities, so this
|
||||
* value is always specified.
|
||||
*
|
||||
* @return An InputSource for the mapped identifier, or null.
|
||||
*/
|
||||
public InputSource resolveEntity (String publicId, String systemId) {
|
||||
String resolved = getResolvedEntity(publicId, systemId);
|
||||
|
||||
if (resolved != null) {
|
||||
try {
|
||||
InputSource iSource = new InputSource(resolved);
|
||||
iSource.setPublicId(publicId);
|
||||
|
||||
// Ideally this method would not attempt to open the
|
||||
// InputStream, but there is a bug (in Xerces, at least)
|
||||
// that causes the parser to mistakenly open the wrong
|
||||
// system identifier if the returned InputSource does
|
||||
// not have a byteStream.
|
||||
//
|
||||
// It could be argued that we still shouldn't do this here,
|
||||
// but since the purpose of calling the entityResolver is
|
||||
// almost certainly to open the input stream, it seems to
|
||||
// do little harm.
|
||||
//
|
||||
URL url = new URL(resolved);
|
||||
InputStream iStream = url.openStream();
|
||||
iSource.setByteStream(iStream);
|
||||
|
||||
return iSource;
|
||||
} catch (Exception e) {
|
||||
catalogManager.debug.message(1,
|
||||
"Failed to create InputSource ("
|
||||
+ e.toString()
|
||||
+ ")", resolved);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/** JAXP URIResolver API */
|
||||
public Source resolve(String href, String base)
|
||||
throws TransformerException {
|
||||
|
||||
String uri = href;
|
||||
String fragment = null;
|
||||
int hashPos = href.indexOf("#");
|
||||
if (hashPos >= 0) {
|
||||
uri = href.substring(0, hashPos);
|
||||
fragment = href.substring(hashPos+1);
|
||||
}
|
||||
|
||||
String result = null;
|
||||
|
||||
try {
|
||||
result = catalog.resolveURI(href);
|
||||
} catch (Exception e) {
|
||||
// nop;
|
||||
}
|
||||
|
||||
if (result == null) {
|
||||
try {
|
||||
URL url = null;
|
||||
|
||||
if (base==null) {
|
||||
url = new URL(uri);
|
||||
result = url.toString();
|
||||
} else {
|
||||
URL baseURL = new URL(base);
|
||||
url = (href.length()==0 ? baseURL : new URL(baseURL, uri));
|
||||
result = url.toString();
|
||||
}
|
||||
} catch (java.net.MalformedURLException mue) {
|
||||
// try to make an absolute URI from the current base
|
||||
String absBase = makeAbsolute(base);
|
||||
if (!absBase.equals(base)) {
|
||||
// don't bother if the absBase isn't different!
|
||||
return resolve(href, absBase);
|
||||
} else {
|
||||
throw new TransformerException("Malformed URL "
|
||||
+ href + "(base " + base + ")",
|
||||
mue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
catalogManager.debug.message(2, "Resolved URI", href, result);
|
||||
|
||||
SAXSource source = new SAXSource();
|
||||
source.setInputSource(new InputSource(result));
|
||||
setEntityResolver(source);
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Establish an entityResolver for newly resolved URIs.</p>
|
||||
*
|
||||
* <p>This is called from the URIResolver to set an EntityResolver
|
||||
* on the SAX parser to be used for new XML documents that are
|
||||
* encountered as a result of the document() function, xsl:import,
|
||||
* or xsl:include. This is done because the XSLT processor calls
|
||||
* out to the SAXParserFactory itself to create a new SAXParser to
|
||||
* parse the new document. The new parser does not automatically
|
||||
* inherit the EntityResolver of the original (although arguably
|
||||
* it should). See below:</p>
|
||||
*
|
||||
* <tt>"If an application wants to set the ErrorHandler or
|
||||
* EntityResolver for an XMLReader used during a transformation,
|
||||
* it should use a URIResolver to return the SAXSource which
|
||||
* provides (with getXMLReader) a reference to the XMLReader"</tt>
|
||||
*
|
||||
* <p>...quoted from page 118 of the Java API for XML
|
||||
* Processing 1.1 specification</p>
|
||||
*
|
||||
*/
|
||||
private void setEntityResolver(SAXSource source) throws TransformerException {
|
||||
XMLReader reader = source.getXMLReader();
|
||||
if (reader == null) {
|
||||
SAXParserFactory spFactory = catalogManager.useServicesMechanism() ?
|
||||
SAXParserFactory.newInstance() : new SAXParserFactoryImpl();
|
||||
spFactory.setNamespaceAware(true);
|
||||
try {
|
||||
reader = spFactory.newSAXParser().getXMLReader();
|
||||
}
|
||||
catch (ParserConfigurationException ex) {
|
||||
throw new TransformerException(ex);
|
||||
}
|
||||
catch (SAXException ex) {
|
||||
throw new TransformerException(ex);
|
||||
}
|
||||
}
|
||||
reader.setEntityResolver(this);
|
||||
source.setXMLReader(reader);
|
||||
}
|
||||
|
||||
/** Attempt to construct an absolute URI */
|
||||
private String makeAbsolute(String uri) {
|
||||
if (uri == null) {
|
||||
uri = "";
|
||||
}
|
||||
|
||||
try {
|
||||
URL url = new URL(uri);
|
||||
return url.toString();
|
||||
} catch (MalformedURLException mue) {
|
||||
try {
|
||||
URL fileURL = FileURL.makeURL(uri);
|
||||
return fileURL.toString();
|
||||
} catch (MalformedURLException mue2) {
|
||||
// bail
|
||||
return uri;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,434 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.sun.org.apache.xml.internal.resolver.tools;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.xml.sax.Parser;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.Locator;
|
||||
import org.xml.sax.ErrorHandler;
|
||||
import org.xml.sax.DTDHandler;
|
||||
import org.xml.sax.DocumentHandler;
|
||||
import org.xml.sax.AttributeList;
|
||||
import org.xml.sax.EntityResolver;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
|
||||
import com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl;
|
||||
import com.sun.org.apache.xml.internal.resolver.Catalog;
|
||||
import com.sun.org.apache.xml.internal.resolver.CatalogManager;
|
||||
import com.sun.org.apache.xml.internal.resolver.helpers.FileURL;
|
||||
|
||||
/**
|
||||
* A SAX Parser that performs catalog-based entity resolution.
|
||||
*
|
||||
* <p>This class implements a SAX Parser that performs entity resolution
|
||||
* using the CatalogResolver. The actual, underlying parser is obtained
|
||||
* from a SAXParserFactory.</p>
|
||||
* </p>
|
||||
*
|
||||
* @deprecated This interface has been replaced by the
|
||||
* {@link com.sun.org.apache.xml.internal.resolver.tools.ResolvingXMLReader} for SAX2.
|
||||
* @see CatalogResolver
|
||||
* @see org.xml.sax.Parser
|
||||
*
|
||||
* @author Norman Walsh
|
||||
* <a href="mailto:Norman.Walsh@Sun.COM">Norman.Walsh@Sun.COM</a>
|
||||
*
|
||||
* @version 1.0
|
||||
*/
|
||||
public class ResolvingParser
|
||||
implements Parser, DTDHandler, DocumentHandler, EntityResolver {
|
||||
|
||||
/** Suppress explanatory message?
|
||||
*
|
||||
* @see #parse(InputSource)
|
||||
*/
|
||||
private static final boolean suppressExplanation = false;
|
||||
|
||||
/** The underlying parser. */
|
||||
private SAXParser saxParser = null;
|
||||
|
||||
/** The underlying reader. */
|
||||
private Parser parser = null;
|
||||
|
||||
/** The underlying DocumentHandler. */
|
||||
private DocumentHandler documentHandler = null;
|
||||
|
||||
/** The underlying DTDHandler. */
|
||||
private DTDHandler dtdHandler = null;
|
||||
|
||||
/** The manager for the underlying resolver. */
|
||||
private CatalogManager catalogManager = CatalogManager.getStaticManager();
|
||||
|
||||
/** The underlying catalog resolver. */
|
||||
private CatalogResolver catalogResolver = null;
|
||||
|
||||
/** A separate resolver for oasis-xml-pi catalogs. */
|
||||
private CatalogResolver piCatalogResolver = null;
|
||||
|
||||
/** Are we in the prolog? Is an oasis-xml-catalog PI valid now? */
|
||||
private boolean allowXMLCatalogPI = false;
|
||||
|
||||
/** The base URI of the input document, if known. */
|
||||
private URL baseURL = null;
|
||||
|
||||
/** Constructor. */
|
||||
public ResolvingParser() {
|
||||
initParser();
|
||||
}
|
||||
|
||||
/** Constructor. */
|
||||
public ResolvingParser(CatalogManager manager) {
|
||||
catalogManager = manager;
|
||||
initParser();
|
||||
}
|
||||
|
||||
/** Initialize the parser. */
|
||||
private void initParser() {
|
||||
catalogResolver = new CatalogResolver(catalogManager);
|
||||
SAXParserFactory spf = catalogManager.useServicesMechanism() ?
|
||||
SAXParserFactory.newInstance() : new SAXParserFactoryImpl();
|
||||
spf.setNamespaceAware(true);
|
||||
spf.setValidating(false);
|
||||
|
||||
try {
|
||||
saxParser = spf.newSAXParser();
|
||||
parser = saxParser.getParser();
|
||||
documentHandler = null;
|
||||
dtdHandler = null;
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/** Return the Catalog being used. */
|
||||
public Catalog getCatalog() {
|
||||
return catalogResolver.getCatalog();
|
||||
}
|
||||
|
||||
/**
|
||||
* SAX Parser API.
|
||||
*
|
||||
* <p>Note that the JAXP 1.1ea2 parser crashes with an InternalError if
|
||||
* it encounters a system identifier that appears to be a relative URI
|
||||
* that begins with a slash. For example, the declaration:</p>
|
||||
*
|
||||
* <pre>
|
||||
* <!DOCTYPE book SYSTEM "/path/to/dtd/on/my/system/docbookx.dtd">
|
||||
* </pre>
|
||||
*
|
||||
* <p>would cause such an error. As a convenience, this method catches
|
||||
* that error and prints an explanation. (Unfortunately, it's not possible
|
||||
* to identify the particular system identifier that causes the problem.)
|
||||
* </p>
|
||||
*
|
||||
* <p>The underlying error is forwarded after printing the explanatory
|
||||
* message. The message is only every printed once and if
|
||||
* <code>suppressExplanation</code> is set to <code>false</code> before
|
||||
* parsing, it will never be printed.</p>
|
||||
*/
|
||||
public void parse(InputSource input)
|
||||
throws IOException,
|
||||
SAXException {
|
||||
setupParse(input.getSystemId());
|
||||
try {
|
||||
parser.parse(input);
|
||||
} catch (InternalError ie) {
|
||||
explain(input.getSystemId());
|
||||
throw ie;
|
||||
}
|
||||
}
|
||||
|
||||
/** SAX Parser API.
|
||||
*
|
||||
* @see #parse(InputSource)
|
||||
*/
|
||||
public void parse(String systemId)
|
||||
throws IOException,
|
||||
SAXException {
|
||||
setupParse(systemId);
|
||||
try {
|
||||
parser.parse(systemId);
|
||||
} catch (InternalError ie) {
|
||||
explain(systemId);
|
||||
throw ie;
|
||||
}
|
||||
}
|
||||
|
||||
/** SAX Parser API. */
|
||||
public void setDocumentHandler(DocumentHandler handler) {
|
||||
documentHandler = handler;
|
||||
}
|
||||
|
||||
/** SAX Parser API. */
|
||||
public void setDTDHandler(DTDHandler handler) {
|
||||
dtdHandler = handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* SAX Parser API.
|
||||
*
|
||||
* <p>The purpose of this class is to implement an entity resolver.
|
||||
* Attempting to set a different one is pointless (and ignored).</p>
|
||||
*/
|
||||
public void setEntityResolver(EntityResolver resolver) {
|
||||
// nop
|
||||
}
|
||||
|
||||
/** SAX Parser API. */
|
||||
public void setErrorHandler(ErrorHandler handler) {
|
||||
parser.setErrorHandler(handler);
|
||||
}
|
||||
|
||||
/** SAX Parser API. */
|
||||
public void setLocale(Locale locale) throws SAXException {
|
||||
parser.setLocale(locale);
|
||||
}
|
||||
|
||||
/** SAX DocumentHandler API. */
|
||||
public void characters(char[] ch, int start, int length)
|
||||
throws SAXException {
|
||||
if (documentHandler != null) {
|
||||
documentHandler.characters(ch,start,length);
|
||||
}
|
||||
}
|
||||
|
||||
/** SAX DocumentHandler API. */
|
||||
public void endDocument() throws SAXException {
|
||||
if (documentHandler != null) {
|
||||
documentHandler.endDocument();
|
||||
}
|
||||
}
|
||||
|
||||
/** SAX DocumentHandler API. */
|
||||
public void endElement(String name) throws SAXException {
|
||||
if (documentHandler != null) {
|
||||
documentHandler.endElement(name);
|
||||
}
|
||||
}
|
||||
|
||||
/** SAX DocumentHandler API. */
|
||||
public void ignorableWhitespace(char[] ch, int start, int length)
|
||||
throws SAXException {
|
||||
if (documentHandler != null) {
|
||||
documentHandler.ignorableWhitespace(ch,start,length);
|
||||
}
|
||||
}
|
||||
|
||||
/** SAX DocumentHandler API. */
|
||||
public void processingInstruction(String target, String pidata)
|
||||
throws SAXException {
|
||||
|
||||
if (target.equals("oasis-xml-catalog")) {
|
||||
URL catalog = null;
|
||||
String data = pidata;
|
||||
|
||||
int pos = data.indexOf("catalog=");
|
||||
if (pos >= 0) {
|
||||
data = data.substring(pos+8);
|
||||
if (data.length() > 1) {
|
||||
String quote = data.substring(0,1);
|
||||
data = data.substring(1);
|
||||
pos = data.indexOf(quote);
|
||||
if (pos >= 0) {
|
||||
data = data.substring(0, pos);
|
||||
try {
|
||||
if (baseURL != null) {
|
||||
catalog = new URL(baseURL, data);
|
||||
} else {
|
||||
catalog = new URL(data);
|
||||
}
|
||||
} catch (MalformedURLException mue) {
|
||||
// nevermind
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (allowXMLCatalogPI) {
|
||||
if (catalogManager.getAllowOasisXMLCatalogPI()) {
|
||||
catalogManager.debug.message(4,"oasis-xml-catalog PI", pidata);
|
||||
|
||||
if (catalog != null) {
|
||||
try {
|
||||
catalogManager.debug.message(4,"oasis-xml-catalog", catalog.toString());
|
||||
|
||||
if (piCatalogResolver == null) {
|
||||
piCatalogResolver = new CatalogResolver(true);
|
||||
}
|
||||
|
||||
piCatalogResolver.getCatalog().parseCatalog(catalog.toString());
|
||||
} catch (Exception e) {
|
||||
catalogManager.debug.message(3, "Exception parsing oasis-xml-catalog: "
|
||||
+ catalog.toString());
|
||||
}
|
||||
} else {
|
||||
catalogManager.debug.message(3, "PI oasis-xml-catalog unparseable: " + pidata);
|
||||
}
|
||||
} else {
|
||||
catalogManager.debug.message(4,"PI oasis-xml-catalog ignored: " + pidata);
|
||||
}
|
||||
} else {
|
||||
catalogManager.debug.message(3, "PI oasis-xml-catalog occurred in an invalid place: "
|
||||
+ pidata);
|
||||
}
|
||||
} else {
|
||||
if (documentHandler != null) {
|
||||
documentHandler.processingInstruction(target, pidata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** SAX DocumentHandler API. */
|
||||
public void setDocumentLocator(Locator locator) {
|
||||
if (documentHandler != null) {
|
||||
documentHandler.setDocumentLocator(locator);
|
||||
}
|
||||
}
|
||||
|
||||
/** SAX DocumentHandler API. */
|
||||
public void startDocument() throws SAXException {
|
||||
if (documentHandler != null) {
|
||||
documentHandler.startDocument();
|
||||
}
|
||||
}
|
||||
|
||||
/** SAX DocumentHandler API. */
|
||||
public void startElement(String name, AttributeList atts)
|
||||
throws SAXException {
|
||||
allowXMLCatalogPI = false;
|
||||
if (documentHandler != null) {
|
||||
documentHandler.startElement(name,atts);
|
||||
}
|
||||
}
|
||||
|
||||
/** SAX DTDHandler API. */
|
||||
public void notationDecl (String name, String publicId, String systemId)
|
||||
throws SAXException {
|
||||
allowXMLCatalogPI = false;
|
||||
if (dtdHandler != null) {
|
||||
dtdHandler.notationDecl(name,publicId,systemId);
|
||||
}
|
||||
}
|
||||
|
||||
/** SAX DTDHandler API. */
|
||||
public void unparsedEntityDecl (String name,
|
||||
String publicId,
|
||||
String systemId,
|
||||
String notationName)
|
||||
throws SAXException {
|
||||
allowXMLCatalogPI = false;
|
||||
if (dtdHandler != null) {
|
||||
dtdHandler.unparsedEntityDecl (name, publicId, systemId, notationName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the <code>resolveEntity</code> method
|
||||
* for the SAX interface, using an underlying CatalogResolver
|
||||
* to do the real work.
|
||||
*/
|
||||
public InputSource resolveEntity (String publicId, String systemId) {
|
||||
allowXMLCatalogPI = false;
|
||||
String resolved = catalogResolver.getResolvedEntity(publicId, systemId);
|
||||
|
||||
if (resolved == null && piCatalogResolver != null) {
|
||||
resolved = piCatalogResolver.getResolvedEntity(publicId, systemId);
|
||||
}
|
||||
|
||||
if (resolved != null) {
|
||||
try {
|
||||
InputSource iSource = new InputSource(resolved);
|
||||
iSource.setPublicId(publicId);
|
||||
|
||||
// Ideally this method would not attempt to open the
|
||||
// InputStream, but there is a bug (in Xerces, at least)
|
||||
// that causes the parser to mistakenly open the wrong
|
||||
// system identifier if the returned InputSource does
|
||||
// not have a byteStream.
|
||||
//
|
||||
// It could be argued that we still shouldn't do this here,
|
||||
// but since the purpose of calling the entityResolver is
|
||||
// almost certainly to open the input stream, it seems to
|
||||
// do little harm.
|
||||
//
|
||||
URL url = new URL(resolved);
|
||||
InputStream iStream = url.openStream();
|
||||
iSource.setByteStream(iStream);
|
||||
|
||||
return iSource;
|
||||
} catch (Exception e) {
|
||||
catalogManager.debug.message(1,
|
||||
"Failed to create InputSource ("
|
||||
+ e.toString()
|
||||
+ ")", resolved);
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Setup for parsing. */
|
||||
private void setupParse(String systemId) {
|
||||
allowXMLCatalogPI = true;
|
||||
parser.setEntityResolver(this);
|
||||
parser.setDocumentHandler(this);
|
||||
parser.setDTDHandler(this);
|
||||
|
||||
URL cwd = null;
|
||||
|
||||
try {
|
||||
cwd = FileURL.makeURL("basename");
|
||||
} catch (MalformedURLException mue) {
|
||||
cwd = null;
|
||||
}
|
||||
|
||||
try {
|
||||
baseURL = new URL(systemId);
|
||||
} catch (MalformedURLException mue) {
|
||||
if (cwd != null) {
|
||||
try {
|
||||
baseURL = new URL(cwd, systemId);
|
||||
} catch (MalformedURLException mue2) {
|
||||
// give up
|
||||
baseURL = null;
|
||||
}
|
||||
} else {
|
||||
// give up
|
||||
baseURL = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Provide one possible explanation for an InternalError. */
|
||||
private void explain(String systemId) {
|
||||
if (!suppressExplanation) {
|
||||
System.out.println("Parser probably encountered bad URI in " + systemId);
|
||||
System.out.println("For example, replace '/some/uri' with 'file:/some/uri'.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,346 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.sun.org.apache.xml.internal.resolver.tools;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.XMLReader;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.helpers.XMLFilterImpl;
|
||||
|
||||
import com.sun.org.apache.xml.internal.resolver.Catalog;
|
||||
import com.sun.org.apache.xml.internal.resolver.CatalogManager;
|
||||
|
||||
import com.sun.org.apache.xml.internal.resolver.helpers.FileURL;
|
||||
|
||||
/**
|
||||
* A SAX XMLFilter that performs catalog-based entity resolution.
|
||||
*
|
||||
* <p>This class implements a SAX XMLFilter that performs entity resolution
|
||||
* using the CatalogResolver. The actual, underlying parser is obtained
|
||||
* from a SAXParserFactory.</p>
|
||||
* </p>
|
||||
*
|
||||
* @see CatalogResolver
|
||||
* @see org.xml.sax.XMLFilter
|
||||
*
|
||||
* @author Norman Walsh
|
||||
* <a href="mailto:Norman.Walsh@Sun.COM">Norman.Walsh@Sun.COM</a>
|
||||
*
|
||||
* @version 1.0
|
||||
*/
|
||||
public class ResolvingXMLFilter extends XMLFilterImpl {
|
||||
/**
|
||||
* Suppress explanatory message?
|
||||
*
|
||||
* @see #parse(InputSource)
|
||||
*/
|
||||
private static boolean suppressExplanation = false;
|
||||
|
||||
/** The manager for the underlying resolver. */
|
||||
CatalogManager catalogManager = CatalogManager.getStaticManager();
|
||||
|
||||
/** The underlying catalog resolver. */
|
||||
private CatalogResolver catalogResolver = null;
|
||||
|
||||
/** A separate resolver for oasis-xml-pi catalogs. */
|
||||
private CatalogResolver piCatalogResolver = null;
|
||||
|
||||
/** Are we in the prolog? Is an oasis-xml-catalog PI valid now? */
|
||||
private boolean allowXMLCatalogPI = false;
|
||||
|
||||
/** The base URI of the input document, if known. */
|
||||
private URL baseURL = null;
|
||||
|
||||
/** Construct an empty XML Filter with no parent. */
|
||||
public ResolvingXMLFilter() {
|
||||
super();
|
||||
catalogResolver = new CatalogResolver(catalogManager);
|
||||
}
|
||||
|
||||
/** Construct an XML filter with the specified parent. */
|
||||
public ResolvingXMLFilter(XMLReader parent) {
|
||||
super(parent);
|
||||
catalogResolver = new CatalogResolver(catalogManager);
|
||||
}
|
||||
|
||||
/** Construct an XML filter with the specified parent. */
|
||||
public ResolvingXMLFilter(CatalogManager manager) {
|
||||
super();
|
||||
catalogManager = manager;
|
||||
catalogResolver = new CatalogResolver(catalogManager);
|
||||
}
|
||||
|
||||
/** Construct an XML filter with the specified parent. */
|
||||
public ResolvingXMLFilter(XMLReader parent, CatalogManager manager) {
|
||||
super(parent);
|
||||
catalogManager = manager;
|
||||
catalogResolver = new CatalogResolver(catalogManager);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide accessto the underlying Catalog.
|
||||
*/
|
||||
public Catalog getCatalog() {
|
||||
return catalogResolver.getCatalog();
|
||||
}
|
||||
|
||||
/**
|
||||
* SAX XMLReader API.
|
||||
*
|
||||
* <p>Note that the JAXP 1.1ea2 parser crashes with an InternalError if
|
||||
* it encounters a system identifier that appears to be a relative URI
|
||||
* that begins with a slash. For example, the declaration:</p>
|
||||
*
|
||||
* <pre>
|
||||
* <!DOCTYPE book SYSTEM "/path/to/dtd/on/my/system/docbookx.dtd">
|
||||
* </pre>
|
||||
*
|
||||
* <p>would cause such an error. As a convenience, this method catches
|
||||
* that error and prints an explanation. (Unfortunately, it's not possible
|
||||
* to identify the particular system identifier that causes the problem.)
|
||||
* </p>
|
||||
*
|
||||
* <p>The underlying error is forwarded after printing the explanatory
|
||||
* message. The message is only every printed once and if
|
||||
* <code>suppressExplanation</code> is set to <code>false</code> before
|
||||
* parsing, it will never be printed.</p>
|
||||
*/
|
||||
public void parse(InputSource input)
|
||||
throws IOException, SAXException {
|
||||
allowXMLCatalogPI = true;
|
||||
|
||||
setupBaseURI(input.getSystemId());
|
||||
|
||||
try {
|
||||
super.parse(input);
|
||||
} catch (InternalError ie) {
|
||||
explain(input.getSystemId());
|
||||
throw ie;
|
||||
}
|
||||
}
|
||||
|
||||
/** SAX XMLReader API.
|
||||
*
|
||||
* @see #parse(InputSource)
|
||||
*/
|
||||
public void parse(String systemId)
|
||||
throws IOException, SAXException {
|
||||
allowXMLCatalogPI = true;
|
||||
|
||||
setupBaseURI(systemId);
|
||||
|
||||
try {
|
||||
super.parse(systemId);
|
||||
} catch (InternalError ie) {
|
||||
explain(systemId);
|
||||
throw ie;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the <code>resolveEntity</code> method
|
||||
* for the SAX interface, using an underlying CatalogResolver
|
||||
* to do the real work.
|
||||
*/
|
||||
public InputSource resolveEntity (String publicId, String systemId) {
|
||||
allowXMLCatalogPI = false;
|
||||
String resolved = catalogResolver.getResolvedEntity(publicId, systemId);
|
||||
|
||||
if (resolved == null && piCatalogResolver != null) {
|
||||
resolved = piCatalogResolver.getResolvedEntity(publicId, systemId);
|
||||
}
|
||||
|
||||
if (resolved != null) {
|
||||
try {
|
||||
InputSource iSource = new InputSource(resolved);
|
||||
iSource.setPublicId(publicId);
|
||||
|
||||
// Ideally this method would not attempt to open the
|
||||
// InputStream, but there is a bug (in Xerces, at least)
|
||||
// that causes the parser to mistakenly open the wrong
|
||||
// system identifier if the returned InputSource does
|
||||
// not have a byteStream.
|
||||
//
|
||||
// It could be argued that we still shouldn't do this here,
|
||||
// but since the purpose of calling the entityResolver is
|
||||
// almost certainly to open the input stream, it seems to
|
||||
// do little harm.
|
||||
//
|
||||
URL url = new URL(resolved);
|
||||
InputStream iStream = url.openStream();
|
||||
iSource.setByteStream(iStream);
|
||||
|
||||
return iSource;
|
||||
} catch (Exception e) {
|
||||
catalogManager.debug.message(1,
|
||||
"Failed to create InputSource ("
|
||||
+ e.toString()
|
||||
+ ")", resolved);
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** SAX DTDHandler API.
|
||||
*
|
||||
* <p>Captured here only to detect the end of the prolog so that
|
||||
* we can ignore subsequent oasis-xml-catalog PIs. Otherwise
|
||||
* the events are just passed through.</p>
|
||||
*/
|
||||
public void notationDecl (String name, String publicId, String systemId)
|
||||
throws SAXException {
|
||||
allowXMLCatalogPI = false;
|
||||
super.notationDecl(name,publicId,systemId);
|
||||
}
|
||||
|
||||
/** SAX DTDHandler API.
|
||||
*
|
||||
* <p>Captured here only to detect the end of the prolog so that
|
||||
* we can ignore subsequent oasis-xml-catalog PIs. Otherwise
|
||||
* the events are just passed through.</p>
|
||||
*/
|
||||
public void unparsedEntityDecl (String name,
|
||||
String publicId,
|
||||
String systemId,
|
||||
String notationName)
|
||||
throws SAXException {
|
||||
allowXMLCatalogPI = false;
|
||||
super.unparsedEntityDecl (name, publicId, systemId, notationName);
|
||||
}
|
||||
|
||||
/** SAX ContentHandler API.
|
||||
*
|
||||
* <p>Captured here only to detect the end of the prolog so that
|
||||
* we can ignore subsequent oasis-xml-catalog PIs. Otherwise
|
||||
* the events are just passed through.</p>
|
||||
*/
|
||||
public void startElement (String uri, String localName, String qName,
|
||||
Attributes atts)
|
||||
throws SAXException {
|
||||
allowXMLCatalogPI = false;
|
||||
super.startElement(uri,localName,qName,atts);
|
||||
}
|
||||
|
||||
/** SAX ContentHandler API.
|
||||
*
|
||||
* <p>Detect and use the oasis-xml-catalog PI if it occurs.</p>
|
||||
*/
|
||||
public void processingInstruction(String target, String pidata)
|
||||
throws SAXException {
|
||||
if (target.equals("oasis-xml-catalog")) {
|
||||
URL catalog = null;
|
||||
String data = pidata;
|
||||
|
||||
int pos = data.indexOf("catalog=");
|
||||
if (pos >= 0) {
|
||||
data = data.substring(pos+8);
|
||||
if (data.length() > 1) {
|
||||
String quote = data.substring(0,1);
|
||||
data = data.substring(1);
|
||||
pos = data.indexOf(quote);
|
||||
if (pos >= 0) {
|
||||
data = data.substring(0, pos);
|
||||
try {
|
||||
if (baseURL != null) {
|
||||
catalog = new URL(baseURL, data);
|
||||
} else {
|
||||
catalog = new URL(data);
|
||||
}
|
||||
} catch (MalformedURLException mue) {
|
||||
// nevermind
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (allowXMLCatalogPI) {
|
||||
if (catalogManager.getAllowOasisXMLCatalogPI()) {
|
||||
catalogManager.debug.message(4,"oasis-xml-catalog PI", pidata);
|
||||
|
||||
if (catalog != null) {
|
||||
try {
|
||||
catalogManager.debug.message(4,"oasis-xml-catalog", catalog.toString());
|
||||
|
||||
if (piCatalogResolver == null) {
|
||||
piCatalogResolver = new CatalogResolver(true);
|
||||
}
|
||||
|
||||
piCatalogResolver.getCatalog().parseCatalog(catalog.toString());
|
||||
} catch (Exception e) {
|
||||
catalogManager.debug.message(3, "Exception parsing oasis-xml-catalog: "
|
||||
+ catalog.toString());
|
||||
}
|
||||
} else {
|
||||
catalogManager.debug.message(3, "PI oasis-xml-catalog unparseable: " + pidata);
|
||||
}
|
||||
} else {
|
||||
catalogManager.debug.message(4,"PI oasis-xml-catalog ignored: " + pidata);
|
||||
}
|
||||
} else {
|
||||
catalogManager.debug.message(3, "PI oasis-xml-catalog occurred in an invalid place: "
|
||||
+ pidata);
|
||||
}
|
||||
} else {
|
||||
super.processingInstruction(target, pidata);
|
||||
}
|
||||
}
|
||||
|
||||
/** Save the base URI of the document being parsed. */
|
||||
private void setupBaseURI(String systemId) {
|
||||
URL cwd = null;
|
||||
|
||||
try {
|
||||
cwd = FileURL.makeURL("basename");
|
||||
} catch (MalformedURLException mue) {
|
||||
cwd = null;
|
||||
}
|
||||
|
||||
try {
|
||||
baseURL = new URL(systemId);
|
||||
} catch (MalformedURLException mue) {
|
||||
if (cwd != null) {
|
||||
try {
|
||||
baseURL = new URL(cwd, systemId);
|
||||
} catch (MalformedURLException mue2) {
|
||||
// give up
|
||||
baseURL = null;
|
||||
}
|
||||
} else {
|
||||
// give up
|
||||
baseURL = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Provide one possible explanation for an InternalError. */
|
||||
private void explain(String systemId) {
|
||||
if (!suppressExplanation) {
|
||||
System.out.println("XMLReader probably encountered bad URI in " + systemId);
|
||||
System.out.println("For example, replace '/some/uri' with 'file:/some/uri'.");
|
||||
}
|
||||
suppressExplanation = true;
|
||||
}
|
||||
}
|
||||
@ -1,90 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.sun.org.apache.xml.internal.resolver.tools;
|
||||
|
||||
|
||||
import javax.xml.parsers.*;
|
||||
|
||||
import com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl;
|
||||
import com.sun.org.apache.xml.internal.resolver.*;
|
||||
|
||||
/**
|
||||
* A SAX XMLReader that performs catalog-based entity resolution.
|
||||
*
|
||||
* <p>This class implements a SAX XMLReader that performs entity resolution
|
||||
* using the CatalogResolver. The actual, underlying parser is obtained
|
||||
* from a SAXParserFactory.</p>
|
||||
* </p>
|
||||
*
|
||||
* @see CatalogResolver
|
||||
* @see org.xml.sax.XMLReader
|
||||
*
|
||||
* @author Norman Walsh
|
||||
* <a href="mailto:Norman.Walsh@Sun.COM">Norman.Walsh@Sun.COM</a>
|
||||
*
|
||||
* @version 1.0
|
||||
*/
|
||||
public class ResolvingXMLReader extends ResolvingXMLFilter {
|
||||
/** Make the parser Namespace aware? */
|
||||
private static final boolean namespaceAware = true;
|
||||
|
||||
/** Make the parser validating? */
|
||||
private static final boolean validating = false;
|
||||
|
||||
/**
|
||||
* Construct a new reader from the JAXP factory.
|
||||
*
|
||||
* <p>In order to do its job, a ResolvingXMLReader must in fact be
|
||||
* a filter. So the only difference between this code and the filter
|
||||
* code is that the constructor builds a new reader.</p>
|
||||
*/
|
||||
public ResolvingXMLReader() {
|
||||
super();
|
||||
SAXParserFactory spf = catalogManager.useServicesMechanism() ?
|
||||
SAXParserFactory.newInstance() : new SAXParserFactoryImpl();
|
||||
spf.setNamespaceAware(namespaceAware);
|
||||
spf.setValidating(validating);
|
||||
try {
|
||||
SAXParser parser = spf.newSAXParser();
|
||||
setParent(parser.getXMLReader());
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new reader from the JAXP factory.
|
||||
*
|
||||
* <p>In order to do its job, a ResolvingXMLReader must in fact be
|
||||
* a filter. So the only difference between this code and the filter
|
||||
* code is that the constructor builds a new reader.</p>
|
||||
*/
|
||||
public ResolvingXMLReader(CatalogManager manager) {
|
||||
super(manager);
|
||||
SAXParserFactory spf = catalogManager.useServicesMechanism() ?
|
||||
SAXParserFactory.newInstance() : new SAXParserFactoryImpl();
|
||||
spf.setNamespaceAware(namespaceAware);
|
||||
spf.setValidating(validating);
|
||||
try {
|
||||
SAXParser parser = spf.newSAXParser();
|
||||
setParent(parser.getXMLReader());
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -27,6 +27,17 @@
|
||||
* Defines the Java API for XML Processing (JAXP), the Streaming API for XML (StAX),
|
||||
* the Simple API for XML (SAX), and the W3C Document Object Model (DOM) API.
|
||||
*
|
||||
* @uses javax.xml.datatype.DatatypeFactory
|
||||
* @uses javax.xml.parsers.DocumentBuilderFactory
|
||||
* @uses javax.xml.parsers.SAXParserFactory
|
||||
* @uses javax.xml.stream.XMLEventFactory
|
||||
* @uses javax.xml.stream.XMLInputFactory
|
||||
* @uses javax.xml.stream.XMLOutputFactory
|
||||
* @uses javax.xml.transform.TransformerFactory
|
||||
* @uses javax.xml.validation.SchemaFactory
|
||||
* @uses javax.xml.xpath.XPathFactory
|
||||
* @uses org.xml.sax.XMLReader
|
||||
*
|
||||
* @moduleGraph
|
||||
* @since 9
|
||||
*/
|
||||
|
||||
@ -431,3 +431,5 @@ e705867d9989d00e4357f66f18b302c95e13b5e7 jdk-10+8
|
||||
8c615099f3e3ca137325be34bf566b767d9e3c64 jdk-9+172
|
||||
2d22d6732a73e615b9e13d6bc93bf026db3bc231 jdk-10+11
|
||||
2bd967aa452c1e0e87a6173bef6fbb96ef1c521b jdk-9+173
|
||||
c2296642010f1b215ac35da89e92c3ce44104e32 jdk-9+174
|
||||
712a3a657654079514590d37a0f4894d43541d5c jdk-10+12
|
||||
|
||||
@ -26,6 +26,8 @@
|
||||
/**
|
||||
* Defines the Java Architecture for XML Binding (JAXB) API.
|
||||
*
|
||||
* @uses javax.xml.bind.JAXBContextFactory
|
||||
*
|
||||
* @moduleGraph
|
||||
* @since 9
|
||||
*/
|
||||
|
||||
@ -27,6 +27,12 @@
|
||||
* Defines the Java API for XML-Based Web Services (JAX-WS), and
|
||||
* the Web Services Metadata API.
|
||||
*
|
||||
* @uses javax.xml.soap.MessageFactory
|
||||
* @uses javax.xml.soap.SAAJMetaFactory
|
||||
* @uses javax.xml.soap.SOAPConnectionFactory
|
||||
* @uses javax.xml.soap.SOAPFactory
|
||||
* @uses javax.xml.ws.spi.Provider
|
||||
*
|
||||
* @moduleGraph
|
||||
* @since 9
|
||||
*/
|
||||
|
||||
@ -23,6 +23,21 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Defines tools for JAXB classes and XML schema generation,
|
||||
* including the <em>{@index schemagen schemagen tool}</em>
|
||||
* and <em>{@index xjc xjc tool}</em> tools.
|
||||
*
|
||||
* <dl style="font-family:'DejaVu Sans', Arial, Helvetica, sans serif">
|
||||
* <dt class="simpleTagLabel">Tool Guides:
|
||||
* <dd>{@extLink schemagen_tool_reference schemagen},
|
||||
* {@extLink xjc_tool_reference xjc}
|
||||
* </dl>
|
||||
*
|
||||
* @moduleGraph
|
||||
* @since 9
|
||||
*/
|
||||
@Deprecated(since="9", forRemoval=true)
|
||||
module jdk.xml.bind {
|
||||
requires java.activation;
|
||||
requires java.compiler;
|
||||
|
||||
@ -23,6 +23,21 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Defines tools for JAX-WS classes and WSDL generation,
|
||||
* including the <em>{@index wsgen wsgen tool}</em>
|
||||
* and <em>{@index wsimport wsimport tool}</em> tools.
|
||||
*
|
||||
* <dl style="font-family:'DejaVu Sans', Arial, Helvetica, sans serif">
|
||||
* <dt class="simpleTagLabel">Tool Guides:
|
||||
* <dd>{@extLink wsgen_tool_reference wsgen},
|
||||
* {@extLink wsimport_tool_reference wsimport}
|
||||
* </dl>
|
||||
*
|
||||
* @moduleGraph
|
||||
* @since 9
|
||||
*/
|
||||
@Deprecated(since="9", forRemoval=true)
|
||||
module jdk.xml.ws {
|
||||
requires java.compiler;
|
||||
requires java.logging;
|
||||
|
||||
@ -428,3 +428,5 @@ df64bd4757d0d130d62a22b8143ba31d3a16ac18 jdk-10+10
|
||||
0ff9ad7d067cd4fa14450cf208bf019175a0aaba jdk-9+172
|
||||
7c54889c0ec649ee04643e5cace434623d0dc667 jdk-10+11
|
||||
a5506b425f1bf91530d8417b57360e5d89328c0c jdk-9+173
|
||||
42f18c931bd4fae5c206ccf6d8e591e4c4e69d31 jdk-9+174
|
||||
5f504872a75b71f2fb19299f0d1e3395cf32eaa0 jdk-10+12
|
||||
|
||||
@ -77,6 +77,13 @@ ifneq ($(FREETYPE_BUNDLE_LIB_PATH), )
|
||||
endif
|
||||
|
||||
TARGETS += $(FREETYPE_TARGET_LIB)
|
||||
|
||||
$(eval $(call SetupCopyFiles, COPY_FREETYPE_LICENSE, \
|
||||
FILES := $(FREETYPE_LICENSE), \
|
||||
DEST := $(LEGAL_DST_DIR), \
|
||||
))
|
||||
|
||||
TARGETS += $(COPY_FREETYPE_LICENSE)
|
||||
endif
|
||||
|
||||
################################################################################
|
||||
|
||||
@ -10,7 +10,9 @@ java.corba \
|
||||
java.transaction \
|
||||
java.xml.bind \
|
||||
java.xml.ws \
|
||||
java.xml.ws.annotation
|
||||
java.xml.ws.annotation \
|
||||
jdk.xml.bind \
|
||||
jdk.xml.ws
|
||||
|
||||
aggregator_modules=\
|
||||
java.se \
|
||||
|
||||
@ -58,7 +58,7 @@ public class ExtLink implements Taglet {
|
||||
|
||||
static final String URL = "https://www.oracle.com/pls/topic/lookup?ctx=javase9&id=";
|
||||
|
||||
static final Pattern TAG_PATTERN = Pattern.compile("(\\s*)(?<name>\\w+)(\\s+)(?<desc>.*)");
|
||||
static final Pattern TAG_PATTERN = Pattern.compile("(?s)(\\s*)(?<name>\\w+)(\\s+)(?<desc>.*)$");
|
||||
|
||||
/**
|
||||
* Returns the set of locations in which the tag may be used.
|
||||
|
||||
@ -42,12 +42,22 @@ include TestFilesCompilation.gmk
|
||||
# Add more directories here when needed.
|
||||
BUILD_JDK_JTREG_NATIVE_SRC := \
|
||||
$(JDK_TOPDIR)/test/native_sanity \
|
||||
$(JDK_TOPDIR)/test/java/lang/String/nativeEncoding \
|
||||
#
|
||||
|
||||
BUILD_JDK_JTREG_OUTPUT_DIR := $(BUILD_OUTPUT)/support/test/jdk/jtreg/native
|
||||
|
||||
BUILD_JDK_JTREG_IMAGE_DIR := $(TEST_IMAGE_DIR)/jdk/jtreg
|
||||
|
||||
ifeq ($(OPENJDK_TARGET_OS), windows)
|
||||
WIN_LIB_JAVA := $(SUPPORT_OUTPUTDIR)/native/java.base/libjava/java.lib
|
||||
BUILD_JDK_JTREG_LIBRARIES_LIBS_libstringPlatformChars := $(WIN_LIB_JAVA)
|
||||
else ifeq ($(OPENJDK_TARGET_OS), solaris)
|
||||
BUILD_JDK_JTREG_LIBRARIES_LIBS_libstringPlatformChars := -ljava -lc
|
||||
else
|
||||
BUILD_JDK_JTREG_LIBRARIES_LIBS_libstringPlatformChars := -ljava
|
||||
endif
|
||||
|
||||
$(eval $(call SetupTestFilesCompilation, BUILD_JDK_JTREG_LIBRARIES, \
|
||||
TYPE := LIBRARY, \
|
||||
SOURCE_DIRS := $(BUILD_JDK_JTREG_NATIVE_SRC), \
|
||||
|
||||
@ -2146,8 +2146,6 @@ public abstract class ClassLoader {
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*
|
||||
* @see <a href="../../../technotes/guides/jar/jar.html#versioning">
|
||||
* The JAR File Specification: Package Versioning</a>
|
||||
* @see <a href="../../../technotes/guides/jar/jar.html#sealing">
|
||||
* The JAR File Specification: Package Sealing</a>
|
||||
*/
|
||||
|
||||
@ -102,9 +102,13 @@ import jdk.internal.reflect.Reflection;
|
||||
* with the {@link Package#getPackages Package.getPackages()} and
|
||||
* {@link ClassLoader#getDefinedPackages} methods.
|
||||
*
|
||||
* @implNote
|
||||
* The <a href="ClassLoader.html#builtinLoaders">builtin class loaders</a>
|
||||
* do not explicitly define {@code Package} objects for packages in
|
||||
* <em>named modules</em>. Instead those packages are automatically defined
|
||||
* and have no specification and implementation versioning information.
|
||||
*
|
||||
* @jvms 5.3 Run-time package
|
||||
* @see <a href="../../../technotes/guides/jar/jar.html#versioning">
|
||||
* The JAR File Specification: Package Versioning</a>
|
||||
* @see <a href="../../../technotes/guides/jar/jar.html#sealing">
|
||||
* The JAR File Specification: Package Sealing</a>
|
||||
* @see ClassLoader#definePackage(String, String, String, String, String, String, String, URL)
|
||||
|
||||
@ -27,6 +27,7 @@ package java.lang;
|
||||
|
||||
import java.io.ObjectStreamField;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.annotation.Native;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@ -3063,8 +3064,8 @@ public final class String
|
||||
return COMPACT_STRINGS && coder == LATIN1;
|
||||
}
|
||||
|
||||
static final byte LATIN1 = 0;
|
||||
static final byte UTF16 = 1;
|
||||
@Native static final byte LATIN1 = 0;
|
||||
@Native static final byte UTF16 = 1;
|
||||
|
||||
/*
|
||||
* StringIndexOutOfBoundsException if {@code index} is
|
||||
|
||||
@ -1212,7 +1212,7 @@ public class BitSet implements Cloneable, java.io.Serializable {
|
||||
*
|
||||
* <p>The stream binds to this bit set when the terminal stream operation
|
||||
* commences (specifically, the spliterator for the stream is
|
||||
* <a href="../Spliterator.html#binding"><em>late-binding</em></a>). If the
|
||||
* <a href="Spliterator.html#binding"><em>late-binding</em></a>). If the
|
||||
* bit set is modified during that operation then the result is undefined.
|
||||
*
|
||||
* @return a stream of integers representing set indices
|
||||
|
||||
@ -26,6 +26,51 @@
|
||||
/**
|
||||
* Defines the foundational APIs of the Java SE Platform.
|
||||
*
|
||||
* <dl style="font-family:'DejaVu Sans', Arial, Helvetica, sans serif">
|
||||
* <dt class="simpleTagLabel">Providers:</dt>
|
||||
* <dd> The JDK implementation of this module provides an implementation of
|
||||
* the {@index jrt jrt} {@linkplain java.nio.file.spi.FileSystemProvider
|
||||
* file system provider} to enumerate and read the class and resource
|
||||
* files in a run-time image.
|
||||
* The jrt file system can be created by calling
|
||||
* {@link java.nio.file.FileSystems#newFileSystem
|
||||
* FileSystems.newFileSystem(URI.create("jrt:/"))}.
|
||||
* <p></dd>
|
||||
* <dt class="simpleTagLabel">Tool Guides:</dt>
|
||||
* <dd> {@extLink java_tool_reference java launcher},
|
||||
* {@extLink keytool_tool_reference keytool}</dd>
|
||||
* </dl>
|
||||
*
|
||||
* @provides java.nio.file.spi.FileSystemProvider
|
||||
*
|
||||
* @uses java.lang.System.LoggerFinder
|
||||
* @uses java.net.ContentHandlerFactory
|
||||
* @uses java.net.spi.URLStreamHandlerProvider
|
||||
* @uses java.nio.channels.spi.AsynchronousChannelProvider
|
||||
* @uses java.nio.channels.spi.SelectorProvider
|
||||
* @uses java.nio.charset.spi.CharsetProvider
|
||||
* @uses java.nio.file.spi.FileSystemProvider
|
||||
* @uses java.nio.file.spi.FileTypeDetector
|
||||
* @uses java.security.Provider
|
||||
* @uses java.text.spi.BreakIteratorProvider
|
||||
* @uses java.text.spi.CollatorProvider
|
||||
* @uses java.text.spi.DateFormatProvider
|
||||
* @uses java.text.spi.DateFormatSymbolsProvider
|
||||
* @uses java.text.spi.DecimalFormatSymbolsProvider
|
||||
* @uses java.text.spi.NumberFormatProvider
|
||||
* @uses java.time.chrono.AbstractChronology
|
||||
* @uses java.time.chrono.Chronology
|
||||
* @uses java.time.zone.ZoneRulesProvider
|
||||
* @uses java.util.spi.CalendarDataProvider
|
||||
* @uses java.util.spi.CalendarNameProvider
|
||||
* @uses java.util.spi.CurrencyNameProvider
|
||||
* @uses java.util.spi.LocaleNameProvider
|
||||
* @uses java.util.spi.ResourceBundleControlProvider
|
||||
* @uses java.util.spi.ResourceBundleProvider
|
||||
* @uses java.util.spi.TimeZoneNameProvider
|
||||
* @uses java.util.spi.ToolProvider
|
||||
* @uses javax.security.auth.spi.LoginModule
|
||||
*
|
||||
* @moduleGraph
|
||||
* @since 9
|
||||
*/
|
||||
|
||||
@ -29,6 +29,7 @@
|
||||
#include "jvm.h"
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "java_lang_String.h"
|
||||
|
||||
/* Due to a bug in the win32 C runtime library strings
|
||||
* such as "z:" need to be appended with a "." so we
|
||||
@ -442,16 +443,18 @@ JNU_NewObjectByName(JNIEnv *env, const char *class_name,
|
||||
return obj;
|
||||
}
|
||||
|
||||
/* Optimized for char set ISO_8559_1 */
|
||||
/* Optimized for charset ISO_8559_1 */
|
||||
static jstring
|
||||
newString8859_1(JNIEnv *env, const char *str)
|
||||
newSizedString8859_1(JNIEnv *env, const char *str, const int len)
|
||||
{
|
||||
int len = (int)strlen(str);
|
||||
jchar buf[512];
|
||||
jchar *str1;
|
||||
jstring result;
|
||||
int i;
|
||||
|
||||
if ((*env)->EnsureLocalCapacity(env, 1) < 0)
|
||||
return NULL;
|
||||
|
||||
if (len > 512) {
|
||||
str1 = (jchar *)malloc(len * sizeof(jchar));
|
||||
if (str1 == 0) {
|
||||
@ -469,6 +472,13 @@ newString8859_1(JNIEnv *env, const char *str)
|
||||
return result;
|
||||
}
|
||||
|
||||
static jstring
|
||||
newString8859_1(JNIEnv *env, const char *str)
|
||||
{
|
||||
int len = (int)strlen(str);
|
||||
return newSizedString8859_1(env, str, len);
|
||||
}
|
||||
|
||||
static const char*
|
||||
getString8859_1Chars(JNIEnv *env, jstring jstr)
|
||||
{
|
||||
@ -501,7 +511,7 @@ getString8859_1Chars(JNIEnv *env, jstring jstr)
|
||||
}
|
||||
|
||||
|
||||
/* Optimized for char set ISO646-US (us-ascii) */
|
||||
/* Optimized for charset ISO646-US (us-ascii) */
|
||||
static jstring
|
||||
newString646_US(JNIEnv *env, const char *str)
|
||||
{
|
||||
@ -573,7 +583,7 @@ static int cp1252c1chars[32] = {
|
||||
0x02Dc,0x2122,0x0161,0x203A,0x0153,0xFFFD,0x017E,0x0178
|
||||
};
|
||||
|
||||
/* Optimized for char set Cp1252 */
|
||||
/* Optimized for charset Cp1252 */
|
||||
static jstring
|
||||
newStringCp1252(JNIEnv *env, const char *str)
|
||||
{
|
||||
@ -582,6 +592,10 @@ newStringCp1252(JNIEnv *env, const char *str)
|
||||
jchar *str1;
|
||||
jstring result;
|
||||
int i;
|
||||
|
||||
if ((*env)->EnsureLocalCapacity(env, 1) < 0)
|
||||
return NULL;
|
||||
|
||||
if (len > 512) {
|
||||
str1 = (jchar *)malloc(len * sizeof(jchar));
|
||||
if (str1 == 0) {
|
||||
@ -625,9 +639,13 @@ getStringCp1252Chars(JNIEnv *env, jstring jstr)
|
||||
|
||||
for (i=0; i<len; i++) {
|
||||
jchar c = str[i];
|
||||
if (c < 256)
|
||||
result[i] = (char)c;
|
||||
else switch(c) {
|
||||
if (c < 256) {
|
||||
if ((c >= 0x80) && (c <= 0x9f)) {
|
||||
result[i] = '?';
|
||||
} else {
|
||||
result[i] = (char)c;
|
||||
}
|
||||
} else switch(c) {
|
||||
case 0x20AC: result[i] = (char)0x80; break;
|
||||
case 0x201A: result[i] = (char)0x82; break;
|
||||
case 0x0192: result[i] = (char)0x83; break;
|
||||
@ -671,8 +689,89 @@ static jstring jnuEncoding = NULL;
|
||||
static jmethodID String_init_ID; /* String(byte[], enc) */
|
||||
static jmethodID String_getBytes_ID; /* String.getBytes(enc) */
|
||||
|
||||
int getFastEncoding() {
|
||||
return fastEncoding;
|
||||
/* Cached field IDs */
|
||||
static jfieldID String_coder_ID; /* String.coder */
|
||||
static jfieldID String_value_ID; /* String.value */
|
||||
|
||||
static jboolean isJNUEncodingSupported = JNI_FALSE;
|
||||
static jboolean jnuEncodingSupported(JNIEnv *env) {
|
||||
jboolean exe;
|
||||
if (isJNUEncodingSupported == JNI_TRUE) {
|
||||
return JNI_TRUE;
|
||||
}
|
||||
isJNUEncodingSupported = (jboolean) JNU_CallStaticMethodByName (
|
||||
env, &exe,
|
||||
"java/nio/charset/Charset",
|
||||
"isSupported",
|
||||
"(Ljava/lang/String;)Z",
|
||||
jnuEncoding).z;
|
||||
return isJNUEncodingSupported;
|
||||
}
|
||||
|
||||
/* Create a new string by converting str to a heap-allocated byte array and
|
||||
* calling the appropriate String constructor.
|
||||
*/
|
||||
static jstring
|
||||
newSizedStringJava(JNIEnv *env, const char *str, const int len)
|
||||
{
|
||||
jstring result = NULL;
|
||||
jbyteArray bytes = 0;
|
||||
|
||||
if ((*env)->EnsureLocalCapacity(env, 2) < 0)
|
||||
return NULL;
|
||||
|
||||
bytes = (*env)->NewByteArray(env, len);
|
||||
if (bytes != NULL) {
|
||||
jclass strClazz = JNU_ClassString(env);
|
||||
CHECK_NULL_RETURN(strClazz, 0);
|
||||
(*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte *)str);
|
||||
if (jnuEncodingSupported(env)) {
|
||||
result = (*env)->NewObject(env, strClazz,
|
||||
String_init_ID, bytes, jnuEncoding);
|
||||
} else {
|
||||
/*If the encoding specified in sun.jnu.encoding is not endorsed
|
||||
by "Charset.isSupported" we have to fall back to use String(byte[])
|
||||
explicitly here without specifying the encoding name, in which the
|
||||
StringCoding class will pickup the iso-8859-1 as the fallback
|
||||
converter for us.
|
||||
*/
|
||||
jmethodID mid = (*env)->GetMethodID(env, strClazz,
|
||||
"<init>", "([B)V");
|
||||
if (mid != NULL) {
|
||||
result = (*env)->NewObject(env, strClazz, mid, bytes);
|
||||
}
|
||||
}
|
||||
(*env)->DeleteLocalRef(env, bytes);
|
||||
return result;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static jstring
|
||||
newStringJava(JNIEnv *env, const char *str)
|
||||
{
|
||||
int len = (int)strlen(str);
|
||||
return newSizedStringJava(env, str, len);
|
||||
}
|
||||
|
||||
/* Optimized for charset UTF-8 */
|
||||
static jstring
|
||||
newStringUTF8(JNIEnv *env, const char *str)
|
||||
{
|
||||
int len;
|
||||
const unsigned char *p;
|
||||
unsigned char asciiCheck;
|
||||
for (asciiCheck = 0, p = (const unsigned char*)str; *p != '\0'; p++) {
|
||||
asciiCheck |= *p;
|
||||
}
|
||||
len = (int)((const char*)p - str);
|
||||
|
||||
if (asciiCheck < 0x80) {
|
||||
// ascii fast-path
|
||||
return newSizedString8859_1(env, str, len);
|
||||
}
|
||||
|
||||
return newSizedStringJava(env, str, len);
|
||||
}
|
||||
|
||||
/* Initialize the fast encoding. If the "sun.jnu.encoding" property
|
||||
@ -718,17 +817,20 @@ initializeEncoding(JNIEnv *env)
|
||||
if ((strcmp(encname, "8859_1") == 0) ||
|
||||
(strcmp(encname, "ISO8859-1") == 0) ||
|
||||
(strcmp(encname, "ISO8859_1") == 0) ||
|
||||
(strcmp(encname, "ISO-8859-1") == 0))
|
||||
(strcmp(encname, "ISO-8859-1") == 0)) {
|
||||
fastEncoding = FAST_8859_1;
|
||||
else if (strcmp(encname, "ISO646-US") == 0)
|
||||
} else if (strcmp(encname, "UTF-8") == 0) {
|
||||
fastEncoding = FAST_UTF_8;
|
||||
jnuEncoding = (jstring)(*env)->NewGlobalRef(env, enc);
|
||||
} else if (strcmp(encname, "ISO646-US") == 0) {
|
||||
fastEncoding = FAST_646_US;
|
||||
else if (strcmp(encname, "Cp1252") == 0 ||
|
||||
} else if (strcmp(encname, "Cp1252") == 0 ||
|
||||
/* This is a temporary fix until we move */
|
||||
/* to wide character versions of all Windows */
|
||||
/* calls. */
|
||||
strcmp(encname, "utf-16le") == 0)
|
||||
strcmp(encname, "utf-16le") == 0) {
|
||||
fastEncoding = FAST_CP1252;
|
||||
else {
|
||||
} else {
|
||||
fastEncoding = NO_FAST_ENCODING;
|
||||
jnuEncoding = (jstring)(*env)->NewGlobalRef(env, enc);
|
||||
}
|
||||
@ -750,24 +852,10 @@ initializeEncoding(JNIEnv *env)
|
||||
CHECK_NULL(String_getBytes_ID);
|
||||
String_init_ID = (*env)->GetMethodID(env, strClazz,
|
||||
"<init>", "([BLjava/lang/String;)V");
|
||||
String_coder_ID = (*env)->GetFieldID(env, strClazz, "coder", "B");
|
||||
String_value_ID = (*env)->GetFieldID(env, strClazz, "value", "[B");
|
||||
}
|
||||
|
||||
static jboolean isJNUEncodingSupported = JNI_FALSE;
|
||||
static jboolean jnuEncodingSupported(JNIEnv *env) {
|
||||
jboolean exe;
|
||||
if (isJNUEncodingSupported == JNI_TRUE) {
|
||||
return JNI_TRUE;
|
||||
}
|
||||
isJNUEncodingSupported = (jboolean) JNU_CallStaticMethodByName (
|
||||
env, &exe,
|
||||
"java/nio/charset/Charset",
|
||||
"isSupported",
|
||||
"(Ljava/lang/String;)Z",
|
||||
jnuEncoding).z;
|
||||
return isJNUEncodingSupported;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jstring
|
||||
NewStringPlatform(JNIEnv *env, const char *str)
|
||||
{
|
||||
@ -777,10 +865,6 @@ NewStringPlatform(JNIEnv *env, const char *str)
|
||||
JNIEXPORT jstring JNICALL
|
||||
JNU_NewStringPlatform(JNIEnv *env, const char *str)
|
||||
{
|
||||
jstring result = NULL;
|
||||
jbyteArray hab = 0;
|
||||
int len;
|
||||
|
||||
if (fastEncoding == NO_ENCODING_YET) {
|
||||
initializeEncoding(env);
|
||||
JNU_CHECK_EXCEPTION_RETURN(env, NULL);
|
||||
@ -792,36 +876,9 @@ JNU_NewStringPlatform(JNIEnv *env, const char *str)
|
||||
return newString646_US(env, str);
|
||||
if (fastEncoding == FAST_CP1252)
|
||||
return newStringCp1252(env, str);
|
||||
|
||||
if ((*env)->EnsureLocalCapacity(env, 2) < 0)
|
||||
return NULL;
|
||||
|
||||
len = (int)strlen(str);
|
||||
hab = (*env)->NewByteArray(env, len);
|
||||
if (hab != 0) {
|
||||
jclass strClazz = JNU_ClassString(env);
|
||||
CHECK_NULL_RETURN(strClazz, 0);
|
||||
(*env)->SetByteArrayRegion(env, hab, 0, len, (jbyte *)str);
|
||||
if (jnuEncodingSupported(env)) {
|
||||
result = (*env)->NewObject(env, strClazz,
|
||||
String_init_ID, hab, jnuEncoding);
|
||||
} else {
|
||||
/*If the encoding specified in sun.jnu.encoding is not endorsed
|
||||
by "Charset.isSupported" we have to fall back to use String(byte[])
|
||||
explicitly here without specifying the encoding name, in which the
|
||||
StringCoding class will pickup the iso-8859-1 as the fallback
|
||||
converter for us.
|
||||
*/
|
||||
jmethodID mid = (*env)->GetMethodID(env, strClazz,
|
||||
"<init>", "([B)V");
|
||||
if (mid != NULL) {
|
||||
result = (*env)->NewObject(env, strClazz, mid, hab);
|
||||
}
|
||||
}
|
||||
(*env)->DeleteLocalRef(env, hab);
|
||||
return result;
|
||||
}
|
||||
return NULL;
|
||||
if (fastEncoding == FAST_UTF_8)
|
||||
return newStringUTF8(env, str);
|
||||
return newStringJava(env, str);
|
||||
}
|
||||
|
||||
JNIEXPORT const char *
|
||||
@ -830,27 +887,10 @@ GetStringPlatformChars(JNIEnv *env, jstring jstr, jboolean *isCopy)
|
||||
return JNU_GetStringPlatformChars(env, jstr, isCopy);
|
||||
}
|
||||
|
||||
JNIEXPORT const char * JNICALL
|
||||
JNU_GetStringPlatformChars(JNIEnv *env, jstring jstr, jboolean *isCopy)
|
||||
{
|
||||
static const char* getStringBytes(JNIEnv *env, jstring jstr) {
|
||||
char *result = NULL;
|
||||
jbyteArray hab = 0;
|
||||
|
||||
if (isCopy)
|
||||
*isCopy = JNI_TRUE;
|
||||
|
||||
if (fastEncoding == NO_ENCODING_YET) {
|
||||
initializeEncoding(env);
|
||||
JNU_CHECK_EXCEPTION_RETURN(env, 0);
|
||||
}
|
||||
|
||||
if ((fastEncoding == FAST_8859_1) || (fastEncoding == NO_ENCODING_YET))
|
||||
return getString8859_1Chars(env, jstr);
|
||||
if (fastEncoding == FAST_646_US)
|
||||
return getString646_USChars(env, jstr);
|
||||
if (fastEncoding == FAST_CP1252)
|
||||
return getStringCp1252Chars(env, jstr);
|
||||
|
||||
if ((*env)->EnsureLocalCapacity(env, 2) < 0)
|
||||
return 0;
|
||||
|
||||
@ -883,6 +923,85 @@ JNU_GetStringPlatformChars(JNIEnv *env, jstring jstr, jboolean *isCopy)
|
||||
return result;
|
||||
}
|
||||
|
||||
static const char*
|
||||
getStringUTF8(JNIEnv *env, jstring jstr)
|
||||
{
|
||||
int i;
|
||||
char *result;
|
||||
jbyteArray value;
|
||||
jint len;
|
||||
jbyte *str;
|
||||
jint rlen;
|
||||
int ri;
|
||||
jbyte coder = (*env)->GetByteField(env, jstr, String_coder_ID);
|
||||
if (coder != java_lang_String_LATIN1) {
|
||||
return getStringBytes(env, jstr);
|
||||
}
|
||||
if ((*env)->EnsureLocalCapacity(env, 2) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
value = (*env)->GetObjectField(env, jstr, String_value_ID);
|
||||
if (value == NULL)
|
||||
return NULL;
|
||||
len = (*env)->GetArrayLength(env, value);
|
||||
str = (*env)->GetPrimitiveArrayCritical(env, value, NULL);
|
||||
if (str == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rlen = len;
|
||||
// we need two bytes for each latin-1 char above 127 (negative jbytes)
|
||||
for (i = 0; i < len; i++) {
|
||||
if (str[i] < 0) {
|
||||
rlen++;
|
||||
}
|
||||
}
|
||||
|
||||
result = MALLOC_MIN4(rlen);
|
||||
if (result == NULL) {
|
||||
(*env)->ReleasePrimitiveArrayCritical(env, value, str, 0);
|
||||
JNU_ThrowOutOfMemoryError(env, 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (ri = 0, i = 0; i < len; i++) {
|
||||
jbyte c = str[i];
|
||||
if (c < 0) {
|
||||
result[ri++] = (char)(0xc0 | ((c & 0xff) >> 6));
|
||||
result[ri++] = (char)(0x80 | (c & 0x3f));
|
||||
} else {
|
||||
result[ri++] = c;
|
||||
}
|
||||
}
|
||||
(*env)->ReleasePrimitiveArrayCritical(env, value, str, 0);
|
||||
result[rlen] = '\0';
|
||||
return result;
|
||||
}
|
||||
|
||||
JNIEXPORT const char * JNICALL
|
||||
JNU_GetStringPlatformChars(JNIEnv *env, jstring jstr, jboolean *isCopy)
|
||||
{
|
||||
|
||||
if (isCopy)
|
||||
*isCopy = JNI_TRUE;
|
||||
|
||||
if (fastEncoding == NO_ENCODING_YET) {
|
||||
initializeEncoding(env);
|
||||
JNU_CHECK_EXCEPTION_RETURN(env, 0);
|
||||
}
|
||||
|
||||
if ((fastEncoding == FAST_8859_1) || (fastEncoding == NO_ENCODING_YET))
|
||||
return getString8859_1Chars(env, jstr);
|
||||
if (fastEncoding == FAST_646_US)
|
||||
return getString646_USChars(env, jstr);
|
||||
if (fastEncoding == FAST_CP1252)
|
||||
return getStringCp1252Chars(env, jstr);
|
||||
if (fastEncoding == FAST_UTF_8)
|
||||
return getStringUTF8(env, jstr);
|
||||
else
|
||||
return getStringBytes(env, jstr);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
JNU_ReleaseStringPlatformChars(JNIEnv *env, jstring jstr, const char *str)
|
||||
{
|
||||
|
||||
@ -382,7 +382,8 @@ enum {
|
||||
NO_FAST_ENCODING, /* Platform encoding is not fast */
|
||||
FAST_8859_1, /* ISO-8859-1 */
|
||||
FAST_CP1252, /* MS-DOS Cp1252 */
|
||||
FAST_646_US /* US-ASCII : ISO646-US */
|
||||
FAST_646_US, /* US-ASCII : ISO646-US */
|
||||
FAST_UTF_8
|
||||
};
|
||||
|
||||
int getFastEncoding();
|
||||
|
||||
@ -1,362 +0,0 @@
|
||||
---
|
||||
# Copyright (c) 2005, 2017, 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.
|
||||
|
||||
include-before: '[CONTENTS](index.html) | [PREV](input.html) | [NEXT](version.html)'
|
||||
include-after: '[CONTENTS](index.html) | [PREV](input.html) | [NEXT](version.html)'
|
||||
|
||||
title: 'Java Object Serialization Specification: 4 - Class Descriptors'
|
||||
---
|
||||
|
||||
- [The ObjectStreamClass Class](#the-objectstreamclass-class)
|
||||
- [Dynamic Proxy Class Descriptors](#dynamic-proxy-class-descriptors)
|
||||
- [Serialized Form](#serialized-form)
|
||||
- [The ObjectStreamField Class](#the-objectstreamfield-class)
|
||||
- [Inspecting Serializable Classes](#inspecting-serializable-classes)
|
||||
- [Stream Unique Identifiers](#stream-unique-identifiers)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
## 4.1 The ObjectStreamClass Class
|
||||
|
||||
The `ObjectStreamClass` provides information about classes that are saved in a
|
||||
Serialization stream. The descriptor provides the fully-qualified name of the
|
||||
class and its serialization version UID. A `SerialVersionUID` identifies the
|
||||
unique original class version for which this class is capable of writing
|
||||
streams and from which it can read.
|
||||
|
||||
```
|
||||
package java.io;
|
||||
|
||||
public class ObjectStreamClass
|
||||
{
|
||||
public static ObjectStreamClass lookup(Class cl);
|
||||
|
||||
public static ObjectStreamClass lookupAny(Class cl);
|
||||
|
||||
public String getName();
|
||||
|
||||
public Class forClass();
|
||||
|
||||
public ObjectStreamField[] getFields();
|
||||
|
||||
public long getSerialVersionUID();
|
||||
|
||||
public String toString();
|
||||
}
|
||||
```
|
||||
|
||||
The `lookup` method returns the `ObjectStreamClass` descriptor for the
|
||||
specified class in the virtual machine. If the class has defined
|
||||
`serialVersionUID` it is retrieved from the class. If the `serialVersionUID` is
|
||||
not defined by the class, it is computed from the definition of the class in
|
||||
the virtual machine. *I*f the specified class is not serializable or
|
||||
externalizable, *null* is returned.
|
||||
|
||||
The `lookupAny` method behaves like the `lookup` method, except that it returns
|
||||
the descriptor for any class, regardless of whether it implements
|
||||
`Serializable`. The `serialVersionUID` of a class that does not implement
|
||||
`Serializable` is *0L.*
|
||||
|
||||
The `getName` method returns the name of the class, in the same format that is
|
||||
used by the `Class.getName` method.
|
||||
|
||||
The `forClass` method returns the `Class` in the local virtual machine if one
|
||||
was found by `ObjectInputStream.resolveClass` method. Otherwise, it returns
|
||||
*null*.
|
||||
|
||||
The `getFields` method returns an array of `ObjectStreamField` objects that
|
||||
represent the serializable fields of this class.
|
||||
|
||||
The `getSerialVersionUID` method returns the `serialVersionUID` of this class.
|
||||
Refer to [Section 4.6, "Stream Unique
|
||||
Identifiers"](#stream-unique-identifiers). If not specified by the class, the
|
||||
value returned is a hash computed from the class's name, interfaces, methods,
|
||||
and fields using the Secure Hash Algorithm (SHA) as defined by the National
|
||||
Institute of Standards.
|
||||
|
||||
The `toString` method returns a printable representation of the class
|
||||
descriptor including the name of the class and the `serialVersionUID`.
|
||||
|
||||
## 4.2 Dynamic Proxy Class Descriptors
|
||||
|
||||
ObjectStreamClass descriptors are also used to provide information about
|
||||
dynamic proxy classes (e.g., classes obtained via calls to the getProxyClass
|
||||
method of java.lang.reflect.Proxy) saved in a serialization stream. A dynamic
|
||||
proxy class itself has no serializable fields and a serialVersionUID of 0L. In
|
||||
other words, when the Class object for a dynamic proxy class is passed to the
|
||||
static lookup method of ObjectStreamClass, the returned ObjectStreamClass
|
||||
instance will have the following properties:
|
||||
|
||||
- Invoking its getSerialVersionUID method will return 0L.
|
||||
- Invoking its getFields method will return an array of length zero.
|
||||
- Invoking its getField method with any String argument will return null.
|
||||
|
||||
## 4.3 Serialized Form
|
||||
|
||||
The serialized form of an ObjectStreamClass instance depends on whether or not
|
||||
the Class object it represents is serializable, externalizable, or a dynamic
|
||||
proxy class.
|
||||
|
||||
When an `ObjectStreamClass` instance that does not represent a dynamic proxy
|
||||
class is written to the stream, it writes the class name and
|
||||
`serialVersionUID`, flags, and the number of fields. Depending on the class,
|
||||
additional information may be written:
|
||||
|
||||
- For non-serializable classes, the number of fields is always zero. Neither
|
||||
the `SC_SERIALIZABLE` nor the `SC_EXTERNALIZABLE` flag bits are set.
|
||||
|
||||
- For serializable classes, the `SC_SERIALIZABLE` flag is set, the number of
|
||||
fields counts the number of serializable fields and is followed by a
|
||||
descriptor for each serializable field. The descriptors are written in
|
||||
canonical order. The descriptors for primitive typed fields are written
|
||||
first sorted by field name followed by descriptors for the object typed
|
||||
fields sorted by field name. The names are sorted using `String.compareTo`.
|
||||
For details of the format, refer to [Section 6.4, "Grammar for the Stream
|
||||
Format"](protocol.html#grammar-for-the-stream-format).
|
||||
|
||||
- For externalizable classes, flags includes the `SC_EXTERNALIZABLE` flag,
|
||||
and the number of fields is always zero.
|
||||
|
||||
- For enum types, flags includes the `SC_ENUM` flag, and the number of fields
|
||||
is always zero.
|
||||
|
||||
When an ObjectOutputStream serializes the ObjectStreamClass descriptor for a
|
||||
dynamic proxy class, as determined by passing its Class object to the
|
||||
isProxyClass method of java.lang.reflect.Proxy, it writes the number of
|
||||
interfaces that the dynamic proxy class implements, followed by the interface
|
||||
names. Interfaces are listed in the order that they are returned by invoking
|
||||
the getInterfaces method on the Class object of the dynamic proxy class.
|
||||
|
||||
The serialized representations of ObjectStreamClass descriptors for dynamic
|
||||
proxy classes and non-dynamic proxy classes are differentiated through the use
|
||||
of different typecodes (`TC_PROXYCLASSDESC` and `TC_CLASSDESC`, respectively);
|
||||
for a more detailed specification of the grammar, see [Section 6.4, "Grammar
|
||||
for the Stream Format"](protocol.html#grammar-for-the-stream-format).
|
||||
|
||||
## 4.4 The ObjectStreamField Class
|
||||
|
||||
An `ObjectStreamField` represents a serializable field of a serializable class.
|
||||
The serializable fields of a class can be retrieved from the
|
||||
`ObjectStreamClass`.
|
||||
|
||||
The special static serializable field, `serialPersistentFields`, is an array of
|
||||
`ObjectStreamField` components that is used to override the default
|
||||
serializable fields.
|
||||
|
||||
```
|
||||
package java.io;
|
||||
|
||||
public class ObjectStreamField implements Comparable {
|
||||
|
||||
public ObjectStreamField(String fieldName,
|
||||
Class fieldType);
|
||||
|
||||
public ObjectStreamField(String fieldName,
|
||||
Class fieldType,
|
||||
boolean unshared);
|
||||
|
||||
public String getName();
|
||||
|
||||
public Class getType();
|
||||
|
||||
public String getTypeString();
|
||||
|
||||
public char getTypeCode();
|
||||
|
||||
public boolean isPrimitive();
|
||||
|
||||
public boolean isUnshared();
|
||||
|
||||
public int getOffset();
|
||||
|
||||
protected void setOffset(int offset);
|
||||
|
||||
public int compareTo(Object obj);
|
||||
|
||||
public String toString();
|
||||
}
|
||||
```
|
||||
|
||||
`ObjectStreamField` objects are used to specify the serializable fields of a
|
||||
class or to describe the fields present in a stream. Its constructors accept
|
||||
arguments describing the field to represent: a string specifying the name of
|
||||
the field, a `Class` object specifying the type of the field, and a `boolean`
|
||||
flag (implicitly `false` for the two-argument constructor) indicating whether
|
||||
or not values of the represented field should be read and written as "unshared"
|
||||
objects if default serialization/deserialization is in use (see the
|
||||
descriptions of the `ObjectInputStream.readUnshared` and
|
||||
`ObjectOutputStream.writeUnshared` methods in [Section 3.1, "The
|
||||
ObjectInputStream Class"](input.html#the-objectinputstream-class) and [Section
|
||||
2.1, "The ObjectOutputStream Class"](output.html#the-objectoutputstream-class),
|
||||
respectively).
|
||||
|
||||
The `getName` method returns the name of the serializable field.
|
||||
|
||||
The `getType` method returns the type of the field.
|
||||
|
||||
The `getTypeString` method returns the type signature of the field.
|
||||
|
||||
The `getTypeCode` method returns a character encoding of the field type ('`B`'
|
||||
for `byte`, '`C`' for `char`, '`D`' for `double`, '`F`' for `float`, '`I`' for
|
||||
`int`, '`J`' for `long`, '`L`' for non-array object types, '`S`' for `short`,
|
||||
'`Z`' for `boolean`, and '`[`' for arrays).
|
||||
|
||||
The `isPrimitive` method returns `true` if the field is of primitive type, or
|
||||
`false` otherwise.
|
||||
|
||||
The `isUnshared` method returns `true` if values of the field should be written
|
||||
as "unshared" objects, or `false` otherwise.
|
||||
|
||||
The `getOffset` method returns the offset of the field's value within instance
|
||||
data of the class defining the field.
|
||||
|
||||
The `setOffset` method allows `ObjectStreamField` subclasses to modify the
|
||||
offset value returned by the `getOffset` method.
|
||||
|
||||
The `compareTo` method compares `ObjectStreamFields` for use in sorting.
|
||||
Primitive fields are ranked as "smaller" than non-primitive fields; fields
|
||||
otherwise equal are ranked alphabetically.
|
||||
|
||||
The `toString` method returns a printable representation with name and type.
|
||||
|
||||
## 4.5 Inspecting Serializable Classes
|
||||
|
||||
The program *serialver* can be used to find out if a class is serializable and
|
||||
to get its `serialVersionUID`.
|
||||
|
||||
When invoked on the command line with one or more class names, serialver prints
|
||||
the `serialVersionUID` for each class in a form suitable for copying into an
|
||||
evolving class. When invoked with no arguments, it prints a usage line.
|
||||
|
||||
## 4.6 Stream Unique Identifiers
|
||||
|
||||
Each versioned class must identify the original class version for which it is
|
||||
capable of writing streams and from which it can read. For example, a versioned
|
||||
class must declare:
|
||||
|
||||
```
|
||||
private static final long serialVersionUID = 3487495895819393L;
|
||||
```
|
||||
|
||||
The stream-unique identifier is a 64-bit hash of the class name, interface
|
||||
class names, methods, and fields. The value must be declared in all versions of
|
||||
a class except the first. It may be declared in the original class but is not
|
||||
required. The value is fixed for all compatible classes. If the SUID is not
|
||||
declared for a class, the value defaults to the hash for that class. The
|
||||
`serialVersionUID` for dynamic proxy classes and enum types always have the
|
||||
value *0L*. Array classes cannot declare an explicit `serialVersionUID`, so
|
||||
they always have the default computed value, but the requirement for matching
|
||||
`serialVersionUID` values is waived for array classes.
|
||||
|
||||
**Note:** It is strongly recommended that all serializable classes explicitly
|
||||
declare `serialVersionUID` values, since the default `serialVersionUID`
|
||||
computation is highly sensitive to class details that may vary depending on
|
||||
compiler implementations, and can thus result in unexpected `serialVersionUID`
|
||||
conflicts during deserialization, causing deserialization to fail.
|
||||
|
||||
The initial version of an `Externalizable` class must output a stream data
|
||||
format that is extensible in the future. The initial version of the method
|
||||
`readExternal` has to be able to read the output format of all future versions
|
||||
of the method `writeExternal`.
|
||||
|
||||
The `serialVersionUID` is computed using the signature of a stream of bytes
|
||||
that reflect the class definition. The National Institute of Standards and
|
||||
Technology (NIST) Secure Hash Algorithm (SHA-1) is used to compute a signature
|
||||
for the stream. The first two 32-bit quantities are used to form a 64-bit hash.
|
||||
A `java.lang.DataOutputStream` is used to convert primitive data types to a
|
||||
sequence of bytes. The values input to the stream are defined by the Java
|
||||
Virtual Machine (VM) specification for classes. Class modifiers may include the
|
||||
`ACC_PUBLIC`, `ACC_FINAL`, `ACC_INTERFACE`, and `ACC_ABSTRACT` flags; other
|
||||
flags are ignored and do not affect `serialVersionUID` computation. Similarly,
|
||||
for field modifiers, only the `ACC_PUBLIC`, `ACC_PRIVATE`, `ACC_PROTECTED`,
|
||||
`ACC_STATIC`, `ACC_FINAL`, `ACC_VOLATILE`, and `ACC_TRANSIENT` flags are used
|
||||
when computing `serialVersionUID` values. For constructor and method modifiers,
|
||||
only the `ACC_PUBLIC`, `ACC_PRIVATE`, `ACC_PROTECTED`, `ACC_STATIC`,
|
||||
`ACC_FINAL`, `ACC_SYNCHRONIZED`, `ACC_NATIVE`, `ACC_ABSTRACT` and `ACC_STRICT`
|
||||
flags are used. Names and descriptors are written in the format used by the
|
||||
`java.io.DataOutputStream.writeUTF` method.
|
||||
|
||||
The sequence of items in the stream is as follows:
|
||||
|
||||
1. The class name.
|
||||
|
||||
2. The class modifiers written as a 32-bit integer.
|
||||
|
||||
3. The name of each interface sorted by name.
|
||||
|
||||
4. For each field of the class sorted by field name (except `private static`
|
||||
and `private transient` fields:
|
||||
|
||||
a. The name of the field.
|
||||
|
||||
b. The modifiers of the field written as a 32-bit integer.
|
||||
|
||||
c. The descriptor of the field.
|
||||
|
||||
5. If a class initializer exists, write out the following:
|
||||
|
||||
a. The name of the method, `<clinit>`.
|
||||
|
||||
b. The modifier of the method, `java.lang.reflect.Modifier.STATIC`,
|
||||
written as a 32-bit integer.
|
||||
|
||||
c. The descriptor of the method, `()V`.
|
||||
|
||||
6. For each non-`private` constructor sorted by method name and signature:
|
||||
|
||||
a. The name of the method, `<init>`.
|
||||
|
||||
b. The modifiers of the method written as a 32-bit integer.
|
||||
|
||||
c. The descriptor of the method.
|
||||
|
||||
7. For each non-`private` method sorted by method name and signature:
|
||||
|
||||
a. The name of the method.
|
||||
|
||||
b. The modifiers of the method written as a 32-bit integer.
|
||||
|
||||
c. The descriptor of the method.
|
||||
|
||||
8. The SHA-1 algorithm is executed on the stream of bytes produced by
|
||||
`DataOutputStream` and produces five 32-bit values `sha[0..4]`.
|
||||
|
||||
9. The hash value is assembled from the first and second 32-bit values of the
|
||||
SHA-1 message digest. If the result of the message digest, the five 32-bit
|
||||
words `H0 H1 H2 H3 H4`, is in an array of five `int` values named `sha`,
|
||||
the hash value would be computed as follows:
|
||||
|
||||
```
|
||||
long hash = ((sha[0] >>> 24) & 0xFF) |
|
||||
((sha[0] >>> 16) & 0xFF) << 8 |
|
||||
((sha[0] >>> 8) & 0xFF) << 16 |
|
||||
((sha[0] >>> 0) & 0xFF) << 24 |
|
||||
((sha[1] >>> 24) & 0xFF) << 32 |
|
||||
((sha[1] >>> 16) & 0xFF) << 40 |
|
||||
((sha[1] >>> 8) & 0xFF) << 48 |
|
||||
((sha[1] >>> 0) & 0xFF) << 56;
|
||||
```
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
*[Copyright](../../../legal/SMICopyright.html) © 2005, 2017, Oracle
|
||||
and/or its affiliates. All rights reserved.*
|
||||
@ -1,111 +0,0 @@
|
||||
---
|
||||
# Copyright (c) 2005, 2017, 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.
|
||||
|
||||
include-before: '[CONTENTS](index.html) | [PREV](exceptions.html) | NEXT'
|
||||
include-after: '[CONTENTS](index.html) | [PREV](exceptions.html) | NEXT'
|
||||
|
||||
title: 'Java Object Serialization Specification: C - Example of Serializable Fields'
|
||||
---
|
||||
|
||||
- [Example Alternate Implementation of
|
||||
java.io.File](#c.1-example-alternate-implementation-of-java.io.file)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
## C.1 Example Alternate Implementation of java.io.File
|
||||
|
||||
This appendix provides a brief example of how an existing class could be
|
||||
specified and implemented to interoperate with the existing implementation but
|
||||
without requiring the same assumptions about the representation of the file
|
||||
name as a *String*.
|
||||
|
||||
The system class `java.io.File` represents a filename and has methods for
|
||||
parsing, manipulating files and directories by name. It has a single private
|
||||
field that contains the current file name. The semantics of the methods that
|
||||
parse paths depend on the current path separator which is held in a static
|
||||
field. This path separator is part of the serialized state of a file so that
|
||||
file name can be adjusted when read.
|
||||
|
||||
The serialized state of a `File` object is defined as the serializable fields
|
||||
and the sequence of data values for the file. In this case, there is one of
|
||||
each.
|
||||
|
||||
```
|
||||
Serializable Fields:
|
||||
String path; // path name with embedded separators
|
||||
Serializable Data:
|
||||
char // path name separator for path name
|
||||
```
|
||||
|
||||
An alternate implementation might be defined as follows:
|
||||
|
||||
```
|
||||
class File implements java.io.Serializable {
|
||||
...
|
||||
private String[] pathcomponents;
|
||||
// Define serializable fields with the ObjectStreamClass
|
||||
|
||||
/**
|
||||
* @serialField path String
|
||||
* Path components separated by separator.
|
||||
*/
|
||||
|
||||
private static final ObjectStreamField[] serialPersistentFields
|
||||
= { new ObjectStreamField("path", String.class) };
|
||||
...
|
||||
/**
|
||||
* @serialData Default fields followed by separator character.
|
||||
*/
|
||||
|
||||
private void writeObject(ObjectOutputStream s)
|
||||
throws IOException
|
||||
{
|
||||
ObjectOutputStream.PutField fields = s.putFields();
|
||||
StringBuffer str = new StringBuffer();
|
||||
for(int i = 0; i < pathcomponents; i++) {
|
||||
str.append(separator);
|
||||
str.append(pathcomponents[i]);
|
||||
}
|
||||
fields.put("path", str.toString());
|
||||
s.writeFields();
|
||||
s.writeChar(separatorChar); // Add the separator character
|
||||
}
|
||||
...
|
||||
|
||||
private void readObject(ObjectInputStream s)
|
||||
throws IOException
|
||||
{
|
||||
ObjectInputStream.GetField fields = s.readFields();
|
||||
String path = (String)fields.get("path", null);
|
||||
...
|
||||
char sep = s.readChar(); // read the previous separator char
|
||||
|
||||
// parse path into components using the separator
|
||||
// and store into pathcomponents array.
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
*[Copyright](../../../legal/SMICopyright.html) © 2005, 2017, Oracle
|
||||
and/or its affiliates. All rights reserved.*
|
||||
@ -1,97 +0,0 @@
|
||||
---
|
||||
# Copyright (c) 2005, 2017, 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.
|
||||
|
||||
include-before: '[CONTENTS](index.html) | [PREV](security.html) | [NEXT](examples.html)'
|
||||
include-after: '[CONTENTS](index.html) | [PREV](security.html) | [NEXT](examples.html)'
|
||||
|
||||
title: 'Java Object Serialization Specification: B - Exceptions In Object Serialization'
|
||||
---
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
All exceptions thrown by serialization classes are subclasses of
|
||||
`ObjectStreamException` which is a subclass of `IOException`.
|
||||
|
||||
### `ObjectStreamException`
|
||||
|
||||
Superclass of all serialization exceptions.
|
||||
|
||||
### `InvalidClassException`
|
||||
|
||||
Thrown when a class cannot be used to restore objects for any of these reasons:
|
||||
|
||||
- The class does not match the serial version of the class in the stream.
|
||||
- The class contains fields with invalid primitive data types.
|
||||
- The `Externalizable` class does not have a public no-arg constructor.
|
||||
- The `Serializable` class can not access the no-arg constructor of its
|
||||
closest non-Serializable superclass.
|
||||
|
||||
### `NotSerializableException`
|
||||
|
||||
Thrown by a `readObject` or `writeObject` method to terminate serialization or
|
||||
deserialization.
|
||||
|
||||
### `StreamCorruptedException`
|
||||
|
||||
Thrown:
|
||||
|
||||
- If the stream header is invalid.
|
||||
- If control information not found.
|
||||
- If control information is invalid.
|
||||
- JDK 1.1.5 or less attempts to call `readExternal` on a `PROTOCOL_VERSION_2`
|
||||
stream.
|
||||
|
||||
### `NotActiveException`
|
||||
|
||||
Thrown if `writeObject` state is invalid within the following
|
||||
`ObjectOutputStream` methods:
|
||||
|
||||
- `defaultWriteObject`
|
||||
- `putFields`
|
||||
- `writeFields`
|
||||
|
||||
Thrown if `readObject` state is invalid within the following
|
||||
`ObjectInputStream` methods:
|
||||
|
||||
- `defaultReadObject`
|
||||
- `readFields`
|
||||
- `registerValidation`
|
||||
|
||||
### `InvalidObjectException`
|
||||
|
||||
Thrown when a restored object cannot be made valid.
|
||||
|
||||
### `OptionalDataException`
|
||||
|
||||
Thrown by `readObject` when there is primitive data in the stream and an object
|
||||
is expected. The length field of the exception indicates the number of bytes
|
||||
that are available in the current block.
|
||||
|
||||
### `WriteAbortedException`
|
||||
|
||||
Thrown when reading a stream terminated by an exception that occurred while the
|
||||
stream was being written.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
*[Copyright](../../../legal/SMICopyright.html) © 2005, 2017, Oracle
|
||||
and/or its affiliates. All rights reserved.*
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.2 KiB |
@ -1,132 +0,0 @@
|
||||
---
|
||||
# Copyright (c) 2005, 2017, 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.
|
||||
|
||||
include-before: 'CONTENTS | PREV | [NEXT](serial-arch.html)'
|
||||
include-after: 'CONTENTS | PREV | [NEXT](serial-arch.html)'
|
||||
|
||||
title: 'Java Object Serialization Specification: Contents'
|
||||
---
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
## Table of Contents
|
||||
|
||||
### 1 [System Architecture](serial-arch.html)
|
||||
|
||||
- 1.1 [Overview](serial-arch.html#overview)
|
||||
- 1.2 [Writing to an Object
|
||||
Stream](serial-arch.html#writing-to-an-object-stream)
|
||||
- 1.3 [Reading from an Object
|
||||
Stream](serial-arch.html#reading-from-an-object-stream)
|
||||
- 1.4 [Object Streams as
|
||||
Containers](serial-arch.html#object-streams-as-containers)
|
||||
- 1.5 [Defining Serializable Fields for a
|
||||
Class](serial-arch.html#defining-serializable-fields-for-a-class)
|
||||
- 1.6 [Documenting Serializable Fields and Data for a
|
||||
Class](serial-arch.html#documenting-serializable-fields-and-data-for-a-class)
|
||||
- 1.7 [Accessing Serializable Fields of a
|
||||
Class](serial-arch.html#accessing-serializable-fields-of-a-class)
|
||||
- 1.8 [The ObjectOutput
|
||||
Interface](serial-arch.html#the-objectoutput-interface)
|
||||
- 1.9 [The ObjectInput Interface](serial-arch.html#the-objectinput-interface)
|
||||
- 1.10 [The Serializable
|
||||
Interface](serial-arch.html#the-serializable-interface)
|
||||
- 1.11 [The Externalizable
|
||||
Interface](serial-arch.html#the-externalizable-interface)
|
||||
- 1.12 [Serialization of Enum
|
||||
Constants](serial-arch.html#serialization-of-enum-constants)
|
||||
- 1.13 [Protecting Sensitive
|
||||
Information](serial-arch.html#protecting-sensitive-information)
|
||||
|
||||
### 2 [Object Output Classes](output.html)
|
||||
|
||||
- 2.1 [The ObjectOutputStream
|
||||
Class](output.html#the-objectoutputstream-class)
|
||||
- 2.2 [The ObjectOutputStream.PutField
|
||||
Class](output.html#the-objectoutputstream.putfield-class)
|
||||
- 2.3 [The writeObject Method](output.html#the-writeobject-method)
|
||||
- 2.4 [The writeExternal Method](output.html#the-writeexternal-method)
|
||||
- 2.5 [The writeReplace Method](output.html#the-writereplace-method)
|
||||
- 2.6 [The useProtocolVersion
|
||||
Method](output.html#the-useprotocolversion-method)
|
||||
|
||||
### 3 [Object Input Classes](input.html)
|
||||
|
||||
- 3.1 [The ObjectInputStream Class](input.html#the-objectinputstream-class)
|
||||
- 3.2 [The ObjectInputStream.GetField
|
||||
Class](input.html#the-objectinputstream.getfield-class)
|
||||
- 3.3 [The ObjectInputValidation
|
||||
Interface](input.html#the-objectinputvalidation-interface)
|
||||
- 3.4 [The readObject Method](input.html#the-readobject-method)
|
||||
- 3.5 [The readObjectNoData Method](input.html#the-readobjectnodata-method)
|
||||
- 3.6 [The readExternal Method](input.html#the-readexternal-method)
|
||||
- 3.7 [The readResolve Method](input.html#the-readresolve-method)
|
||||
|
||||
### 4 [Class Descriptors](class.html)
|
||||
|
||||
- 4.1 [The ObjectStreamClass Class](class.html#the-objectstreamclass-class)
|
||||
- 4.2 [Dynamic Proxy Class
|
||||
Descriptors](class.html#dynamic-proxy-class-descriptors)
|
||||
- 4.3 [Serialized Form](class.html#serialized-form)
|
||||
- 4.4 [The ObjectStreamField Class](class.html#the-objectstreamfield-class)
|
||||
- 4.5 [Inspecting Serializable
|
||||
Classes](class.html#inspecting-serializable-classes)
|
||||
- 4.6 [Stream Unique Identifiers](class.html#stream-unique-identifiers)
|
||||
|
||||
### 5 [Versioning of Serializable Objects](version.html)
|
||||
|
||||
- 5.1 [Overview](version.html#overview)
|
||||
- 5.2 [Goals](version.html#goals)
|
||||
- 5.3 [Assumptions](version.html#assumptions)
|
||||
- 5.4 [Who's Responsible for Versioning of
|
||||
Streams](version.html#whos-responsible-for-versioning-of-streams)
|
||||
- 5.5 [Compatible Java Type
|
||||
Evolution](version.html#compatible-java-type-evolution)
|
||||
- 5.6 [Type Changes Affecting
|
||||
Serialization](version.html#type-changes-affecting-serialization)
|
||||
- 5.6.1 [Incompatible Changes](version.html#incompatible-changes)
|
||||
- 5.6.2 [Compatible Changes](version.html#compatible-changes)
|
||||
|
||||
### 6 [Object Serialization Stream Protocol](protocol.html)
|
||||
|
||||
- 6.1 [Overview](protocol.html#overview)
|
||||
- 6.2 [Stream Elements](protocol.html#stream-elements)
|
||||
- 6.3 [Stream Protocol Versions](protocol.html#stream-protocol-versions)
|
||||
- 6.4 [Grammar for the Stream
|
||||
Format](protocol.html#grammar-for-the-stream-format)
|
||||
- 6.4.1 [Rules of the Grammar](protocol.html#rules-of-the-grammar)
|
||||
- 6.4.2 [Terminal Symbols and
|
||||
Constants](protocol.html#terminal-symbols-and-constants)
|
||||
|
||||
### A [Security in Object Serialization](security.html)
|
||||
|
||||
### B [Exceptions In Object Serialization](exceptions.html)
|
||||
|
||||
### C [Example of Serializable Fields](examples.html)
|
||||
|
||||
- [C.1 Example Alternate Implementation of
|
||||
`java.io.File`](examples.html#c.1-example-alternate-implementation-of-java.io.file)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
*[Copyright](../../../legal/SMICopyright.html) © 2005, 2017, Oracle
|
||||
and/or its affiliates. All rights reserved.*
|
||||
@ -1,672 +0,0 @@
|
||||
---
|
||||
# Copyright (c) 2005, 2017, 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.
|
||||
|
||||
include-before: '[CONTENTS](index.html) | [PREV](output.html) | [NEXT](class.html)'
|
||||
include-after: '[CONTENTS](index.html) | [PREV](output.html) | [NEXT](class.html)'
|
||||
|
||||
title: 'Java Object Serialization Specification: 3 - Object Input Classes'
|
||||
---
|
||||
|
||||
- [The ObjectInputStream Class](#the-objectinputstream-class)
|
||||
- [The ObjectInputStream.GetField
|
||||
Class](#the-objectinputstream.getfield-class)
|
||||
- [The ObjectInputValidation Interface](#the-objectinputvalidation-interface)
|
||||
- [The readObject Method](#the-readobject-method)
|
||||
- [The readExternal Method](#the-readexternal-method)
|
||||
- [The readResolve Method](#the-readresolve-method)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
## 3.1 The ObjectInputStream Class
|
||||
|
||||
Class `ObjectInputStream` implements object deserialization. It maintains the
|
||||
state of the stream including the set of objects already deserialized. Its
|
||||
methods allow primitive types and objects to be read from a stream written by
|
||||
`ObjectOutputStream`. It manages restoration of the object and the objects that
|
||||
it refers to from the stream.
|
||||
|
||||
```
|
||||
package java.io;
|
||||
|
||||
public class ObjectInputStream
|
||||
extends InputStream
|
||||
implements ObjectInput, ObjectStreamConstants
|
||||
{
|
||||
public ObjectInputStream(InputStream in)
|
||||
throws StreamCorruptedException, IOException;
|
||||
|
||||
public final Object readObject()
|
||||
throws OptionalDataException, ClassNotFoundException,
|
||||
IOException;
|
||||
|
||||
public Object readUnshared()
|
||||
throws OptionalDataException, ClassNotFoundException,
|
||||
IOException;
|
||||
|
||||
public void defaultReadObject()
|
||||
throws IOException, ClassNotFoundException,
|
||||
NotActiveException;
|
||||
|
||||
public GetField readFields()
|
||||
throws IOException;
|
||||
|
||||
public synchronized void registerValidation(
|
||||
ObjectInputValidation obj, int prio)
|
||||
throws NotActiveException, InvalidObjectException;
|
||||
|
||||
protected ObjectStreamClass readClassDescriptor()
|
||||
throws IOException, ClassNotFoundException;
|
||||
|
||||
protected Class resolveClass(ObjectStreamClass v)
|
||||
throws IOException, ClassNotFoundException;
|
||||
|
||||
protected Object resolveObject(Object obj)
|
||||
throws IOException;
|
||||
|
||||
protected boolean enableResolveObject(boolean enable)
|
||||
throws SecurityException;
|
||||
|
||||
protected void readStreamHeader()
|
||||
throws IOException, StreamCorruptedException;
|
||||
|
||||
public int read() throws IOException;
|
||||
|
||||
public int read(byte[] data, int offset, int length)
|
||||
throws IOException
|
||||
|
||||
public int available() throws IOException;
|
||||
|
||||
public void close() throws IOException;
|
||||
|
||||
public boolean readBoolean() throws IOException;
|
||||
|
||||
public byte readByte() throws IOException;
|
||||
|
||||
public int readUnsignedByte() throws IOException;
|
||||
|
||||
public short readShort() throws IOException;
|
||||
|
||||
public int readUnsignedShort() throws IOException;
|
||||
|
||||
public char readChar() throws IOException;
|
||||
|
||||
public int readInt() throws IOException;
|
||||
|
||||
public long readLong() throws IOException;
|
||||
|
||||
public float readFloat() throws IOException;
|
||||
|
||||
public double readDouble() throws IOException;
|
||||
|
||||
public void readFully(byte[] data) throws IOException;
|
||||
|
||||
public void readFully(byte[] data, int offset, int size)
|
||||
throws IOException;
|
||||
|
||||
public int skipBytes(int len) throws IOException;
|
||||
|
||||
public String readLine() throws IOException;
|
||||
|
||||
public String readUTF() throws IOException;
|
||||
|
||||
// Class to provide access to serializable fields.
|
||||
static abstract public class GetField
|
||||
{
|
||||
public ObjectStreamClass getObjectStreamClass();
|
||||
|
||||
public boolean defaulted(String name)
|
||||
throws IOException, IllegalArgumentException;
|
||||
|
||||
public char get(String name, char default)
|
||||
throws IOException, IllegalArgumentException;
|
||||
|
||||
public boolean get(String name, boolean default)
|
||||
throws IOException, IllegalArgumentException;
|
||||
|
||||
public byte get(String name, byte default)
|
||||
throws IOException, IllegalArgumentException;
|
||||
|
||||
public short get(String name, short default)
|
||||
throws IOException, IllegalArgumentException;
|
||||
|
||||
public int get(String name, int default)
|
||||
throws IOException, IllegalArgumentException;
|
||||
|
||||
public long get(String name, long default)
|
||||
throws IOException, IllegalArgumentException;
|
||||
|
||||
public float get(String name, float default)
|
||||
throws IOException, IllegalArgumentException;
|
||||
|
||||
public double get(String name, double default)
|
||||
throws IOException, IllegalArgumentException;
|
||||
|
||||
public Object get(String name, Object default)
|
||||
throws IOException, IllegalArgumentException;
|
||||
}
|
||||
|
||||
protected ObjectInputStream()
|
||||
throws StreamCorruptedException, IOException;
|
||||
|
||||
protected readObjectOverride()
|
||||
throws OptionalDataException, ClassNotFoundException,
|
||||
IOException;
|
||||
}
|
||||
```
|
||||
|
||||
The single-argument `ObjectInputStream` constructor requires an `InputStream`.
|
||||
The constructor calls `readStreamHeader` to read and verifies the header and
|
||||
version written by the corresponding `ObjectOutputStream.writeStreamHeader`
|
||||
method. If a security manager is installed, this constructor checks for the
|
||||
`"enableSubclassImplementation"` `SerializablePermission` when invoked directly
|
||||
or indirectly by the constructor of a subclass which overrides the `readFields`
|
||||
and/or `readUnshared` methods.
|
||||
|
||||
**Note:** The `ObjectInputStream` constructor blocks until it completes reading
|
||||
the serialization stream header. Code which waits for an `ObjectInputStream` to
|
||||
be constructed before creating the corresponding `ObjectOutputStream` for that
|
||||
stream will deadlock, since the `ObjectInputStream` constructor will block
|
||||
until a header is written to the stream, and the header will not be written to
|
||||
the stream until the `ObjectOutputStream` constructor executes. This problem
|
||||
can be resolved by creating the `ObjectOutputStream` before the
|
||||
`ObjectInputStream`, or otherwise removing the timing dependency between
|
||||
completion of `ObjectInputStream` construction and the creation of the
|
||||
`ObjectOutputStream`.
|
||||
|
||||
The `readObject` method is used to deserialize an object from the stream. It
|
||||
reads from the stream to reconstruct an object.
|
||||
|
||||
1. If the `ObjectInputStream` subclass is overriding the implementation, call
|
||||
the `readObjectOverride` method and return. Reimplementation is described
|
||||
at the end of this section.
|
||||
|
||||
2. If a block data record occurs in the stream, throw a `BlockDataException`
|
||||
with the number of available bytes.
|
||||
|
||||
3. If the object in the stream is null, return null.
|
||||
|
||||
4. If the object in the stream is a handle to a previous object, return the
|
||||
object.
|
||||
|
||||
5. If the object in the stream is a `Class`, read its `ObjectStreamClass`
|
||||
descriptor, add it and its handle to the set of known objects, and return
|
||||
the corresponding `Class` object.
|
||||
|
||||
6. If the object in the stream is an `ObjectStreamClass`, read in its data
|
||||
according to the formats described in [Section 4.3, "Serialized
|
||||
Form"](class.html#serialized-form). Add it and its handle to the set of
|
||||
known objects. In versions 1.3 and later of the Java 2 SDK, Standard
|
||||
Edition, the `readClassDescriptor` method is called to read in the
|
||||
`ObjectStreamClass` if it represents a class that is not a dynamic proxy
|
||||
class, as indicated in the stream data. If the class descriptor represents
|
||||
a dynamic proxy class, call the `resolveProxyClass` method on the stream to
|
||||
get the local class for the descriptor; otherwise, call the `resolveClass`
|
||||
method on the stream to get the local class. If the class cannot be
|
||||
resolved, throw a ClassNotFoundException. Return the resulting
|
||||
`ObjectStreamClass` object.
|
||||
|
||||
7. If the object in the stream is a `String`, read its length information
|
||||
followed by the contents of the string encoded in modified UTF-8. For
|
||||
details, refer to [Section 6.2, "Stream
|
||||
Elements"](protocol.html#stream-elements). Add the `String` and its handle
|
||||
to the set of known objects, and proceed to Step 12.
|
||||
|
||||
8. If the object in the stream is an array, read its `ObjectStreamClass` and
|
||||
the length of the array. Allocate the array, and add it and its handle in
|
||||
the set of known objects. Read each element using the appropriate method
|
||||
for its type and assign it to the array. Proceed to Step 12.
|
||||
|
||||
9. If the object in the stream is an enum constant, read its
|
||||
`ObjectStreamClass` and the enum constant name. If the `ObjectStreamClass`
|
||||
represents a class that is not an enum type, an `InvalidClassException` is
|
||||
thrown. Obtain a reference to the enum constant by calling the
|
||||
`java.lang.Enum.valueOf` method, passing the enum type bound to the
|
||||
received `ObjectStreamClass` along with the received name as arguments. If
|
||||
the `valueOf` method throws an `IllegalArgumentException`, an
|
||||
`InvalidObjectException` is thrown with the `IllegalArgumentException` as
|
||||
its cause. Add the enum constant and its handle in the set of known
|
||||
objects, and proceed to Step 12.
|
||||
|
||||
10. For all other objects, the `ObjectStreamClass` of the object is read from
|
||||
the stream. The local class for that `ObjectStreamClass` is retrieved. The
|
||||
class must be serializable or externalizable, and must not be an enum type.
|
||||
If the class does not satisfy these criteria, an `InvalidClassException` is
|
||||
thrown.
|
||||
|
||||
11. An instance of the class is allocated. The instance and its handle are
|
||||
added to the set of known objects. The contents restored appropriately:
|
||||
|
||||
a. For serializable objects, the no-arg constructor for the first
|
||||
non-serializable supertype is run. For serializable classes, the fields
|
||||
are initialized to the default value appropriate for its type. Then the
|
||||
fields of each class are restored by calling class-specific
|
||||
`readObject` methods, or if these are not defined, by calling the
|
||||
`defaultReadObject` method. Note that field initializers and
|
||||
constructors are not executed for serializable classes during
|
||||
deserialization. In the normal case, the version of the class that
|
||||
wrote the stream will be the same as the class reading the stream. In
|
||||
this case, all of the supertypes of the object in the stream will match
|
||||
the supertypes in the currently-loaded class. If the version of the
|
||||
class that wrote the stream had different supertypes than the loaded
|
||||
class, the `ObjectInputStream` must be more careful about restoring or
|
||||
initializing the state of the differing classes. It must step through
|
||||
the classes, matching the available data in the stream with the classes
|
||||
of the object being restored. Data for classes that occur in the
|
||||
stream, but do not occur in the object, is discarded. For classes that
|
||||
occur in the object, but not in the stream, the class fields are set to
|
||||
default values by default serialization.
|
||||
|
||||
b. For externalizable objects, the no-arg constructor for the class is run
|
||||
and then the `readExternal` method is called to restore the contents of
|
||||
the object.
|
||||
|
||||
12. Process potential substitutions by the class of the object and/or by a
|
||||
subclass of `ObjectInputStream`:
|
||||
|
||||
a. If the class of the object is not an enum type and defines the
|
||||
appropriate `readResolve` method, the method is called to allow the
|
||||
object to replace itself.
|
||||
|
||||
b. Then if previously enabled by `enableResolveObject,` the
|
||||
`resolveObject` method is called to allow subclasses of the stream to
|
||||
examine and replace the object. If the previous step did replace the
|
||||
original object, the `resolveObject` method is called with the
|
||||
replacement object. If a replacement took place, the table of known
|
||||
objects is updated so the replacement object is associated with the
|
||||
handle. The replacement object is then returned from `readObject`.
|
||||
|
||||
All of the methods for reading primitives types only consume bytes from the
|
||||
block data records in the stream. If a read for primitive data occurs when the
|
||||
next item in the stream is an object, the read methods return *-1* or the
|
||||
`EOFException` as appropriate. The value of a primitive type is read by a
|
||||
`DataInputStream` from the block data record.
|
||||
|
||||
The exceptions thrown reflect errors during the traversal or exceptions that
|
||||
occur on the underlying stream. If any exception is thrown, the underlying
|
||||
stream is left in an unknown and unusable state.
|
||||
|
||||
When the reset token occurs in the stream, all of the state of the stream is
|
||||
discarded. The set of known objects is cleared.
|
||||
|
||||
When the exception token occurs in the stream, the exception is read and a new
|
||||
`WriteAbortedException` is thrown with the terminating exception as an
|
||||
argument. The stream context is reset as described earlier.
|
||||
|
||||
The `readUnshared` method is used to read "unshared" objects from the stream.
|
||||
This method is identical to `readObject`, except that it prevents subsequent
|
||||
calls to `readObject` and `readUnshared` from returning additional references
|
||||
to the deserialized instance returned by the original call to `readUnshared`.
|
||||
Specifically:
|
||||
|
||||
- If `readUnshared` is called to deserialize a back-reference (the stream
|
||||
representation of an object which has been written previously to the
|
||||
stream), an `ObjectStreamException` will be thrown.
|
||||
|
||||
- If `readUnshared` returns successfully, then any subsequent attempts to
|
||||
deserialize back-references to the stream handle deserialized by
|
||||
`readUnshared` will cause an `ObjectStreamException` to be thrown.
|
||||
|
||||
Deserializing an object via `readUnshared` invalidates the stream handle
|
||||
associated with the returned object. Note that this in itself does not always
|
||||
guarantee that the reference returned by `readUnshared` is unique; the
|
||||
deserialized object may define a `readResolve` method which returns an object
|
||||
visible to other parties, or `readUnshared` may return a `Class` object or enum
|
||||
constant obtainable elsewhere in the stream or through external means. If the
|
||||
deserialized object defines a `readResolve` method and the invocation of that
|
||||
method returns an array, then `readUnshared` returns a shallow clone of that
|
||||
array; this guarantees that the returned array object is unique and cannot be
|
||||
obtained a second time from an invocation of `readObject` or `readUnshared` on
|
||||
the `ObjectInputStream`, even if the underlying data stream has been
|
||||
manipulated.
|
||||
|
||||
The `defaultReadObject` method is used to read the fields and object from the
|
||||
stream. It uses the class descriptor in the stream to read the fields in the
|
||||
canonical order by name and type from the stream. The values are assigned to
|
||||
the matching fields by name in the current class. Details of the versioning
|
||||
mechanism can be found in [Section 5.5, "Compatible Java Type
|
||||
Evolution"](version.html#compatible-java-type-evolution). Any field of the
|
||||
object that does not appear in the stream is set to its default value. Values
|
||||
that appear in the stream, but not in the object, are discarded. This occurs
|
||||
primarily when a later version of a class has written additional fields that do
|
||||
not occur in the earlier version. This method may only be called from the
|
||||
`readObject` method while restoring the fields of a class. When called at any
|
||||
other time, the `NotActiveException` is thrown.
|
||||
|
||||
The `readFields` method reads the values of the serializable fields from the
|
||||
stream and makes them available via the `GetField` class. The `readFields`
|
||||
method is only callable from within the `readObject` method of a serializable
|
||||
class. It cannot be called more than once or if `defaultReadObject` has been
|
||||
called. The `GetFields` object uses the current object's `ObjectStreamClass` to
|
||||
verify the fields that can be retrieved for this class. The `GetFields` object
|
||||
returned by `readFields` is only valid during this call to the classes
|
||||
`readObject` method. The fields may be retrieved in any order. Additional data
|
||||
may only be read directly from stream after `readFields` has been called.
|
||||
|
||||
The `registerValidation` method can be called to request a callback when the
|
||||
entire graph has been restored but before the object is returned to the
|
||||
original caller of `readObject`. The order of validate callbacks can be
|
||||
controlled using the priority. Callbacks registered with higher values are
|
||||
called before those with lower values. The object to be validated must support
|
||||
the `ObjectInputValidation` interface and implement the `validateObject`
|
||||
method. It is only correct to register validations during a call to a class's
|
||||
`readObject` method. Otherwise, a `NotActiveException` is thrown. If the
|
||||
callback object supplied to `registerValidation` is null, an
|
||||
`InvalidObjectException` is thrown.
|
||||
|
||||
Starting with the Java SDK, Standard Edition, v1.3, the `readClassDescriptor`
|
||||
method is used to read in all `ObjectStreamClass` objects.
|
||||
`readClassDescriptor` is called when the `ObjectInputStream` expects a class
|
||||
descriptor as the next item in the serialization stream. Subclasses of
|
||||
`ObjectInputStream` may override this method to read in class descriptors that
|
||||
have been written in non-standard formats (by subclasses of
|
||||
`ObjectOutputStream` which have overridden the `writeClassDescriptor` method).
|
||||
By default, this method reads class descriptors according to the format
|
||||
described in [Section 6.4, "Grammar for the Stream
|
||||
Format"](protocol.html#grammar-for-the-stream-format).
|
||||
|
||||
The `resolveClass` method is called while a class is being deserialized, and
|
||||
after the class descriptor has been read. Subclasses may extend this method to
|
||||
read other information about the class written by the corresponding subclass of
|
||||
`ObjectOutputStream`. The method must find and return the class with the given
|
||||
name and `serialVersionUID`. The default implementation locates the class by
|
||||
calling the class loader of the closest caller of `readObject` that has a class
|
||||
loader. If the class cannot be found `ClassNotFoundException` should be thrown.
|
||||
Prior to JDK 1.1.6, the `resolveClass` method was required to return the same
|
||||
fully qualified class name as the class name in the stream. In order to
|
||||
accommodate package renaming across releases, `method` `resolveClass` only
|
||||
needs to return a class with the same base class name and `SerialVersionUID` in
|
||||
JDK 1.1.6 and later versions.
|
||||
|
||||
The `resolveObject` method is used by trusted subclasses to monitor or
|
||||
substitute one object for another during deserialization. Resolving objects
|
||||
must be enabled explicitly by calling `enableResolveObject` before calling
|
||||
`readObject` for the first object to be resolved. Once enabled, `resolveObject`
|
||||
is called once for each serializable object just prior to the first time it is
|
||||
being returned from `readObject`. Note that the `resolveObject` method is not
|
||||
called for objects of the specially handled classes, `Class`,
|
||||
`ObjectStreamClass`, `String`, and arrays. A subclass's implementation of
|
||||
`resolveObject` may return a substitute object that will be assigned or
|
||||
returned instead of the original. The object returned must be of a type that is
|
||||
consistent and assignable to every reference of the original object or else a
|
||||
`ClassCastException` will be thrown. All assignments are type-checked. All
|
||||
references in the stream to the original object will be replaced by references
|
||||
to the substitute object.
|
||||
|
||||
The `enableResolveObject` method is called by trusted subclasses of
|
||||
`ObjectOutputStream` to enable the monitoring or substitution of one object for
|
||||
another during deserialization. Replacing objects is disabled until
|
||||
`enableResolveObject` is called with a `true` value. It may thereafter be
|
||||
disabled by setting it to `false`. The previous setting is returned. The
|
||||
`enableResolveObject` method checks if the stream has permission to request
|
||||
substitution during serialization. To ensure that the private state of objects
|
||||
is not unintentionally exposed, only trusted streams may use `resolveObject`.
|
||||
Trusted classes are those classes with a class loader equal to null or belong
|
||||
to a security protection domain that provides permission to enable
|
||||
substitution.
|
||||
|
||||
If the subclass of `ObjectInputStream` is not considered part of the system
|
||||
domain, a line has to be added to the security policy file to provide to a
|
||||
subclass of `ObjectInputStream` permission to call `enableResolveObject`. The
|
||||
`SerializablePermission` to add is `"enableSubstitution"`.
|
||||
`AccessControlException` is thrown if the protection domain of the subclass of
|
||||
`ObjectStreamClass` does not have permission to `"enableSubstitution"` by
|
||||
calling `enableResolveObject`. See the document Java Security Architecture (JDK
|
||||
1.2) for additional information about the security model.
|
||||
|
||||
The `readStreamHeader` method reads and verifies the magic number and version
|
||||
of the stream. If they do not match, the `StreamCorruptedMismatch` is thrown.
|
||||
|
||||
To override the implementation of deserialization, a subclass of
|
||||
`ObjectInputStream` should call the protected no-arg `ObjectInputStream`,
|
||||
constructor. There is a security check within the no-arg constructor for
|
||||
`SerializablePermission "enableSubclassImplementation"` to ensure that only
|
||||
trusted classes are allowed to override the default implementation. This
|
||||
constructor does not allocate any private data for `ObjectInputStream` and sets
|
||||
a flag that indicates that the final `readObject` method should invoke the
|
||||
`readObjectOverride` method and return. All other `ObjectInputStream` methods
|
||||
are not final and can be directly overridden by the subclass.
|
||||
|
||||
## 3.2 The ObjectInputStream.GetField Class
|
||||
|
||||
The class `ObjectInputStream.GetField` provides the API for getting the values
|
||||
of serializable fields. The protocol of the stream is the same as used by
|
||||
`defaultReadObject.` Using `readFields` to access the serializable fields does
|
||||
not change the format of the stream. It only provides an alternate API to
|
||||
access the values which does not require the class to have the corresponding
|
||||
non-transient and non-static fields for each named serializable field. The
|
||||
serializable fields are those declared using `serialPersistentFields` or if it
|
||||
is not declared the non-transient and non-static fields of the object. When the
|
||||
stream is read the available serializable fields are those written to the
|
||||
stream when the object was serialized. If the class that wrote the stream is a
|
||||
different version not all fields will correspond to the serializable fields of
|
||||
the current class. The available fields can be retrieved from the
|
||||
`ObjectStreamClass` of the `GetField` object.
|
||||
|
||||
The `getObjectStreamClass` method returns an `ObjectStreamClass` object
|
||||
representing the class in the stream. It contains the list of serializable
|
||||
fields.
|
||||
|
||||
The `defaulted` method returns *true* if the field is not present in the
|
||||
stream. An `IllegalArgumentException` is thrown if the requested field is not a
|
||||
serializable field of the current class.
|
||||
|
||||
Each `get` method returns the specified serializable field from the stream. I/O
|
||||
exceptions will be thrown if the underlying stream throws an exception. An
|
||||
`IllegalArgumentException` is thrown if the name or type does not match the
|
||||
name and type of an field serializable field of the current class. The default
|
||||
value is returned if the stream does not contain an explicit value for the
|
||||
field.
|
||||
|
||||
## 3.3 The ObjectInputValidation Interface
|
||||
|
||||
This interface allows an object to be called when a complete graph of objects
|
||||
has been deserialized. If the object cannot be made valid, it should throw the
|
||||
`ObjectInvalidException`. Any exception that occurs during a call to
|
||||
`validateObject` will terminate the validation process, and the
|
||||
`InvalidObjectException` will be thrown.
|
||||
|
||||
```
|
||||
package java.io;
|
||||
|
||||
public interface ObjectInputValidation
|
||||
{
|
||||
public void validateObject()
|
||||
throws InvalidObjectException;
|
||||
}
|
||||
```
|
||||
|
||||
## 3.4 The readObject Method
|
||||
|
||||
For serializable objects, the `readObject` method allows a class to control the
|
||||
deserialization of its own fields. Here is its signature:
|
||||
|
||||
```
|
||||
private void readObject(ObjectInputStream stream)
|
||||
throws IOException, ClassNotFoundException;
|
||||
```
|
||||
|
||||
Each subclass of a serializable object may define its own `readObject` method.
|
||||
If a class does not implement the method, the default serialization provided by
|
||||
`defaultReadObject` will be used. When implemented, the class is only
|
||||
responsible for restoring its own fields, not those of its supertypes or
|
||||
subtypes.
|
||||
|
||||
The `readObject` method of the class, if implemented, is responsible for
|
||||
restoring the state of the class. The values of every field of the object
|
||||
whether transient or not, static or not are set to the default value for the
|
||||
fields type. Either `ObjectInputStream`'s `defaultReadObject` or `readFields`
|
||||
method must be called once (and only once) before reading any optional data
|
||||
written by the corresponding `writeObject` method; even if no optional data is
|
||||
read, `defaultReadObject` or `readFields` must still be invoked once. If the
|
||||
`readObject` method of the class attempts to read more data than is present in
|
||||
the optional part of the stream for this class, the stream will return `-1` for
|
||||
bytewise reads, throw an `EOFException` for primitive data reads (e.g.,
|
||||
`readInt`, `readFloat`), or throw an `OptionalDataException` with the `eof`
|
||||
field set to `true` for object reads.
|
||||
|
||||
The responsibility for the format, structure, and versioning of the optional
|
||||
data lies completely with the class. The `@serialData` javadoc tag within the
|
||||
javadoc comment for the `readObject` method should be used to document the
|
||||
format and structure of the optional data.
|
||||
|
||||
If the class being restored is not present in the stream being read, then its
|
||||
`readObjectNoData` method, if defined, is invoked (instead of `readObject`);
|
||||
otherwise, its fields are initialized to the appropriate default values. For
|
||||
further detail, see [Section 3.5, "The readObjectNoData
|
||||
Method"](#the-readobjectnodata-method).
|
||||
|
||||
Reading an object from the `ObjectInputStream` is analogous to creating a new
|
||||
object. Just as a new object's constructors are invoked in the order from the
|
||||
superclass to the subclass, an object being read from a stream is deserialized
|
||||
from superclass to subclass. The `readObject` or `readObjectNoData` method is
|
||||
called instead of the constructor for each `Serializable` subclass during
|
||||
deserialization.
|
||||
|
||||
One last similarity between a constructor and a `readObject` method is that
|
||||
both provide the opportunity to invoke a method on an object that is not fully
|
||||
constructed. Any overridable (neither private, static nor final) method called
|
||||
while an object is being constructed can potentially be overridden by a
|
||||
subclass. Methods called during the construction phase of an object are
|
||||
resolved by the actual type of the object, not the type currently being
|
||||
initialized by either its constructor or `readObject`/`readObjectNoData`
|
||||
method. Therefore, calling an overridable method from within a `readObject` or
|
||||
`readObjectNoData` method may result in the unintentional invocation of a
|
||||
subclass method before the superclass has been fully initialized.
|
||||
|
||||
## 3.5 The readObjectNoData Method
|
||||
|
||||
For serializable objects, the `readObjectNoData` method allows a class to
|
||||
control the initialization of its own fields in the event that a subclass
|
||||
instance is deserialized and the serialization stream does not list the class
|
||||
in question as a superclass of the deserialized object. This may occur in cases
|
||||
where the receiving party uses a different version of the deserialized
|
||||
instance's class than the sending party, and the receiver's version extends
|
||||
classes that are not extended by the sender's version. This may also occur if
|
||||
the serialization stream has been tampered; hence, `readObjectNoData` is useful
|
||||
for initializing deserialized objects properly despite a "hostile" or
|
||||
incomplete source stream.
|
||||
|
||||
```
|
||||
private void readObjectNoData() throws ObjectStreamException;
|
||||
```
|
||||
|
||||
Each serializable class may define its own `readObjectNoData` method. If a
|
||||
serializable class does not define a `readObjectNoData` method, then in the
|
||||
circumstances listed above the fields of the class will be initialized to their
|
||||
default values (as listed in The Java Language Specification); this behavior is
|
||||
consistent with that of `ObjectInputStream` prior to version 1.4 of the Java 2
|
||||
SDK, Standard Edition, when support for `readObjectNoData` methods was
|
||||
introduced. If a serializable class does define a `readObjectNoData` method and
|
||||
the aforementioned conditions arise, then `readObjectNoData` will be invoked at
|
||||
the point during deserialization when a class-defined `readObject` method would
|
||||
otherwise be called had the class in question been listed by the stream as a
|
||||
superclass of the instance being deserialized.
|
||||
|
||||
## 3.6 The readExternal Method
|
||||
|
||||
Objects implementing `java.io.Externalizable` must implement the `readExternal`
|
||||
method to restore the entire state of the object. It must coordinate with its
|
||||
superclasses to restore their state. All of the methods of `ObjectInput` are
|
||||
available to restore the object's primitive typed fields and object fields.
|
||||
|
||||
```
|
||||
public void readExternal(ObjectInput stream)
|
||||
throws IOException;
|
||||
```
|
||||
|
||||
**Note:** The `readExternal` method is public, and it raises the risk of a
|
||||
client being able to overwrite an existing object from a stream. The class may
|
||||
add its own checks to insure that this is only called when appropriate.
|
||||
|
||||
A new stream protocol version has been introduced in JDK 1.2 to correct a
|
||||
problem with `Externalizable` objects. The old definition of `Externalizable`
|
||||
objects required the local virtual machine to find a `readExternal` method to
|
||||
be able to properly read an `Externalizable` object from the stream. The new
|
||||
format adds enough information to the stream protocol so serialization can skip
|
||||
an `Externalizable` object when the local `readExternal` method is not
|
||||
available. Due to class evolution rules, serialization must be able to skip an
|
||||
`Externalizable` object in the input stream if there is not a mapping for the
|
||||
object using the local classes.
|
||||
|
||||
An additional benefit of the new `Externalizable` stream format is that
|
||||
`ObjectInputStream` can detect attempts to read more External data than is
|
||||
available, and can also skip by any data that is left unconsumed by a
|
||||
`readExternal` method. The behavior of `ObjectInputStream` in response to a
|
||||
read past the end of External data is the same as the behavior when a
|
||||
class-defined `readObject` method attempts to read past the end of its optional
|
||||
data: bytewise reads will return `-1`, primitive reads will throw
|
||||
`EOFException`s, and object reads will throw `OptionalDataException`s with the
|
||||
`eof` field set to `true`.
|
||||
|
||||
Due to the format change, JDK 1.1.6 and earlier releases are not able to read
|
||||
the new format. `StreamCorruptedException` is thrown when JDK 1.1.6 or earlier
|
||||
attempts to read an `Externalizable` object from a stream written in
|
||||
`PROTOCOL_VERSION_2`. Compatibility issues are discussed in more detail in
|
||||
[Section 6.3, "Stream Protocol
|
||||
Versions"](protocol.html#stream-protocol-versions).
|
||||
|
||||
## 3.7 The readResolve Method
|
||||
|
||||
For Serializable and Externalizable classes, the `readResolve` method allows a
|
||||
class to replace/resolve the object read from the stream before it is returned
|
||||
to the caller. By implementing the `readResolve` method, a class can directly
|
||||
control the types and instances of its own instances being deserialized. The
|
||||
method is defined as follows:
|
||||
|
||||
```
|
||||
ANY-ACCESS-MODIFIER Object readResolve()
|
||||
throws ObjectStreamException;
|
||||
```
|
||||
|
||||
The `readResolve` method is called when `ObjectInputStream` has read an object
|
||||
from the stream and is preparing to return it to the caller.
|
||||
`ObjectInputStream` checks whether the class of the object defines the
|
||||
`readResolve` method. If the method is defined, the `readResolve` method is
|
||||
called to allow the object in the stream to designate the object to be
|
||||
returned. The object returned should be of a type that is compatible with all
|
||||
uses. If it is not compatible, a `ClassCastException` will be thrown when the
|
||||
type mismatch is discovered.
|
||||
|
||||
For example, a `Symbol` class could be created for which only a single instance
|
||||
of each symbol binding existed within a virtual machine. The `readResolve`
|
||||
method would be implemented to determine if that symbol was already defined and
|
||||
substitute the preexisting equivalent `Symbol` object to maintain the identity
|
||||
constraint. In this way the uniqueness of `Symbol` objects can be maintained
|
||||
across serialization.
|
||||
|
||||
**Note:** The `readResolve` method is not invoked on the object until the
|
||||
object is fully constructed, so any references to this object in its object
|
||||
graph will not be updated to the new object nominated by `readResolve`.
|
||||
However, during the serialization of an object with the `writeReplace` method,
|
||||
all references to the original object in the replacement object's object graph
|
||||
are replaced with references to the replacement object. Therefore in cases
|
||||
where an object being serialized nominates a replacement object whose object
|
||||
graph has a reference to the original object, deserialization will result in an
|
||||
incorrect graph of objects. Furthermore, if the reference types of the object
|
||||
being read (nominated by `writeReplace`) and the original object are not
|
||||
compatible, the construction of the object graph will raise a
|
||||
`ClassCastException`.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
*[Copyright](../../../legal/SMICopyright.html) © 2005, 2017, Oracle
|
||||
and/or its affiliates. All rights reserved.*
|
||||
@ -1,514 +0,0 @@
|
||||
---
|
||||
# Copyright (c) 2005, 2017, 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.
|
||||
|
||||
include-before: '[CONTENTS](index.html) | [PREV](serial-arch.html) | [NEXT](input.html)'
|
||||
include-after: '[CONTENTS](index.html) | [PREV](serial-arch.html) | [NEXT](input.html)'
|
||||
|
||||
title: 'Java Object Serialization Specification: 2 - Object Output Classes'
|
||||
---
|
||||
|
||||
- [The ObjectOutputStream Class](#the-objectoutputstream-class)
|
||||
- [The ObjectOutputStream.PutField
|
||||
Class](#the-objectoutputstream.putfield-class)
|
||||
- [The writeObject Method](#the-writeobject-method)
|
||||
- [The writeExternal Method](#the-writeexternal-method)
|
||||
- [The writeReplace Method](#the-writereplace-method)
|
||||
- [The useProtocolVersion Method](#the-useprotocolversion-method)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
## 2.1 The ObjectOutputStream Class
|
||||
|
||||
Class `ObjectOutputStream` implements object serialization. It maintains the
|
||||
state of the stream including the set of objects already serialized. Its
|
||||
methods control the traversal of objects to be serialized to save the specified
|
||||
objects and the objects to which they refer.
|
||||
|
||||
```
|
||||
package java.io;
|
||||
|
||||
public class ObjectOutputStream
|
||||
extends OutputStream
|
||||
implements ObjectOutput, ObjectStreamConstants
|
||||
{
|
||||
public ObjectOutputStream(OutputStream out)
|
||||
throws IOException;
|
||||
|
||||
public final void writeObject(Object obj)
|
||||
throws IOException;
|
||||
|
||||
public void writeUnshared(Object obj)
|
||||
throws IOException;
|
||||
|
||||
public void defaultWriteObject()
|
||||
throws IOException, NotActiveException;
|
||||
|
||||
public PutField putFields()
|
||||
throws IOException;
|
||||
|
||||
public writeFields()
|
||||
throws IOException;
|
||||
|
||||
public void reset() throws IOException;
|
||||
|
||||
protected void annotateClass(Class cl) throws IOException;
|
||||
|
||||
protected void writeClassDescriptor(ObjectStreamClass desc)
|
||||
throws IOException;
|
||||
|
||||
protected Object replaceObject(Object obj) throws IOException;
|
||||
|
||||
protected boolean enableReplaceObject(boolean enable)
|
||||
throws SecurityException;
|
||||
|
||||
protected void writeStreamHeader() throws IOException;
|
||||
|
||||
public void write(int data) throws IOException;
|
||||
|
||||
public void write(byte b[]) throws IOException;
|
||||
|
||||
public void write(byte b[], int off, int len) throws IOException;
|
||||
|
||||
public void flush() throws IOException;
|
||||
|
||||
protected void drain() throws IOException;
|
||||
|
||||
public void close() throws IOException;
|
||||
|
||||
public void writeBoolean(boolean data) throws IOException;
|
||||
|
||||
public void writeByte(int data) throws IOException;
|
||||
|
||||
public void writeShort(int data) throws IOException;
|
||||
|
||||
public void writeChar(int data) throws IOException;
|
||||
|
||||
public void writeInt(int data) throws IOException;
|
||||
|
||||
public void writeLong(long data) throws IOException;
|
||||
|
||||
public void writeFloat(float data) throws IOException;
|
||||
|
||||
public void writeDouble(double data) throws IOException;
|
||||
|
||||
public void writeBytes(String data) throws IOException;
|
||||
|
||||
public void writeChars(String data) throws IOException;
|
||||
|
||||
public void writeUTF(String data) throws IOException;
|
||||
|
||||
// Inner class to provide access to serializable fields.
|
||||
abstract static public class PutField
|
||||
{
|
||||
public void put(String name, boolean value)
|
||||
throws IOException, IllegalArgumentException;
|
||||
|
||||
public void put(String name, char data)
|
||||
throws IOException, IllegalArgumentException;
|
||||
|
||||
public void put(String name, byte data)
|
||||
throws IOException, IllegalArgumentException;
|
||||
|
||||
public void put(String name, short data)
|
||||
throws IOException, IllegalArgumentException;
|
||||
|
||||
public void put(String name, int data)
|
||||
throws IOException, IllegalArgumentException;
|
||||
|
||||
public void put(String name, long data)
|
||||
throws IOException, IllegalArgumentException;
|
||||
|
||||
public void put(String name, float data)
|
||||
throws IOException, IllegalArgumentException;
|
||||
|
||||
public void put(String name, double data)
|
||||
throws IOException, IllegalArgumentException;
|
||||
|
||||
public void put(String name, Object data)
|
||||
throws IOException, IllegalArgumentException;
|
||||
}
|
||||
|
||||
public void useProtocolVersion(int version) throws IOException;
|
||||
|
||||
protected ObjectOutputStream()
|
||||
throws IOException;
|
||||
|
||||
protected writeObjectOverride()
|
||||
throws NotActiveException, IOException;
|
||||
}
|
||||
```
|
||||
|
||||
The single-argument `ObjectOutputStream` constructor creates an
|
||||
`ObjectOutputStream` that serializes objects to the given `OutputStream`. The
|
||||
constructor calls `writeStreamHeader` to write a magic number and version to
|
||||
the stream that will be read and verified by a corresponding call to
|
||||
`readStreamHeader` in the single-argument `ObjectInputStream` constructor. If a
|
||||
security manager is installed, this constructor checks for the
|
||||
`"enableSubclassImplementation"` `SerializablePermission` when invoked directly
|
||||
or indirectly by the constructor of a subclass which overrides the `putFields`
|
||||
and/or `writeUnshared` methods.
|
||||
|
||||
The `writeObject` method is used to serialize an object to the stream. An
|
||||
object is serialized as follows:
|
||||
|
||||
1. If a subclass is overriding the implementation, call the
|
||||
`writeObjectOverride` method and return. Overriding the implementation is
|
||||
described at the end of this section.
|
||||
|
||||
2. If there is data in the block-data buffer, the data is written to the
|
||||
stream and the buffer is reset.
|
||||
|
||||
3. If the object is null, null is put in the stream and `writeObject` returns.
|
||||
|
||||
4. If the object has been previously replaced, as described in Step 8, write
|
||||
the handle of the replacement to the stream and `writeObject` returns.
|
||||
|
||||
5. If the object has already been written to the stream, its handle is written
|
||||
to the stream and `writeObject` returns.
|
||||
|
||||
6. If the object is a `Class`, the corresponding `ObjectStreamClass` is
|
||||
written to the stream, a handle is assigned for the class, and
|
||||
`writeObject` returns.
|
||||
|
||||
7. If the object is an `ObjectStreamClass`, a handle is assigned to the
|
||||
object, after which it is written to the stream using one of the class
|
||||
descriptor formats described in [Section 4.3, "Serialized
|
||||
Form"](class.html#serialized-form). In versions 1.3 and later of the Java 2
|
||||
SDK, Standard Edition, the `writeClassDescriptor` method is called to
|
||||
output the `ObjectStreamClass` if it represents a class that is not a
|
||||
dynamic proxy class, as determined by passing the associated `Class` object
|
||||
to the `isProxyClass` method of `java.lang.reflect.Proxy`. Afterwards, an
|
||||
annotation for the represented class is written: if the class is a dynamic
|
||||
proxy class, then the `annotateProxyClass` method is called; otherwise, the
|
||||
`annotateClass` method is called. The `writeObject` method then returns.
|
||||
|
||||
8. Process potential substitutions by the class of the object and/or by a
|
||||
subclass of `ObjectInputStream`.
|
||||
|
||||
a. If the class of an object is not an enum type and defines the
|
||||
appropriate `writeReplace` method, the method is called. Optionally, it
|
||||
can return a substitute object to be serialized.
|
||||
|
||||
b. Then, if enabled by calling the `enableReplaceObject` method, the
|
||||
`replaceObject` method is called to allow subclasses of
|
||||
`ObjectOutputStream` to substitute for the object being serialized. If
|
||||
the original object was replaced in the previous step, the
|
||||
`replaceObject` method is called with the replacement object.
|
||||
|
||||
If the original object was replaced by either one or both steps above, the
|
||||
mapping from the original object to the replacement is recorded for later
|
||||
use in Step 4. Then, Steps 3 through 7 are repeated on the new object.
|
||||
|
||||
If the replacement object is not one of the types covered by Steps 3
|
||||
through 7, processing resumes using the replacement object at Step 10.
|
||||
|
||||
9. <a id="java-lang-string-encoding"></a>
|
||||
If the object is a `java.lang.String,` the string is written as length
|
||||
information followed by the contents of the string encoded in modified
|
||||
UTF-8. For details, refer to [Section 6.2, "Stream
|
||||
Elements"](protocol.html#stream-elements). A handle is assigned to the
|
||||
string, and `writeObject` returns.
|
||||
|
||||
10. If the object is an array, `writeObject` is called recursively to write the
|
||||
`ObjectStreamClass` of the array. The handle for the array is assigned. It
|
||||
is followed by the length of the array. Each element of the array is then
|
||||
written to the stream, after which `writeObject` returns.
|
||||
|
||||
11. If the object is an enum constant, the `ObjectStreamClass` for the enum
|
||||
type of the constant is written by recursively calling `writeObject`. It
|
||||
will appear in the stream only the first time it is referenced. A handle is
|
||||
assigned for the enum constant. Next, the value returned by the `name`
|
||||
method of the enum constant is written as a `String` object, as described
|
||||
in step 9. Note that if the same name string has appeared previously in the
|
||||
stream, a back reference to it will be written. The `writeObject` method
|
||||
then returns.
|
||||
|
||||
12. For regular objects, the `ObjectStreamClass` for the class of the object is
|
||||
written by recursively calling `writeObject`. It will appear in the stream
|
||||
only the first time it is referenced. A handle is assigned for the object.
|
||||
|
||||
13. The contents of the object are written to the stream.
|
||||
|
||||
a. If the object is serializable, the highest serializable class is
|
||||
located. For that class, and each derived class, that class's fields
|
||||
are written. If the class does not have a `writeObject` method, the
|
||||
`defaultWriteObject` method is called to write the serializable fields
|
||||
to the stream. If the class does have a `writeObject` method, it is
|
||||
called. It may call `defaultWriteObject` or `putFields` and
|
||||
`writeFields` to save the state of the object, and then it can write
|
||||
other information to the stream.
|
||||
|
||||
b. If the object is externalizable, the `writeExternal` method of the
|
||||
object is called.
|
||||
|
||||
c. If the object is neither serializable or externalizable, the
|
||||
`NotSerializableException` is thrown.
|
||||
|
||||
Exceptions may occur during the traversal or may occur in the underlying
|
||||
stream. For any subclass of `IOException`, the exception is written to the
|
||||
stream using the exception protocol and the stream state is discarded. If a
|
||||
second `IOException` is thrown while attempting to write the first exception
|
||||
into the stream, the stream is left in an unknown state and
|
||||
`StreamCorruptedException` is thrown from `writeObject`. For other exceptions,
|
||||
the stream is aborted and left in an unknown and unusable state.
|
||||
|
||||
The `writeUnshared` method writes an "unshared" object to the
|
||||
`ObjectOutputStream`. This method is identical to `writeObject`, except that it
|
||||
always writes the given object as a new, unique object in the stream (as
|
||||
opposed to a back-reference pointing to a previously serialized instance).
|
||||
Specifically:
|
||||
|
||||
- An object written via `writeUnshared` is always serialized in the same
|
||||
manner as a newly appearing object (an object that has not been written to
|
||||
the stream yet), regardless of whether or not the object has been written
|
||||
previously.
|
||||
|
||||
- If `writeObject` is used to write an object that has been previously
|
||||
written with `writeUnshared`, the previous `writeUnshared` operation is
|
||||
treated as if it were a write of a separate object. In other words,
|
||||
`ObjectOutputStream` will never generate back-references to object data
|
||||
written by calls to `writeUnshared`.
|
||||
|
||||
While writing an object via `writeUnshared` does not in itself guarantee a
|
||||
unique reference to the object when it is deserialized, it allows a single
|
||||
object to be defined multiple times in a stream, so that multiple calls to the
|
||||
`ObjectInputStream.readUnshared` method (see [Section 3.1, "The
|
||||
ObjectInputStream Class"](input.html#the-objectinputstream-class)) by the
|
||||
receiver will not conflict. Note that the rules described above only apply to
|
||||
the base-level object written with `writeUnshared`, and not to any transitively
|
||||
referenced sub-objects in the object graph to be serialized.
|
||||
|
||||
The `defaultWriteObject` method implements the default serialization mechanism
|
||||
for the current class. This method may be called only from a class's
|
||||
`writeObject` method. The method writes all of the serializable fields of the
|
||||
current class to the stream. If called from outside the `writeObject` method,
|
||||
the `NotActiveException` is thrown.
|
||||
|
||||
The `putFields` method returns a `PutField` object the caller uses to set the
|
||||
values of the serializable fields in the stream. The fields may be set in any
|
||||
order. After all of the fields have been set, `writeFields` must be called to
|
||||
write the field values in the canonical order to the stream. If a field is not
|
||||
set, the default value appropriate for its type will be written to the stream.
|
||||
This method may only be called from within the `writeObject` method of a
|
||||
serializable class. It may not be called more than once or if
|
||||
`defaultWriteObject` has been called. Only after `writeFields` has been called
|
||||
can other data be written to the stream.
|
||||
|
||||
The `reset` method resets the stream state to be the same as if it had just
|
||||
been constructed. `Reset` will discard the state of any objects already written
|
||||
to the stream. The current point in the stream is marked as reset, so the
|
||||
corresponding `ObjectInputStream` will reset at the same point. Objects
|
||||
previously written to the stream will not be remembered as already having been
|
||||
written to the stream. They will be written to the stream again. This is useful
|
||||
when the contents of an object or objects must be sent again. `Reset` may not
|
||||
be called while objects are being serialized. If called inappropriately, an
|
||||
`IOException` is thrown.
|
||||
|
||||
Starting with the Java 2 SDK, Standard Edition, v1.3, the
|
||||
`writeClassDescriptor` method is called when an `ObjectStreamClass` needs to be
|
||||
serialized. `writeClassDescriptor` is responsible for writing a representation
|
||||
of the `ObjectStreamClass` to the serialization stream. Subclasses may override
|
||||
this method to customize the way in which class descriptors are written to the
|
||||
serialization stream. If this method is overridden, then the corresponding
|
||||
`readClassDescriptor` method in `ObjectInputStream` should also be overridden
|
||||
to reconstitute the class descriptor from its custom stream representation. By
|
||||
default, `writeClassDescriptor` writes class descriptors according to the
|
||||
format specified in [Section 6.4, "Grammar for the Stream
|
||||
Format"](protocol.html#grammar-for-the-stream-format). Note that this method
|
||||
will only be called if the `ObjectOutputStream` is not using the old
|
||||
serialization stream format (see [Section 6.3, "Stream Protocol
|
||||
Versions"](protocol.html#stream-protocol-versions)). If the serialization
|
||||
stream is using the old format (`ObjectStreamConstants.PROTOCOL_VERSION_1`),
|
||||
the class descriptor will be written internally in a manner that cannot be
|
||||
overridden or customized.
|
||||
|
||||
The `annotateClass` method is called while a `Class` is being serialized, and
|
||||
after the class descriptor has been written to the stream. Subclasses may
|
||||
extend this method and write other information to the stream about the class.
|
||||
This information must be read by the `resolveClass` method in a corresponding
|
||||
`ObjectInputStream` subclass.
|
||||
|
||||
An `ObjectOutputStream` subclass can implement the `replaceObject` method to
|
||||
monitor or replace objects during serialization. Replacing objects must be
|
||||
enabled explicitly by calling `enableReplaceObject` before calling
|
||||
`writeObject` with the first object to be replaced. Once enabled,
|
||||
`replaceObject` is called for each object just prior to serializing the object
|
||||
for the first time. Note that the `replaceObject` method is not called for
|
||||
objects of the specially handled classes, `Class` and `ObjectStreamClass`. An
|
||||
implementation of a subclass may return a substitute object that will be
|
||||
serialized instead of the original. The substitute object must be serializable.
|
||||
All references in the stream to the original object will be replaced by the
|
||||
substitute object.
|
||||
|
||||
When objects are being replaced, the subclass must ensure that the substituted
|
||||
object is compatible with every field where the reference will be stored, or
|
||||
that a complementary substitution will be made during deserialization. Objects,
|
||||
whose type is not a subclass of the type of the field or array element, will
|
||||
later abort the deserialization by raising a `ClassCastException` and the
|
||||
reference will not be stored.
|
||||
|
||||
The `enableReplaceObject` method can be called by trusted subclasses of
|
||||
`ObjectOutputStream` to enable the substitution of one object for another
|
||||
during serialization. Replacing objects is disabled until `enableReplaceObject`
|
||||
is called with a `true` value. It may thereafter be disabled by setting it to
|
||||
`false`. The previous setting is returned. The `enableReplaceObject` method
|
||||
checks that the stream requesting the replacement can be trusted. To ensure
|
||||
that the private state of objects is not unintentionally exposed, only trusted
|
||||
stream subclasses may use `replaceObject`. Trusted classes are those classes
|
||||
that belong to a security protection domain with permission to enable
|
||||
Serializable substitution.
|
||||
|
||||
If the subclass of `ObjectOutputStream` is not considered part of the system
|
||||
domain, `SerializablePermission "enableSubstitution"` must be added to the
|
||||
security policy file. `AccessControlException` is thrown if the protection
|
||||
domain of the subclass of `ObjectInputStream` does not have permission to
|
||||
`"enableSubstitution"` by calling `enableReplaceObject`. See the document Java
|
||||
Security Architecture (JDK1.2) for additional information about the security
|
||||
model.
|
||||
|
||||
The `writeStreamHeader` method writes the magic number and version to the
|
||||
stream. This information must be read by the `readStreamHeader` method of
|
||||
`ObjectInputStream`. Subclasses may need to implement this method to identify
|
||||
the stream's unique format.
|
||||
|
||||
The `flush` method is used to empty any buffers being held by the stream and to
|
||||
forward the flush to the underlying stream. The `drain` method may be used by
|
||||
subclassers to empty only the `ObjectOutputStream`'s buffers without forcing
|
||||
the underlying stream to be flushed.
|
||||
|
||||
All of the write methods for primitive types encode their values using a
|
||||
`DataOutputStream` to put them in the standard stream format. The bytes are
|
||||
buffered into block data records so they can be distinguished from the encoding
|
||||
of objects. This buffering allows primitive data to be skipped if necessary for
|
||||
class versioning. It also allows the stream to be parsed without invoking
|
||||
class-specific methods.
|
||||
|
||||
To override the implementation of serialization, the subclass of
|
||||
`ObjectOutputStream` should call the protected no-arg `ObjectOutputStream`,
|
||||
constructor. There is a security check within the no-arg constructor for
|
||||
`SerializablePermission "enableSubclassImplementation"` to ensure that only
|
||||
trusted classes are allowed to override the default implementation. This
|
||||
constructor does not allocate any private data for `ObjectOutputStream` and
|
||||
sets a flag that indicates that the final `writeObject` method should invoke
|
||||
the `writeObjectOverride` method and return. All other `ObjectOutputStream`
|
||||
methods are not final and can be directly overridden by the subclass.
|
||||
|
||||
## 2.2 The ObjectOutputStream.PutField Class
|
||||
|
||||
Class `PutField` provides the API for setting values of the serializable fields
|
||||
for a class when the class does not use default serialization. Each method puts
|
||||
the specified named value into the stream. An `IllegalArgumentException` is
|
||||
thrown if `name` does not match the name of a serializable field for the class
|
||||
whose fields are being written, or if the type of the named field does not
|
||||
match the second parameter type of the specific `put` method invoked.
|
||||
|
||||
## 2.3 The writeObject Method
|
||||
|
||||
For serializable objects, the `writeObject` method allows a class to control
|
||||
the serialization of its own fields. Here is its signature:
|
||||
|
||||
```
|
||||
private void writeObject(ObjectOutputStream stream)
|
||||
throws IOException;
|
||||
```
|
||||
|
||||
Each subclass of a serializable object may define its own `writeObject` method.
|
||||
If a class does not implement the method, the default serialization provided by
|
||||
`defaultWriteObject` will be used. When implemented, the class is only
|
||||
responsible for writing its own fields, not those of its supertypes or
|
||||
subtypes.
|
||||
|
||||
The class's `writeObject` method, if implemented, is responsible for saving the
|
||||
state of the class. Either `ObjectOutputStream`'s `defaultWriteObject` or
|
||||
`writeFields` method must be called once (and only once) before writing any
|
||||
optional data that will be needed by the corresponding `readObject` method to
|
||||
restore the state of the object; even if no optional data is written,
|
||||
`defaultWriteObject` or `writeFields` must still be invoked once. If
|
||||
`defaultWriteObject` or `writeFields` is not invoked once prior to the writing
|
||||
of optional data (if any), then the behavior of instance deserialization is
|
||||
undefined in cases where the `ObjectInputStream` cannot resolve the class which
|
||||
defined the `writeObject` method in question.
|
||||
|
||||
The responsibility for the format, structure, and versioning of the optional
|
||||
data lies completely with the class.
|
||||
|
||||
## 2.4 The writeExternal Method
|
||||
|
||||
Objects implementing `java.io.Externalizable` must implement the
|
||||
`writeExternal` method to save the entire state of the object. It must
|
||||
coordinate with its superclasses to save their state. All of the methods of
|
||||
`ObjectOutput` are available to save the object's primitive typed fields and
|
||||
object fields.
|
||||
|
||||
```
|
||||
public void writeExternal(ObjectOutput stream)
|
||||
throws IOException;
|
||||
```
|
||||
|
||||
A new default format for writing Externalizable data has been introduced in JDK
|
||||
1.2. The new format specifies that primitive data will be written in block data
|
||||
mode by `writeExternal` methods. Additionally, a tag denoting the end of the
|
||||
External object is appended to the stream after the `writeExternal` method
|
||||
returns. The benefits of this format change are discussed in [Section 3.6, "The
|
||||
readExternal Method"](input.html#the-readexternal-method). Compatibility issues
|
||||
caused by this change are discussed in [Section 2.6, "The useProtocolVersion
|
||||
Method"](#the-useprotocolversion-method).
|
||||
|
||||
## 2.5 The writeReplace Method
|
||||
|
||||
For Serializable and Externalizable classes, the `writeReplace` method allows a
|
||||
class of an object to nominate its own replacement in the stream before the
|
||||
object is written. By implementing the `writeReplace` method, a class can
|
||||
directly control the types and instances of its own instances being serialized.
|
||||
|
||||
The method is defined as follows:
|
||||
|
||||
```
|
||||
ANY-ACCESS-MODIFIER Object writeReplace()
|
||||
throws ObjectStreamException;
|
||||
```
|
||||
|
||||
The `writeReplace` method is called when `ObjectOutputStream` is preparing to
|
||||
write the object to the stream. The `ObjectOutputStream` checks whether the
|
||||
class defines the `writeReplace` method. If the method is defined, the
|
||||
`writeReplace` method is called to allow the object to designate its
|
||||
replacement in the stream. The object returned should be either of the same
|
||||
type as the object passed in or an object that when read and resolved will
|
||||
result in an object of a type that is compatible with all references to the
|
||||
object. If it is not, a `ClassCastException` will occur when the type mismatch
|
||||
is discovered.
|
||||
|
||||
## 2.6 The useProtocolVersion Method
|
||||
|
||||
Due to a stream protocol change that was not backwards compatible, a mechanism
|
||||
has been added to enable the current Virtual Machine to write a serialization
|
||||
stream that is readable by a previous release. Of course, the problems that are
|
||||
corrected by the new stream format will exist when using the backwards
|
||||
compatible protocol.
|
||||
|
||||
Stream protocol versions are discussed in [Section 6.3, "Stream Protocol
|
||||
Versions"](protocol.html#stream-protocol-versions).
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
*[Copyright](../../../legal/SMICopyright.html) © 2005, 2017, Oracle
|
||||
and/or its affiliates. All rights reserved.*
|
||||
@ -1,504 +0,0 @@
|
||||
---
|
||||
# Copyright (c) 2005, 2017, 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.
|
||||
|
||||
include-before: '[CONTENTS](index.html) | [PREV](version.html) | [NEXT](security.html)'
|
||||
include-after: '[CONTENTS](index.html) | [PREV](version.html) | [NEXT](security.html)'
|
||||
|
||||
title: 'Java Object Serialization Specification: 6 - Object Serialization Stream Protocol'
|
||||
---
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Stream Elements](#stream-elements)
|
||||
- [Stream Protocol Versions](#stream-protocol-versions)
|
||||
- [Grammar for the Stream Format](#grammar-for-the-stream-format)
|
||||
- [Example](#example)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
## 6.1 Overview
|
||||
|
||||
The stream format satisfies the following design goals:
|
||||
|
||||
- Is compact and is structured for efficient reading.
|
||||
- Allows skipping through the stream using only the knowledge of the
|
||||
structure and format of the stream. Does not require invoking any per class
|
||||
code.
|
||||
- Requires only stream access to the data.
|
||||
|
||||
## 6.2 Stream Elements
|
||||
|
||||
A basic structure is needed to represent objects in a stream. Each attribute of
|
||||
the object needs to be represented: its classes, its fields, and data written
|
||||
and later read by class-specific methods. The representation of objects in the
|
||||
stream can be described with a grammar. There are special representations for
|
||||
null objects, new objects, classes, arrays, strings, and back references to any
|
||||
object already in the stream. Each object written to the stream is assigned a
|
||||
handle that is used to refer back to the object. Handles are assigned
|
||||
sequentially starting from 0x7E0000. The handles restart at 0x7E0000 when the
|
||||
stream is reset.
|
||||
|
||||
A class object is represented by the following:
|
||||
|
||||
- Its `ObjectStreamClass` object.
|
||||
|
||||
An `ObjectStreamClass` object for a Class that is not a dynamic proxy class is
|
||||
represented by the following:
|
||||
|
||||
- The Stream Unique Identifier (SUID) of compatible classes.
|
||||
|
||||
- A set of flags indicating various properties of the class, such as whether
|
||||
the class defines a `writeObject` method, and whether the class is
|
||||
serializable, externalizable, or an enum type
|
||||
|
||||
- The number of serializable fields
|
||||
|
||||
- The array of fields of the class that are serialized by the default
|
||||
mechanismFor arrays and object fields, the type of the field is included as
|
||||
a string which must be in "field descriptor" format (e.g.,
|
||||
"`Ljava/lang/Object;`") as specified in The Java Virtual Machine
|
||||
Specification.
|
||||
|
||||
- Optional block-data records or objects written by the `annotateClass`
|
||||
method
|
||||
|
||||
- The `ObjectStreamClass` of its supertype (null if the superclass is not
|
||||
serializable)
|
||||
|
||||
An `ObjectStreamClass` object for a dynamic proxy class is represented by the
|
||||
following:
|
||||
|
||||
- The number of interfaces that the dynamic proxy class implements
|
||||
|
||||
- The names of all of the interfaces implemented by the dynamic proxy class,
|
||||
listed in the order that they are returned by invoking the `getInterfaces`
|
||||
method on the Class object.
|
||||
|
||||
- Optional block-data records or objects written by the `annotateProxyClass`
|
||||
method.
|
||||
|
||||
- The ObjectStreamClass of its supertype, `java.lang.reflect.Proxy`.
|
||||
|
||||
The representation of `String` objects consists of length information followed
|
||||
by the contents of the string encoded in modified UTF-8. The modified UTF-8
|
||||
encoding is the same as used in the Java Virtual Machine and in the
|
||||
`java.io.DataInput` and `DataOutput` interfaces; it differs from standard UTF-8
|
||||
in the representation of supplementary characters and of the null character.
|
||||
The form of the length information depends on the length of the string in
|
||||
modified UTF-8 encoding. If the modified UTF-8 encoding of the given `String`
|
||||
is less than 65536 bytes in length, the length is written as 2 bytes
|
||||
representing an unsigned 16-bit integer. Starting with the Java 2 platform,
|
||||
Standard Edition, v1.3, if the length of the string in modified UTF-8 encoding
|
||||
is 65536 bytes or more, the length is written in 8 bytes representing a signed
|
||||
64-bit integer. The typecode preceding the `String` in the serialization stream
|
||||
indicates which format was used to write the `String`.
|
||||
|
||||
Arrays are represented by the following:
|
||||
|
||||
- Their `ObjectStreamClass` object.
|
||||
|
||||
- The number of elements.
|
||||
|
||||
- The sequence of values. The type of the values is implicit in the type of
|
||||
the array. for example the values of a byte array are of type byte.
|
||||
|
||||
Enum constants are represented by the following:
|
||||
|
||||
- The `ObjectStreamClass` object of the constant's base enum type.
|
||||
|
||||
- The constant's name string.
|
||||
|
||||
New objects in the stream are represented by the following:
|
||||
|
||||
- The most derived class of the object.
|
||||
|
||||
- Data for each serializable class of the object, with the highest superclass
|
||||
first. For each class the stream contains the following:
|
||||
|
||||
- The serializable fields.See [Section 1.5, "Defining Serializable Fields
|
||||
for a
|
||||
Class"](serial-arch.html#defining-serializable-fields-for-a-class).
|
||||
|
||||
- If the class has `writeObject`/`readObject` methods, there may be
|
||||
optional objects and/or block-data records of primitive types written
|
||||
by the `writeObject` method followed by an `endBlockData` code.
|
||||
|
||||
All primitive data written by classes is buffered and wrapped in block-data
|
||||
records, regardless if the data is written to the stream within a `writeObject`
|
||||
method or written directly to the stream from outside a `writeObject` method.
|
||||
This data can only be read by the corresponding `readObject` methods or be read
|
||||
directly from the stream. Objects written by the `writeObject` method terminate
|
||||
any previous block-data record and are written either as regular objects or
|
||||
null or back references, as appropriate. The block-data records allow error
|
||||
recovery to discard any optional data. When called from within a class, the
|
||||
stream can discard any data or objects until the `endBlockData`.
|
||||
|
||||
## 6.3 Stream Protocol Versions
|
||||
|
||||
It was necessary to make a change to the serialization stream format in JDK 1.2
|
||||
that is not backwards compatible to all minor releases of JDK 1.1. To provide
|
||||
for cases where backwards compatibility is required, a capability has been
|
||||
added to indicate what `PROTOCOL_VERSION` to use when writing a serialization
|
||||
stream. The method `ObjectOutputStream.useProtocolVersion` takes as a parameter
|
||||
the protocol version to use to write the serialization stream.
|
||||
|
||||
The Stream Protocol Versions are as follows:
|
||||
|
||||
- `ObjectStreamConstants.PROTOCOL_VERSION_1`: Indicates the initial stream
|
||||
format.
|
||||
|
||||
- `ObjectStreamConstants.PROTOCOL_VERSION_2`: Indicates the new external data
|
||||
format. Primitive data is written in block data mode and is terminated with
|
||||
`TC_ENDBLOCKDATA`.
|
||||
|
||||
Block data boundaries have been standardized. Primitive data written in
|
||||
block data mode is normalized to not exceed 1024 byte chunks. The benefit
|
||||
of this change was to tighten the specification of serialized data format
|
||||
within the stream. This change is fully backward and forward compatible.
|
||||
|
||||
JDK 1.2 defaults to writing `PROTOCOL_VERSION_2`.
|
||||
|
||||
JDK 1.1 defaults to writing `PROTOCOL_VERSION_1`.
|
||||
|
||||
JDK 1.1.7 and greater can read both versions.
|
||||
|
||||
Releases prior to JDK 1.1.7 can only read `PROTOCOL_VERSION_1`.
|
||||
|
||||
## 6.4 Grammar for the Stream Format
|
||||
|
||||
The table below contains the grammar for the stream format. Nonterminal symbols
|
||||
are shown in italics. Terminal symbols in a *fixed width font*. Definitions of
|
||||
nonterminals are followed by a ":". The definition is followed by one or more
|
||||
alternatives, each on a separate line. The following table describes the
|
||||
notation:
|
||||
|
||||
------------- --------------------------------------------------------------
|
||||
**Notation** **Meaning**
|
||||
------------- --------------------------------------------------------------
|
||||
(*datatype*) This token has the data type specified, such as byte.
|
||||
|
||||
*token*\[n\] A predefined number of occurrences of the token, that is an
|
||||
array.
|
||||
|
||||
*x0001* A literal value expressed in hexadecimal. The number of hex
|
||||
digits reflects the size of the value.
|
||||
|
||||
<*xxx*> A value read from the stream used to indicate the length of an
|
||||
array.
|
||||
------------- --------------------------------------------------------------
|
||||
|
||||
Note that the symbol (utf) is used to designate a string written using 2-byte
|
||||
length information, and (long-utf) is used to designate a string written using
|
||||
8-byte length information. For details, refer to [Section 6.2, "Stream
|
||||
Elements"](#stream-elements).
|
||||
|
||||
### 6.4.1 Rules of the Grammar
|
||||
|
||||
A Serialized stream is represented by any stream satisfying the *stream* rule.
|
||||
|
||||
```
|
||||
stream:
|
||||
magic version contents
|
||||
|
||||
contents:
|
||||
content
|
||||
contents content
|
||||
|
||||
content:
|
||||
object
|
||||
blockdata
|
||||
|
||||
object:
|
||||
newObject
|
||||
newClass
|
||||
newArray
|
||||
newString
|
||||
newEnum
|
||||
newClassDesc
|
||||
prevObject
|
||||
nullReference
|
||||
exception
|
||||
TC_RESET
|
||||
|
||||
newClass:
|
||||
TC_CLASS classDesc newHandle
|
||||
|
||||
classDesc:
|
||||
newClassDesc
|
||||
nullReference
|
||||
(ClassDesc)prevObject // an object required to be of type ClassDesc
|
||||
|
||||
superClassDesc:
|
||||
classDesc
|
||||
|
||||
newClassDesc:
|
||||
TC_CLASSDESC className serialVersionUID newHandle classDescInfo
|
||||
TC_PROXYCLASSDESC newHandle proxyClassDescInfo
|
||||
|
||||
classDescInfo:
|
||||
classDescFlags fields classAnnotation superClassDesc
|
||||
|
||||
className:
|
||||
(utf)
|
||||
|
||||
serialVersionUID:
|
||||
(long)
|
||||
|
||||
classDescFlags:
|
||||
(byte) // Defined in Terminal Symbols and Constants
|
||||
|
||||
proxyClassDescInfo:
|
||||
(int)<count> proxyInterfaceName[count] classAnnotation
|
||||
superClassDesc
|
||||
|
||||
proxyInterfaceName:
|
||||
(utf)
|
||||
|
||||
fields:
|
||||
(short)<count> fieldDesc[count]
|
||||
|
||||
fieldDesc:
|
||||
primitiveDesc
|
||||
objectDesc
|
||||
|
||||
primitiveDesc:
|
||||
prim_typecode fieldName
|
||||
|
||||
objectDesc:
|
||||
obj_typecode fieldName className1
|
||||
|
||||
fieldName:
|
||||
(utf)
|
||||
|
||||
className1:
|
||||
(String)object // String containing the field's type,
|
||||
// in field descriptor format
|
||||
|
||||
classAnnotation:
|
||||
endBlockData
|
||||
contents endBlockData // contents written by annotateClass
|
||||
|
||||
prim_typecode:
|
||||
'B' // byte
|
||||
'C' // char
|
||||
'D' // double
|
||||
'F' // float
|
||||
'I' // integer
|
||||
'J' // long
|
||||
'S' // short
|
||||
'Z' // boolean
|
||||
|
||||
obj_typecode:
|
||||
'[' // array
|
||||
'L' // object
|
||||
|
||||
newArray:
|
||||
TC_ARRAY classDesc newHandle (int)<size> values[size]
|
||||
|
||||
newObject:
|
||||
TC_OBJECT classDesc newHandle classdata[] // data for each class
|
||||
|
||||
classdata:
|
||||
nowrclass // SC_SERIALIZABLE & classDescFlag &&
|
||||
// !(SC_WRITE_METHOD & classDescFlags)
|
||||
wrclass objectAnnotation // SC_SERIALIZABLE & classDescFlag &&
|
||||
// SC_WRITE_METHOD & classDescFlags
|
||||
externalContents // SC_EXTERNALIZABLE & classDescFlag &&
|
||||
// !(SC_BLOCKDATA & classDescFlags
|
||||
objectAnnotation // SC_EXTERNALIZABLE & classDescFlag&&
|
||||
// SC_BLOCKDATA & classDescFlags
|
||||
|
||||
nowrclass:
|
||||
values // fields in order of class descriptor
|
||||
|
||||
wrclass:
|
||||
nowrclass
|
||||
|
||||
objectAnnotation:
|
||||
endBlockData
|
||||
contents endBlockData // contents written by writeObject
|
||||
// or writeExternal PROTOCOL_VERSION_2.
|
||||
|
||||
blockdata:
|
||||
blockdatashort
|
||||
blockdatalong
|
||||
|
||||
blockdatashort:
|
||||
TC_BLOCKDATA (unsigned byte)<size> (byte)[size]
|
||||
|
||||
blockdatalong:
|
||||
TC_BLOCKDATALONG (int)<size> (byte)[size]
|
||||
|
||||
endBlockData:
|
||||
TC_ENDBLOCKDATA
|
||||
|
||||
externalContent: // Only parseable by readExternal
|
||||
(bytes) // primitive data
|
||||
object
|
||||
|
||||
externalContents: // externalContent written by
|
||||
externalContent // writeExternal in PROTOCOL_VERSION_1.
|
||||
externalContents externalContent
|
||||
|
||||
newString:
|
||||
TC_STRING newHandle (utf)
|
||||
TC_LONGSTRING newHandle (long-utf)
|
||||
|
||||
newEnum:
|
||||
TC_ENUM classDesc newHandle enumConstantName
|
||||
|
||||
enumConstantName:
|
||||
(String)object
|
||||
|
||||
prevObject:
|
||||
TC_REFERENCE (int)handle
|
||||
|
||||
nullReference:
|
||||
TC_NULL
|
||||
|
||||
exception:
|
||||
TC_EXCEPTION reset (Throwable)object reset
|
||||
|
||||
magic:
|
||||
STREAM_MAGIC
|
||||
|
||||
version:
|
||||
STREAM_VERSION
|
||||
|
||||
values: // The size and types are described by the
|
||||
// classDesc for the current object
|
||||
|
||||
newHandle: // The next number in sequence is assigned
|
||||
// to the object being serialized or deserialized
|
||||
|
||||
reset: // The set of known objects is discarded
|
||||
// so the objects of the exception do not
|
||||
// overlap with the previously sent objects
|
||||
// or with objects that may be sent after
|
||||
// the exception
|
||||
```
|
||||
|
||||
### 6.4.2 Terminal Symbols and Constants
|
||||
|
||||
The following symbols in `java.io.ObjectStreamConstants` define the terminal
|
||||
and constant values expected in a stream.
|
||||
|
||||
```
|
||||
final static short STREAM_MAGIC = (short)0xaced;
|
||||
final static short STREAM_VERSION = 5;
|
||||
final static byte TC_NULL = (byte)0x70;
|
||||
final static byte TC_REFERENCE = (byte)0x71;
|
||||
final static byte TC_CLASSDESC = (byte)0x72;
|
||||
final static byte TC_OBJECT = (byte)0x73;
|
||||
final static byte TC_STRING = (byte)0x74;
|
||||
final static byte TC_ARRAY = (byte)0x75;
|
||||
final static byte TC_CLASS = (byte)0x76;
|
||||
final static byte TC_BLOCKDATA = (byte)0x77;
|
||||
final static byte TC_ENDBLOCKDATA = (byte)0x78;
|
||||
final static byte TC_RESET = (byte)0x79;
|
||||
final static byte TC_BLOCKDATALONG = (byte)0x7A;
|
||||
final static byte TC_EXCEPTION = (byte)0x7B;
|
||||
final static byte TC_LONGSTRING = (byte) 0x7C;
|
||||
final static byte TC_PROXYCLASSDESC = (byte) 0x7D;
|
||||
final static byte TC_ENUM = (byte) 0x7E;
|
||||
final static int baseWireHandle = 0x7E0000;
|
||||
```
|
||||
|
||||
The flag byte *classDescFlags* may include values of
|
||||
|
||||
```
|
||||
final static byte SC_WRITE_METHOD = 0x01; //if SC_SERIALIZABLE
|
||||
final static byte SC_BLOCK_DATA = 0x08; //if SC_EXTERNALIZABLE
|
||||
final static byte SC_SERIALIZABLE = 0x02;
|
||||
final static byte SC_EXTERNALIZABLE = 0x04;
|
||||
final static byte SC_ENUM = 0x10;
|
||||
```
|
||||
|
||||
The flag `SC_WRITE_METHOD` is set if the Serializable class writing the stream
|
||||
had a `writeObject` method that may have written additional data to the stream.
|
||||
In this case a `TC_ENDBLOCKDATA` marker is always expected to terminate the
|
||||
data for that class.
|
||||
|
||||
The flag `SC_BLOCKDATA` is set if the `Externalizable` class is written into
|
||||
the stream using `STREAM_PROTOCOL_2`. By default, this is the protocol used to
|
||||
write `Externalizable` objects into the stream in JDK 1.2. JDK 1.1 writes
|
||||
`STREAM_PROTOCOL_1`.
|
||||
|
||||
The flag `SC_SERIALIZABLE` is set if the class that wrote the stream extended
|
||||
`java.io.Serializable` but not `java.io.Externalizable`, the class reading the
|
||||
stream must also extend `java.io.Serializable` and the default serialization
|
||||
mechanism is to be used.
|
||||
|
||||
The flag `SC_EXTERNALIZABLE` is set if the class that wrote the stream extended
|
||||
`java.io.Externalizable`, the class reading the data must also extend
|
||||
`Externalizable` and the data will be read using its `writeExternal` and
|
||||
`readExternal` methods.
|
||||
|
||||
The flag `SC_ENUM` is set if the class that wrote the stream was an enum type.
|
||||
The receiver's corresponding class must also be an enum type. Data for
|
||||
constants of the enum type will be written and read as described in [Section
|
||||
1.12, "Serialization of Enum
|
||||
Constants"](serial-arch.html#serialization-of-enum-constants).
|
||||
|
||||
#### Example
|
||||
|
||||
Consider the case of an original class and two instances in a linked list:
|
||||
|
||||
```
|
||||
class List implements java.io.Serializable {
|
||||
int value;
|
||||
List next;
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
List list1 = new List();
|
||||
List list2 = new List();
|
||||
list1.value = 17;
|
||||
list1.next = list2;
|
||||
list2.value = 19;
|
||||
list2.next = null;
|
||||
|
||||
ByteArrayOutputStream o = new ByteArrayOutputStream();
|
||||
ObjectOutputStream out = new ObjectOutputStream(o);
|
||||
out.writeObject(list1);
|
||||
out.writeObject(list2);
|
||||
out.flush();
|
||||
...
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The resulting stream contains:
|
||||
|
||||
```
|
||||
00: ac ed 00 05 73 72 00 04 4c 69 73 74 69 c8 8a 15 >....sr..Listi...<
|
||||
10: 40 16 ae 68 02 00 02 49 00 05 76 61 6c 75 65 4c >Z......I..valueL<
|
||||
20: 00 04 6e 65 78 74 74 00 06 4c 4c 69 73 74 3b 78 >..nextt..LList;x<
|
||||
30: 70 00 00 00 11 73 71 00 7e 00 00 00 00 00 13 70 >p....sq.~......p<
|
||||
40: 71 00 7e 00 03 >q.~..<
|
||||
```
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
*[Copyright](../../../legal/SMICopyright.html) © 2005, 2017, Oracle
|
||||
and/or its affiliates. All rights reserved.*
|
||||
@ -1,38 +0,0 @@
|
||||
---
|
||||
# Copyright (c) 2005, 2017, 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.
|
||||
|
||||
include-before: '[CONTENTS](index.html) | [PREV](protocol.html) | [NEXT](exceptions.html)'
|
||||
include-after: '[CONTENTS](index.html) | [PREV](protocol.html) | [NEXT](exceptions.html)'
|
||||
|
||||
title: 'Java Object Serialization Specification: A - Security in Object Serialization'
|
||||
---
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Refer to the [Secure Coding Guidelines for the Java Programming
|
||||
Language](http://www.oracle.com/pls/topic/lookup?ctx=javase9&id=secure_coding_guidelines_javase)
|
||||
for information about security in object serialization.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
*[Copyright](../../../legal/SMICopyright.html) © 2005, 2017, Oracle
|
||||
and/or its affiliates. All rights reserved.*
|
||||
@ -1,575 +0,0 @@
|
||||
---
|
||||
# Copyright (c) 2005, 2017, 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.
|
||||
|
||||
include-before: '[CONTENTS](index.html) | [PREV](index.html) | [NEXT](output.html)'
|
||||
include-after: '[CONTENTS](index.html) | [PREV](index.html) | [NEXT](output.html)'
|
||||
|
||||
title: 'Java Object Serialization Specification: 1 - System Architecture'
|
||||
---
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Writing to an Object Stream](#writing-to-an-object-stream)
|
||||
- [Reading from an Object Stream](#reading-from-an-object-stream)
|
||||
- [Object Streams as Containers](#object-streams-as-containers)
|
||||
- [Defining Serializable Fields for a
|
||||
Class](#defining-serializable-fields-for-a-class)
|
||||
- [Documenting Serializable Fields and Data for a
|
||||
Class](#documenting-serializable-fields-and-data-for-a-class)
|
||||
- [Accessing Serializable Fields of a
|
||||
Class](#accessing-serializable-fields-of-a-class)
|
||||
- [The ObjectOutput Interface](#the-objectoutput-interface)
|
||||
- [The ObjectInput Interface](#the-objectinput-interface)
|
||||
- [The Serializable Interface](#the-serializable-interface)
|
||||
- [The Externalizable Interface](#the-externalizable-interface)
|
||||
- [Serialization of Enum Constants](#serialization-of-enum-constants)
|
||||
- [Protecting Sensitive Information](#protecting-sensitive-information)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
## 1.1 Overview
|
||||
|
||||
The ability to store and retrieve Java^TM^ objects is essential to building all
|
||||
but the most transient applications. The key to storing and retrieving objects
|
||||
in a serialized form is representing the state of objects sufficient to
|
||||
reconstruct the object(s). Objects to be saved in the stream may support either
|
||||
the `Serializable` or the `Externalizable` interface. For Java^TM^ objects, the
|
||||
serialized form must be able to identify and verify the Java^TM^ class from
|
||||
which the contents of the object were saved and to restore the contents to a
|
||||
new instance. For serializable objects, the stream includes sufficient
|
||||
information to restore the fields in the stream to a compatible version of the
|
||||
class. For Externalizable objects, the class is solely responsible for the
|
||||
external format of its contents.
|
||||
|
||||
Objects to be stored and retrieved frequently refer to other objects. Those
|
||||
other objects must be stored and retrieved at the same time to maintain the
|
||||
relationships between the objects. When an object is stored, all of the objects
|
||||
that are reachable from that object are stored as well.
|
||||
|
||||
The goals for serializing Java^TM^ objects are to:
|
||||
|
||||
- Have a simple yet extensible mechanism.
|
||||
- Maintain the Java^TM^ object type and safety properties in the serialized
|
||||
form.
|
||||
- Be extensible to support marshaling and unmarshaling as needed for remote
|
||||
objects.
|
||||
- Be extensible to support simple persistence of Java^TM^ objects.
|
||||
- Require per class implementation only for customization.
|
||||
- Allow the object to define its external format.
|
||||
|
||||
## 1.2 Writing to an Object Stream
|
||||
|
||||
Writing objects and primitives to a stream is a straightforward process. For
|
||||
example:
|
||||
|
||||
```
|
||||
// Serialize today's date to a file.
|
||||
FileOutputStream f = new FileOutputStream("tmp");
|
||||
ObjectOutput s = new ObjectOutputStream(f);
|
||||
s.writeObject("Today");
|
||||
s.writeObject(new Date());
|
||||
s.flush();
|
||||
```
|
||||
|
||||
First an `OutputStream`, in this case a `FileOutputStream`, is needed to
|
||||
receive the bytes. Then an `ObjectOutputStream` is created that writes to the
|
||||
`FileOutputStream`. Next, the string "Today" and a Date object are written to
|
||||
the stream. More generally, objects are written with the `writeObject` method
|
||||
and primitives are written to the stream with the methods of `DataOutput`.
|
||||
|
||||
The `writeObject` method (see [Section 2.3, "The writeObject
|
||||
Method"](output.html#the-writeobject-method)) serializes the specified object
|
||||
and traverses its references to other objects in the object graph recursively
|
||||
to create a complete serialized representation of the graph. Within a stream,
|
||||
the first reference to any object results in the object being serialized or
|
||||
externalized and the assignment of a handle for that object. Subsequent
|
||||
references to that object are encoded as the handle. Using object handles
|
||||
preserves sharing and circular references that occur naturally in object
|
||||
graphs. Subsequent references to an object use only the handle allowing a very
|
||||
compact representation.
|
||||
|
||||
Special handling is required for arrays, enum constants, and objects of type
|
||||
`Class`, `ObjectStreamClass`, and `String`. Other objects must implement either
|
||||
the `Serializable` or the `Externalizable` interface to be saved in or restored
|
||||
from a stream.
|
||||
|
||||
Primitive data types are written to the stream with the methods in the
|
||||
`DataOutput` interface, such as `writeInt`, `writeFloat`, or `writeUTF`.
|
||||
Individual bytes and arrays of bytes are written with the methods of
|
||||
`OutputStream`. Except for serializable fields, primitive data is written to
|
||||
the stream in block-data records, with each record prefixed by a marker and an
|
||||
indication of the number of bytes in the record.
|
||||
|
||||
`ObjectOutputStream` can be extended to customize the information about classes
|
||||
in the stream or to replace objects to be serialized. Refer to the
|
||||
`annotateClass` and `replaceObject` method descriptions for details.
|
||||
|
||||
## 1.3 Reading from an Object Stream
|
||||
|
||||
Reading an object from a stream, like writing, is straightforward:
|
||||
|
||||
```
|
||||
// Deserialize a string and date from a file.
|
||||
FileInputStream in = new FileInputStream("tmp");
|
||||
ObjectInputStream s = new ObjectInputStream(in);
|
||||
String today = (String)s.readObject();
|
||||
Date date = (Date)s.readObject();
|
||||
```
|
||||
|
||||
First an `InputStream`, in this case a `FileInputStream`, is needed as the
|
||||
source stream. Then an `ObjectInputStream` is created that reads from the
|
||||
`InputStream`. Next, the string "Today" and a Date object are read from the
|
||||
stream. Generally, objects are read with the `readObject` method and primitives
|
||||
are read from the stream with the methods of `DataInput`.
|
||||
|
||||
The `readObject` method deserializes the next object in the stream and
|
||||
traverses its references to other objects recursively to create the complete
|
||||
graph of objects serialized.
|
||||
|
||||
Primitive data types are read from the stream with the methods in the
|
||||
`DataInput` interface, such as `readInt`, `readFloat`, or `readUTF`. Individual
|
||||
bytes and arrays of bytes are read with the methods of `InputStream`. Except
|
||||
for serializable fields, primitive data is read from block-data records.
|
||||
|
||||
`ObjectInputStream` can be extended to utilize customized information in the
|
||||
stream about classes or to replace objects that have been deserialized. Refer
|
||||
to the `resolveClass` and `resolveObject` method descriptions for details.
|
||||
|
||||
## 1.4 Object Streams as Containers
|
||||
|
||||
Object Serialization produces and consumes a stream of bytes that contain one
|
||||
or more primitives and objects. The objects written to the stream, in turn,
|
||||
refer to other objects, which are also represented in the stream. Object
|
||||
Serialization produces just one stream format that encodes and stores the
|
||||
contained objects.
|
||||
|
||||
Each object that acts as a container implements an interface which allows
|
||||
primitives and objects to be stored in or retrieved from it. These interfaces
|
||||
are the `ObjectOutput` and `ObjectInput` interfaces which:
|
||||
|
||||
- Provide a stream to write to and to read from
|
||||
- Handle requests to write primitive types and objects to the stream
|
||||
- Handle requests to read primitive types and objects from the stream
|
||||
|
||||
Each object which is to be stored in a stream must explicitly allow itself to
|
||||
be stored and must implement the protocols needed to save and restore its
|
||||
state. Object Serialization defines two such protocols. The protocols allow the
|
||||
container to ask the object to write and read its state.
|
||||
|
||||
To be stored in an Object Stream, each object must implement either the
|
||||
`Serializable` or the `Externalizable` interface:
|
||||
|
||||
- For a `Serializable` class, Object Serialization can automatically save and
|
||||
restore fields of each class of an object and automatically handle classes
|
||||
that evolve by adding fields or supertypes. A serializable class can
|
||||
declare which of its fields are saved or restored, and write and read
|
||||
optional values and objects.
|
||||
|
||||
- For an `Externalizable` class, Object Serialization delegates to the class
|
||||
complete control over its external format and how the state of the
|
||||
supertype(s) is saved and restored.
|
||||
|
||||
## 1.5 Defining Serializable Fields for a Class
|
||||
|
||||
The serializable fields of a class can be defined two different ways. Default
|
||||
serializable fields of a class are defined to be the non-transient and
|
||||
non-static fields. This default computation can be overridden by declaring a
|
||||
special field in the `Serializable` class, `serialPersistentFields`. This field
|
||||
must be initialized with an array of `ObjectStreamField` objects that list the
|
||||
names and types of the serializable fields. The modifiers for the field are
|
||||
required to be private, static, and final. If the field's value is null or is
|
||||
otherwise not an instance of `ObjectStreamField[]`, or if the field does not
|
||||
have the required modifiers, then the behavior is as if the field were not
|
||||
declared at all.
|
||||
|
||||
For example, the following declaration duplicates the default behavior.
|
||||
|
||||
```
|
||||
class List implements Serializable {
|
||||
List next;
|
||||
|
||||
private static final ObjectStreamField[] serialPersistentFields
|
||||
= {new ObjectStreamField("next", List.class)};
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
By using `serialPersistentFields` to define the Serializable fields for a
|
||||
class, there no longer is a limitation that a serializable field must be a
|
||||
field within the current definition of the `Serializable` class. The
|
||||
`writeObject` and `readObject` methods of the `Serializable` class can map the
|
||||
current implementation of the class to the serializable fields of the class
|
||||
using the interface that is described in [Section 1.7, "Accessing Serializable
|
||||
Fields of a Class"](#accessing-serializable-fields-of-a-class). Therefore, the
|
||||
fields for a `Serializable` class can change in a later release, as long as it
|
||||
maintains the mapping back to its Serializable fields that must remain
|
||||
compatible across release boundaries.
|
||||
|
||||
**Note:** There is, however, a limitation to the use of this mechanism to
|
||||
specify serializable fields for inner classes. Inner classes can only contain
|
||||
final static fields that are initialized to constants or expressions built up
|
||||
from constants. Consequently, it is not possible to set
|
||||
`serialPersistentFields` for an inner class (though it is possible to set it
|
||||
for static member classes). For other restrictions pertaining to serialization
|
||||
of inner class instances, see section [Section 1.10, "The Serializable
|
||||
Interface"](#the-serializable-interface).
|
||||
|
||||
## 1.6 Documenting Serializable Fields and Data for a Class
|
||||
|
||||
It is important to document the serializable state of a class to enable
|
||||
interoperability with alternative implementations of a Serializable class and
|
||||
to document class evolution. Documenting a serializable field gives one a final
|
||||
opportunity to review whether or not the field should be serializable. The
|
||||
serialization javadoc tags, `@serial`, `@serialField`, and `@serialData`,
|
||||
provide a way to document the serialized form for a Serializable class within
|
||||
the source code.
|
||||
|
||||
- The `@serial` tag should be placed in the javadoc comment for a default
|
||||
serializable field. The syntax is as follows: `@serial` *field-description*
|
||||
The optional *field-description* describes the meaning of the field and its
|
||||
acceptable values. The *field-description* can span multiple lines. When a
|
||||
field is added after the initial release, a *@since* tag indicates the
|
||||
version the field was added. The *field-description* for `@serial` provides
|
||||
serialization-specific documentation and is appended to the javadoc comment
|
||||
for the field within the serialized form documentation.
|
||||
|
||||
- The `@serialField` tag is used to document an `ObjectStreamField` component
|
||||
of a `serialPersistentFields` array. One of these tags should be used for
|
||||
each `ObjectStreamField` component. The syntax is as follows:
|
||||
`@serialField` *field-name field-type field-description*
|
||||
|
||||
- The `@serialData` tag describes the sequences and types of data written or
|
||||
read. The tag describes the sequence and type of optional data written by
|
||||
`writeObject` or all data written by the `Externalizable.writeExternal`
|
||||
method. The syntax is as follows: `@serialData` *data-description*
|
||||
|
||||
The javadoc application recognizes the serialization javadoc tags and generates
|
||||
a specification for each Serializable and Externalizable class. See [Section
|
||||
C.1, "Example Alternate Implementation of
|
||||
java.io.File"](examples.html#c.1-example-alternate-implementation-of-java.io.file)
|
||||
for an example that uses these tags.
|
||||
|
||||
When a class is declared Serializable, the serializable state of the object is
|
||||
defined by serializable fields (by name and type) plus optional data. Optional
|
||||
data can only be written explicitly by the `writeObject` method of a
|
||||
`Serializable` class. Optional data can be read by the `Serializable` class'
|
||||
`readObject` method or serialization will skip unread optional data.
|
||||
|
||||
When a class is declared Externalizable, the data that is written to the stream
|
||||
by the class itself defines the serialized state. The class must specify the
|
||||
order, types, and meaning of each datum that is written to the stream. The
|
||||
class must handle its own evolution, so that it can continue to read data
|
||||
written by and write data that can be read by previous versions. The class must
|
||||
coordinate with the superclass when saving and restoring data. The location of
|
||||
the superclasses data in the stream must be specified.
|
||||
|
||||
The designer of a Serializable class must ensure that the information saved for
|
||||
the class is appropriate for persistence and follows the
|
||||
serialization-specified rules for interoperability and evolution. Class
|
||||
evolution is explained in greater detail in [Chapter
|
||||
5](version.html#versioning-of-serializable-objects), "Versioning of
|
||||
Serializable Objects".
|
||||
|
||||
## 1.7 Accessing Serializable Fields of a Class
|
||||
|
||||
Serialization provides two mechanisms for accessing the serializable fields in
|
||||
a stream:
|
||||
|
||||
- The default mechanism requires no customization
|
||||
- The Serializable Fields API allows a class to explicitly access/set the
|
||||
serializable fields by name and type
|
||||
|
||||
The default mechanism is used automatically when reading or writing objects
|
||||
that implement the `Serializable` interface and do no further customization.
|
||||
The serializable fields are mapped to the corresponding fields of the class and
|
||||
values are either written to the stream from those fields or are read in and
|
||||
assigned respectively. If the class provides `writeObject` and `readObject`
|
||||
methods, the default mechanism can be invoked by calling `defaultWriteObject`
|
||||
and `defaultReadObject`. When the `writeObject` and `readObject` methods are
|
||||
implemented, the class has an opportunity to modify the serializable field
|
||||
values before they are written or after they are read.
|
||||
|
||||
When the default mechanism cannot be used, the serializable class can use the
|
||||
`putFields` method of `ObjectOutputStream` to put the values for the
|
||||
serializable fields into the stream. The `writeFields` method of
|
||||
`ObjectOutputStream` puts the values in the correct order, then writes them to
|
||||
the stream using the existing protocol for serialization. Correspondingly, the
|
||||
`readFields` method of `ObjectInputStream` reads the values from the stream and
|
||||
makes them available to the class by name in any order. See [Section 2.2, "The
|
||||
ObjectOutputStream.PutField
|
||||
Class"](output.html#the-objectoutputstream.putfield-class) and [Section 3.2,
|
||||
"The ObjectInputStream.GetField
|
||||
Class"](input.html#the-objectinputstream.getfield-class) for a detailed
|
||||
description of the Serializable Fields API.
|
||||
|
||||
## 1.8 The ObjectOutput Interface
|
||||
|
||||
The `ObjectOutput` interface provides an abstract, stream-based interface to
|
||||
object storage. It extends the DataOutput interface so those methods can be
|
||||
used for writing primitive data types. Objects that implement this interface
|
||||
can be used to store primitives and objects.
|
||||
|
||||
```
|
||||
package java.io;
|
||||
|
||||
public interface ObjectOutput extends DataOutput
|
||||
{
|
||||
public void writeObject(Object obj) throws IOException;
|
||||
public void write(int b) throws IOException;
|
||||
public void write(byte b[]) throws IOException;
|
||||
public void write(byte b[], int off, int len) throws IOException;
|
||||
public void flush() throws IOException;
|
||||
public void close() throws IOException;
|
||||
}
|
||||
```
|
||||
|
||||
`The` `writeObject` method is used to write an object. The exceptions thrown
|
||||
reflect errors while accessing the object or its fields, or exceptions that
|
||||
occur in writing to storage. If any exception is thrown, the underlying storage
|
||||
may be corrupted. If this occurs, refer to the object that is implementing this
|
||||
interface for more information.
|
||||
|
||||
## 1.9 The ObjectInput Interface
|
||||
|
||||
The `ObjectInput` interface provides an abstract stream based interface to
|
||||
object retrieval. It extends the `DataInput` interface so those methods for
|
||||
reading primitive data types are accessible in this interface.
|
||||
|
||||
```
|
||||
package java.io;
|
||||
|
||||
public interface ObjectInput extends DataInput
|
||||
{
|
||||
public Object readObject()
|
||||
throws ClassNotFoundException, IOException;
|
||||
public int read() throws IOException;
|
||||
public int read(byte b[]) throws IOException;
|
||||
public int read(byte b[], int off, int len) throws IOException;
|
||||
public long skip(long n) throws IOException;
|
||||
public int available() throws IOException;
|
||||
public void close() throws IOException;
|
||||
}
|
||||
```
|
||||
|
||||
The `readObject` method is used to read and return an object. The exceptions
|
||||
thrown reflect errors while accessing the objects or its fields or exceptions
|
||||
that occur in reading from the storage. If any exception is thrown, the
|
||||
underlying storage may be corrupted. If this occurs, refer to the object
|
||||
implementing this interface for additional information.
|
||||
|
||||
## 1.10 The Serializable Interface
|
||||
|
||||
Object Serialization produces a stream with information about the Java^TM^
|
||||
classes for the objects which are being saved. For serializable objects,
|
||||
sufficient information is kept to restore those objects even if a different
|
||||
(but compatible) version of the implementation of the class is present. The
|
||||
`Serializable` interface is defined to identify classes which implement the
|
||||
serializable protocol:
|
||||
|
||||
```
|
||||
package java.io;
|
||||
|
||||
public interface Serializable {};
|
||||
```
|
||||
|
||||
A Serializable class must do the following:
|
||||
|
||||
- Implement the `java.io.Serializable` interface
|
||||
|
||||
- Identify the fields that should be serializable
|
||||
|
||||
(Use the `serialPersistentFields` member to explicitly declare them
|
||||
serializable or use the transient keyword to denote nonserializable
|
||||
fields.)
|
||||
|
||||
- Have access to the no-arg constructor of its first nonserializable
|
||||
superclass
|
||||
|
||||
The class can optionally define the following methods:
|
||||
|
||||
- A `writeObject` method to control what information is saved or to append
|
||||
additional information to the stream
|
||||
|
||||
- A `readObject` method either to read the information written by the
|
||||
corresponding `writeObject` method or to update the state of the object
|
||||
after it has been restored
|
||||
|
||||
- A `writeReplace` method to allow a class to nominate a replacement object
|
||||
to be written to the stream
|
||||
|
||||
(See [Section 2.5, "The writeReplace
|
||||
Method"](output.html#the-writereplace-method) for additional information.)
|
||||
|
||||
- A `readResolve` method to allow a class to designate a replacement object
|
||||
for the object just read from the stream
|
||||
|
||||
(See [Section 3.7, "The readResolve
|
||||
Method](input.html#the-readresolve-method) for additional information.)
|
||||
|
||||
`ObjectOutputStream` and `ObjectInputStream` allow the serializable classes on
|
||||
which they operate to evolve (allow changes to the classes that are compatible
|
||||
with the earlier versions of the classes). See [Section 5.5, "Compatible Java
|
||||
Type Evolution"](version.html#compatible-java-type-evolution) for information
|
||||
about the mechanism which is used to allow compatible changes.
|
||||
|
||||
**Note:** Serialization of inner classes (i.e., nested classes that are not
|
||||
static member classes), including local and anonymous classes, is strongly
|
||||
discouraged for several reasons. Because inner classes declared in non-static
|
||||
contexts contain implicit non-transient references to enclosing class
|
||||
instances, serializing such an inner class instance will result in
|
||||
serialization of its associated outer class instance as well. Synthetic fields
|
||||
generated by `javac` (or other Java^TM^ compilers) to implement inner classes
|
||||
are implementation dependent and may vary between compilers; differences in
|
||||
such fields can disrupt compatibility as well as result in conflicting default
|
||||
`serialVersionUID` values. The names assigned to local and anonymous inner
|
||||
classes are also implementation dependent and may differ between compilers.
|
||||
Since inner classes cannot declare static members other than compile-time
|
||||
constant fields, they cannot use the `serialPersistentFields` mechanism to
|
||||
designate serializable fields. Finally, because inner classes associated with
|
||||
outer instances do not have zero-argument constructors (constructors of such
|
||||
inner classes implicitly accept the enclosing instance as a prepended
|
||||
parameter), they cannot implement `Externalizable`. None of the issues listed
|
||||
above, however, apply to static member classes.
|
||||
|
||||
## 1.11 The Externalizable Interface
|
||||
|
||||
For Externalizable objects, only the identity of the class of the object is
|
||||
saved by the container; the class must save and restore the contents. The
|
||||
`Externalizable` interface is defined as follows:
|
||||
|
||||
```
|
||||
package java.io;
|
||||
|
||||
public interface Externalizable extends Serializable
|
||||
{
|
||||
public void writeExternal(ObjectOutput out)
|
||||
throws IOException;
|
||||
|
||||
public void readExternal(ObjectInput in)
|
||||
throws IOException, java.lang.ClassNotFoundException;
|
||||
}
|
||||
```
|
||||
|
||||
The class of an Externalizable object must do the following:
|
||||
|
||||
- Implement the `java.io.Externalizable` interface
|
||||
|
||||
- Implement a `writeExternal` method to save the state of the object
|
||||
|
||||
(It must explicitly coordinate with its supertype to save its state.)
|
||||
|
||||
- Implement a `readExternal` method to read the data written by the
|
||||
`writeExternal` method from the stream and restore the state of the object
|
||||
|
||||
(It must explicitly coordinate with the supertype to save its state.)
|
||||
|
||||
- Have the `writeExternal` and `readExternal` methods be solely responsible
|
||||
for the format, if an externally defined format is written
|
||||
|
||||
**Note:** The `writeExternal` and `readExternal` methods are public and
|
||||
raise the risk that a client may be able to write or read information in
|
||||
the object other than by using its methods and fields. These methods must
|
||||
be used only when the information held by the object is not sensitive or
|
||||
when exposing it does not present a security risk.
|
||||
|
||||
- Have a public no-arg constructor
|
||||
|
||||
**Note:** Inner classes associated with enclosing instances cannot have
|
||||
no-arg constructors, since constructors of such classes implicitly accept
|
||||
the enclosing instance as a prepended parameter. Consequently the
|
||||
`Externalizable` interface mechanism cannot be used for inner classes and
|
||||
they should implement the `Serializable` interface, if they must be
|
||||
serialized. Several limitations exist for serializable inner classes as
|
||||
well, however; see [Section 1.10, "The Serializable
|
||||
Interface"](#the-serializable-interface), for a full enumeration.
|
||||
|
||||
An Externalizable class can optionally define the following methods:
|
||||
|
||||
- A `writeReplace` method to allow a class to nominate a replacement object
|
||||
to be written to the stream
|
||||
|
||||
(See [Section 2.5, "The writeReplace
|
||||
Method"](output.html#the-writereplace-method) for additional information.)
|
||||
|
||||
- A `readResolve` method to allow a class to designate a replacement object
|
||||
for the object just read from the stream
|
||||
|
||||
(See [Section 3.7, "The readResolve
|
||||
Method"](input.html#the-readresolve-method) for additional information.)
|
||||
|
||||
## 1.12 Serialization of Enum Constants
|
||||
|
||||
Enum constants are serialized differently than ordinary serializable or
|
||||
externalizable objects. The serialized form of an enum constant consists solely
|
||||
of its name; field values of the constant are not present in the form. To
|
||||
serialize an enum constant, `ObjectOutputStream` writes the value returned by
|
||||
the enum constant's `name` method. To deserialize an enum constant,
|
||||
`ObjectInputStream` reads the constant name from the stream; the deserialized
|
||||
constant is then obtained by calling the `java.lang.Enum.valueOf` method,
|
||||
passing the constant's enum type along with the received constant name as
|
||||
arguments. Like other serializable or externalizable objects, enum constants
|
||||
can function as the targets of back references appearing subsequently in the
|
||||
serialization stream.
|
||||
|
||||
The process by which enum constants are serialized cannot be customized: any
|
||||
class-specific `writeObject`, `readObject`, `readObjectNoData`, `writeReplace`,
|
||||
and `readResolve` methods defined by enum types are ignored during
|
||||
serialization and deserialization. Similarly, any `serialPersistentFields` or
|
||||
`serialVersionUID` field declarations are also ignored--all enum types have a
|
||||
fixed `serialVersionUID` of `0L`. Documenting serializable fields and data for
|
||||
enum types is unnecessary, since there is no variation in the type of data
|
||||
sent.
|
||||
|
||||
## 1.13 Protecting Sensitive Information
|
||||
|
||||
When developing a class that provides controlled access to resources, care must
|
||||
be taken to protect sensitive information and functions. During
|
||||
deserialization, the private state of the object is restored. For example, a
|
||||
file descriptor contains a handle that provides access to an operating system
|
||||
resource. Being able to forge a file descriptor would allow some forms of
|
||||
illegal access, since restoring state is done from a stream. Therefore, the
|
||||
serializing runtime must take the conservative approach and not trust the
|
||||
stream to contain only valid representations of objects. To avoid compromising
|
||||
a class, the sensitive state of an object must not be restored from the stream,
|
||||
or it must be reverified by the class. Several techniques are available to
|
||||
protect sensitive data in classes.
|
||||
|
||||
The easiest technique is to mark fields that contain sensitive data as *private
|
||||
transient*. Transient fields are not persistent and will not be saved by any
|
||||
persistence mechanism. Marking the field will prevent the state from appearing
|
||||
in the stream and from being restored during deserialization. Since writing and
|
||||
reading (of private fields) cannot be superseded outside of the class, the
|
||||
transient fields of the class are safe.
|
||||
|
||||
Particularly sensitive classes should not be serialized at all. To accomplish
|
||||
this, the object should not implement either the `Serializable` or the
|
||||
`Externalizable` interface.
|
||||
|
||||
Some classes may find it beneficial to allow writing and reading but
|
||||
specifically handle and revalidate the state as it is deserialized. The class
|
||||
should implement `writeObject` and `readObject` methods to save and restore
|
||||
only the appropriate state. If access should be denied, throwing a
|
||||
`NotSerializableException` will prevent further access.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
*[Copyright](../../../legal/SMICopyright.html) © 2005, 2017, Oracle
|
||||
and/or its affiliates. All rights reserved.*
|
||||
@ -1,304 +0,0 @@
|
||||
---
|
||||
# Copyright (c) 2005, 2017, 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.
|
||||
|
||||
include-before: '[CONTENTS](index.html) | [PREV](class.html) | [NEXT](protocol.html)'
|
||||
include-after: '[CONTENTS](index.html) | [PREV](class.html) | [NEXT](protocol.html)'
|
||||
|
||||
title: 'Java Object Serialization Specification: 5 - Versioning of Serializable Objects'
|
||||
---
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Goals](#goals)
|
||||
- [Assumptions](#assumptions)
|
||||
- [Who's Responsible for Versioning of
|
||||
Streams](#whos-responsible-for-versioning-of-streams)
|
||||
- [Compatible Java Type Evolution](#compatible-java-type-evolution)
|
||||
- [Type Changes Affecting
|
||||
Serialization](#type-changes-affecting-serialization)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
## 5.1 Overview
|
||||
|
||||
When Java objects use serialization to save state in files, or as blobs in
|
||||
databases, the potential arises that the version of a class reading the data is
|
||||
different than the version that wrote the data.
|
||||
|
||||
Versioning raises some fundamental questions about the identity of a class,
|
||||
including what constitutes a compatible change. A ***compatible change*** is a
|
||||
change that does not affect the contract between the class and its callers.
|
||||
|
||||
This section describes the goals, assumptions, and a solution that attempts to
|
||||
address this problem by restricting the kinds of changes allowed and by
|
||||
carefully choosing the mechanisms.
|
||||
|
||||
The proposed solution provides a mechanism for "automatic" handling of classes
|
||||
that evolve by adding fields and adding classes. Serialization will handle
|
||||
versioning without class-specific methods to be implemented for each version.
|
||||
The stream format can be traversed without invoking class-specific methods.
|
||||
|
||||
## 5.2 Goals
|
||||
|
||||
The goals are to:
|
||||
|
||||
- Support bidirectional communication between different versions of a class
|
||||
operating in different virtual machines by:
|
||||
|
||||
- Defining a mechanism that allows Java classes to read streams written
|
||||
by older versions of the same class.
|
||||
|
||||
- Defining a mechanism that allows Java classes to write streams intended
|
||||
to be read by older versions of the same class.
|
||||
|
||||
- Provide default serialization for persistence and for RMI.
|
||||
|
||||
- Perform well and produce compact streams in simple cases, so that RMI can
|
||||
use serialization.
|
||||
|
||||
- Be able to identify and load classes that match the exact class used to
|
||||
write the stream.
|
||||
|
||||
- Keep the overhead low for nonversioned classes.
|
||||
|
||||
- Use a stream format that allows the traversal of the stream without having
|
||||
to invoke methods specific to the objects saved in the stream.
|
||||
|
||||
## 5.3 Assumptions
|
||||
|
||||
The assumptions are that:
|
||||
|
||||
- Versioning will only apply to serializable classes since it must control
|
||||
the stream format to achieve it goals. Externalizable classes will be
|
||||
responsible for their own versioning which is tied to the external format.
|
||||
|
||||
- All data and objects must be read from, or skipped in, the stream in the
|
||||
same order as they were written.
|
||||
|
||||
- Classes evolve individually as well as in concert with supertypes and
|
||||
subtypes.
|
||||
|
||||
- Classes are identified by name. Two classes with the same name may be
|
||||
different versions or completely different classes that can be
|
||||
distinguished only by comparing their interfaces or by comparing hashes of
|
||||
the interfaces.
|
||||
|
||||
- Default serialization will not perform any type conversions.
|
||||
|
||||
- The stream format only needs to support a linear sequence of type changes,
|
||||
not arbitrary branching of a type.
|
||||
|
||||
## 5.4 Who's Responsible for Versioning of Streams
|
||||
|
||||
In the evolution of classes, it is the responsibility of the evolved (later
|
||||
version) class to maintain the contract established by the nonevolved class.
|
||||
This takes two forms. First, the evolved class must not break the existing
|
||||
assumptions about the interface provided by the original version, so that the
|
||||
evolved class can be used in place of the original. Secondly, when
|
||||
communicating with the original (or previous) versions, the evolved class must
|
||||
provide sufficient and equivalent information to allow the earlier version to
|
||||
continue to satisfy the nonevolved contract.
|
||||
|
||||
> 
|
||||
|
||||
For the purposes of the discussion here, each class implements and extends the
|
||||
interface or contract defined by its supertype. New versions of a class, for
|
||||
example `foo'`, must continue to satisfy the contract for `foo` and may extend
|
||||
the interface or modify its implementation.
|
||||
|
||||
Communication between objects via serialization is not part of the contract
|
||||
defined by these interfaces. Serialization is a private protocol between the
|
||||
implementations. It is the responsibility of the implementations to communicate
|
||||
sufficiently to allow each implementation to continue to satisfy the contract
|
||||
expected by its clients.
|
||||
|
||||
## 5.5 Compatible Java Type Evolution
|
||||
|
||||
The Java Language Specification discusses binary compatibility of Java classes
|
||||
as those classes evolve. Most of the flexibility of binary compatibility comes
|
||||
from the use of late binding of symbolic references for the names of classes,
|
||||
interfaces, fields, methods, and so on.
|
||||
|
||||
The following are the principle aspects of the design for versioning of
|
||||
serialized object streams.
|
||||
|
||||
- The default serialization mechanism will use a symbolic model for binding
|
||||
the fields in the stream to the fields in the corresponding class in the
|
||||
virtual machine.
|
||||
|
||||
- Each class referenced in the stream will uniquely identify itself, its
|
||||
supertype, and the types and names of each serializable field written to
|
||||
the stream. The fields are ordered with the primitive types first sorted by
|
||||
field name, followed by the object fields sorted by field name.
|
||||
|
||||
- Two types of data may occur in the stream for each class: required data
|
||||
(corresponding directly to the serializable fields of the object); and
|
||||
optional data (consisting of an arbitrary sequence of primitives and
|
||||
objects). The stream format defines how the required and optional data
|
||||
occur in the stream so that the whole class, the required, or the optional
|
||||
parts can be skipped if necessary.
|
||||
|
||||
- The required data consists of the fields of the object in the order
|
||||
defined by the class descriptor.
|
||||
|
||||
- The optional data is written to the stream and does not correspond
|
||||
directly to fields of the class. The class itself is responsible for
|
||||
the length, types, and versioning of this optional information.
|
||||
|
||||
- If defined for a class, the `writeObject`/`readObject` methods supersede
|
||||
the default mechanism to write/read the state of the class. These methods
|
||||
write and read the optional data for a class. The required data is written
|
||||
by calling `defaultWriteObject` and read by calling `defaultReadObject`.
|
||||
|
||||
- The stream format of each class is identified by the use of a Stream Unique
|
||||
Identifier (SUID). By default, this is the hash of the class. All later
|
||||
versions of the class must declare the Stream Unique Identifier (SUID) that
|
||||
they are compatible with. This guards against classes with the same name
|
||||
that might inadvertently be identified as being versions of a single class.
|
||||
|
||||
- Subtypes of `ObjectOutputStream` and `ObjectInputStream` may include their
|
||||
own information identifying the class using the `annotateClass` method; for
|
||||
example, `MarshalOutputStream` embeds the URL of the class.
|
||||
|
||||
## 5.6 Type Changes Affecting Serialization
|
||||
|
||||
With these concepts, we can now describe how the design will cope with the
|
||||
different cases of an evolving class. The cases are described in terms of a
|
||||
stream written by some version of a class. When the stream is read back by the
|
||||
same version of the class, there is no loss of information or functionality.
|
||||
The stream is the only source of information about the original class. Its
|
||||
class descriptions, while a subset of the original class description, are
|
||||
sufficient to match up the data in the stream with the version of the class
|
||||
being reconstituted.
|
||||
|
||||
The descriptions are from the perspective of the stream being read in order to
|
||||
reconstitute either an earlier or later version of the class. In the parlance
|
||||
of RPC systems, this is a "receiver makes right" system. The writer writes its
|
||||
data in the most suitable form and the receiver must interpret that information
|
||||
to extract the parts it needs and to fill in the parts that are not available.
|
||||
|
||||
### 5.6.1 Incompatible Changes
|
||||
|
||||
Incompatible changes to classes are those changes for which the guarantee of
|
||||
interoperability cannot be maintained. The incompatible changes that may occur
|
||||
while evolving a class are:
|
||||
|
||||
- Deleting fields - If a field is deleted in a class, the stream written will
|
||||
not contain its value. When the stream is read by an earlier class, the
|
||||
value of the field will be set to the default value because no value is
|
||||
available in the stream. However, this default value may adversely impair
|
||||
the ability of the earlier version to fulfill its contract.
|
||||
|
||||
- Moving classes up or down the hierarchy - This cannot be allowed since the
|
||||
data in the stream appears in the wrong sequence.
|
||||
|
||||
- Changing a nonstatic field to static or a nontransient field to transient -
|
||||
When relying on default serialization, this change is equivalent to
|
||||
deleting a field from the class. This version of the class will not write
|
||||
that data to the stream, so it will not be available to be read by earlier
|
||||
versions of the class. As when deleting a field, the field of the earlier
|
||||
version will be initialized to the default value, which can cause the class
|
||||
to fail in unexpected ways.
|
||||
|
||||
- Changing the declared type of a primitive field - Each version of the class
|
||||
writes the data with its declared type. Earlier versions of the class
|
||||
attempting to read the field will fail because the type of the data in the
|
||||
stream does not match the type of the field.
|
||||
|
||||
- Changing the `writeObject` or `readObject` method so that it no longer
|
||||
writes or reads the default field data or changing it so that it attempts
|
||||
to write it or read it when the previous version did not. The default field
|
||||
data must consistently either appear or not appear in the stream.
|
||||
|
||||
- Changing a class from `Serializable` to `Externalizable` or vice versa is
|
||||
an incompatible change since the stream will contain data that is
|
||||
incompatible with the implementation of the available class.
|
||||
|
||||
- Changing a class from a non-enum type to an enum type or vice versa since
|
||||
the stream will contain data that is incompatible with the implementation
|
||||
of the available class.
|
||||
|
||||
- Removing either `Serializable` or `Externalizable` is an incompatible
|
||||
change since when written it will no longer supply the fields needed by
|
||||
older versions of the class.
|
||||
|
||||
- Adding the `writeReplace` or `readResolve` method to a class is
|
||||
incompatible if the behavior would produce an object that is incompatible
|
||||
with any older version of the class.
|
||||
|
||||
### 5.6.2 Compatible Changes
|
||||
|
||||
The compatible changes to a class are handled as follows:
|
||||
|
||||
- Adding fields - When the class being reconstituted has a field that does
|
||||
not occur in the stream, that field in the object will be initialized to
|
||||
the default value for its type. If class-specific initialization is needed,
|
||||
the class may provide a readObject method that can initialize the field to
|
||||
nondefault values.
|
||||
|
||||
- Adding classes - The stream will contain the type hierarchy of each object
|
||||
in the stream. Comparing this hierarchy in the stream with the current
|
||||
class can detect additional classes. Since there is no information in the
|
||||
stream from which to initialize the object, the class's fields will be
|
||||
initialized to the default values.
|
||||
|
||||
- Removing classes - Comparing the class hierarchy in the stream with that of
|
||||
the current class can detect that a class has been deleted. In this case,
|
||||
the fields and objects corresponding to that class are read from the
|
||||
stream. Primitive fields are discarded, but the objects referenced by the
|
||||
deleted class are created, since they may be referred to later in the
|
||||
stream. They will be garbage-collected when the stream is garbage-collected
|
||||
or reset.
|
||||
|
||||
- Adding `writeObject`/`readObject` methods - If the version reading the
|
||||
stream has these methods then `readObject` is expected, as usual, to read
|
||||
the required data written to the stream by the default serialization. It
|
||||
should call `defaultReadObject` first before reading any optional data. The
|
||||
`writeObject` method is expected as usual to call `defaultWriteObject` to
|
||||
write the required data and then may write optional data.
|
||||
|
||||
- Removing `writeObject`/`readObject` methods - If the class reading the
|
||||
stream does not have these methods, the required data will be read by
|
||||
default serialization, and the optional data will be discarded.
|
||||
|
||||
- Adding `java.io.Serializable` - This is equivalent to adding types. There
|
||||
will be no values in the stream for this class so its fields will be
|
||||
initialized to default values. The support for subclassing nonserializable
|
||||
classes requires that the class's supertype have a no-arg constructor and
|
||||
the class itself will be initialized to default values. If the no-arg
|
||||
constructor is not available, the `InvalidClassException` is thrown.
|
||||
|
||||
- Changing the access to a field - The access modifiers public, package,
|
||||
protected, and private have no effect on the ability of serialization to
|
||||
assign values to the fields.
|
||||
|
||||
- Changing a field from static to nonstatic or transient to nontransient -
|
||||
When relying on default serialization to compute the serializable fields,
|
||||
this change is equivalent to adding a field to the class. The new field
|
||||
will be written to the stream but earlier classes will ignore the value
|
||||
since serialization will not assign values to static or transient fields.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
*[Copyright](../../../legal/SMICopyright.html) © 2005, 2017, Oracle
|
||||
and/or its affiliates. All rights reserved.*
|
||||
@ -376,7 +376,7 @@ static void javaPrinterJobToNSPrintInfo(JNIEnv* env, jobject srcPrinterJob, jobj
|
||||
static JNF_MEMBER_CACHE(jm_getMaxPage, sjc_CPrinterJob, "getMaxPageAttrib", "()I");
|
||||
static JNF_MEMBER_CACHE(jm_getSelectAttrib, sjc_CPrinterJob, "getSelectAttrib", "()I");
|
||||
static JNF_MEMBER_CACHE(jm_getNumberOfPages, jc_Pageable, "getNumberOfPages", "()I");
|
||||
static JNF_MEMBER_CACHE(jm_getPageFormat, sjc_CPrinterJob, "getPageFormat", "(I)Ljava/awt/print/PageFormat;");
|
||||
static JNF_MEMBER_CACHE(jm_getPageFormat, sjc_CPrinterJob, "getPageFormatFromAttributes", "()Ljava/awt/print/PageFormat;");
|
||||
|
||||
NSMutableDictionary* printingDictionary = [dst dictionary];
|
||||
|
||||
@ -412,7 +412,7 @@ static void javaPrinterJobToNSPrintInfo(JNIEnv* env, jobject srcPrinterJob, jobj
|
||||
[printingDictionary setObject:[NSNumber numberWithInteger:fromPage] forKey:NSPrintFirstPage];
|
||||
[printingDictionary setObject:[NSNumber numberWithInteger:toPage] forKey:NSPrintLastPage];
|
||||
|
||||
jobject page = JNFCallObjectMethod(env, srcPrinterJob, jm_getPageFormat, (jint)0);
|
||||
jobject page = JNFCallObjectMethod(env, srcPrinterJob, jm_getPageFormat);
|
||||
if (page != NULL) {
|
||||
javaPageFormatToNSPrintInfo(env, NULL, page, dst);
|
||||
}
|
||||
|
||||
@ -812,7 +812,7 @@ public class JEditorPane extends JTextComponent {
|
||||
|
||||
/**
|
||||
* Scrolls the view to the given reference location
|
||||
* (that is, the value returned by the <code>UL.getRef</code>
|
||||
* (that is, the value returned by the <code>URL.getRef</code>
|
||||
* method for the URL being displayed). By default, this
|
||||
* method only knows how to locate a reference in an
|
||||
* HTMLDocument. The implementation calls the
|
||||
|
||||
@ -1900,7 +1900,7 @@ public class JTabbedPane extends JComponent
|
||||
* Returns the accessible name of this object, or {@code null} if
|
||||
* there is no accessible name.
|
||||
*
|
||||
* @return the accessible name of this object, nor {@code null}.
|
||||
* @return the accessible name of this object, or {@code null}.
|
||||
* @since 1.6
|
||||
*/
|
||||
public String getAccessibleName() {
|
||||
|
||||
@ -27,6 +27,24 @@
|
||||
* Defines the AWT and Swing user interface toolkits, plus APIs for
|
||||
* accessibility, audio, imaging, printing, and JavaBeans.
|
||||
*
|
||||
* @uses java.awt.im.spi.InputMethodDescriptor
|
||||
* @uses javax.accessibility.AccessibilityProvider
|
||||
* @uses javax.imageio.spi.ImageInputStreamSpi
|
||||
* @uses javax.imageio.spi.ImageOutputStreamSpi
|
||||
* @uses javax.imageio.spi.ImageReaderSpi
|
||||
* @uses javax.imageio.spi.ImageTranscoderSpi
|
||||
* @uses javax.imageio.spi.ImageWriterSpi
|
||||
* @uses javax.print.PrintServiceLookup
|
||||
* @uses javax.print.StreamPrintServiceFactory
|
||||
* @uses javax.sound.midi.spi.MidiDeviceProvider
|
||||
* @uses javax.sound.midi.spi.MidiFileReader
|
||||
* @uses javax.sound.midi.spi.MidiFileWriter
|
||||
* @uses javax.sound.midi.spi.SoundbankReader
|
||||
* @uses javax.sound.sampled.spi.AudioFileReader
|
||||
* @uses javax.sound.sampled.spi.AudioFileWriter
|
||||
* @uses javax.sound.sampled.spi.FormatConversionProvider
|
||||
* @uses javax.sound.sampled.spi.MixerProvider
|
||||
*
|
||||
* @moduleGraph
|
||||
* @since 9
|
||||
*/
|
||||
|
||||
@ -886,6 +886,14 @@ public abstract class RasterPrinterJob extends PrinterJob {
|
||||
}
|
||||
}
|
||||
|
||||
protected PageFormat getPageFormatFromAttributes() {
|
||||
if (attributes == null || attributes.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return attributeToPageFormat(getPrintService(), this.attributes);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Presents the user a dialog for changing properties of the
|
||||
* print job interactively.
|
||||
|
||||
@ -1,776 +0,0 @@
|
||||
<!--
|
||||
Copyright (c) 2005, 2017, 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.
|
||||
-->
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html lang="en-US" xmlns="http://www.w3.org/1999/xhtml" xml:lang=
|
||||
"en-US">
|
||||
<head>
|
||||
<title>Java AWT Native Interface Specification and Guide</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2>The Java AWT Native Interface Specification and Guide</h2>
|
||||
<h3>Introduction</h3>
|
||||
<p>The Java AWT Native Interface (JAWT) comprises a small set of native
|
||||
(eg C language-based) APIs that provide a standard supported way
|
||||
for interaction between Java API windows and surfaces, and
|
||||
platform native API windows and surfaces.
|
||||
Non-Java libraries may then render to a Java owned window.
|
||||
<p>
|
||||
Note: in this document the terms "Java AWT Native Interface",
|
||||
"AWT Native Interface" and "JAWT" are interchangeable and
|
||||
refer to this same specification.
|
||||
<p>
|
||||
The fundamental obstacle to native rendering without JAWT is that
|
||||
is that the rendering code cannot identify where to draw.
|
||||
The native code needs access to information about a Java
|
||||
drawing surface (such as a handle to the underlying native ID of a
|
||||
<tt>Canvas</tt>), but cannot get it.</p>
|
||||
Without that information (ie without JAWT) an application could
|
||||
use native rendering only by creating its own top-level window
|
||||
not shared at all with Java. This is unacceptable for most uses.
|
||||
Except for usage via JAWT, this is considered to be entirely
|
||||
internal to the Java platform implementation: private, unsupported
|
||||
and undocumented.
|
||||
<p>
|
||||
JAWT should be supported in all headful implementations
|
||||
where technically possible although this is not enforced by the JCK.
|
||||
There is a platform-specific and a platform
|
||||
independent portion to the API, to account for the differing
|
||||
data structures and requirements of each platform.
|
||||
This document specifies the platform independent portions and
|
||||
also documents the platform dependent portions for the Oracle JDK
|
||||
supported desktop operating environments.
|
||||
For AWT the term platform is less tied to the underlying operating
|
||||
system than it is to the desktop windowing environment.
|
||||
<p>
|
||||
Reasons for using the AWT Native Interface include
|
||||
<ul>
|
||||
<li>Use of a 3rd party native library not available in Java
|
||||
<li>A temporary porting aid before converting legacy code to Java
|
||||
<li>Rendering performance available only to native hardware accelerated APIs
|
||||
<li>Interoperation with another toolkit
|
||||
</ul>
|
||||
<p>
|
||||
Drawbacks include
|
||||
<ul>
|
||||
<li>A more complex application implementation, eg for painting
|
||||
<li>Potential for application instability if the native library does
|
||||
not interoperate properly with AWT.
|
||||
<li>Increased application delivery complexity - per platform binaries
|
||||
</ul>
|
||||
The header file <a href="#jawt.h"> "jawt.h"</a>
|
||||
in the Appendix fully specifies the APIs provided by JAWT.
|
||||
<p>
|
||||
An example illustrating how easy it is to use the AWT Native Interface
|
||||
is presented and discussed later in this document.</p>
|
||||
|
||||
<p><b>JAWT usage depends on JNI</b></p>
|
||||
<p>The definition of Java Standard Edition includes JNI, the Java
|
||||
Native Interface. Many Java developers will never need to use it,
|
||||
but the interface is the only standard supported way for a Java
|
||||
language program to interact directly with
|
||||
application code that has been compiled to the native machine
|
||||
instructions for the host processor architecture.
|
||||
JNI is used where ever there is a need for mixed languages.
|
||||
These are by no means limited to cases like AWT. For example, you
|
||||
could use JNI to integrate with native code that communicates with
|
||||
a peripheral device, such as a scanner, connected to a system via a
|
||||
USB port.</p>
|
||||
<p>So JNI is general enough to be used to access almost any
|
||||
sort of native library.
|
||||
The rest of this document assumes a familiarity with how
|
||||
to use JNI.
|
||||
|
||||
<p><b>How to use JAWT </b></p>
|
||||
<p>In this section we describe the most common usage of the AWT
|
||||
Native Interface — overriding the <tt>paint</tt> method to
|
||||
direct drawing operations to a native rendering library which then
|
||||
queries the Java VM to determine the information it needs in order
|
||||
to render. Note, however, that any native code may use the AWT
|
||||
Native Interface to learn about a target drawing surface, not just
|
||||
code in a <tt>paint</tt> method.</p>
|
||||
<p>The first step in hooking up a native rendering library to a
|
||||
Java <tt>Canvas</tt> is to define a new class that extends
|
||||
<tt>Canvas</tt> and overrides the <tt>paint</tt> method. The Java
|
||||
system routes all drawing operations for a <tt>Canvas</tt> object
|
||||
through the <tt>paint</tt> method, as it does for all other GUI
|
||||
objects. Canvas is a good candidate for the rendering surface as
|
||||
it does not have any content as a Button would.</p>
|
||||
<p>The new <tt>paint</tt> method, to be implemented in the native
|
||||
rendering library, must be declared as <tt>public native void</tt>
|
||||
, and the native library itself is loaded at runtime by including a
|
||||
call to <tt>System.loadLibrary( "myRenderingLib")</tt>in
|
||||
the <tt>static</tt> block of the class. The <tt>myRenderingLib</tt>
|
||||
name is used for the native shared library; for Linux or the Solaris
|
||||
operating environment, the actual name for the library file on disk
|
||||
is <tt>libmyRenderingLib.so</tt> .</p>
|
||||
<p>Here is a simple example of such a class:</p>
|
||||
<pre>
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
|
||||
public class MyCanvas extends Canvas {
|
||||
static {
|
||||
System.loadLibrary("myRenderingLib");
|
||||
}
|
||||
public native void paint(Graphics g);
|
||||
|
||||
public static void main(String[] args) {
|
||||
Frame f = new Frame();
|
||||
f.setBounds(0, 0, 500, 110);
|
||||
f.add(new MyCanvas());
|
||||
f.addWindowListener( new WindowAdapter() {
|
||||
public void windowClosing(WindowEvent ev) {
|
||||
System.exit(0);
|
||||
}
|
||||
} );
|
||||
f.show();
|
||||
}
|
||||
}
|
||||
<br />
|
||||
</pre>
|
||||
<p>Note that this class has a <tt>main</tt> method that can be used
|
||||
to run this code as an application for testing purposes.</p>
|
||||
<p>The next step is to run the <tt>javah</tt> tool on the
|
||||
<tt>MyCanvas</tt> class file above to generate a C/C++ header file
|
||||
that describes the interface to the native <tt>paint</tt> method
|
||||
that Java expects to be used. <tt>javah</tt> is a standard tool
|
||||
included with the JDK. NB: <tt>javac -h outputdir</tt> may also be used.</p>
|
||||
|
||||
<p>The final step ­ and the most interesting one ­ is to
|
||||
write the native rendering method, with an interface that conforms
|
||||
to the header file that <tt>javah</tt> generated, and build it as a
|
||||
standard shared library (called <tt>myRenderingLib</tt> in the
|
||||
above example) by linking it, against the appropriate JDK provided
|
||||
$JDK_HOME/lib/$JAWT_LIB library for the target platform.
|
||||
Where JAWT_LIB has the base name "jawt" and follows platform
|
||||
shared object naming rules. i.e.:
|
||||
<ul>
|
||||
<li>Windows: jawt.dll
|
||||
<li>MacOS: libjawt.dylib
|
||||
<li>Linux: libjawt.so
|
||||
<li>Solaris: libjawt.so
|
||||
</ul>
|
||||
|
||||
This code will call back to the Java virtual machine to
|
||||
get the drawing surface information it needs to access the
|
||||
<tt>MyCanvas</tt> peer. Once this information is available, the
|
||||
code can draw directly to <tt>MyCanvas</tt> using standard drawing
|
||||
routines supplied by the underlying operating system.</p>
|
||||
<p>Here is sample source code for a native <tt>paint</tt> method
|
||||
designed for use in a X11-based drawing environment (Linux
|
||||
or Solaris) and a Java VM where the AWT Native Interface is present:</p>
|
||||
<pre>
|
||||
#include "MyCanvas.h"
|
||||
#include "jawt_md.h"
|
||||
|
||||
/*
|
||||
* Class: MyCanvas
|
||||
* Method: paint
|
||||
* Signature: (Ljava/awt/Graphics;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_MyCanvas_paint
|
||||
(JNIEnv* env, jobject canvas, jobject graphics)
|
||||
{
|
||||
JAWT awt;
|
||||
JAWT_DrawingSurface* ds;
|
||||
JAWT_DrawingSurfaceInfo* dsi;
|
||||
JAWT_X11DrawingSurfaceInfo* dsi_x11;
|
||||
jboolean result;
|
||||
jint lock;
|
||||
GC gc;
|
||||
|
||||
short i;
|
||||
char *testString = "^^^ rendered from native code ^^^";
|
||||
|
||||
/* Get the AWT */
|
||||
awt.version = JAWT_VERSION_9;
|
||||
if (JAWT_GetAWT(env, &awt) == JNI_FALSE) {
|
||||
printf("AWT Not found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the drawing surface */
|
||||
ds = awt.GetDrawingSurface(env, canvas);
|
||||
if (ds == NULL) {
|
||||
printf("NULL drawing surface\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Lock the drawing surface */
|
||||
lock = ds->Lock(ds);
|
||||
if((lock & JAWT_LOCK_ERROR) != 0) {
|
||||
printf("Error locking surface\n");
|
||||
awt.FreeDrawingSurface(ds);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the drawing surface info */
|
||||
dsi = ds->GetDrawingSurfaceInfo(ds);
|
||||
if (dsi == NULL) {
|
||||
printf("Error getting surface info\n");
|
||||
ds->Unlock(ds);
|
||||
awt.FreeDrawingSurface(ds);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the platform-specific drawing info */
|
||||
dsi_x11 = (JAWT_X11DrawingSurfaceInfo*)dsi->platformInfo;
|
||||
|
||||
|
||||
/* Now paint */
|
||||
gc = XCreateGC(dsi_x11->display, dsi_x11->drawable, 0, 0);
|
||||
XSetBackground(dsi_x11->display, gc, 0);
|
||||
for (i=0; i<36;i++)
|
||||
{
|
||||
XSetForeground(dsi_x11->display, gc, 10*i);
|
||||
XFillRectangle(dsi_x11->display, dsi_x11->drawable, gc,
|
||||
10*i, 5, 90, 90);
|
||||
}
|
||||
XSetForeground(dsi_x11->display, gc, 155);
|
||||
XDrawImageString(dsi_x11->display, dsi_x11->drawable, gc,
|
||||
100, 110, testString, strlen(testString));
|
||||
XFreeGC(dsi_x11->display, gc);
|
||||
|
||||
|
||||
/* Free the drawing surface info */
|
||||
ds->FreeDrawingSurfaceInfo(dsi);
|
||||
|
||||
/* Unlock the drawing surface */
|
||||
ds->Unlock(ds);
|
||||
|
||||
/* Free the drawing surface */
|
||||
awt.FreeDrawingSurface(ds);
|
||||
}
|
||||
</pre>
|
||||
<p>The key data structure here is <tt>JAWT</tt> , which is defined
|
||||
in <tt>jawt.h</tt> (included by <tt>jawt_md.h)</tt> ; it provides
|
||||
access to all the information the native code needs to get the job
|
||||
done. The first part of the native method is boilerplate: it
|
||||
populates the <tt>JAWT</tt> structure, gets a
|
||||
<tt>JAWT_DrawingSurface</tt> structure, locks the surface (only one
|
||||
drawing engine at a time, please!), then gets a
|
||||
<tt>JAWT_DrawingSurfaceInfo</tt> structure that contains a pointer
|
||||
(in the <tt>platformInfo</tt> field) to the necessary
|
||||
platform-specific drawing information. It also includes the
|
||||
bounding rectangle of the drawing surface and the current clipping
|
||||
region.</p>
|
||||
<p>The structure of the information pointed to by
|
||||
<tt>platformInfo</tt> is defined in a machine-dependent header file
|
||||
called <tt>jawt_md.h</tt>. For X11 drawing, it includes
|
||||
information about the X11 display and X11 drawable associated with
|
||||
<tt>MyCanvas</tt>. After the drawing operations are completed,
|
||||
there is more boilerplate code as <tt>JAWT_DrawingSurfaceInfo</tt>
|
||||
is freed and <tt>JAWT_DrawingSurface</tt> is unlocked and
|
||||
freed.</p>
|
||||
<p>The corresponding code for the GDI API on the Microsoft Windows platform would
|
||||
be structured similarly, but would include the version of
|
||||
<tt>jawt_md.h</tt> for Microsoft Windows and the structure located
|
||||
in the <tt>platformInfo</tt> field of drawing surface info would be
|
||||
cast as a <tt>JAWT_Win32DrawingSurfaceInfo*</tt> . And, of course,
|
||||
the actual drawing operations would need to be changed to those
|
||||
appropriate for the Microsoft Windows platform.
|
||||
The same also for MacOS.
|
||||
</p>
|
||||
<p><b>Summary</b></p>
|
||||
<p>The ability to draw directly into a Java <tt>Canvas</tt> from a
|
||||
native code library is extremely useful for developers planning to
|
||||
migrate a legacy software system to Java, especially one that
|
||||
includes a high-performance rendering engine. It makes it much
|
||||
easier to migrate in stages, leaving performance-sensitive
|
||||
rendering code alone, while other less-sensitive portions of code
|
||||
are converted to Java. The result can be a modern Java-centric
|
||||
application, providing the benefit of portability and development
|
||||
efficiency, but one that does not sacrifice an investment in
|
||||
performance of a key piece of native code.</p>
|
||||
<p><b>References</b></p>
|
||||
<p>The definitive reference to the Java Native Interface is <i>The
|
||||
Java Native Interface: Programmer's Guide and Specification</i> by
|
||||
Sheng Liang. This book was published in June
|
||||
1999 by Addison-Wesley. The ISBN is 0-201-32577-2.</p>
|
||||
<p><b>Appendix</b></p>
|
||||
<p><b>Header Files for jawt.h and jawt_md.h</b></p>
|
||||
<a name="jawt.h"></a>
|
||||
<p>jawt.h</p>
|
||||
<pre>
|
||||
#ifndef _JAVASOFT_JAWT_H_
|
||||
#define _JAVASOFT_JAWT_H_
|
||||
|
||||
#include "jni.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* AWT native interface.
|
||||
*
|
||||
* The AWT native interface allows a native C or C++ application a means
|
||||
* by which to access native structures in AWT. This is to facilitate moving
|
||||
* legacy C and C++ applications to Java and to target the needs of the
|
||||
* developers who need to do their own native rendering to canvases
|
||||
* for performance or other reasons.
|
||||
*
|
||||
* Conversely it also provides mechanisms for an application which already
|
||||
* has a native window to provide that to AWT for AWT rendering.
|
||||
*
|
||||
* Since every platform may be different in its native data structures
|
||||
* and APIs for windowing systems the application must necessarily
|
||||
* provided per-platform source and compile and deliver per-platform
|
||||
* native code to use this API.
|
||||
*
|
||||
* These interfaces are not part of the Java SE specification and
|
||||
* a VM is not required to implement this API. However it is strongly
|
||||
* recommended that all implementations which support headful AWT
|
||||
* also support these interfaces.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* AWT Native Drawing Surface (JAWT_DrawingSurface).
|
||||
*
|
||||
* For each platform, there is a native drawing surface structure. This
|
||||
* platform-specific structure can be found in jawt_md.h. It is recommended
|
||||
* that additional platforms follow the same model. It is also recommended
|
||||
* that VMs on all platforms support the existing structures in jawt_md.h.
|
||||
*
|
||||
*******************
|
||||
* EXAMPLE OF USAGE:
|
||||
*******************
|
||||
*
|
||||
* On Microsoft Windows, a programmer wishes to access the HWND of a canvas
|
||||
* to perform native rendering into it. The programmer has declared the
|
||||
* paint() method for their canvas subclass to be native:
|
||||
*
|
||||
*
|
||||
* MyCanvas.java:
|
||||
*
|
||||
* import java.awt.*;
|
||||
*
|
||||
* public class MyCanvas extends Canvas {
|
||||
*
|
||||
* static {
|
||||
* System.loadLibrary("mylib");
|
||||
* }
|
||||
*
|
||||
* public native void paint(Graphics g);
|
||||
* }
|
||||
*
|
||||
*
|
||||
* myfile.c:
|
||||
*
|
||||
* #include "jawt_md.h"
|
||||
* #include <assert.h>
|
||||
*
|
||||
* JNIEXPORT void JNICALL
|
||||
* Java_MyCanvas_paint(JNIEnv* env, jobject canvas, jobject graphics)
|
||||
* {
|
||||
* JAWT awt;
|
||||
* JAWT_DrawingSurface* ds;
|
||||
* JAWT_DrawingSurfaceInfo* dsi;
|
||||
* JAWT_Win32DrawingSurfaceInfo* dsi_win;
|
||||
* jboolean result;
|
||||
* jint lock;
|
||||
*
|
||||
* // Get the AWT. Request version 9 to access features in that release.
|
||||
* awt.version = JAWT_VERSION_9;
|
||||
* result = JAWT_GetAWT(env, &awt);
|
||||
* assert(result != JNI_FALSE);
|
||||
*
|
||||
* // Get the drawing surface
|
||||
* ds = awt.GetDrawingSurface(env, canvas);
|
||||
* assert(ds != NULL);
|
||||
*
|
||||
* // Lock the drawing surface
|
||||
* lock = ds->Lock(ds);
|
||||
* assert((lock & JAWT_LOCK_ERROR) == 0);
|
||||
*
|
||||
* // Get the drawing surface info
|
||||
* dsi = ds->GetDrawingSurfaceInfo(ds);
|
||||
*
|
||||
* // Get the platform-specific drawing info
|
||||
* dsi_win = (JAWT_Win32DrawingSurfaceInfo*)dsi->platformInfo;
|
||||
*
|
||||
* //////////////////////////////
|
||||
* // !!! DO PAINTING HERE !!! //
|
||||
* //////////////////////////////
|
||||
*
|
||||
* // Free the drawing surface info
|
||||
* ds->FreeDrawingSurfaceInfo(dsi);
|
||||
*
|
||||
* // Unlock the drawing surface
|
||||
* ds->Unlock(ds);
|
||||
*
|
||||
* // Free the drawing surface
|
||||
* awt.FreeDrawingSurface(ds);
|
||||
* }
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* JAWT_Rectangle
|
||||
* Structure for a native rectangle.
|
||||
*/
|
||||
typedef struct jawt_Rectangle {
|
||||
jint x;
|
||||
jint y;
|
||||
jint width;
|
||||
jint height;
|
||||
} JAWT_Rectangle;
|
||||
|
||||
struct jawt_DrawingSurface;
|
||||
|
||||
/*
|
||||
* JAWT_DrawingSurfaceInfo
|
||||
* Structure for containing the underlying drawing information of a component.
|
||||
*/
|
||||
typedef struct jawt_DrawingSurfaceInfo {
|
||||
/*
|
||||
* Pointer to the platform-specific information. This can be safely
|
||||
* cast to a JAWT_Win32DrawingSurfaceInfo on Microsoft Windows or a
|
||||
* JAWT_X11DrawingSurfaceInfo on Linux and Solaris. On MacOS this is a
|
||||
* pointer to a NSObject that conforms to the JAWT_SurfaceLayers protocol.
|
||||
* See jawt_md.h for details.
|
||||
*/
|
||||
void* platformInfo;
|
||||
/* Cached pointer to the underlying drawing surface */
|
||||
struct jawt_DrawingSurface* ds;
|
||||
/* Bounding rectangle of the drawing surface */
|
||||
JAWT_Rectangle bounds;
|
||||
/* Number of rectangles in the clip */
|
||||
jint clipSize;
|
||||
/* Clip rectangle array */
|
||||
JAWT_Rectangle* clip;
|
||||
} JAWT_DrawingSurfaceInfo;
|
||||
|
||||
#define JAWT_LOCK_ERROR 0x00000001
|
||||
#define JAWT_LOCK_CLIP_CHANGED 0x00000002
|
||||
#define JAWT_LOCK_BOUNDS_CHANGED 0x00000004
|
||||
#define JAWT_LOCK_SURFACE_CHANGED 0x00000008
|
||||
|
||||
/*
|
||||
* JAWT_DrawingSurface
|
||||
* Structure for containing the underlying drawing information of a component.
|
||||
* All operations on a JAWT_DrawingSurface MUST be performed from the same
|
||||
* thread as the call to GetDrawingSurface.
|
||||
*/
|
||||
typedef struct jawt_DrawingSurface {
|
||||
/* Cached reference to the Java environment of the calling thread.
|
||||
* If Lock(), Unlock(), GetDrawingSurfaceInfo() or
|
||||
* FreeDrawingSurfaceInfo() are called from a different thread,
|
||||
* this data member should be set before calling those functions.
|
||||
*/
|
||||
JNIEnv* env;
|
||||
/* Cached reference to the target object */
|
||||
jobject target;
|
||||
/*
|
||||
* Lock the surface of the target component for native rendering.
|
||||
* When finished drawing, the surface must be unlocked with
|
||||
* Unlock(). This function returns a bitmask with one or more of the
|
||||
* following values:
|
||||
*
|
||||
* JAWT_LOCK_ERROR - When an error has occurred and the surface could not
|
||||
* be locked.
|
||||
*
|
||||
* JAWT_LOCK_CLIP_CHANGED - When the clip region has changed.
|
||||
*
|
||||
* JAWT_LOCK_BOUNDS_CHANGED - When the bounds of the surface have changed.
|
||||
*
|
||||
* JAWT_LOCK_SURFACE_CHANGED - When the surface itself has changed
|
||||
*/
|
||||
jint (JNICALL *Lock)
|
||||
(struct jawt_DrawingSurface* ds);
|
||||
/*
|
||||
* Get the drawing surface info.
|
||||
* The value returned may be cached, but the values may change if
|
||||
* additional calls to Lock() or Unlock() are made.
|
||||
* Lock() must be called before this can return a valid value.
|
||||
* Returns NULL if an error has occurred.
|
||||
* When finished with the returned value, FreeDrawingSurfaceInfo must be
|
||||
* called.
|
||||
*/
|
||||
JAWT_DrawingSurfaceInfo* (JNICALL *GetDrawingSurfaceInfo)
|
||||
(struct jawt_DrawingSurface* ds);
|
||||
/*
|
||||
* Free the drawing surface info.
|
||||
*/
|
||||
void (JNICALL *FreeDrawingSurfaceInfo)
|
||||
(JAWT_DrawingSurfaceInfo* dsi);
|
||||
/*
|
||||
* Unlock the drawing surface of the target component for native rendering.
|
||||
*/
|
||||
void (JNICALL *Unlock)
|
||||
(struct jawt_DrawingSurface* ds);
|
||||
} JAWT_DrawingSurface;
|
||||
|
||||
/*
|
||||
* JAWT
|
||||
* Structure for containing native AWT functions.
|
||||
*/
|
||||
typedef struct jawt {
|
||||
/*
|
||||
* Version of this structure. This must always be set before
|
||||
* calling JAWT_GetAWT(). It affects the functions returned.
|
||||
* Must be one of the known pre-defined versions.
|
||||
*/
|
||||
jint version;
|
||||
/*
|
||||
* Return a drawing surface from a target jobject. This value
|
||||
* may be cached.
|
||||
* Returns NULL if an error has occurred.
|
||||
* Target must be a java.awt.Component (should be a Canvas
|
||||
* or Window for native rendering).
|
||||
* FreeDrawingSurface() must be called when finished with the
|
||||
* returned JAWT_DrawingSurface.
|
||||
*/
|
||||
JAWT_DrawingSurface* (JNICALL *GetDrawingSurface)
|
||||
(JNIEnv* env, jobject target);
|
||||
/*
|
||||
* Free the drawing surface allocated in GetDrawingSurface.
|
||||
*/
|
||||
void (JNICALL *FreeDrawingSurface)
|
||||
(JAWT_DrawingSurface* ds);
|
||||
/*
|
||||
* Since 1.4
|
||||
* Locks the entire AWT for synchronization purposes
|
||||
*/
|
||||
void (JNICALL *Lock)(JNIEnv* env);
|
||||
/*
|
||||
* Since 1.4
|
||||
* Unlocks the entire AWT for synchronization purposes
|
||||
*/
|
||||
void (JNICALL *Unlock)(JNIEnv* env);
|
||||
/*
|
||||
* Since 1.4
|
||||
* Returns a reference to a java.awt.Component from a native
|
||||
* platform handle. On Windows, this corresponds to an HWND;
|
||||
* on Solaris and Linux, this is a Drawable. For other platforms,
|
||||
* see the appropriate machine-dependent header file for a description.
|
||||
* The reference returned by this function is a local
|
||||
* reference that is only valid in this environment.
|
||||
* This function returns a NULL reference if no component could be
|
||||
* found with matching platform information.
|
||||
*/
|
||||
jobject (JNICALL *GetComponent)(JNIEnv* env, void* platformInfo);
|
||||
|
||||
/**
|
||||
* Since 9
|
||||
* Creates a java.awt.Frame placed in a native container. Container is
|
||||
* referenced by the native platform handle. For example on Windows this
|
||||
* corresponds to an HWND. For other platforms, see the appropriate
|
||||
* machine-dependent header file for a description. The reference returned
|
||||
* by this function is a local reference that is only valid in this
|
||||
* environment. This function returns a NULL reference if no frame could be
|
||||
* created with matching platform information.
|
||||
*/
|
||||
jobject (JNICALL *CreateEmbeddedFrame) (JNIEnv *env, void* platformInfo);
|
||||
|
||||
/**
|
||||
* Since 9
|
||||
* Moves and resizes the embedded frame. The new location of the top-left
|
||||
* corner is specified by x and y parameters relative to the native parent
|
||||
* component. The new size is specified by width and height.
|
||||
*
|
||||
* The embedded frame should be created by CreateEmbeddedFrame() method, or
|
||||
* this function will not have any effect.
|
||||
*
|
||||
* java.awt.Component.setLocation() and java.awt.Component.setBounds() for
|
||||
* EmbeddedFrame really don't move it within the native parent. These
|
||||
* methods always locate the embedded frame at (0, 0) for backward
|
||||
* compatibility. To allow moving embedded frames this method was
|
||||
* introduced, and it works just the same way as setLocation() and
|
||||
* setBounds() for usual, non-embedded components.
|
||||
*
|
||||
* Using usual get/setLocation() and get/setBounds() together with this new
|
||||
* method is not recommended.
|
||||
*/
|
||||
void (JNICALL *SetBounds) (JNIEnv *env, jobject embeddedFrame,
|
||||
jint x, jint y, jint w, jint h);
|
||||
/**
|
||||
* Since 9
|
||||
* Synthesize a native message to activate or deactivate an EmbeddedFrame
|
||||
* window depending on the value of parameter doActivate, if "true"
|
||||
* activates the window; otherwise, deactivates the window.
|
||||
*
|
||||
* The embedded frame should be created by CreateEmbeddedFrame() method, or
|
||||
* this function will not have any effect.
|
||||
*/
|
||||
void (JNICALL *SynthesizeWindowActivation) (JNIEnv *env,
|
||||
jobject embeddedFrame, jboolean doActivate);
|
||||
} JAWT;
|
||||
|
||||
/*
|
||||
* Get the AWT native structure. This function returns JNI_FALSE if
|
||||
* an error occurs.
|
||||
*/
|
||||
_JNI_IMPORT_OR_EXPORT_
|
||||
jboolean JNICALL JAWT_GetAWT(JNIEnv* env, JAWT* awt);
|
||||
|
||||
/*
|
||||
* Specify one of these constants as the JAWT.version
|
||||
* Specifying an earlier version will limit the available functions to
|
||||
* those provided in that earlier version of JAWT.
|
||||
* See the "Since" note on each API. Methods with no "Since"
|
||||
* may be presumed to be present in JAWT_VERSION_1_3.
|
||||
*/
|
||||
#define JAWT_VERSION_1_3 0x00010003
|
||||
#define JAWT_VERSION_1_4 0x00010004
|
||||
#define JAWT_VERSION_1_7 0x00010007
|
||||
#define JAWT_VERSION_9 0x00090000
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* !_JAVASOFT_JAWT_H_ */
|
||||
|
||||
</pre>
|
||||
<p>jawt_md.h (Linux/Solaris/X11 operating environment version)</p>
|
||||
<pre>
|
||||
#ifndef _JAVASOFT_JAWT_MD_H_
|
||||
#define _JAVASOFT_JAWT_MD_H_
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/Intrinsic.h>
|
||||
#include "jawt.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* X11-specific declarations for AWT native interface.
|
||||
* See notes in jawt.h for an example of use.
|
||||
*/
|
||||
typedef struct jawt_X11DrawingSurfaceInfo {
|
||||
Drawable drawable;
|
||||
Display* display;
|
||||
VisualID visualID;
|
||||
Colormap colormapID;
|
||||
int depth;
|
||||
} JAWT_X11DrawingSurfaceInfo;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !_JAVASOFT_JAWT_MD_H_ */
|
||||
</pre>
|
||||
<p>jawt_md.h (Microsoft Windows version)</p>
|
||||
<pre>
|
||||
#ifndef _JAVASOFT_JAWT_MD_H_
|
||||
#define _JAVASOFT_JAWT_MD_H_
|
||||
|
||||
#include <windows.h>
|
||||
#include "jawt.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Microsoft Windows specific declarations for AWT native interface.
|
||||
* See notes in jawt.h for an example of use.
|
||||
*/
|
||||
typedef struct jawt_Win32DrawingSurfaceInfo {
|
||||
/* Native window, DDB, or DIB handle */
|
||||
union {
|
||||
HWND hwnd;
|
||||
HBITMAP hbitmap;
|
||||
void* pbits;
|
||||
};
|
||||
/*
|
||||
* This HDC should always be used instead of the HDC returned from
|
||||
* BeginPaint() or any calls to GetDC().
|
||||
*/
|
||||
HDC hdc;
|
||||
HPALETTE hpalette;
|
||||
} JAWT_Win32DrawingSurfaceInfo;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !_JAVASOFT_JAWT_MD_H_ */
|
||||
</pre>
|
||||
<p>jawt_md.h (MacOS version)</p>
|
||||
<pre>
|
||||
#ifndef _JAVASOFT_JAWT_MD_H_
|
||||
#define _JAVASOFT_JAWT_MD_H_
|
||||
|
||||
#include "jawt.h"
|
||||
|
||||
#ifdef __OBJC__
|
||||
#import <QuartzCore/CALayer.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* MacOS specific declarations for AWT native interface.
|
||||
* See notes in jawt.h for an example of use.
|
||||
*/
|
||||
|
||||
/*
|
||||
* When calling JAWT_GetAWT with a JAWT version less than 1.7, you must pass this
|
||||
* flag or you will not be able to get a valid drawing surface and JAWT_GetAWT will
|
||||
* return false. This is to maintain compatibility with applications that used the
|
||||
* interface with Java 6 which had multiple rendering models. This flag is not necessary
|
||||
* when JAWT version 1.7 or greater is used as this is the only supported rendering mode.
|
||||
*
|
||||
* Example:
|
||||
* JAWT awt;
|
||||
* awt.version = JAWT_VERSION_1_4 | JAWT_MACOSX_USE_CALAYER;
|
||||
* jboolean success = JAWT_GetAWT(env, &awt);
|
||||
*/
|
||||
#define JAWT_MACOSX_USE_CALAYER 0x80000000
|
||||
|
||||
/*
|
||||
* When the native Cocoa toolkit is in use, the pointer stored in
|
||||
* JAWT_DrawingSurfaceInfo->platformInfo points to a NSObject that conforms to the
|
||||
* JAWT_SurfaceLayers protocol. Setting the layer property of this object will cause the
|
||||
* specified layer to be overlaid on the Components rectangle. If the window the
|
||||
* Component belongs to has a CALayer attached to it, this layer will be accessible via
|
||||
* the windowLayer property.
|
||||
*/
|
||||
#ifdef __OBJC__
|
||||
@protocol JAWT_SurfaceLayers
|
||||
@property (readwrite, retain) CALayer *layer;
|
||||
@property (readonly) CALayer *windowLayer;
|
||||
@end
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !_JAVASOFT_JAWT_MD_H_ */
|
||||
</pre>
|
||||
<!-- Body text ends here -->
|
||||
</body>
|
||||
</html>
|
||||
@ -24,27 +24,27 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Defines the RMI Connector for the Java Management Extensions (JMX) Remote API.
|
||||
* <P>
|
||||
* The {@linkplain javax.management.remote.rmi RMI connector} is a connector
|
||||
* for the JMX Remote API that uses RMI to transmit client requests to a remote
|
||||
* MBean server.
|
||||
* Defines the {@linkplain javax.management.remote.rmi RMI connector}
|
||||
* for the Java Management Extensions (JMX) Remote API.
|
||||
*
|
||||
* <dl style="font-family:'DejaVu Sans', Arial, Helvetica, sans serif">
|
||||
* <dt class="simpleTagLabel">Providers:</dt>
|
||||
* <dd>This module provides
|
||||
* {@link javax.management.remote.JMXConnectorProvider} service
|
||||
* that creates the JMX connector clients using RMI protocol.
|
||||
* Instances of {@code JMXConnector} can be obtained via the
|
||||
* {@link javax.management.remote.JMXConnectorFactory#newJMXConnector
|
||||
* JMXConnectorFactory.newJMXConnector} factory method.
|
||||
* It also provides {@link javax.management.remote.JMXConnectorServerProvider} service
|
||||
* that creates the JMX connector servers using RMI protocol.
|
||||
* Instances of {@code JMXConnectorServer} can be obtained via the
|
||||
* {@link javax.management.remote.JMXConnectorServerFactory#newJMXConnectorServer
|
||||
* JMXConnectorServerFactory.newJMXConnectorServer} factory method.
|
||||
* </dd>
|
||||
* </dl>
|
||||
*
|
||||
* @provides javax.management.remote.JMXConnectorProvider
|
||||
* A provider of {@code JMXConnector} for the RMI protocol.<br>
|
||||
* Instances of {@code JMXConnector} using the RMI protocol
|
||||
* are usually created by the {@link
|
||||
* javax.management.remote.JMXConnectorFactory} which will locate
|
||||
* and load the appropriate {@code JMXConnectorProvider} service
|
||||
* implementation for the given protocol.
|
||||
*
|
||||
* @provides javax.management.remote.JMXConnectorServerProvider
|
||||
* A provider of {@code JMXConnectorServer} for the RMI protocol.<br>
|
||||
* Instances of {@code JMXConnectorServer} using the RMI protocol
|
||||
* are usually created by the {@link
|
||||
* javax.management.remote.JMXConnectorServerFactory} which will locate
|
||||
* and load the appropriate {@code JMXConnectorServerProvider} service
|
||||
* implementation for the given protocol.
|
||||
*
|
||||
* @moduleGraph
|
||||
* @since 9
|
||||
|
||||
@ -29,6 +29,9 @@
|
||||
* The JMX API consists of interfaces for monitoring and management of the
|
||||
* JVM and other components in the Java runtime.
|
||||
*
|
||||
* @uses javax.management.remote.JMXConnectorProvider
|
||||
* @uses javax.management.remote.JMXConnectorServerProvider
|
||||
*
|
||||
* @moduleGraph
|
||||
* @since 9
|
||||
*/
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2017, 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,6 +28,8 @@ package com.sun.jndi.ldap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Vector;
|
||||
import java.util.EventObject;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.naming.*;
|
||||
import javax.naming.event.*;
|
||||
@ -204,31 +206,35 @@ final class EventSupport {
|
||||
* Removes {@code l} from all notifiers in this context.
|
||||
*/
|
||||
synchronized void removeNamingListener(NamingListener l) {
|
||||
if (debug) System.err.println("EventSupport removing listener");
|
||||
|
||||
if (debug) {
|
||||
System.err.println("EventSupport removing listener");
|
||||
}
|
||||
// Go through list of notifiers, remove 'l' from each.
|
||||
// If 'l' is notifier's only listener, remove notifier too.
|
||||
for (NamingEventNotifier notifier : notifiers.values()) {
|
||||
Iterator<NamingEventNotifier> iterator = notifiers.values().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
NamingEventNotifier notifier = iterator.next();
|
||||
if (notifier != null) {
|
||||
if (debug)
|
||||
if (debug) {
|
||||
System.err.println("EventSupport removing listener from notifier");
|
||||
}
|
||||
notifier.removeNamingListener(l);
|
||||
if (!notifier.hasNamingListeners()) {
|
||||
if (debug)
|
||||
if (debug) {
|
||||
System.err.println("EventSupport stopping notifier");
|
||||
}
|
||||
notifier.stop();
|
||||
notifiers.remove(notifier.info);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove from list of unsolicited notifier
|
||||
if (debug) System.err.println("EventSupport removing unsolicited: " +
|
||||
unsolicited);
|
||||
if (debug) {
|
||||
System.err.println("EventSupport removing unsolicited: " + unsolicited);
|
||||
}
|
||||
if (unsolicited != null) {
|
||||
unsolicited.removeElement(l);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
synchronized boolean hasUnsolicited() {
|
||||
|
||||
@ -26,6 +26,8 @@
|
||||
/**
|
||||
* Defines the Preferences API.
|
||||
*
|
||||
* @uses java.util.prefs.PreferencesFactory
|
||||
*
|
||||
* @moduleGraph
|
||||
* @since 9
|
||||
*/
|
||||
@ -35,4 +37,3 @@ module java.prefs {
|
||||
exports java.util.prefs;
|
||||
uses java.util.prefs.PreferencesFactory;
|
||||
}
|
||||
|
||||
|
||||
@ -26,6 +26,21 @@
|
||||
/**
|
||||
* Defines the Remote Method Invocation (RMI) API.
|
||||
*
|
||||
* <p> The JDK implementation of this module includes
|
||||
* the <em>{@index rmiregistry rmiregistry tool}</em> tool to start a remote
|
||||
* object registry, and the <em>{@index rmid rmid tool}</em> tool to start
|
||||
* the activation system daemon.
|
||||
*
|
||||
* <p>
|
||||
* <dl style="font-family:'DejaVu Sans', Arial, Helvetica, sans serif">
|
||||
* <dt class="simpleTagLabel">Tool Guides:</dt>
|
||||
* <dd> {@extLink rmiregistry_tool_reference rmiregistry},
|
||||
* {@extLink rmid_tool_reference rmid}
|
||||
* </dd>
|
||||
* </dl>
|
||||
*
|
||||
* @uses java.rmi.server.RMIClassLoaderSpi
|
||||
*
|
||||
* @moduleGraph
|
||||
* @since 9
|
||||
*/
|
||||
|
||||
@ -26,6 +26,19 @@
|
||||
/**
|
||||
* Defines the Scripting API.
|
||||
*
|
||||
* <p> The JDK implementation of this module includes a language-independent
|
||||
* command-line script shell, <em>{@index jrunscript jrunscript tool}</em>,
|
||||
* that supports executing JavaScript and other languages if its corresponding
|
||||
* script engine is installed.
|
||||
*
|
||||
* <p>
|
||||
* <dl style="font-family:'DejaVu Sans', Arial, Helvetica, sans serif">
|
||||
* <dt class="simpleTagLabel">Tool Guides:
|
||||
* <dd> {@extLink jrunscript_tool_reference jrunscript}</dd>
|
||||
* </dl>
|
||||
*
|
||||
* @uses javax.script.ScriptEngineFactory
|
||||
*
|
||||
* @moduleGraph
|
||||
* @since 9
|
||||
*/
|
||||
@ -33,4 +46,3 @@ module java.scripting {
|
||||
exports javax.script;
|
||||
uses javax.script.ScriptEngineFactory;
|
||||
}
|
||||
|
||||
|
||||
@ -34,6 +34,7 @@
|
||||
*/
|
||||
@SuppressWarnings({"deprecation",
|
||||
"removal"}) // java.corba and other modules
|
||||
@Deprecated(since="9", forRemoval=true)
|
||||
module java.se.ee {
|
||||
|
||||
requires transitive java.se;
|
||||
|
||||
@ -29,6 +29,15 @@
|
||||
* The modules defining CORBA and Java EE APIs are not required by
|
||||
* this module, but they are required by {@code java.se.ee}.
|
||||
*
|
||||
* <dl style="font-family:'DejaVu Sans', Arial, Helvetica, sans serif">
|
||||
* <dt class="simpleTagLabel">Optional for Java SE Platform:</dt>
|
||||
* <dd>
|
||||
* <a href="../specs/jni/index.html">Java Native Interface (JNI)</a><br>
|
||||
* <a href="../specs/jvmti.html">Java Virtual Machine Tool Interface (JVM TI)</a><br>
|
||||
* <a href="../specs/jdwp/jdwp-spec.html">Java Debug Wire Protocol (JDWP)</a><br>
|
||||
* </dd>
|
||||
* </dl>
|
||||
*
|
||||
* @moduleGraph
|
||||
* @since 9
|
||||
*/
|
||||
|
||||
@ -26,6 +26,8 @@
|
||||
/**
|
||||
* Defines the JDBC RowSet API.
|
||||
*
|
||||
* @uses javax.sql.rowset.RowSetFactory
|
||||
*
|
||||
* @moduleGraph
|
||||
* @since 9
|
||||
*/
|
||||
@ -39,4 +41,3 @@ module java.sql.rowset {
|
||||
exports javax.sql.rowset.spi;
|
||||
uses javax.sql.rowset.RowSetFactory;
|
||||
}
|
||||
|
||||
|
||||
@ -26,6 +26,8 @@
|
||||
/**
|
||||
* Defines the JDBC API.
|
||||
*
|
||||
* @uses java.sql.Driver
|
||||
*
|
||||
* @moduleGraph
|
||||
* @since 9
|
||||
*/
|
||||
@ -38,4 +40,3 @@ module java.sql {
|
||||
exports javax.transaction.xa;
|
||||
uses java.sql.Driver;
|
||||
}
|
||||
|
||||
|
||||
@ -26,6 +26,8 @@
|
||||
/**
|
||||
* Defines the attach API.
|
||||
*
|
||||
* @uses com.sun.tools.attach.spi.AttachProvider
|
||||
*
|
||||
* @moduleGraph
|
||||
* @since 9
|
||||
*/
|
||||
@ -39,4 +41,3 @@ module jdk.attach {
|
||||
uses com.sun.tools.attach.spi.AttachProvider;
|
||||
provides com.sun.tools.attach.spi.AttachProvider with sun.tools.attach.AttachProviderImpl;
|
||||
}
|
||||
|
||||
|
||||
@ -24,9 +24,11 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* {@link java.nio.charset.Charset Charset} provider for the charsets that
|
||||
* Provides {@link java.nio.charset.Charset charsets} that
|
||||
* are not in {@code java.base} (mostly double byte and IBM charsets).
|
||||
*
|
||||
* @provides java.nio.charset.spi.CharsetProvider
|
||||
*
|
||||
* @moduleGraph
|
||||
* @since 9
|
||||
*/
|
||||
@ -34,4 +36,3 @@ module jdk.charsets {
|
||||
provides java.nio.charset.spi.CharsetProvider
|
||||
with sun.nio.cs.ext.ExtendedCharsets;
|
||||
}
|
||||
|
||||
|
||||
@ -24,7 +24,9 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* The SunPKCS11 security provider.
|
||||
* Provides the implementation of the SunPKCS11 security provider.
|
||||
*
|
||||
* @provides java.security.Provider
|
||||
*
|
||||
* @moduleGraph
|
||||
* @since 9
|
||||
@ -34,4 +36,3 @@ module jdk.crypto.cryptoki {
|
||||
requires jdk.crypto.ec;
|
||||
provides java.security.Provider with sun.security.pkcs11.SunPKCS11;
|
||||
}
|
||||
|
||||
|
||||
@ -24,7 +24,9 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* The SunEC security provider.
|
||||
* Provides the implementation of the SunEC security provider.
|
||||
*
|
||||
* @provides java.security.Provider
|
||||
*
|
||||
* @moduleGraph
|
||||
* @since 9
|
||||
@ -32,4 +34,3 @@
|
||||
module jdk.crypto.ec {
|
||||
provides java.security.Provider with sun.security.ec.SunEC;
|
||||
}
|
||||
|
||||
|
||||
@ -24,8 +24,9 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* The SunMSCAPI security provider.
|
||||
* Provides the implementation of the SunMSCAPI security provider.
|
||||
*
|
||||
* @provides java.security.Provider
|
||||
* @moduleGraph
|
||||
* @since 9
|
||||
*/
|
||||
|
||||
@ -24,8 +24,9 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* The OracleUCrypto security provider.
|
||||
* Provides the implementation of the OracleUCrypto security provider.
|
||||
*
|
||||
* @provides java.security.Provider
|
||||
* @moduleGraph
|
||||
* @since 9
|
||||
*/
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implementation of the edit pad service.
|
||||
* Provides the implementation of the edit pad service used by {@link jdk.jshell}.
|
||||
*
|
||||
* @moduleGraph
|
||||
* @since 9
|
||||
|
||||
@ -26,6 +26,8 @@
|
||||
/**
|
||||
* Defines the JDK-specific API for HTTP server.
|
||||
*
|
||||
* @uses com.sun.net.httpserver.spi.HttpServerProvider
|
||||
*
|
||||
* @moduleGraph
|
||||
* @since 9
|
||||
*/
|
||||
@ -35,4 +37,3 @@ module jdk.httpserver {
|
||||
exports com.sun.net.httpserver.spi;
|
||||
uses com.sun.net.httpserver.spi.HttpServerProvider;
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2017, 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
|
||||
@ -111,47 +111,56 @@ class Http2Connection {
|
||||
*/
|
||||
|
||||
|
||||
// A small class that allows to control the state of
|
||||
// the connection preface. This is just a thin wrapper
|
||||
// over a CountDownLatch.
|
||||
private final class PrefaceController {
|
||||
// A small class that allows to control frames with respect to the state of
|
||||
// the connection preface. Any data received before the connection
|
||||
// preface is sent will be buffered.
|
||||
private final class FramesController {
|
||||
volatile boolean prefaceSent;
|
||||
private final CountDownLatch latch = new CountDownLatch(1);
|
||||
volatile List<ByteBufferReference> pending;
|
||||
|
||||
// This method returns immediately if the preface is sent,
|
||||
// and blocks until the preface is sent if not.
|
||||
// In the common case this where the preface is already sent
|
||||
// this will cost not more than a volatile read.
|
||||
void waitUntilPrefaceSent() {
|
||||
boolean processReceivedData(FramesDecoder decoder, ByteBufferReference buf)
|
||||
throws IOException
|
||||
{
|
||||
// if preface is not sent, buffers data in the pending list
|
||||
if (!prefaceSent) {
|
||||
try {
|
||||
// If the preface is not sent then await on the latch
|
||||
Log.logTrace("Waiting until connection preface is sent");
|
||||
latch.await();
|
||||
Log.logTrace("Preface sent: resuming reading");
|
||||
assert prefaceSent;
|
||||
} catch (InterruptedException e) {
|
||||
String msg = Utils.stackTrace(e);
|
||||
Log.logTrace(msg);
|
||||
shutdown(e);
|
||||
synchronized (this) {
|
||||
if (!prefaceSent) {
|
||||
if (pending == null) pending = new ArrayList<>();
|
||||
pending.add(buf);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Preface is sent. Checks for pending data and flush it.
|
||||
// We rely on this method being called from within the readlock,
|
||||
// so we know that no other thread could execute this method
|
||||
// concurrently while we're here.
|
||||
// This ensures that later incoming buffers will not
|
||||
// be processed before we have flushed the pending queue.
|
||||
// No additional synchronization is therefore necessary here.
|
||||
List<ByteBufferReference> pending = this.pending;
|
||||
this.pending = null;
|
||||
if (pending != null) {
|
||||
// flush pending data
|
||||
for (ByteBufferReference b : pending) {
|
||||
decoder.decode(b);
|
||||
}
|
||||
}
|
||||
|
||||
// push the received buffer to the frames decoder.
|
||||
decoder.decode(buf);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Mark that the connection preface is sent
|
||||
void markPrefaceSent() {
|
||||
assert !prefaceSent;
|
||||
prefaceSent = true;
|
||||
// Release the latch. If asyncReceive was scheduled it will
|
||||
// be waiting for the release and will be woken up by this
|
||||
// call. If not, then the semaphore will no longer be used after
|
||||
// this.
|
||||
latch.countDown();
|
||||
synchronized (this) {
|
||||
prefaceSent = true;
|
||||
}
|
||||
}
|
||||
|
||||
boolean isPrefaceSent() {
|
||||
return prefaceSent;
|
||||
}
|
||||
}
|
||||
|
||||
volatile boolean closed;
|
||||
@ -176,7 +185,7 @@ class Http2Connection {
|
||||
* Each of this connection's Streams MUST use this controller.
|
||||
*/
|
||||
private final WindowController windowController = new WindowController();
|
||||
private final PrefaceController prefaceController = new PrefaceController();
|
||||
private final FramesController framesController = new FramesController();
|
||||
final WindowUpdateSender windowUpdater;
|
||||
|
||||
static final int DEFAULT_FRAME_SIZE = 16 * 1024;
|
||||
@ -409,11 +418,11 @@ class Http2Connection {
|
||||
// SettingsFrame sent by the server) before the connection
|
||||
// preface is fully sent might result in the server
|
||||
// sending a GOAWAY frame with 'invalid_preface'.
|
||||
prefaceController.waitUntilPrefaceSent();
|
||||
synchronized (readlock) {
|
||||
assert prefaceController.isPrefaceSent();
|
||||
try {
|
||||
framesDecoder.decode(buffer);
|
||||
// the readlock ensures that the order of incoming buffers
|
||||
// is preserved.
|
||||
framesController.processReceivedData(framesDecoder, buffer);
|
||||
} catch (Throwable e) {
|
||||
String msg = Utils.stackTrace(e);
|
||||
Log.logTrace(msg);
|
||||
@ -646,7 +655,8 @@ class Http2Connection {
|
||||
Log.logFrames(sf, "OUT");
|
||||
// send preface bytes and SettingsFrame together
|
||||
connection.write(ref.get());
|
||||
|
||||
// mark preface sent.
|
||||
framesController.markPrefaceSent();
|
||||
Log.logTrace("PREFACE_BYTES sent");
|
||||
Log.logTrace("Settings Frame sent");
|
||||
|
||||
@ -654,8 +664,10 @@ class Http2Connection {
|
||||
// minus the initial 64 K specified in protocol
|
||||
final int len = client2.client().getReceiveBufferSize() - (64 * 1024 - 1);
|
||||
windowUpdater.sendWindowUpdate(len);
|
||||
// there will be an ACK to the windows update - which should
|
||||
// cause any pending data stored before the preface was sent to be
|
||||
// flushed (see PrefaceController).
|
||||
Log.logTrace("finished sending connection preface");
|
||||
prefaceController.markPrefaceSent();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -344,7 +344,13 @@ class HttpClientImpl extends HttpClient {
|
||||
c.configureBlocking(false);
|
||||
SelectionKey key = c.keyFor(selector);
|
||||
SelectorAttachment sa;
|
||||
if (key == null) {
|
||||
if (key == null || !key.isValid()) {
|
||||
if (key != null) {
|
||||
// key is canceled.
|
||||
// invoke selectNow() to purge it
|
||||
// before registering the new event.
|
||||
selector.selectNow();
|
||||
}
|
||||
sa = new SelectorAttachment(c, selector);
|
||||
} else {
|
||||
sa = (SelectorAttachment) key.attachment();
|
||||
|
||||
@ -62,6 +62,7 @@ class PlainHttpConnection extends HttpConnection implements AsyncConnection {
|
||||
private volatile Consumer<ByteBufferReference> asyncReceiver;
|
||||
private volatile Consumer<Throwable> errorReceiver;
|
||||
private volatile Supplier<ByteBufferReference> readBufferSupplier;
|
||||
private boolean asyncReading;
|
||||
|
||||
private final AsyncWriteQueue asyncOutputQ = new AsyncWriteQueue(this::asyncOutput);
|
||||
|
||||
@ -70,6 +71,9 @@ class PlainHttpConnection extends HttpConnection implements AsyncConnection {
|
||||
@Override
|
||||
public void startReading() {
|
||||
try {
|
||||
synchronized(reading) {
|
||||
asyncReading = true;
|
||||
}
|
||||
client.registerEvent(new ReadEvent());
|
||||
} catch (IOException e) {
|
||||
shutdown();
|
||||
@ -78,6 +82,9 @@ class PlainHttpConnection extends HttpConnection implements AsyncConnection {
|
||||
|
||||
@Override
|
||||
public void stopAsyncReading() {
|
||||
synchronized(reading) {
|
||||
asyncReading = false;
|
||||
}
|
||||
client.cancelRegistration(chan);
|
||||
}
|
||||
|
||||
@ -279,7 +286,7 @@ class PlainHttpConnection extends HttpConnection implements AsyncConnection {
|
||||
void asyncRead() {
|
||||
synchronized (reading) {
|
||||
try {
|
||||
while (true) {
|
||||
while (asyncReading) {
|
||||
ByteBufferReference buf = readBufferSupplier.get();
|
||||
int n = chan.read(buf.get());
|
||||
if (n == -1) {
|
||||
@ -325,7 +332,7 @@ class PlainHttpConnection extends HttpConnection implements AsyncConnection {
|
||||
return -1;
|
||||
}
|
||||
Utils.flipToMark(buf, mark);
|
||||
String s = "Receive (" + n + " bytes) ";
|
||||
// String s = "Receive (" + n + " bytes) ";
|
||||
//debugPrint(s, buf);
|
||||
return n;
|
||||
}
|
||||
@ -393,6 +400,10 @@ class PlainHttpConnection extends HttpConnection implements AsyncConnection {
|
||||
shutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + "/" + chan;
|
||||
}
|
||||
}
|
||||
|
||||
// used in blocking channels only
|
||||
@ -422,6 +433,11 @@ class PlainHttpConnection extends HttpConnection implements AsyncConnection {
|
||||
public void abort() {
|
||||
close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + "/" + chan;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -447,7 +463,8 @@ class PlainHttpConnection extends HttpConnection implements AsyncConnection {
|
||||
CompletableFuture<Void> whenReceivingResponse() {
|
||||
CompletableFuture<Void> cf = new MinimalFuture<>();
|
||||
try {
|
||||
client.registerEvent(new ReceiveResponseEvent(cf));
|
||||
ReceiveResponseEvent evt = new ReceiveResponseEvent(cf);
|
||||
client.registerEvent(evt);
|
||||
} catch (IOException e) {
|
||||
cf.completeExceptionally(e);
|
||||
}
|
||||
|
||||
@ -803,7 +803,9 @@ class Stream<T> extends ExchangeImpl<T> {
|
||||
completeResponseExceptionally(e);
|
||||
try {
|
||||
// will send a RST_STREAM frame
|
||||
connection.resetStream(streamid, ResetFrame.CANCEL);
|
||||
if (streamid != 0) {
|
||||
connection.resetStream(streamid, ResetFrame.CANCEL);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
Log.logError(ex);
|
||||
}
|
||||
|
||||
@ -25,7 +25,21 @@
|
||||
|
||||
/**
|
||||
* Defines tools for manipulating Java Archive (JAR) files,
|
||||
* including the jar and jarsigner tools.
|
||||
* including the <em>{@index jar jar tool}</em> and
|
||||
* <em>{@index jarsigner jarsigner tool}</em> tools.
|
||||
*
|
||||
* <p> This module provides the equivalent of command-line access to
|
||||
* <em>jar</em> via the {@link java.util.spi.ToolProvider ToolProvider} SPI.
|
||||
* Instances of the tool can be obtained by calling
|
||||
* {@link java.util.spi.ToolProvider#findFirst ToolProvider.findFirst}
|
||||
* or the {@link java.util.ServiceLoader service loader} with the name
|
||||
* {@code "jar"}.
|
||||
*
|
||||
* <dl style="font-family:'DejaVu Sans', Arial, Helvetica, sans serif">
|
||||
* <dt class="simpleTagLabel">Tool Guides:
|
||||
* <dd>{@extLink jar_tool_reference jar},
|
||||
* {@extLink jarsigner_tool_reference jarsigner}
|
||||
* </dl>
|
||||
*
|
||||
* @moduleGraph
|
||||
* @since 9
|
||||
@ -36,4 +50,3 @@ module jdk.jartool {
|
||||
|
||||
provides java.util.spi.ToolProvider with sun.tools.jar.JarToolProvider;
|
||||
}
|
||||
|
||||
|
||||
@ -24,8 +24,20 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Defines tools for diagnostics and troubleshooting a JVM,
|
||||
* including the jcmd, jps, jstat and other diagnostics tools.
|
||||
* Defines tools for diagnostics and troubleshooting a JVM
|
||||
* such as the <em>{@index jcmd jcmd tool}</em>, <em>{@index jps jps tool}</em>,
|
||||
* <em>{@index jstat jstat tool}</em> tools.
|
||||
*
|
||||
* <dl style="font-family:'DejaVu Sans', Arial, Helvetica, sans serif">
|
||||
* <dt class="simpleTagLabel">Tool Guides:
|
||||
* <dd>
|
||||
* {@extLink jcmd_tool_reference jcmd},
|
||||
* {@extLink jinfo_tool_reference jinfo},
|
||||
* {@extLink jmap_tool_reference jmap},
|
||||
* {@extLink jps_tool_reference jps},
|
||||
* {@extLink jstack_tool_reference jstack},
|
||||
* {@extLink jstat_tool_reference jstat}
|
||||
* </dl>
|
||||
*
|
||||
* @moduleGraph
|
||||
* @since 9
|
||||
|
||||
@ -24,8 +24,16 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Defines the JMX graphical tool, jconsole, for monitoring and managing
|
||||
* a running application.
|
||||
* Defines the JMX graphical tool, <em>{@index jconsole jconsole}</em>,
|
||||
* for monitoring and managing a running application.
|
||||
*
|
||||
* <dl style="font-family:'DejaVu Sans', Arial, Helvetica, sans serif">
|
||||
* <dt class="simpleTagLabel">Tool Guides:
|
||||
* <dd>{@extLink jconsole_tool_reference jconsole},
|
||||
* {@extLink using_jconsole Using JConsole}
|
||||
* </dl>
|
||||
*
|
||||
* @uses com.sun.tools.jconsole.JConsolePlugin
|
||||
*
|
||||
* @moduleGraph
|
||||
* @since 9
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user