Merge
This commit is contained in:
commit
556157743b
@ -239,6 +239,48 @@ TARGETS += $(BUILD_LIBZIP)
|
||||
|
||||
##########################################################################################
|
||||
|
||||
$(eval $(call SetupNativeCompilation,BUILD_LIBJIMAGE, \
|
||||
LIBRARY := jimage, \
|
||||
OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
|
||||
OPTIMIZATION := LOW, \
|
||||
SRC := $(JDK_TOPDIR)/src/java.base/share/native/libjimage \
|
||||
$(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/libjimage, \
|
||||
EXCLUDES := $(LIBJIMAGE_EXCLUDES), \
|
||||
CFLAGS := $(CFLAGS_JDKLIB) \
|
||||
$(JIMAGELIB_CPPFLAGS) \
|
||||
-I$(JDK_TOPDIR)/src/java.base/share/native/libjava \
|
||||
-I$(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/libjava \
|
||||
-I$(JDK_TOPDIR)/src/java.base/share/native/libjimage \
|
||||
-I$(SUPPORT_OUTPUTDIR)/headers/java.base, \
|
||||
CFLAGS_unix := -UDEBUG, \
|
||||
MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libjimage/mapfile-vers, \
|
||||
LDFLAGS := $(LDFLAGS_JDKLIB) \
|
||||
$(call SET_SHARED_LIBRARY_ORIGIN) \
|
||||
$(EXPORT_JIMAGE_FUNCS), \
|
||||
LDFLAGS_windows := -export:JIMAGE_Open -export:JIMAGE_Close \
|
||||
-export:JIMAGE_PackageToModule \
|
||||
-export:JIMAGE_FindResource -export:JIMAGE_GetResource \
|
||||
-export:JIMAGE_ResourceIterator, \
|
||||
LDFLAGS_SUFFIX_unix := -ljvm -ldl $(LIBCXX), \
|
||||
LDFLAGS_SUFFIX_linux := , \
|
||||
LDFLAGS_SUFFIX_solaris := -lc, \
|
||||
LDFLAGS_SUFFIX_aix := ,\
|
||||
LDFLAGS_SUFFIX_macosx := -lc++, \
|
||||
LDFLAGS_SUFFIX_windows := jvm.lib, \
|
||||
VERSIONINFO_RESOURCE := $(GLOBAL_VERSION_INFO_RESOURCE), \
|
||||
RC_FLAGS := $(RC_FLAGS) \
|
||||
-D "JDK_FNAME=jimage.dll" \
|
||||
-D "JDK_INTERNAL_NAME=jimage" \
|
||||
-D "JDK_FTYPE=0x2L", \
|
||||
OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libjimage, \
|
||||
DEBUG_SYMBOLS := $(DEBUG_ALL_BINARIES)))
|
||||
|
||||
$(BUILD_LIBJIMAGE): $(BUILD_LIBJAVA)
|
||||
|
||||
TARGETS += $(BUILD_LIBJIMAGE)
|
||||
|
||||
##########################################################################################
|
||||
|
||||
LIBJLI_SRC_DIRS := $(call FindSrcDirsForLib, java.base, jli)
|
||||
|
||||
LIBJLI_CFLAGS := $(CFLAGS_JDKLIB)
|
||||
|
@ -240,16 +240,6 @@ SUNWprivate_1.1 {
|
||||
Java_java_util_TimeZone_getSystemTimeZoneID;
|
||||
Java_java_util_TimeZone_getSystemGMTOffsetID;
|
||||
Java_java_util_concurrent_atomic_AtomicLong_VMSupportsCS8;
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_openImage;
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_closeImage;
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_getIndexAddress;
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_getDataAddress;
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_read;
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_readCompressed;
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_getStringBytes;
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_getAttributes;
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_findAttributes;
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_attributeOffsets;
|
||||
Java_sun_misc_MessageUtils_toStderr;
|
||||
Java_sun_misc_MessageUtils_toStdout;
|
||||
Java_sun_misc_NativeSignalHandler_handle0;
|
||||
|
55
jdk/make/mapfiles/libjimage/mapfile-vers
Normal file
55
jdk/make/mapfiles/libjimage/mapfile-vers
Normal file
@ -0,0 +1,55 @@
|
||||
#
|
||||
# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
# Define public interface.
|
||||
|
||||
SUNWprivate_1.1 {
|
||||
global:
|
||||
JNI_OnLoad;
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_openImage;
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_closeImage;
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_getIndexAddress;
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_getDataAddress;
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_read;
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_readCompressed;
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_getStringBytes;
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_getAttributes;
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_findAttributes;
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_attributeOffsets;
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1Open;
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1Close;
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1FindResource;
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1GetResource;
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1PackageToModule;
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1Resources;
|
||||
JIMAGE_Open;
|
||||
JIMAGE_Close;
|
||||
JIMAGE_PackageToModule;
|
||||
JIMAGE_FindResource;
|
||||
JIMAGE_GetResource;
|
||||
JIMAGE_ResourceIterator;
|
||||
local:
|
||||
*;
|
||||
};
|
@ -12,6 +12,7 @@ text: .text%isMetaName: OUTPUTDIR/zip_util.o;
|
||||
text: .text%addMetaName: OUTPUTDIR/zip_util.o;
|
||||
text: .text%ZIP_FindEntry;
|
||||
text: .text%ZIP_GetEntry;
|
||||
text: .text%ZIP_InflateFully;
|
||||
text: .text%ZIP_Lock;
|
||||
text: .text%ZIP_Unlock;
|
||||
text: .text%ZIP_FreeEntry;
|
||||
|
@ -11,6 +11,7 @@ text: .text%isMetaName: OUTPUTDIR/zip_util.o;
|
||||
text: .text%addMetaName: OUTPUTDIR/zip_util.o;
|
||||
text: .text%ZIP_FindEntry;
|
||||
text: .text%ZIP_GetEntry;
|
||||
text: .text%ZIP_InflateFully;
|
||||
text: .text%ZIP_Lock;
|
||||
text: .text%ZIP_Unlock;
|
||||
text: .text%ZIP_FreeEntry;
|
||||
|
@ -12,6 +12,7 @@ text: .text%isMetaName: OUTPUTDIR/zip_util.o;
|
||||
text: .text%addMetaName: OUTPUTDIR/zip_util.o;
|
||||
text: .text%ZIP_FindEntry;
|
||||
text: .text%ZIP_GetEntry;
|
||||
text: .text%ZIP_InflateFully;
|
||||
text: .text%ZIP_Lock;
|
||||
text: .text%ZIP_Unlock;
|
||||
text: .text%ZIP_FreeEntry;
|
||||
|
@ -63,8 +63,8 @@
|
||||
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~ -->
|
||||
<!-- Call rmic-jmx subtargets -->
|
||||
|
||||
<target name="-rmic-jmx" depends="-init,-rmic-jmx-jrmp,-rmic-jmx-iiop"
|
||||
description="Calls -init,-rmic-jmx-jrmp,-rmic-jmx-iiop"
|
||||
<target name="-rmic-jmx" depends="-init,-rmic-jmx-jrmp"
|
||||
description="Calls -init,-rmic-jmx-jrmp"
|
||||
/>
|
||||
|
||||
|
||||
@ -90,44 +90,6 @@
|
||||
|
||||
</target>
|
||||
|
||||
|
||||
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
|
||||
<!-- Generate RMI IIOP stub class files for remote objects -->
|
||||
|
||||
<target name="-rmic-jmx-iiop" depends="-init,-check-jmx-iiop-uptodate" unless="jmx-iiop-uptodate"
|
||||
description="Generate RMI IIOP stub class files for remote objects. Do not keep generated java files." >
|
||||
|
||||
<rmic base="${classes.dir}"
|
||||
includeAntRuntime="no"
|
||||
includeJavaRuntime="no"
|
||||
stubversion="1.2"
|
||||
iiop="yes"
|
||||
>
|
||||
<include name="javax/management/remote/rmi/RMIConnectionImpl.class" />
|
||||
<include name="javax/management/remote/rmi/RMIServerImpl.class" />
|
||||
</rmic>
|
||||
|
||||
</target>
|
||||
|
||||
|
||||
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
|
||||
<!-- Check if jmx rmic generated IIOP stub and tie class files are up to date -->
|
||||
|
||||
<target name="-check-jmx-iiop-uptodate" depends="-init">
|
||||
|
||||
<uptodate property="jmx-iiop-uptodate"
|
||||
srcfile="${classes.dir}/javax/management/remote/rmi/RMIConnectionImpl.class"
|
||||
targetfile="${classes.dir}/org/omg/stub/javax/management/remote/rmi/_RMIConnectionImpl_Tie.class"
|
||||
/>
|
||||
<uptodate property="jmx-iiop-uptodate"
|
||||
srcfile="${classes.dir}/javax/management/remote/rmi/RMIServerImpl.class"
|
||||
targetfile="${classes.dir}/org/omg/stub/javax/management/remote/rmi/_RMIServerImpl_Tie.class"
|
||||
/>
|
||||
|
||||
<echo message="jmx-iiop-uptodate=${jmx-iiop-uptodate}" />
|
||||
|
||||
</target>
|
||||
|
||||
<target name="-post-compile" depends="-init,-rmic-jmx"
|
||||
description="Jar JMX class files (including RMI stubs)" >
|
||||
<mkdir dir="${dist.dir}/lib"/>
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
@ -32,38 +32,31 @@ include RmicCommon.gmk
|
||||
# Generate RMI stubs
|
||||
#
|
||||
|
||||
# For RMI/IIOP call rmic a second time with -standardPackage option
|
||||
# so that *_tie classes are generated in package without the prefix
|
||||
# org.omg.stub (6375696)
|
||||
JMX_RMI_CLASSES := javax.management.remote.rmi.RMIConnectionImpl \
|
||||
javax.management.remote.rmi.RMIServerImpl
|
||||
GENRMIIIOPCLASSES :=
|
||||
ifneq ($(RMICONNECTOR_IIOP), false)
|
||||
GENRMIIIOPCLASSES := $(RMICONNECTOR_IIOP)
|
||||
endif
|
||||
$(eval $(call SetupRMICompilation,RMI_IIOP, \
|
||||
CLASSES := $(JMX_RMI_CLASSES), \
|
||||
CLASSES_DIR := $(CLASSES_DIR)/java.management, \
|
||||
STUB_CLASSES_DIR := $(STUB_CLASSES_DIR)/java.management, \
|
||||
RUN_V12 := true, \
|
||||
RUN_IIOP := $(GENRMIIIOPCLASSES), \
|
||||
RUN_IIOP_STDPKG := $(GENRMIIIOPCLASSES)))
|
||||
|
||||
# Keep generated RMI/JRMP Stub source files and copy them to RMIC_GENSRC_DIR
|
||||
# so that javadoc can include them in the API (4997471)
|
||||
$(eval $(call SetupRMICompilation,RMI_SRC, \
|
||||
# Generate into gensrc dir where sources get picked up for javadoc, then move the classes
|
||||
# into the stub classes dir.
|
||||
$(eval $(call SetupRMICompilation,RMI_GEN, \
|
||||
CLASSES := $(JMX_RMI_CLASSES), \
|
||||
CLASSES_DIR := $(CLASSES_DIR)/java.management, \
|
||||
STUB_CLASSES_DIR := $(RMIC_GENSRC_DIR)/java.management, \
|
||||
STUB_CLASSES_DIR := $(RMIC_GENSRC_DIR), \
|
||||
RUN_V12 := true, \
|
||||
KEEP_GENERATED := true))
|
||||
KEEP_GENERATED := true, \
|
||||
))
|
||||
|
||||
# Find all classes generated and move them from the gensrc dir to the stub classes dir
|
||||
$(RMIC_GENSRC_DIR)/_classes.moved: $(RMI_GEN)
|
||||
$(eval classfiles := $(shell $(FIND) $(RMIC_GENSRC_DIR) -name "*.class"))
|
||||
$(foreach src, $(classfiles), \
|
||||
$(eval target := $(patsubst $(RMIC_GENSRC_DIR)/%, \
|
||||
$(STUB_CLASSES_DIR)/java.management/%, $(src))) \
|
||||
$(MKDIR) -p $(dir $(target)) ; \
|
||||
$(MV) $(src) $(target) $(NEWLINE))
|
||||
$(TOUCH) $@
|
||||
|
||||
##########################################################################################
|
||||
|
||||
$(RMIC_GENSRC_DIR)/_the.classes.removed: $(RMI_IIOP) $(RMI_SRC)
|
||||
$(FIND) $(RMIC_GENSRC_DIR) -name "*.class" $(FIND_DELETE)
|
||||
$(TOUCH) $@
|
||||
|
||||
all: $(RMIC_GENSRC_DIR)/_the.classes.removed $(RMI_IIOP) $(RMI_SRC)
|
||||
all: $(RMIC_GENSRC_DIR)/_classes.moved $(RMI_GEN)
|
||||
|
||||
.PHONY: all
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -28,6 +28,8 @@ package java.util.zip;
|
||||
import java.nio.ByteBuffer;
|
||||
import sun.nio.ch.DirectBuffer;
|
||||
|
||||
import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
|
||||
/**
|
||||
* A class that can be used to compute the Adler-32 checksum of a data
|
||||
* stream. An Adler-32 checksum is almost as reliable as a CRC-32 but
|
||||
@ -126,8 +128,11 @@ class Adler32 implements Checksum {
|
||||
}
|
||||
|
||||
private native static int update(int adler, int b);
|
||||
|
||||
@HotSpotIntrinsicCandidate
|
||||
private native static int updateBytes(int adler, byte[] b, int off,
|
||||
int len);
|
||||
@HotSpotIntrinsicCandidate
|
||||
private native static int updateByteBuffer(int adler, long addr,
|
||||
int off, int len);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -34,7 +34,7 @@ import java.nio.IntBuffer;
|
||||
import java.util.Comparator;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class BasicImageReader {
|
||||
public class BasicImageReader implements AutoCloseable {
|
||||
private final String imagePath;
|
||||
private final ImageSubstrate substrate;
|
||||
private final ByteOrder byteOrder;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -30,7 +30,18 @@ import java.nio.ByteOrder;
|
||||
import sun.misc.JavaNioAccess;
|
||||
import sun.misc.SharedSecrets;
|
||||
|
||||
final class ImageNativeSubstrate implements ImageSubstrate {
|
||||
public final class ImageNativeSubstrate implements ImageSubstrate {
|
||||
static {
|
||||
java.security.AccessController.doPrivileged(
|
||||
new java.security.PrivilegedAction<Void>() {
|
||||
@Override
|
||||
public Void run() {
|
||||
System.loadLibrary("jimage");
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static final JavaNioAccess NIOACCESS =
|
||||
SharedSecrets.getJavaNioAccess();
|
||||
|
||||
@ -52,6 +63,20 @@ final class ImageNativeSubstrate implements ImageSubstrate {
|
||||
native static long[] findAttributes(long id, byte[] path);
|
||||
native static int[] attributeOffsets(long id);
|
||||
|
||||
public native static long JIMAGE_Open(String path) throws IOException;
|
||||
public native static void JIMAGE_Close(long jimageHandle);
|
||||
public native static long JIMAGE_FindResource(long jimageHandle,
|
||||
String moduleName, String Version, String path,
|
||||
long[] size);
|
||||
public native static long JIMAGE_GetResource(long jimageHandle,
|
||||
long locationHandle, byte[] buffer, long size);
|
||||
// Get an array of names that match; return the count found upto array size
|
||||
public native static int JIMAGE_Resources(long jimageHandle,
|
||||
String[] outputNames);
|
||||
// Return the module name for the package
|
||||
public native static String JIMAGE_PackageToModule(long imageHandle,
|
||||
String packageName);
|
||||
|
||||
static ByteBuffer newDirectByteBuffer(long address, long capacity) {
|
||||
assert capacity < Integer.MAX_VALUE;
|
||||
return NIOACCESS.newDirectByteBuffer(address, (int)capacity, null);
|
||||
|
@ -556,48 +556,6 @@ JVM_AssertionStatusDirectives(JNIEnv *env, jclass unused);
|
||||
JNIEXPORT jboolean JNICALL
|
||||
JVM_SupportsCX8(void);
|
||||
|
||||
/*
|
||||
* jdk.internal.jimage
|
||||
*/
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
JVM_ImageOpen(JNIEnv *env, const char *nativePath, jboolean big_endian);
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
JVM_ImageClose(JNIEnv *env, jlong id);
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
JVM_ImageGetIndexAddress(JNIEnv *env, jlong id);
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
JVM_ImageGetDataAddress(JNIEnv *env,jlong id);
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
JVM_ImageRead(JNIEnv *env, jlong id, jlong offset,
|
||||
unsigned char* uncompressedAddress, jlong uncompressed_size);
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
JVM_ImageReadCompressed(JNIEnv *env, jlong id, jlong offset,
|
||||
unsigned char* compressedBuffer, jlong compressed_size,
|
||||
unsigned char* uncompressedBuffer, jlong uncompressed_size);
|
||||
|
||||
JNIEXPORT const char* JNICALL
|
||||
JVM_ImageGetStringBytes(JNIEnv *env, jlong id, jint offset);
|
||||
|
||||
JNIEXPORT jlong* JNICALL
|
||||
JVM_ImageGetAttributes(JNIEnv *env, jlong* rawAttributes, jlong id, jint offset);
|
||||
|
||||
JNIEXPORT jsize JNICALL
|
||||
JVM_ImageGetAttributesCount(JNIEnv *env);
|
||||
|
||||
JNIEXPORT jlong* JNICALL
|
||||
JVM_ImageFindAttributes(JNIEnv *env, jlong* rawAttributes, jbyte* rawBytes, jsize size, jlong id);
|
||||
|
||||
JNIEXPORT jint* JNICALL
|
||||
JVM_ImageAttributeOffsets(JNIEnv *env, jint* rawOffsets, unsigned int length, jlong id);
|
||||
|
||||
JNIEXPORT unsigned int JNICALL
|
||||
JVM_ImageAttributeOffsetsLength(JNIEnv *env, jlong id);
|
||||
/*
|
||||
* com.sun.dtrace.jsdt support
|
||||
*/
|
||||
|
@ -1,189 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "jvm.h"
|
||||
#include "jdk_internal_jimage_ImageNativeSubstrate.h"
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_openImage(JNIEnv *env,
|
||||
jclass cls, jstring path, jboolean big_endian) {
|
||||
const char *nativePath;
|
||||
jlong ret;
|
||||
|
||||
nativePath = (*env)->GetStringUTFChars(env, path, NULL);
|
||||
ret = JVM_ImageOpen(env, nativePath, big_endian);
|
||||
(*env)->ReleaseStringUTFChars(env, path, nativePath);
|
||||
return ret;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_closeImage(JNIEnv *env,
|
||||
jclass cls, jlong id) {
|
||||
JVM_ImageClose(env, id);
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_getIndexAddress(JNIEnv *env,
|
||||
jclass cls, jlong id) {
|
||||
return JVM_ImageGetIndexAddress(env, id);
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_getDataAddress(JNIEnv *env,
|
||||
jclass cls, jlong id) {
|
||||
return JVM_ImageGetDataAddress(env, id);
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_read(JNIEnv *env,
|
||||
jclass cls, jlong id, jlong offset,
|
||||
jobject uncompressedBuffer, jlong uncompressed_size) {
|
||||
unsigned char* uncompressedAddress;
|
||||
|
||||
uncompressedAddress = (unsigned char*) (*env)->GetDirectBufferAddress(env, uncompressedBuffer);
|
||||
if (uncompressedBuffer == NULL) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
return JVM_ImageRead(env, id, offset, uncompressedAddress, uncompressed_size);
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_readCompressed(JNIEnv *env,
|
||||
jclass cls, jlong id, jlong offset,
|
||||
jobject compressedBuffer, jlong compressed_size,
|
||||
jobject uncompressedBuffer, jlong uncompressed_size) {
|
||||
// Get address of read direct buffer.
|
||||
unsigned char* compressedAddress;
|
||||
unsigned char* uncompressedAddress;
|
||||
|
||||
compressedAddress = (unsigned char*) (*env)->GetDirectBufferAddress(env, compressedBuffer);
|
||||
// Get address of decompression direct buffer.
|
||||
uncompressedAddress = (unsigned char*) (*env)->GetDirectBufferAddress(env, uncompressedBuffer);
|
||||
if (uncompressedBuffer == NULL || compressedBuffer == NULL) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
return JVM_ImageReadCompressed(env, id, offset, compressedAddress, compressed_size,
|
||||
uncompressedAddress, uncompressed_size);
|
||||
}
|
||||
|
||||
JNIEXPORT jbyteArray JNICALL
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_getStringBytes(JNIEnv *env,
|
||||
jclass cls, jlong id, jint offset) {
|
||||
const char* data;
|
||||
size_t size;
|
||||
jbyteArray byteArray;
|
||||
jbyte* rawBytes;
|
||||
|
||||
data = JVM_ImageGetStringBytes(env, id, offset);
|
||||
// Determine String length.
|
||||
size = strlen(data);
|
||||
// Allocate byte array.
|
||||
byteArray = (*env)->NewByteArray(env, (jsize) size);
|
||||
if (byteArray == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
// Get array base address.
|
||||
rawBytes = (*env)->GetByteArrayElements(env, byteArray, NULL);
|
||||
// Copy bytes from image string table.
|
||||
memcpy(rawBytes, data, size);
|
||||
// Release byte array base address.
|
||||
(*env)->ReleaseByteArrayElements(env, byteArray, rawBytes, 0);
|
||||
return byteArray;
|
||||
}
|
||||
|
||||
JNIEXPORT jlongArray JNICALL
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_getAttributes(JNIEnv *env,
|
||||
jclass cls, jlong id, jint offset) {
|
||||
// Allocate a jlong large enough for all location attributes.
|
||||
jlongArray attributes;
|
||||
jlong* rawAttributes;
|
||||
jlong* ret;
|
||||
|
||||
attributes = (*env)->NewLongArray(env, JVM_ImageGetAttributesCount(env));
|
||||
if (attributes == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
// Get base address for jlong array.
|
||||
rawAttributes = (*env)->GetLongArrayElements(env, attributes, NULL);
|
||||
ret = JVM_ImageGetAttributes(env, rawAttributes, id, offset);
|
||||
// Release jlong array base address.
|
||||
(*env)->ReleaseLongArrayElements(env, attributes, rawAttributes, 0);
|
||||
return ret == NULL ? NULL : attributes;
|
||||
}
|
||||
|
||||
JNIEXPORT jlongArray JNICALL
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_findAttributes(JNIEnv *env,
|
||||
jclass cls, jlong id, jbyteArray utf8) {
|
||||
// Allocate a jlong large enough for all location attributes.
|
||||
jsize count;
|
||||
jlongArray attributes;
|
||||
jlong* rawAttributes;
|
||||
jsize size;
|
||||
jbyte* rawBytes;
|
||||
jlong* ret;
|
||||
|
||||
count = JVM_ImageGetAttributesCount(env);
|
||||
attributes = (*env)->NewLongArray(env, JVM_ImageGetAttributesCount(env));
|
||||
if (attributes == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
// Get base address for jlong array.
|
||||
rawAttributes = (*env)->GetLongArrayElements(env, attributes, NULL);
|
||||
size = (*env)->GetArrayLength(env, utf8);
|
||||
rawBytes = (*env)->GetByteArrayElements(env, utf8, NULL);
|
||||
ret = JVM_ImageFindAttributes(env, rawAttributes, rawBytes, size, id);
|
||||
(*env)->ReleaseByteArrayElements(env, utf8, rawBytes, 0);
|
||||
// Release jlong array base address.
|
||||
(*env)->ReleaseLongArrayElements(env, attributes, rawAttributes, 0);
|
||||
return ret == NULL ? NULL : attributes;
|
||||
|
||||
}
|
||||
|
||||
JNIEXPORT jintArray JNICALL
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_attributeOffsets(JNIEnv *env,
|
||||
jclass cls, jlong id) {
|
||||
unsigned int length;
|
||||
jintArray offsets;
|
||||
jint* rawOffsets;
|
||||
jint* ret;
|
||||
|
||||
length = JVM_ImageAttributeOffsetsLength(env, id);
|
||||
offsets = (*env)->NewIntArray(env, length);
|
||||
if (offsets == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
// Get base address of result.
|
||||
rawOffsets = (*env)->GetIntArrayElements(env, offsets, NULL);
|
||||
ret = JVM_ImageAttributeOffsets(env, rawOffsets, length, id);
|
||||
if (length == 0) {
|
||||
return NULL;
|
||||
}
|
||||
// Release result base address.
|
||||
(*env)->ReleaseIntArrayElements(env, offsets, rawOffsets, 0);
|
||||
return ret == NULL ? NULL : offsets;
|
||||
}
|
@ -0,0 +1,598 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "jdk_util.h"
|
||||
#include "endian.hpp"
|
||||
#include "imageDecompressor.hpp"
|
||||
#include "imageFile.hpp"
|
||||
#include "inttypes.hpp"
|
||||
#include "jimage.hpp"
|
||||
#include "osSupport.hpp"
|
||||
|
||||
#include "jdk_internal_jimage_ImageNativeSubstrate.h"
|
||||
|
||||
extern bool MemoryMapImage;
|
||||
|
||||
// jdk.internal.jimage /////////////////////////////////////////////////////////
|
||||
|
||||
// Java entry to open an image file for sharing.
|
||||
|
||||
static jlong JIMAGE_Open(JNIEnv *env, const char *nativePath, jboolean big_endian) {
|
||||
// Open image file for reading.
|
||||
ImageFileReader* reader = ImageFileReader::open(nativePath, big_endian != JNI_FALSE);
|
||||
// Return image ID as a jlong.
|
||||
return ImageFileReader::readerToID(reader);
|
||||
}
|
||||
|
||||
// Java entry for closing a shared image file.
|
||||
|
||||
static void JIMAGE_Close(JNIEnv *env, jlong id) {
|
||||
// Convert image ID to image reader structure.
|
||||
ImageFileReader* reader = ImageFileReader::idToReader(id);
|
||||
// If valid reader the close.
|
||||
if (reader != NULL) {
|
||||
ImageFileReader::close(reader);
|
||||
}
|
||||
}
|
||||
|
||||
// Java entry for accessing the base address of the image index.
|
||||
|
||||
static jlong JIMAGE_GetIndexAddress(JNIEnv *env, jlong id) {
|
||||
// Convert image ID to image reader structure.
|
||||
ImageFileReader* reader = ImageFileReader::idToReader(id);
|
||||
// If valid reader return index base address (as jlong) else zero.
|
||||
return reader != NULL ? (jlong) reader->get_index_address() : 0L;
|
||||
}
|
||||
|
||||
// Java entry for accessing the base address of the image data.
|
||||
|
||||
static jlong JIMAGE_GetDataAddress(JNIEnv *env, jlong id) {
|
||||
// Convert image ID to image reader structure.
|
||||
ImageFileReader* reader = ImageFileReader::idToReader(id);
|
||||
// If valid reader return data base address (as jlong) else zero.
|
||||
return MemoryMapImage && reader != NULL ? (jlong) reader->get_data_address() : 0L;
|
||||
}
|
||||
|
||||
// Java entry for reading an uncompressed resource from the image.
|
||||
|
||||
static jboolean JIMAGE_Read(JNIEnv *env, jlong id, jlong offset,
|
||||
unsigned char* uncompressedAddress, jlong uncompressed_size) {
|
||||
// Convert image ID to image reader structure.
|
||||
ImageFileReader* reader = ImageFileReader::idToReader(id);\
|
||||
// If not a valid reader the fail the read.
|
||||
if (reader == NULL) return false;
|
||||
// Get the file offset of resource data.
|
||||
u8 file_offset = reader->get_index_size() + offset;
|
||||
// Check validity of arguments.
|
||||
if (offset < 0 ||
|
||||
uncompressed_size < 0 ||
|
||||
file_offset > reader->file_size() - uncompressed_size) {
|
||||
return false;
|
||||
}
|
||||
// Read file content into buffer.
|
||||
return (jboolean) reader->read_at((u1*) uncompressedAddress, uncompressed_size,
|
||||
file_offset);
|
||||
}
|
||||
|
||||
// Java entry for reading a compressed resource from the image.
|
||||
|
||||
static jboolean JIMAGE_ReadCompressed(JNIEnv *env,
|
||||
jlong id, jlong offset,
|
||||
unsigned char* compressedAddress, jlong compressed_size,
|
||||
unsigned char* uncompressedAddress, jlong uncompressed_size) {
|
||||
// Convert image ID to image reader structure.
|
||||
ImageFileReader* reader = ImageFileReader::idToReader(id);
|
||||
// If not a valid reader the fail the read.
|
||||
if (reader == NULL) return false;
|
||||
// Get the file offset of resource data.
|
||||
u8 file_offset = reader->get_index_size() + offset;
|
||||
// Check validity of arguments.
|
||||
if (offset < 0 ||
|
||||
compressed_size < 0 ||
|
||||
uncompressed_size < 0 ||
|
||||
file_offset > reader->file_size() - compressed_size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read file content into buffer.
|
||||
bool is_read = reader->read_at(compressedAddress, compressed_size,
|
||||
file_offset);
|
||||
// If successfully read then decompress.
|
||||
if (is_read) {
|
||||
const ImageStrings strings = reader->get_strings();
|
||||
ImageDecompressor::decompress_resource(compressedAddress, uncompressedAddress,
|
||||
(u4) uncompressed_size, &strings);
|
||||
}
|
||||
return (jboolean) is_read;
|
||||
}
|
||||
|
||||
// Java entry for retrieving UTF-8 bytes from image string table.
|
||||
|
||||
static const char* JIMAGE_GetStringBytes(JNIEnv *env, jlong id, jint offset) {
|
||||
// Convert image ID to image reader structure.
|
||||
ImageFileReader* reader = ImageFileReader::idToReader(id);
|
||||
// Fail if not valid reader.
|
||||
if (reader == NULL) return NULL;
|
||||
// Manage image string table.
|
||||
ImageStrings strings = reader->get_strings();
|
||||
// Retrieve string adrress from table.
|
||||
const char* data = strings.get(offset);
|
||||
return data;
|
||||
}
|
||||
|
||||
// Utility function to copy location information into a jlong array.
|
||||
// WARNING: This function is experimental and temporary during JDK 9 development
|
||||
// cycle. It will not be supported in the eventual JDK 9 release.
|
||||
|
||||
static void image_expand_location(JNIEnv *env, jlong* rawAttributes, ImageLocation& location) {
|
||||
// Copy attributes from location.
|
||||
for (int kind = ImageLocation::ATTRIBUTE_END + 1;
|
||||
kind < ImageLocation::ATTRIBUTE_COUNT;
|
||||
kind++) {
|
||||
rawAttributes[kind] = location.get_attribute(kind);
|
||||
}
|
||||
}
|
||||
|
||||
// Java entry for retrieving location attributes for attribute offset.
|
||||
|
||||
static jlong* JIMAGE_GetAttributes(JNIEnv *env, jlong* rawAttributes, jlong id, jint offset) {
|
||||
// Convert image ID to image reader structure.
|
||||
ImageFileReader* reader = ImageFileReader::idToReader(id);
|
||||
// Fail if not valid reader.
|
||||
if (reader == NULL) return NULL;
|
||||
// Retrieve first byte address of resource's location attribute stream.
|
||||
u1* data = reader->get_location_offset_data(offset);
|
||||
// Fail if not valid offset.
|
||||
if (data == NULL) return NULL;
|
||||
// Expand stream into array.
|
||||
ImageLocation location(data);
|
||||
image_expand_location(env, rawAttributes, location);
|
||||
return rawAttributes;
|
||||
}
|
||||
|
||||
// Java entry for retrieving location attributes count for attribute offset.
|
||||
|
||||
static jsize JIMAGE_GetAttributesCount(JNIEnv *env) {
|
||||
return ImageLocation::ATTRIBUTE_COUNT;
|
||||
}
|
||||
|
||||
// Java entry for retrieving location attributes for named resource.
|
||||
|
||||
static jlong* JIMAGE_FindAttributes(JNIEnv *env, jlong* rawAttributes, jbyte* rawBytes, jsize size, jlong id) {
|
||||
// Convert image ID to image reader structure.
|
||||
ImageFileReader* reader = ImageFileReader::idToReader(id);
|
||||
// Fail if not valid reader.
|
||||
if (reader == NULL) return NULL;
|
||||
// Convert byte array to a cstring.
|
||||
char* path = new char[size + 1];
|
||||
memcpy(path, rawBytes, size);
|
||||
path[size] = '\0';
|
||||
// Locate resource location data.
|
||||
ImageLocation location;
|
||||
bool found = reader->find_location(path, location);
|
||||
delete path;
|
||||
// Resource not found.
|
||||
if (!found) return NULL;
|
||||
// Expand stream into array.
|
||||
image_expand_location(env, rawAttributes, location);
|
||||
return rawAttributes;
|
||||
}
|
||||
|
||||
// Java entry for retrieving all the attribute stream offsets from an image.
|
||||
|
||||
static jint* JIMAGE_AttributeOffsets(JNIEnv *env, jint* rawOffsets, unsigned int length, jlong id) {
|
||||
// Convert image ID to image reader structure.
|
||||
ImageFileReader* reader = ImageFileReader::idToReader(id);
|
||||
// Fail if not valid reader.
|
||||
if (reader == NULL) return NULL;
|
||||
// Determine endian for reader.
|
||||
Endian* endian = reader->endian();
|
||||
// Get base address of attribute stream offsets table.
|
||||
u4* offsets_table = reader->offsets_table();
|
||||
// Allocate int array result.
|
||||
// Copy values to result (converting endian.)
|
||||
for (u4 i = 0; i < length; i++) {
|
||||
rawOffsets[i] = endian->get(offsets_table[i]);
|
||||
}
|
||||
return rawOffsets;
|
||||
}
|
||||
|
||||
// Java entry for retrieving all the attribute stream offsets length from an image.
|
||||
|
||||
static unsigned int JIMAGE_AttributeOffsetsLength(JNIEnv *env, jlong id) {
|
||||
// Convert image ID to image reader structure.
|
||||
ImageFileReader* reader = ImageFileReader::idToReader(id);
|
||||
// Fail if not valid reader.
|
||||
if (reader == NULL) return 0;
|
||||
// Get perfect hash table length.
|
||||
u4 length = reader->table_length();
|
||||
return (jint) length;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
JNIEnv *env;
|
||||
|
||||
if (vm->GetEnv((void**) &env, JNI_VERSION_1_2) != JNI_OK) {
|
||||
return JNI_EVERSION; /* JNI version not supported */
|
||||
}
|
||||
|
||||
return JNI_VERSION_1_2;
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_openImage(JNIEnv *env,
|
||||
jclass cls, jstring path, jboolean big_endian) {
|
||||
const char *nativePath;
|
||||
jlong ret;
|
||||
|
||||
nativePath = env->GetStringUTFChars(path, NULL);
|
||||
ret = JIMAGE_Open(env, nativePath, big_endian);
|
||||
env->ReleaseStringUTFChars(path, nativePath);
|
||||
return ret;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_closeImage(JNIEnv *env,
|
||||
jclass cls, jlong id) {
|
||||
JIMAGE_Close(env, id);
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_getIndexAddress(JNIEnv *env,
|
||||
jclass cls, jlong id) {
|
||||
return JIMAGE_GetIndexAddress(env, id);
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_getDataAddress(JNIEnv *env,
|
||||
jclass cls, jlong id) {
|
||||
return JIMAGE_GetDataAddress(env, id);
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_read(JNIEnv *env,
|
||||
jclass cls, jlong id, jlong offset,
|
||||
jobject uncompressedBuffer, jlong uncompressed_size) {
|
||||
unsigned char* uncompressedAddress;
|
||||
|
||||
uncompressedAddress = (unsigned char*) env->GetDirectBufferAddress(uncompressedBuffer);
|
||||
if (uncompressedAddress == NULL) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
return JIMAGE_Read(env, id, offset, uncompressedAddress, uncompressed_size);
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_readCompressed(JNIEnv *env,
|
||||
jclass cls, jlong id, jlong offset,
|
||||
jobject compressedBuffer, jlong compressed_size,
|
||||
jobject uncompressedBuffer, jlong uncompressed_size) {
|
||||
// Get address of read direct buffer.
|
||||
unsigned char* compressedAddress;
|
||||
unsigned char* uncompressedAddress;
|
||||
|
||||
compressedAddress = (unsigned char*) env->GetDirectBufferAddress(compressedBuffer);
|
||||
// Get address of decompression direct buffer.
|
||||
uncompressedAddress = (unsigned char*) env->GetDirectBufferAddress(uncompressedBuffer);
|
||||
if (compressedAddress == NULL || uncompressedAddress == NULL) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
return JIMAGE_ReadCompressed(env, id, offset, compressedAddress, compressed_size,
|
||||
uncompressedAddress, uncompressed_size);
|
||||
}
|
||||
|
||||
JNIEXPORT jbyteArray JNICALL
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_getStringBytes(JNIEnv *env,
|
||||
jclass cls, jlong id, jint offset) {
|
||||
const char* data;
|
||||
size_t size;
|
||||
jbyteArray byteArray;
|
||||
jbyte* rawBytes;
|
||||
|
||||
data = JIMAGE_GetStringBytes(env, id, offset);
|
||||
// Determine String length.
|
||||
size = strlen(data);
|
||||
// Allocate byte array.
|
||||
byteArray = env->NewByteArray((jsize) size);
|
||||
if (byteArray == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
// Get array base address.
|
||||
rawBytes = env->GetByteArrayElements(byteArray, NULL);
|
||||
// Copy bytes from image string table.
|
||||
memcpy(rawBytes, data, size);
|
||||
// Release byte array base address.
|
||||
env->ReleaseByteArrayElements(byteArray, rawBytes, 0);
|
||||
return byteArray;
|
||||
}
|
||||
|
||||
JNIEXPORT jlongArray JNICALL
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_getAttributes(JNIEnv *env,
|
||||
jclass cls, jlong id, jint offset) {
|
||||
// Allocate a jlong large enough for all location attributes.
|
||||
jlongArray attributes;
|
||||
jlong* rawAttributes;
|
||||
jlong* ret;
|
||||
|
||||
attributes = env->NewLongArray(JIMAGE_GetAttributesCount(env));
|
||||
if (attributes == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
// Get base address for jlong array.
|
||||
rawAttributes = env->GetLongArrayElements(attributes, NULL);
|
||||
ret = JIMAGE_GetAttributes(env, rawAttributes, id, offset);
|
||||
// Release jlong array base address.
|
||||
env->ReleaseLongArrayElements(attributes, rawAttributes, 0);
|
||||
return ret == NULL ? NULL : attributes;
|
||||
}
|
||||
|
||||
JNIEXPORT jlongArray JNICALL
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_findAttributes(JNIEnv *env,
|
||||
jclass cls, jlong id, jbyteArray utf8) {
|
||||
// Allocate a jlong large enough for all location attributes.
|
||||
jsize count;
|
||||
jlongArray attributes;
|
||||
jlong* rawAttributes;
|
||||
jsize size;
|
||||
jbyte* rawBytes;
|
||||
jlong* ret;
|
||||
|
||||
count = JIMAGE_GetAttributesCount(env);
|
||||
attributes = env->NewLongArray(JIMAGE_GetAttributesCount(env));
|
||||
if (attributes == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
// Get base address for jlong array.
|
||||
rawAttributes = env->GetLongArrayElements(attributes, NULL);
|
||||
size = env->GetArrayLength(utf8);
|
||||
rawBytes = env->GetByteArrayElements(utf8, NULL);
|
||||
ret = JIMAGE_FindAttributes(env, rawAttributes, rawBytes, size, id);
|
||||
env->ReleaseByteArrayElements(utf8, rawBytes, 0);
|
||||
// Release jlong array base address.
|
||||
env->ReleaseLongArrayElements(attributes, rawAttributes, 0);
|
||||
return ret == NULL ? NULL : attributes;
|
||||
|
||||
}
|
||||
|
||||
JNIEXPORT jintArray JNICALL
|
||||
Java_jdk_internal_jimage_ImageNativeSubstrate_attributeOffsets(JNIEnv *env,
|
||||
jclass cls, jlong id) {
|
||||
unsigned int length;
|
||||
jintArray offsets;
|
||||
jint* rawOffsets;
|
||||
jint* ret;
|
||||
|
||||
length = JIMAGE_AttributeOffsetsLength(env, id);
|
||||
offsets = env->NewIntArray(length);
|
||||
if (offsets == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
// Get base address of result.
|
||||
rawOffsets = env->GetIntArrayElements(offsets, NULL);
|
||||
ret = JIMAGE_AttributeOffsets(env, rawOffsets, length, id);
|
||||
if (length == 0) {
|
||||
return NULL;
|
||||
}
|
||||
// Release result base address.
|
||||
env->ReleaseIntArrayElements(offsets, rawOffsets, 0);
|
||||
return ret == NULL ? NULL : offsets;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: jdk_internal_jimage_ImageNativeSubstrate
|
||||
* Method: JIMAGE_open
|
||||
* Signature: (Ljava/lang/String;)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1Open
|
||||
(JNIEnv *env, jclass, jstring path) {
|
||||
const char *nativePath = env->GetStringUTFChars(path, NULL);
|
||||
if (nativePath == NULL)
|
||||
return 0; // Exception already thrown
|
||||
jint error;
|
||||
jlong ret = (jlong) JIMAGE_Open(nativePath, &error);
|
||||
env->ReleaseStringUTFChars(path, nativePath);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: jdk_internal_jimage_ImageNativeSubstrate
|
||||
* Method: JIMAGE_Close
|
||||
* Signature: (J)J
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1Close
|
||||
(JNIEnv *env, jclass, jlong jimageHandle) {
|
||||
JIMAGE_Close((JImageFile*) jimageHandle);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: jdk_internal_jimage_ImageNativeSubstrate
|
||||
* Method: JIMAGE_FindResource
|
||||
* Signature: (JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;[J)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1FindResource
|
||||
(JNIEnv *env, jclass, jlong jimageHandle, jstring moduleName,
|
||||
jstring version, jstring path, jlongArray output_size) {
|
||||
const char *native_module = NULL;
|
||||
const char *native_version = NULL;
|
||||
const char *native_path = NULL;
|
||||
jlong * native_array = NULL;
|
||||
jlong size = 0;
|
||||
jlong ret = 0;
|
||||
|
||||
do {
|
||||
native_module = env->GetStringUTFChars(moduleName, NULL);
|
||||
if (native_module == NULL)
|
||||
break;
|
||||
native_version = env->GetStringUTFChars(version, NULL);
|
||||
if (native_version == NULL)
|
||||
break;
|
||||
native_path = env->GetStringUTFChars(path, NULL);
|
||||
if (native_path == NULL)
|
||||
break;
|
||||
if (env->GetArrayLength(output_size) < 1)
|
||||
break;
|
||||
// Get base address for jlong array.
|
||||
native_array = env->GetLongArrayElements(output_size, NULL);
|
||||
if (native_array == NULL)
|
||||
break;
|
||||
|
||||
ret = (jlong) JIMAGE_FindResource((JImageFile *) jimageHandle,
|
||||
native_module, native_version, native_path, &size);
|
||||
if (ret != 0)
|
||||
*native_array = size;
|
||||
} while (0);
|
||||
|
||||
if (native_array != NULL)
|
||||
env->ReleaseLongArrayElements(output_size, native_array, 0);
|
||||
if (native_path != NULL)
|
||||
env->ReleaseStringUTFChars(path, native_path);
|
||||
if (native_version != NULL)
|
||||
env->ReleaseStringUTFChars(path, native_version);
|
||||
if (native_module != NULL)
|
||||
env->ReleaseStringUTFChars(path, native_module);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: jdk_internal_jimage_ImageNativeSubstrate
|
||||
* Method: JIMAGE_GetResource
|
||||
* Signature: (JJ[BJ)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1GetResource
|
||||
(JNIEnv *env, jclass, jlong jimageHandle, jlong jlocationHandle, jbyteArray buffer, jlong size) {
|
||||
jbyte * native_buffer = NULL;
|
||||
jlong actual_size = 0;
|
||||
do {
|
||||
if (env->GetArrayLength(buffer) < size)
|
||||
break;
|
||||
|
||||
native_buffer = env->GetByteArrayElements(buffer, NULL);
|
||||
if (native_buffer == NULL)
|
||||
break;
|
||||
|
||||
actual_size = JIMAGE_GetResource((JImageFile*) jimageHandle,
|
||||
(JImageLocationRef) jlocationHandle,
|
||||
(char *) native_buffer, size);
|
||||
} while (0);
|
||||
// Release byte array
|
||||
if (native_buffer != NULL)
|
||||
env->ReleaseByteArrayElements(buffer, native_buffer, 0);
|
||||
|
||||
return actual_size;
|
||||
}
|
||||
|
||||
// Structure passed from iterator to a visitor to accumulate the results
|
||||
|
||||
struct VisitorData {
|
||||
JNIEnv *env;
|
||||
int size; // current number of strings
|
||||
int max; // Maximum number of strings
|
||||
jobjectArray array; // String array to store the strings
|
||||
};
|
||||
|
||||
// Visitor to accumulate fully qualified resource names
|
||||
|
||||
static bool resourceVisitor(JImageFile* image,
|
||||
const char* module, const char* version, const char* package,
|
||||
const char* name, const char* extension, void* arg) {
|
||||
struct VisitorData *vdata = (struct VisitorData *) arg;
|
||||
JNIEnv* env = vdata->env;
|
||||
if (vdata->size < vdata->max) {
|
||||
// Store if there is room in the array
|
||||
// Concatenate to get full path
|
||||
char fullpath[IMAGE_MAX_PATH];
|
||||
fullpath[0] = '\0';
|
||||
if (*module != '\0') {
|
||||
strncpy(fullpath, "/", IMAGE_MAX_PATH - 1);
|
||||
strncat(fullpath, module, IMAGE_MAX_PATH - 1);
|
||||
strncat(fullpath, "/", IMAGE_MAX_PATH - 1);
|
||||
}
|
||||
if (*package != '\0') {
|
||||
strncat(fullpath, package, IMAGE_MAX_PATH - 1);
|
||||
strncat(fullpath, "/", IMAGE_MAX_PATH - 1);
|
||||
}
|
||||
strncat(fullpath, name, IMAGE_MAX_PATH - 1);
|
||||
if (*extension != '\0') {
|
||||
strncat(fullpath, ".", IMAGE_MAX_PATH - 1);
|
||||
strncat(fullpath, extension, IMAGE_MAX_PATH - 1);
|
||||
}
|
||||
jobject str = env->NewStringUTF(fullpath);
|
||||
JNU_CHECK_EXCEPTION_RETURN(env, true);
|
||||
env->SetObjectArrayElement(vdata->array, vdata->size, str);
|
||||
JNU_CHECK_EXCEPTION_RETURN(env, true);
|
||||
}
|
||||
vdata->size++; // always count so the total size is returned
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: jdk_internal_jimage_ImageNativeSubstrate
|
||||
* Method: JIMAGE_Resources
|
||||
* Signature: (J)V
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1Resources
|
||||
(JNIEnv *env, jclass, jlong jimageHandle,
|
||||
jobjectArray outputNames) {
|
||||
struct VisitorData vdata;
|
||||
vdata.env = env;
|
||||
vdata.max = 0;
|
||||
vdata.size = 0;
|
||||
vdata.array = outputNames;
|
||||
|
||||
vdata.max = (outputNames != NULL) ? env->GetArrayLength(outputNames) : 0;
|
||||
JIMAGE_ResourceIterator((JImageFile*) jimageHandle, &resourceVisitor, &vdata);
|
||||
return vdata.size;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: jdk_internal_jimage_ImageNativeSubstrate
|
||||
* Method: JIMAGE_PackageToModule
|
||||
* Signature: (JLjava/lang/String;)Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1PackageToModule
|
||||
(JNIEnv *env, jclass, jlong jimageHandle, jstring package_name) {
|
||||
const char *native_package = NULL;
|
||||
const char *native_module = NULL;
|
||||
jstring module = NULL;
|
||||
|
||||
native_package = env->GetStringUTFChars(package_name, NULL);
|
||||
JNU_CHECK_EXCEPTION_RETURN(env, NULL);
|
||||
|
||||
native_module = JIMAGE_PackageToModule((JImageFile*) jimageHandle, native_package);
|
||||
if (native_module != NULL) {
|
||||
module = env->NewStringUTF(native_module);
|
||||
}
|
||||
env->ReleaseStringUTFChars(package_name, native_package);
|
||||
return module;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) {
|
||||
ImageDecompressor::image_decompressor_close();
|
||||
}
|
102
jdk/src/java.base/share/native/libjimage/endian.cpp
Normal file
102
jdk/src/java.base/share/native/libjimage/endian.cpp
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "endian.hpp"
|
||||
#include "inttypes.hpp"
|
||||
|
||||
// Most modern compilers optimize the bswap routines to native instructions.
|
||||
inline static u2 bswap_16(u2 x) {
|
||||
return ((x & 0xFF) << 8) |
|
||||
((x >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
inline static u4 bswap_32(u4 x) {
|
||||
return ((x & 0xFF) << 24) |
|
||||
((x & 0xFF00) << 8) |
|
||||
((x >> 8) & 0xFF00) |
|
||||
((x >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
inline static u8 bswap_64(u8 x) {
|
||||
return (u8)bswap_32((u4)x) << 32 |
|
||||
(u8)bswap_32((u4)(x >> 32));
|
||||
}
|
||||
|
||||
u2 NativeEndian::get(u2 x) { return x; }
|
||||
u4 NativeEndian::get(u4 x) { return x; }
|
||||
u8 NativeEndian::get(u8 x) { return x; }
|
||||
s2 NativeEndian::get(s2 x) { return x; }
|
||||
s4 NativeEndian::get(s4 x) { return x; }
|
||||
s8 NativeEndian::get(s8 x) { return x; }
|
||||
|
||||
void NativeEndian::set(u2& x, u2 y) { x = y; }
|
||||
void NativeEndian::set(u4& x, u4 y) { x = y; }
|
||||
void NativeEndian::set(u8& x, u8 y) { x = y; }
|
||||
void NativeEndian::set(s2& x, s2 y) { x = y; }
|
||||
void NativeEndian::set(s4& x, s4 y) { x = y; }
|
||||
void NativeEndian::set(s8& x, s8 y) { x = y; }
|
||||
|
||||
NativeEndian NativeEndian::_native;
|
||||
|
||||
u2 SwappingEndian::get(u2 x) { return bswap_16(x); }
|
||||
u4 SwappingEndian::get(u4 x) { return bswap_32(x); }
|
||||
u8 SwappingEndian::get(u8 x) { return bswap_64(x); }
|
||||
s2 SwappingEndian::get(s2 x) { return bswap_16(x); }
|
||||
s4 SwappingEndian::get(s4 x) { return bswap_32(x); }
|
||||
s8 SwappingEndian::get(s8 x) { return bswap_64(x); }
|
||||
|
||||
void SwappingEndian::set(u2& x, u2 y) { x = bswap_16(y); }
|
||||
void SwappingEndian::set(u4& x, u4 y) { x = bswap_32(y); }
|
||||
void SwappingEndian::set(u8& x, u8 y) { x = bswap_64(y); }
|
||||
void SwappingEndian::set(s2& x, s2 y) { x = bswap_16(y); }
|
||||
void SwappingEndian::set(s4& x, s4 y) { x = bswap_32(y); }
|
||||
void SwappingEndian::set(s8& x, s8 y) { x = bswap_64(y); }
|
||||
|
||||
SwappingEndian SwappingEndian::_swapping;
|
||||
|
||||
Endian* Endian::get_handler(bool big_endian) {
|
||||
// If requesting little endian on a little endian machine or
|
||||
// big endian on a big endian machine use native handler
|
||||
if (big_endian == is_big_endian()) {
|
||||
return NativeEndian::get_native();
|
||||
} else {
|
||||
// Use swapping handler.
|
||||
return SwappingEndian::get_swapping();
|
||||
}
|
||||
}
|
||||
|
||||
// Return a platform u2 from an array in which Big Endian is applied.
|
||||
u2 Endian::get_java(u1* x) {
|
||||
return (u2) (x[0]<<8 | x[1]);
|
||||
}
|
||||
|
||||
// Add a platform u2 to the array as a Big Endian u2
|
||||
void Endian::set_java(u1* p, u2 x) {
|
||||
p[0] = (x >> 8) & 0xff;
|
||||
p[1] = x & 0xff;
|
||||
}
|
||||
|
||||
Endian* Endian::get_native_handler() {
|
||||
return NativeEndian::get_native();
|
||||
}
|
124
jdk/src/java.base/share/native/libjimage/endian.hpp
Normal file
124
jdk/src/java.base/share/native/libjimage/endian.hpp
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LIBJIMAGE_ENDIAN_HPP
|
||||
#define LIBJIMAGE_ENDIAN_HPP
|
||||
|
||||
#include "inttypes.hpp"
|
||||
|
||||
// Selectable endian handling. Endian handlers are used when accessing values
|
||||
// that are of unknown (until runtime) endian. The only requirement of the values
|
||||
// accessed are that they are aligned to proper size boundaries (no misalignment.)
|
||||
// To select an endian handler, one should call Endian::get_handler(big_endian);
|
||||
// Where big_endian is true if big endian is required and false otherwise. The
|
||||
// native endian handler can be fetched with Endian::get_native_handler();
|
||||
// To retrieve a value using the approprate endian, use one of the overloaded
|
||||
// calls to get. To set a value, then use one of the overloaded set calls.
|
||||
// Ex.
|
||||
// s4 value; // Imported value;
|
||||
// ...
|
||||
// Endian* endian = Endian::get_handler(true); // Use big endian
|
||||
// s4 corrected = endian->get(value);
|
||||
// endian->set(value, 1);
|
||||
//
|
||||
class Endian {
|
||||
public:
|
||||
virtual u2 get(u2 x) = 0;
|
||||
virtual u4 get(u4 x) = 0;
|
||||
virtual u8 get(u8 x) = 0;
|
||||
virtual s2 get(s2 x) = 0;
|
||||
virtual s4 get(s4 x) = 0;
|
||||
virtual s8 get(s8 x) = 0;
|
||||
|
||||
virtual void set(u2& x, u2 y) = 0;
|
||||
virtual void set(u4& x, u4 y) = 0;
|
||||
virtual void set(u8& x, u8 y) = 0;
|
||||
virtual void set(s2& x, s2 y) = 0;
|
||||
virtual void set(s4& x, s4 y) = 0;
|
||||
virtual void set(s8& x, s8 y) = 0;
|
||||
|
||||
// Quick little endian test.
|
||||
static bool is_little_endian() { u4 x = 1; return *(u1 *)&x != 0; }
|
||||
|
||||
// Quick big endian test.
|
||||
static bool is_big_endian() { return !is_little_endian(); }
|
||||
|
||||
// Select an appropriate endian handler.
|
||||
static Endian* get_handler(bool big_endian);
|
||||
|
||||
// Return the native endian handler.
|
||||
static Endian* get_native_handler();
|
||||
|
||||
// get platform u2 from Java Big endian
|
||||
static u2 get_java(u1* x);
|
||||
// set platform u2 to Java Big endian
|
||||
static void set_java(u1* p, u2 x);
|
||||
};
|
||||
|
||||
// Normal endian handling.
|
||||
class NativeEndian : public Endian {
|
||||
private:
|
||||
static NativeEndian _native;
|
||||
|
||||
public:
|
||||
u2 get(u2 x);
|
||||
u4 get(u4 x);
|
||||
u8 get(u8 x);
|
||||
s2 get(s2 x);
|
||||
s4 get(s4 x);
|
||||
s8 get(s8 x);
|
||||
|
||||
void set(u2& x, u2 y);
|
||||
void set(u4& x, u4 y);
|
||||
void set(u8& x, u8 y);
|
||||
void set(s2& x, s2 y);
|
||||
void set(s4& x, s4 y);
|
||||
void set(s8& x, s8 y);
|
||||
|
||||
static Endian* get_native() { return &_native; }
|
||||
};
|
||||
|
||||
// Swapping endian handling.
|
||||
class SwappingEndian : public Endian {
|
||||
private:
|
||||
static SwappingEndian _swapping;
|
||||
|
||||
public:
|
||||
u2 get(u2 x);
|
||||
u4 get(u4 x);
|
||||
u8 get(u8 x);
|
||||
s2 get(s2 x);
|
||||
s4 get(s4 x);
|
||||
s8 get(s8 x);
|
||||
|
||||
void set(u2& x, u2 y);
|
||||
void set(u4& x, u4 y);
|
||||
void set(u8& x, u8 y);
|
||||
void set(s2& x, s2 y);
|
||||
void set(s4& x, s4 y);
|
||||
void set(s8& x, s8 y);
|
||||
|
||||
static Endian* get_swapping() { return &_swapping; }
|
||||
};
|
||||
#endif // LIBJIMAGE_ENDIAN_HPP
|
332
jdk/src/java.base/share/native/libjimage/imageDecompressor.cpp
Normal file
332
jdk/src/java.base/share/native/libjimage/imageDecompressor.cpp
Normal file
@ -0,0 +1,332 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "jni.h"
|
||||
#include "imageDecompressor.hpp"
|
||||
#include "endian.hpp"
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
typedef jboolean (JNICALL *ZipInflateFully_t)(void *inBuf, jlong inLen, void *outBuf, jlong outLen, char **pmsg);
|
||||
static ZipInflateFully_t ZipInflateFully = NULL;
|
||||
|
||||
#ifndef WIN32
|
||||
#define JNI_LIB_PREFIX "lib"
|
||||
#ifdef __APPLE__
|
||||
#define JNI_LIB_SUFFIX ".dylib"
|
||||
#else
|
||||
#define JNI_LIB_SUFFIX ".so"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Return the address of the entry point named in the zip shared library.
|
||||
* @param name - the name of the entry point
|
||||
* @return the address of the entry point or NULL
|
||||
*/
|
||||
static void* findEntry(const char* name) {
|
||||
void *addr = NULL;
|
||||
#ifdef WIN32
|
||||
HMODULE handle = GetModuleHandle("zip.dll");
|
||||
if (handle == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
addr = (void*) GetProcAddress(handle, name);
|
||||
return addr;
|
||||
#else
|
||||
addr = dlopen(JNI_LIB_PREFIX "zip" JNI_LIB_SUFFIX, RTLD_GLOBAL|RTLD_LAZY);
|
||||
if (addr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
addr = dlsym(addr, name);
|
||||
return addr;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the array of decompressors.
|
||||
*/
|
||||
int ImageDecompressor::_decompressors_num = 0;
|
||||
ImageDecompressor** ImageDecompressor::_decompressors = NULL;
|
||||
void ImageDecompressor::image_decompressor_init() {
|
||||
if (_decompressors == NULL) {
|
||||
ZipInflateFully = (ZipInflateFully_t) findEntry("ZIP_InflateFully");
|
||||
assert(ZipInflateFully != NULL && "ZIP decompressor not found.");
|
||||
_decompressors_num = 2;
|
||||
_decompressors = new ImageDecompressor*[_decompressors_num];
|
||||
_decompressors[0] = new ZipDecompressor("zip");
|
||||
_decompressors[1] = new SharedStringDecompressor("compact-cp");
|
||||
}
|
||||
}
|
||||
|
||||
void ImageDecompressor::image_decompressor_close() {
|
||||
delete _decompressors;
|
||||
}
|
||||
|
||||
/*
|
||||
* Locate decompressor.
|
||||
*/
|
||||
ImageDecompressor* ImageDecompressor::get_decompressor(const char * decompressor_name) {
|
||||
image_decompressor_init();
|
||||
for (int i = 0; i < _decompressors_num; i++) {
|
||||
ImageDecompressor* decompressor = _decompressors[i];
|
||||
assert(decompressor != NULL && "Decompressors not initialized.");
|
||||
if (strcmp(decompressor->get_name(), decompressor_name) == 0) {
|
||||
return decompressor;
|
||||
}
|
||||
}
|
||||
assert(false && "No decompressor found.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decompression entry point. Called from ImageFileReader::get_resource.
|
||||
*/
|
||||
void ImageDecompressor::decompress_resource(u1* compressed, u1* uncompressed,
|
||||
u4 uncompressed_size, const ImageStrings* strings) {
|
||||
bool has_header = false;
|
||||
u1* decompressed_resource = compressed;
|
||||
u1* compressed_resource = compressed;
|
||||
|
||||
// Resource could have been transformed by a stack of decompressors.
|
||||
// Iterate and decompress resources until there is no more header.
|
||||
do {
|
||||
ResourceHeader _header;
|
||||
memcpy(&_header, compressed_resource, sizeof (ResourceHeader));
|
||||
has_header = _header._magic == ResourceHeader::resource_header_magic;
|
||||
if (has_header) {
|
||||
// decompressed_resource array contains the result of decompression
|
||||
decompressed_resource = new u1[_header._uncompressed_size];
|
||||
// Retrieve the decompressor name
|
||||
const char* decompressor_name = strings->get(_header._decompressor_name_offset);
|
||||
assert(decompressor_name && "image decompressor not found");
|
||||
// Retrieve the decompressor instance
|
||||
ImageDecompressor* decompressor = get_decompressor(decompressor_name);
|
||||
assert(decompressor && "image decompressor not found");
|
||||
u1* compressed_resource_base = compressed_resource;
|
||||
compressed_resource += ResourceHeader::resource_header_length;
|
||||
// Ask the decompressor to decompress the compressed content
|
||||
decompressor->decompress_resource(compressed_resource, decompressed_resource,
|
||||
&_header, strings);
|
||||
if (compressed_resource_base != compressed) {
|
||||
delete compressed_resource_base;
|
||||
}
|
||||
compressed_resource = decompressed_resource;
|
||||
}
|
||||
} while (has_header);
|
||||
memcpy(uncompressed, decompressed_resource, uncompressed_size);
|
||||
delete decompressed_resource;
|
||||
}
|
||||
|
||||
// Zip decompressor
|
||||
|
||||
void ZipDecompressor::decompress_resource(u1* data, u1* uncompressed,
|
||||
ResourceHeader* header, const ImageStrings* strings) {
|
||||
char* msg = NULL;
|
||||
jboolean res = ZipDecompressor::decompress(data, header->_size, uncompressed,
|
||||
header->_uncompressed_size, &msg);
|
||||
assert(res && "decompression failed");
|
||||
}
|
||||
|
||||
jboolean ZipDecompressor::decompress(void *in, u8 inSize, void *out, u8 outSize, char **pmsg) {
|
||||
return (*ZipInflateFully)(in, inSize, out, outSize, pmsg);
|
||||
}
|
||||
|
||||
// END Zip Decompressor
|
||||
|
||||
// Shared String decompressor
|
||||
|
||||
// array index is the constant pool tag. value is size.
|
||||
// eg: array[5] = 8; means size of long is 8 bytes.
|
||||
const u1 SharedStringDecompressor::sizes[] = {0, 0, 0, 4, 4, 8, 8, 2, 2, 4, 4, 4, 4, 0, 0, 3, 2, 0, 4};
|
||||
/**
|
||||
* Recreate the class by reconstructing the constant pool.
|
||||
*/
|
||||
void SharedStringDecompressor::decompress_resource(u1* data,
|
||||
u1* uncompressed_resource,
|
||||
ResourceHeader* header, const ImageStrings* strings) {
|
||||
u1* uncompressed_base = uncompressed_resource;
|
||||
u1* data_base = data;
|
||||
int header_size = 8; // magic + major + minor
|
||||
memcpy(uncompressed_resource, data, header_size + 2); //+ cp count
|
||||
uncompressed_resource += header_size + 2;
|
||||
data += header_size;
|
||||
u2 cp_count = Endian::get_java(data);
|
||||
data += 2;
|
||||
for (int i = 1; i < cp_count; i++) {
|
||||
u1 tag = *data;
|
||||
data += 1;
|
||||
switch (tag) {
|
||||
|
||||
case externalized_string:
|
||||
{ // String in Strings table
|
||||
*uncompressed_resource = 1;
|
||||
uncompressed_resource += 1;
|
||||
int i = decompress_int(data);
|
||||
const char * string = strings->get(i);
|
||||
int str_length = (int) strlen(string);
|
||||
Endian::set_java(uncompressed_resource, str_length);
|
||||
uncompressed_resource += 2;
|
||||
memcpy(uncompressed_resource, string, str_length);
|
||||
uncompressed_resource += str_length;
|
||||
break;
|
||||
}
|
||||
// Descriptor String has been split and types added to Strings table
|
||||
case externalized_string_descriptor:
|
||||
{
|
||||
*uncompressed_resource = 1;
|
||||
uncompressed_resource += 1;
|
||||
int descriptor_index = decompress_int(data);
|
||||
int indexes_length = decompress_int(data);
|
||||
u1* length_address = uncompressed_resource;
|
||||
uncompressed_resource += 2;
|
||||
int desc_length = 0;
|
||||
const char * desc_string = strings->get(descriptor_index);
|
||||
if (indexes_length > 0) {
|
||||
u1* indexes_base = data;
|
||||
data += indexes_length;
|
||||
char c = *desc_string;
|
||||
do {
|
||||
*uncompressed_resource = c;
|
||||
uncompressed_resource++;
|
||||
desc_length += 1;
|
||||
/*
|
||||
* Every L character is the marker we are looking at in order
|
||||
* to reconstruct the descriptor. Each time an L is found, then
|
||||
* we retrieve the couple token/token at the current index and
|
||||
* add it to the descriptor.
|
||||
* "(L;I)V" and "java/lang","String" couple of tokens,
|
||||
* this becomes "(Ljava/lang/String;I)V"
|
||||
*/
|
||||
if (c == 'L') {
|
||||
int index = decompress_int(indexes_base);
|
||||
const char * pkg = strings->get(index);
|
||||
int str_length = (int) strlen(pkg);
|
||||
// the case where we have a package.
|
||||
// reconstruct the type full name
|
||||
if (str_length > 0) {
|
||||
int len = str_length + 1;
|
||||
char* fullpkg = new char[len];
|
||||
char* pkg_base = fullpkg;
|
||||
memcpy(fullpkg, pkg, str_length);
|
||||
fullpkg += str_length;
|
||||
*fullpkg = '/';
|
||||
memcpy(uncompressed_resource, pkg_base, len);
|
||||
uncompressed_resource += len;
|
||||
delete pkg_base;
|
||||
desc_length += len;
|
||||
} else { // Empty package
|
||||
// Nothing to do.
|
||||
}
|
||||
int classIndex = decompress_int(indexes_base);
|
||||
const char * clazz = strings->get(classIndex);
|
||||
int clazz_length = (int) strlen(clazz);
|
||||
memcpy(uncompressed_resource, clazz, clazz_length);
|
||||
uncompressed_resource += clazz_length;
|
||||
desc_length += clazz_length;
|
||||
}
|
||||
desc_string += 1;
|
||||
c = *desc_string;
|
||||
} while (c != '\0');
|
||||
} else {
|
||||
desc_length = (int) strlen(desc_string);
|
||||
memcpy(uncompressed_resource, desc_string, desc_length);
|
||||
uncompressed_resource += desc_length;
|
||||
}
|
||||
Endian::set_java(length_address, desc_length);
|
||||
break;
|
||||
}
|
||||
|
||||
case constant_utf8:
|
||||
{ // UTF-8
|
||||
*uncompressed_resource = tag;
|
||||
uncompressed_resource += 1;
|
||||
u2 str_length = Endian::get_java(data);
|
||||
int len = str_length + 2;
|
||||
memcpy(uncompressed_resource, data, len);
|
||||
uncompressed_resource += len;
|
||||
data += len;
|
||||
break;
|
||||
}
|
||||
|
||||
case constant_long:
|
||||
case constant_double:
|
||||
{
|
||||
i++;
|
||||
}
|
||||
default:
|
||||
{
|
||||
*uncompressed_resource = tag;
|
||||
uncompressed_resource += 1;
|
||||
int size = sizes[tag];
|
||||
memcpy(uncompressed_resource, data, size);
|
||||
uncompressed_resource += size;
|
||||
data += size;
|
||||
}
|
||||
}
|
||||
}
|
||||
u4 remain = header->_size - (int)(data - data_base);
|
||||
u4 computed = (u4)(uncompressed_resource - uncompressed_base) + remain;
|
||||
if (header->_uncompressed_size != computed)
|
||||
printf("Failure, expecting %d but getting %d\n", header->_uncompressed_size,
|
||||
computed);
|
||||
assert(header->_uncompressed_size == computed &&
|
||||
"Constant Pool reconstruction failed");
|
||||
memcpy(uncompressed_resource, data, remain);
|
||||
}
|
||||
|
||||
/*
|
||||
* Decompress integers. Compressed integers are negative.
|
||||
* If positive, the integer is not decompressed.
|
||||
* If negative, length extracted from the first byte, then reconstruct the integer
|
||||
* from the following bytes.
|
||||
* Example of compression: 1 is compressed on 1 byte: 10100001
|
||||
*/
|
||||
int SharedStringDecompressor::decompress_int(unsigned char*& value) {
|
||||
int len = 4;
|
||||
int res = 0;
|
||||
char b1 = *value;
|
||||
if (is_compressed((signed char)b1)) { // compressed
|
||||
len = get_compressed_length(b1);
|
||||
char clearedValue = b1 &= 0x1F;
|
||||
if (len == 1) {
|
||||
res = clearedValue;
|
||||
} else {
|
||||
res = (clearedValue & 0xFF) << 8 * (len - 1);
|
||||
for (int i = 1; i < len; i++) {
|
||||
res |= (value[i]&0xFF) << 8 * (len - i - 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
res = (value[0] & 0xFF) << 24 | (value[1]&0xFF) << 16 |
|
||||
(value[2]&0xFF) << 8 | (value[3]&0xFF);
|
||||
}
|
||||
value += len;
|
||||
return res;
|
||||
}
|
||||
// END Shared String decompressor
|
162
jdk/src/java.base/share/native/libjimage/imageDecompressor.hpp
Normal file
162
jdk/src/java.base/share/native/libjimage/imageDecompressor.hpp
Normal file
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LIBJIMAGE_IMAGEDECOMPRESSOR_HPP
|
||||
#define LIBJIMAGE_IMAGEDECOMPRESSOR_HPP
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "imageFile.hpp"
|
||||
#include "inttypes.hpp"
|
||||
#include "jni.h"
|
||||
|
||||
/*
|
||||
* Compressed resources located in image have an header.
|
||||
* This header contains:
|
||||
* - _magic: A magic u4, required to retrieved the header in the compressed content
|
||||
* - _size: The size of the compressed resource.
|
||||
* - _uncompressed_size: The uncompressed size of the compressed resource.
|
||||
* - _decompressor_name_offset: The ImageDecompressor instance name StringsTable offset.
|
||||
* - _decompressor_config_offset: StringsTable offset of configuration that could be needed by
|
||||
* the decompressor in order to decompress.
|
||||
* - _is_terminal: 1: the compressed content is terminal. Uncompressing it would
|
||||
* create the actual resource. 0: the compressed content is not terminal. Uncompressing it
|
||||
* will result in a compressed content to be decompressed (This occurs when a stack of compressors
|
||||
* have been used to compress the resource.
|
||||
*/
|
||||
struct ResourceHeader {
|
||||
/* Length of header, needed to retrieve content offset */
|
||||
static const u1 resource_header_length = 21;
|
||||
/* magic bytes that identifies a compressed resource header*/
|
||||
static const u4 resource_header_magic = 0xCAFEFAFA;
|
||||
u4 _magic; // Resource header
|
||||
u4 _size; // Resource size
|
||||
u4 _uncompressed_size; // Expected uncompressed size
|
||||
u4 _decompressor_name_offset; // Strings table decompressor offset
|
||||
u4 _decompressor_config_offset; // Strings table config offset
|
||||
u1 _is_terminal; // Last decompressor 1, otherwise 0.
|
||||
};
|
||||
|
||||
/*
|
||||
* Resources located in jimage file can be compressed. Compression occurs at
|
||||
* jimage file creation time. When compressed a resource is added an header that
|
||||
* contains the name of the compressor that compressed it.
|
||||
* Various compression strategies can be applied to compress a resource.
|
||||
* The same resource can even be compressed multiple time by a stack of compressors.
|
||||
* At runtime, a resource is decompressed in a loop until there is no more header
|
||||
* meaning that the resource is equivalent to the not compressed resource.
|
||||
* In each iteration, the name of the compressor located in the current header
|
||||
* is used to retrieve the associated instance of ImageDecompressor.
|
||||
* For example “zip” is the name of the compressor that compresses resources
|
||||
* using the zip algorithm. The ZipDecompressor class name is also “zip”.
|
||||
* ImageDecompressor instances are retrieved from a static array in which
|
||||
* they are registered.
|
||||
*/
|
||||
class ImageDecompressor {
|
||||
|
||||
private:
|
||||
const char* _name;
|
||||
|
||||
/*
|
||||
* Array of concrete decompressors. This array is used to retrieve the decompressor
|
||||
* that can handle resource decompression.
|
||||
*/
|
||||
static ImageDecompressor** _decompressors;
|
||||
/**
|
||||
* Num of decompressors
|
||||
*/
|
||||
static int _decompressors_num;
|
||||
/*
|
||||
* Identifier of a decompressor. This name is the identification key to retrieve
|
||||
* decompressor from a resource header.
|
||||
*/
|
||||
inline const char* get_name() const { return _name; }
|
||||
|
||||
|
||||
protected:
|
||||
ImageDecompressor(const char* name) : _name(name) {
|
||||
}
|
||||
virtual void decompress_resource(u1* data, u1* uncompressed,
|
||||
ResourceHeader* header, const ImageStrings* strings) = 0;
|
||||
|
||||
public:
|
||||
static void image_decompressor_init();
|
||||
static void image_decompressor_close();
|
||||
static ImageDecompressor* get_decompressor(const char * decompressor_name) ;
|
||||
static void decompress_resource(u1* compressed, u1* uncompressed,
|
||||
u4 uncompressed_size, const ImageStrings* strings);
|
||||
};
|
||||
|
||||
/**
|
||||
* Zip decompressor.
|
||||
*/
|
||||
class ZipDecompressor : public ImageDecompressor {
|
||||
public:
|
||||
ZipDecompressor(const char* sym) : ImageDecompressor(sym) { }
|
||||
void decompress_resource(u1* data, u1* uncompressed, ResourceHeader* header,
|
||||
const ImageStrings* strings);
|
||||
static jboolean decompress(void *in, u8 inSize, void *out, u8 outSize, char **pmsg);
|
||||
};
|
||||
|
||||
/*
|
||||
* Shared Strings decompressor. This decompressor reconstruct the class
|
||||
* constant pool UTF_U entries by retrieving strings stored in jimage strings table.
|
||||
* In addition, if the UTF_8 entry is a descriptor, the descriptor has to be rebuilt,
|
||||
* all java type having been removed from the descriptor and added to the sting table.
|
||||
* eg: "(Ljava/lang/String;I)V" ==> "(L;I)V" and "java/lang", "String"
|
||||
* stored in string table. offsets to the 2 strings are compressed and stored in the
|
||||
* constantpool entry.
|
||||
*/
|
||||
class SharedStringDecompressor : public ImageDecompressor {
|
||||
private:
|
||||
// the constant pool tag for UTF8 string located in strings table
|
||||
static const int externalized_string = 23;
|
||||
// the constant pool tag for UTF8 descriptors string located in strings table
|
||||
static const int externalized_string_descriptor = 25;
|
||||
// the constant pool tag for UTF8
|
||||
static const int constant_utf8 = 1;
|
||||
// the constant pool tag for long
|
||||
static const int constant_long = 5;
|
||||
// the constant pool tag for double
|
||||
static const int constant_double = 6;
|
||||
// array index is the constant pool tag. value is size.
|
||||
// eg: array[5] = 8; means size of long is 8 bytes.
|
||||
static const u1 sizes[];
|
||||
// bit 5 and 6 are used to store the length of the compressed integer.
|
||||
// size can be 1 (01), 2 (10), 3 (11).
|
||||
// 0x60 ==> 0110000
|
||||
static const int compressed_index_size_mask = 0x60;
|
||||
/*
|
||||
* mask the length bits (5 and 6) and move to the right 5 bits.
|
||||
*/
|
||||
inline static int get_compressed_length(char c) { return ((char) (c & compressed_index_size_mask) >> 5); }
|
||||
inline static bool is_compressed(signed char b1) { return b1 < 0; }
|
||||
static int decompress_int(unsigned char*& value);
|
||||
public:
|
||||
SharedStringDecompressor(const char* sym) : ImageDecompressor(sym){}
|
||||
void decompress_resource(u1* data, u1* uncompressed, ResourceHeader* header,
|
||||
const ImageStrings* strings);
|
||||
};
|
||||
#endif // LIBJIMAGE_IMAGEDECOMPRESSOR_HPP
|
682
jdk/src/java.base/share/native/libjimage/imageFile.cpp
Normal file
682
jdk/src/java.base/share/native/libjimage/imageFile.cpp
Normal file
@ -0,0 +1,682 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "endian.hpp"
|
||||
#include "imageDecompressor.hpp"
|
||||
#include "imageFile.hpp"
|
||||
#include "inttypes.hpp"
|
||||
#include "jni.h"
|
||||
#include "osSupport.hpp"
|
||||
|
||||
// Map the full jimage, only with 64 bit addressing.
|
||||
bool MemoryMapImage = sizeof(void *) == 8;
|
||||
|
||||
#ifdef WIN32
|
||||
const char FileSeparator = '\\';
|
||||
#else
|
||||
const char FileSeparator = '/';
|
||||
#endif
|
||||
|
||||
// Image files are an alternate file format for storing classes and resources. The
|
||||
// goal is to supply file access which is faster and smaller than the jar format.
|
||||
//
|
||||
// (More detailed nodes in the header.)
|
||||
//
|
||||
|
||||
// Compute the Perfect Hashing hash code for the supplied UTF-8 string.
|
||||
s4 ImageStrings::hash_code(const char* string, s4 seed) {
|
||||
// Access bytes as unsigned.
|
||||
u1* bytes = (u1*)string;
|
||||
// Compute hash code.
|
||||
for (u1 byte = *bytes++; byte; byte = *bytes++) {
|
||||
seed = (seed * HASH_MULTIPLIER) ^ byte;
|
||||
}
|
||||
// Ensure the result is not signed.
|
||||
return seed & 0x7FFFFFFF;
|
||||
}
|
||||
|
||||
// Match up a string in a perfect hash table.
|
||||
// Returns the index where the name should be.
|
||||
// Result still needs validation for precise match (false positive.)
|
||||
s4 ImageStrings::find(Endian* endian, const char* name, s4* redirect, u4 length) {
|
||||
// If the table is empty, then short cut.
|
||||
if (!redirect || !length) {
|
||||
return NOT_FOUND;
|
||||
}
|
||||
// Compute the basic perfect hash for name.
|
||||
s4 hash_code = ImageStrings::hash_code(name);
|
||||
// Modulo table size.
|
||||
s4 index = hash_code % length;
|
||||
// Get redirect entry.
|
||||
// value == 0 then not found
|
||||
// value < 0 then -1 - value is true index
|
||||
// value > 0 then value is seed for recomputing hash.
|
||||
s4 value = endian->get(redirect[index]);
|
||||
// if recompute is required.
|
||||
if (value > 0 ) {
|
||||
// Entry collision value, need to recompute hash.
|
||||
hash_code = ImageStrings::hash_code(name, value);
|
||||
// Modulo table size.
|
||||
return hash_code % length;
|
||||
} else if (value < 0) {
|
||||
// Compute direct index.
|
||||
return -1 - value;
|
||||
}
|
||||
// No entry found.
|
||||
return NOT_FOUND;
|
||||
}
|
||||
|
||||
// Test to see if UTF-8 string begins with the start UTF-8 string. If so,
|
||||
// return non-NULL address of remaining portion of string. Otherwise, return
|
||||
// NULL. Used to test sections of a path without copying from image string
|
||||
// table.
|
||||
const char* ImageStrings::starts_with(const char* string, const char* start) {
|
||||
char ch1, ch2;
|
||||
// Match up the strings the best we can.
|
||||
while ((ch1 = *string) && (ch2 = *start)) {
|
||||
if (ch1 != ch2) {
|
||||
// Mismatch, return NULL.
|
||||
return NULL;
|
||||
}
|
||||
// Next characters.
|
||||
string++, start++;
|
||||
}
|
||||
// Return remainder of string.
|
||||
return string;
|
||||
}
|
||||
|
||||
// Inflates the attribute stream into individual values stored in the long
|
||||
// array _attributes. This allows an attribute value to be quickly accessed by
|
||||
// direct indexing. Unspecified values default to zero (from constructor.)
|
||||
void ImageLocation::set_data(u1* data) {
|
||||
// Deflate the attribute stream into an array of attributes.
|
||||
u1 byte;
|
||||
// Repeat until end header is found.
|
||||
while ((byte = *data)) {
|
||||
// Extract kind from header byte.
|
||||
u1 kind = attribute_kind(byte);
|
||||
assert(kind < ATTRIBUTE_COUNT && "invalid image location attribute");
|
||||
// Extract length of data (in bytes).
|
||||
u1 n = attribute_length(byte);
|
||||
// Read value (most significant first.)
|
||||
_attributes[kind] = attribute_value(data + 1, n);
|
||||
// Position to next attribute by skipping attribute header and data bytes.
|
||||
data += n + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Zero all attribute values.
|
||||
void ImageLocation::clear_data() {
|
||||
// Set defaults to zero.
|
||||
memset(_attributes, 0, sizeof(_attributes));
|
||||
}
|
||||
|
||||
// ImageModuleData constructor maps out sub-tables for faster access.
|
||||
ImageModuleData::ImageModuleData(const ImageFileReader* image_file,
|
||||
const char* module_data_name) :
|
||||
_image_file(image_file),
|
||||
_endian(image_file->endian()),
|
||||
_strings(image_file->get_strings()) {
|
||||
// Retrieve the resource containing the module data for the image file.
|
||||
ImageLocation location;
|
||||
bool found = image_file->find_location(module_data_name, location);
|
||||
if (found) {
|
||||
u8 data_size = location.get_attribute(ImageLocation::ATTRIBUTE_UNCOMPRESSED);
|
||||
_data = new u1[(size_t)data_size];
|
||||
_image_file->get_resource(location, _data);
|
||||
// Map out the header.
|
||||
_header = (Header*)_data;
|
||||
// Get the package to module entry count.
|
||||
u4 ptm_count = _header->ptm_count(_endian);
|
||||
// Get the module to package entry count.
|
||||
u4 mtp_count = _header->mtp_count(_endian);
|
||||
// Compute the offset of the package to module perfect hash redirect.
|
||||
u4 ptm_redirect_offset = sizeof(Header);
|
||||
// Compute the offset of the package to module data.
|
||||
u4 ptm_data_offset = ptm_redirect_offset + ptm_count * sizeof(s4);
|
||||
// Compute the offset of the module to package perfect hash redirect.
|
||||
u4 mtp_redirect_offset = ptm_data_offset + ptm_count * sizeof(PTMData);
|
||||
// Compute the offset of the module to package data.
|
||||
u4 mtp_data_offset = mtp_redirect_offset + mtp_count * sizeof(s4);
|
||||
// Compute the offset of the module to package tables.
|
||||
u4 mtp_packages_offset = mtp_data_offset + mtp_count * sizeof(MTPData);
|
||||
// Compute the address of the package to module perfect hash redirect.
|
||||
_ptm_redirect = (s4*)(_data + ptm_redirect_offset);
|
||||
// Compute the address of the package to module data.
|
||||
_ptm_data = (PTMData*)(_data + ptm_data_offset);
|
||||
// Compute the address of the module to package perfect hash redirect.
|
||||
_mtp_redirect = (s4*)(_data + mtp_redirect_offset);
|
||||
// Compute the address of the module to package data.
|
||||
_mtp_data = (MTPData*)(_data + mtp_data_offset);
|
||||
// Compute the address of the module to package tables.
|
||||
_mtp_packages = (s4*)(_data + mtp_packages_offset);
|
||||
} else {
|
||||
// No module data present.
|
||||
_data = NULL;
|
||||
_header = NULL;
|
||||
_ptm_redirect = NULL;
|
||||
_ptm_data = NULL;
|
||||
_mtp_redirect = NULL;
|
||||
_mtp_data = NULL;
|
||||
_mtp_packages = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Release module data resource.
|
||||
ImageModuleData::~ImageModuleData() {
|
||||
if (_data) {
|
||||
delete _data;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the name of the module data resource. Ex. "./lib/modules/file.jimage"
|
||||
// yields "file.jdata"
|
||||
void ImageModuleData::module_data_name(char* buffer, const char* image_file_name) {
|
||||
// Locate the last slash in the file name path.
|
||||
const char* slash = strrchr(image_file_name, FileSeparator);
|
||||
// Trim the path to name and extension.
|
||||
const char* name = slash ? slash + 1 : (char *)image_file_name;
|
||||
// Locate the extension period.
|
||||
const char* dot = strrchr(name, '.');
|
||||
assert(dot && "missing extension on jimage name");
|
||||
// Trim to only base name.
|
||||
int length = (int)(dot - name);
|
||||
strncpy(buffer, name, length);
|
||||
buffer[length] = '\0';
|
||||
// Append extension.
|
||||
strcat(buffer, ".jdata");
|
||||
}
|
||||
|
||||
// Return the module in which a package resides. Returns NULL if not found.
|
||||
const char* ImageModuleData::package_to_module(const char* package_name) {
|
||||
// Test files may contain no module data.
|
||||
if (_data != NULL) {
|
||||
// Search the package to module table.
|
||||
s4 index = ImageStrings::find(_endian, package_name, _ptm_redirect,
|
||||
_header->ptm_count(_endian));
|
||||
// If entry is found.
|
||||
if (index != ImageStrings::NOT_FOUND) {
|
||||
// Retrieve the package to module entry.
|
||||
PTMData* data = _ptm_data + index;
|
||||
// Verify that it is the correct data.
|
||||
if (strcmp(package_name, get_string(data->name_offset(_endian))) != 0) {
|
||||
return NULL;
|
||||
}
|
||||
// Return the module name.
|
||||
return get_string(data->module_name_offset(_endian));
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Returns all the package names in a module in a NULL terminated array.
|
||||
// Returns NULL if module not found.
|
||||
const char** ImageModuleData::module_to_packages(const char* module_name) {
|
||||
// Test files may contain no module data.
|
||||
if (_data != NULL) {
|
||||
// Search the module to package table.
|
||||
s4 index = ImageStrings::find(_endian, module_name, _mtp_redirect,
|
||||
_header->mtp_count(_endian));
|
||||
// If entry is found.
|
||||
if (index != ImageStrings::NOT_FOUND) {
|
||||
// Retrieve the module to package entry.
|
||||
MTPData* data = _mtp_data + index;
|
||||
// Verify that it is the correct data.
|
||||
if (strcmp(module_name, get_string(data->name_offset(_endian))) != 0) {
|
||||
return NULL;
|
||||
}
|
||||
// Construct an array of all the package entries.
|
||||
u4 count = data->package_count(_endian);
|
||||
const char** packages = new const char*[count + 1];
|
||||
s4 package_offset = data->package_offset(_endian);
|
||||
for (u4 i = 0; i < count; i++) {
|
||||
u4 package_name_offset = mtp_package(package_offset + i);
|
||||
const char* package_name = get_string(package_name_offset);
|
||||
packages[i] = package_name;
|
||||
}
|
||||
packages[count] = NULL;
|
||||
return packages;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Manage a table of open image files. This table allows multiple access points
|
||||
// to share an open image.
|
||||
ImageFileReaderTable::ImageFileReaderTable() : _count(0), _max(_growth) {
|
||||
_table = new ImageFileReader*[_max];
|
||||
}
|
||||
|
||||
ImageFileReaderTable::~ImageFileReaderTable() {
|
||||
delete _table;
|
||||
}
|
||||
|
||||
// Add a new image entry to the table.
|
||||
void ImageFileReaderTable::add(ImageFileReader* image) {
|
||||
if (_count == _max) {
|
||||
_max += _growth;
|
||||
_table = static_cast<ImageFileReader**>(realloc(_table, _max * sizeof(ImageFileReader*)));
|
||||
}
|
||||
_table[_count++] = image;
|
||||
}
|
||||
|
||||
// Remove an image entry from the table.
|
||||
void ImageFileReaderTable::remove(ImageFileReader* image) {
|
||||
s4 last = _count - 1;
|
||||
for (s4 i = 0; _count; i++) {
|
||||
if (_table[i] == image) {
|
||||
if (i != last) {
|
||||
_table[i] = _table[last];
|
||||
_count = last;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (_count != 0 && _count == _max - _growth) {
|
||||
_max -= _growth;
|
||||
_table = static_cast<ImageFileReader**>(realloc(_table, _max * sizeof(ImageFileReader*)));
|
||||
}
|
||||
}
|
||||
|
||||
// Determine if image entry is in table.
|
||||
bool ImageFileReaderTable::contains(ImageFileReader* image) {
|
||||
for (s4 i = 0; _count; i++) {
|
||||
if (_table[i] == image) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Table to manage multiple opens of an image file.
|
||||
ImageFileReaderTable ImageFileReader::_reader_table;
|
||||
|
||||
SimpleCriticalSection _reader_table_lock;
|
||||
|
||||
// Open an image file, reuse structure if file already open.
|
||||
ImageFileReader* ImageFileReader::open(const char* name, bool big_endian) {
|
||||
{
|
||||
// Lock out _reader_table.
|
||||
SimpleCriticalSectionLock cs(&_reader_table_lock);
|
||||
// Search for an exist image file.
|
||||
for (u4 i = 0; i < _reader_table.count(); i++) {
|
||||
// Retrieve table entry.
|
||||
ImageFileReader* reader = _reader_table.get(i);
|
||||
// If name matches, then reuse (bump up use count.)
|
||||
if (strcmp(reader->name(), name) == 0) {
|
||||
reader->inc_use();
|
||||
return reader;
|
||||
}
|
||||
}
|
||||
} // Unlock the mutex
|
||||
|
||||
// Need a new image reader.
|
||||
ImageFileReader* reader = new ImageFileReader(name, big_endian);
|
||||
bool opened = reader->open();
|
||||
// If failed to open.
|
||||
if (!opened) {
|
||||
delete reader;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Lock to update
|
||||
SimpleCriticalSectionLock cs(&_reader_table_lock);
|
||||
// Search for an exist image file.
|
||||
for (u4 i = 0; i < _reader_table.count(); i++) {
|
||||
// Retrieve table entry.
|
||||
ImageFileReader* existing_reader = _reader_table.get(i);
|
||||
// If name matches, then reuse (bump up use count.)
|
||||
if (strcmp(existing_reader->name(), name) == 0) {
|
||||
existing_reader->inc_use();
|
||||
reader->close();
|
||||
delete reader;
|
||||
return existing_reader;
|
||||
}
|
||||
}
|
||||
// Bump use count and add to table.
|
||||
reader->inc_use();
|
||||
_reader_table.add(reader);
|
||||
return reader;
|
||||
}
|
||||
|
||||
// Close an image file if the file is not in use elsewhere.
|
||||
void ImageFileReader::close(ImageFileReader *reader) {
|
||||
// Lock out _reader_table.
|
||||
SimpleCriticalSectionLock cs(&_reader_table_lock);
|
||||
// If last use then remove from table and then close.
|
||||
if (reader->dec_use()) {
|
||||
_reader_table.remove(reader);
|
||||
delete reader;
|
||||
}
|
||||
}
|
||||
|
||||
// Return an id for the specifed ImageFileReader.
|
||||
u8 ImageFileReader::readerToID(ImageFileReader *reader) {
|
||||
// ID is just the cloaked reader address.
|
||||
return (u8)reader;
|
||||
}
|
||||
|
||||
// Validate the image id.
|
||||
bool ImageFileReader::idCheck(u8 id) {
|
||||
// Make sure the ID is a managed (_reader_table) reader.
|
||||
SimpleCriticalSectionLock cs(&_reader_table_lock);
|
||||
return _reader_table.contains((ImageFileReader*)id);
|
||||
}
|
||||
|
||||
// Return an id for the specifed ImageFileReader.
|
||||
ImageFileReader* ImageFileReader::idToReader(u8 id) {
|
||||
assert(idCheck(id) && "invalid image id");
|
||||
return (ImageFileReader*)id;
|
||||
}
|
||||
|
||||
// Constructor intializes to a closed state.
|
||||
ImageFileReader::ImageFileReader(const char* name, bool big_endian) {
|
||||
// Copy the image file name.
|
||||
int len = (int) strlen(name) + 1;
|
||||
_name = new char[len];
|
||||
strncpy(_name, name, len);
|
||||
// Initialize for a closed file.
|
||||
_fd = -1;
|
||||
_endian = Endian::get_handler(big_endian);
|
||||
_index_data = NULL;
|
||||
}
|
||||
|
||||
// Close image and free up data structures.
|
||||
ImageFileReader::~ImageFileReader() {
|
||||
// Ensure file is closed.
|
||||
close();
|
||||
// Free up name.
|
||||
if (_name) {
|
||||
delete _name;
|
||||
_name = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Open image file for read access.
|
||||
bool ImageFileReader::open() {
|
||||
char buffer[IMAGE_MAX_PATH];
|
||||
|
||||
// If file exists open for reading.
|
||||
_fd = osSupport::openReadOnly(_name);
|
||||
if (_fd == -1) {
|
||||
return false;
|
||||
}
|
||||
// Retrieve the file size.
|
||||
_file_size = osSupport::size(_name);
|
||||
// Read image file header and verify it has a valid header.
|
||||
size_t header_size = sizeof(ImageHeader);
|
||||
if (_file_size < header_size ||
|
||||
!read_at((u1*)&_header, header_size, 0) ||
|
||||
_header.magic(_endian) != IMAGE_MAGIC ||
|
||||
_header.major_version(_endian) != MAJOR_VERSION ||
|
||||
_header.minor_version(_endian) != MINOR_VERSION) {
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
// Size of image index.
|
||||
_index_size = index_size();
|
||||
// Make sure file is large enough to contain the index.
|
||||
if (_file_size < _index_size) {
|
||||
return false;
|
||||
}
|
||||
// Determine how much of the image is memory mapped.
|
||||
size_t map_size = (size_t)(MemoryMapImage ? _file_size : _index_size);
|
||||
// Memory map image (minimally the index.)
|
||||
_index_data = (u1*)osSupport::map_memory(_fd, _name, 0, map_size);
|
||||
assert(_index_data && "image file not memory mapped");
|
||||
// Retrieve length of index perfect hash table.
|
||||
u4 length = table_length();
|
||||
// Compute offset of the perfect hash table redirect table.
|
||||
u4 redirect_table_offset = (u4)header_size;
|
||||
// Compute offset of index attribute offsets.
|
||||
u4 offsets_table_offset = redirect_table_offset + length * sizeof(s4);
|
||||
// Compute offset of index location attribute data.
|
||||
u4 location_bytes_offset = offsets_table_offset + length * sizeof(u4);
|
||||
// Compute offset of index string table.
|
||||
u4 string_bytes_offset = location_bytes_offset + locations_size();
|
||||
// Compute address of the perfect hash table redirect table.
|
||||
_redirect_table = (s4*)(_index_data + redirect_table_offset);
|
||||
// Compute address of index attribute offsets.
|
||||
_offsets_table = (u4*)(_index_data + offsets_table_offset);
|
||||
// Compute address of index location attribute data.
|
||||
_location_bytes = _index_data + location_bytes_offset;
|
||||
// Compute address of index string table.
|
||||
_string_bytes = _index_data + string_bytes_offset;
|
||||
|
||||
// Initialize the module data
|
||||
ImageModuleData::module_data_name(buffer, _name);
|
||||
module_data = new ImageModuleData(this, buffer);
|
||||
// Successful open.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Close image file.
|
||||
void ImageFileReader::close() {
|
||||
// Deallocate the index.
|
||||
if (_index_data) {
|
||||
osSupport::unmap_memory((char*)_index_data, _index_size);
|
||||
_index_data = NULL;
|
||||
}
|
||||
// Close file.
|
||||
if (_fd != -1) {
|
||||
osSupport::close(_fd);
|
||||
_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Read directly from the file.
|
||||
bool ImageFileReader::read_at(u1* data, u8 size, u8 offset) const {
|
||||
return (u8)osSupport::read(_fd, (char*)data, size, offset) == size;
|
||||
}
|
||||
|
||||
// Find the location attributes associated with the path. Returns true if
|
||||
// the location is found, false otherwise.
|
||||
bool ImageFileReader::find_location(const char* path, ImageLocation& location) const {
|
||||
// Locate the entry in the index perfect hash table.
|
||||
s4 index = ImageStrings::find(_endian, path, _redirect_table, table_length());
|
||||
// If is found.
|
||||
if (index != ImageStrings::NOT_FOUND) {
|
||||
// Get address of first byte of location attribute stream.
|
||||
u1* data = get_location_data(index);
|
||||
// Expand location attributes.
|
||||
location.set_data(data);
|
||||
// Make sure result is not a false positive.
|
||||
return verify_location(location, path);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find the location index and size associated with the path.
|
||||
// Returns the location index and size if the location is found, 0 otherwise.
|
||||
u4 ImageFileReader::find_location_index(const char* path, u8 *size) const {
|
||||
// Locate the entry in the index perfect hash table.
|
||||
s4 index = ImageStrings::find(_endian, path, _redirect_table, table_length());
|
||||
// If found.
|
||||
if (index != ImageStrings::NOT_FOUND) {
|
||||
// Get address of first byte of location attribute stream.
|
||||
u4 offset = get_location_offset(index);
|
||||
u1* data = get_location_offset_data(offset);
|
||||
// Expand location attributes.
|
||||
ImageLocation location(data);
|
||||
// Make sure result is not a false positive.
|
||||
if (verify_location(location, path)) {
|
||||
*size = (jlong)location.get_attribute(ImageLocation::ATTRIBUTE_UNCOMPRESSED);
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
return 0; // not found
|
||||
}
|
||||
|
||||
// Assemble the location path from the string fragments indicated in the location attributes.
|
||||
void ImageFileReader::location_path(ImageLocation& location, char* path, size_t max) const {
|
||||
// Manage the image string table.
|
||||
ImageStrings strings(_string_bytes, _header.strings_size(_endian));
|
||||
// Position to first character of the path buffer.
|
||||
char* next = path;
|
||||
// Temp for string length.
|
||||
size_t length;
|
||||
// Get module string.
|
||||
const char* module = location.get_attribute(ImageLocation::ATTRIBUTE_MODULE, strings);
|
||||
// If module string is not empty string.
|
||||
if (*module != '\0') {
|
||||
// Get length of module name.
|
||||
length = strlen(module);
|
||||
// Make sure there is no buffer overflow.
|
||||
assert(next - path + length + 2 < max && "buffer overflow");
|
||||
// Append '/module/'.
|
||||
*next++ = '/';
|
||||
strncpy(next, module, length); next += length;
|
||||
*next++ = '/';
|
||||
}
|
||||
// Get parent (package) string.
|
||||
const char* parent = location.get_attribute(ImageLocation::ATTRIBUTE_PARENT, strings);
|
||||
// If parent string is not empty string.
|
||||
if (*parent != '\0') {
|
||||
// Get length of module string.
|
||||
length = strlen(parent);
|
||||
// Make sure there is no buffer overflow.
|
||||
assert(next - path + length + 1 < max && "buffer overflow");
|
||||
// Append 'patent/' .
|
||||
strncpy(next, parent, length); next += length;
|
||||
*next++ = '/';
|
||||
}
|
||||
// Get base name string.
|
||||
const char* base = location.get_attribute(ImageLocation::ATTRIBUTE_BASE, strings);
|
||||
// Get length of base name.
|
||||
length = strlen(base);
|
||||
// Make sure there is no buffer overflow.
|
||||
assert(next - path + length < max && "buffer overflow");
|
||||
// Append base name.
|
||||
strncpy(next, base, length); next += length;
|
||||
// Get extension string.
|
||||
const char* extension = location.get_attribute(ImageLocation::ATTRIBUTE_EXTENSION, strings);
|
||||
// If extension string is not empty string.
|
||||
if (*extension != '\0') {
|
||||
// Get length of extension string.
|
||||
length = strlen(extension);
|
||||
// Make sure there is no buffer overflow.
|
||||
assert(next - path + length + 1 < max && "buffer overflow");
|
||||
// Append '.extension' .
|
||||
*next++ = '.';
|
||||
strncpy(next, extension, length); next += length;
|
||||
}
|
||||
// Make sure there is no buffer overflow.
|
||||
assert((size_t)(next - path) < max && "buffer overflow");
|
||||
// Terminate string.
|
||||
*next = '\0';
|
||||
}
|
||||
|
||||
// Verify that a found location matches the supplied path (without copying.)
|
||||
bool ImageFileReader::verify_location(ImageLocation& location, const char* path) const {
|
||||
// Manage the image string table.
|
||||
ImageStrings strings(_string_bytes, _header.strings_size(_endian));
|
||||
// Position to first character of the path string.
|
||||
const char* next = path;
|
||||
// Get module name string.
|
||||
const char* module = location.get_attribute(ImageLocation::ATTRIBUTE_MODULE, strings);
|
||||
// If module string is not empty.
|
||||
if (*module != '\0') {
|
||||
// Compare '/module/' .
|
||||
if (*next++ != '/') return false;
|
||||
if (!(next = ImageStrings::starts_with(next, module))) return false;
|
||||
if (*next++ != '/') return false;
|
||||
}
|
||||
// Get parent (package) string
|
||||
const char* parent = location.get_attribute(ImageLocation::ATTRIBUTE_PARENT, strings);
|
||||
// If parent string is not empty string.
|
||||
if (*parent != '\0') {
|
||||
// Compare 'parent/' .
|
||||
if (!(next = ImageStrings::starts_with(next, parent))) return false;
|
||||
if (*next++ != '/') return false;
|
||||
}
|
||||
// Get base name string.
|
||||
const char* base = location.get_attribute(ImageLocation::ATTRIBUTE_BASE, strings);
|
||||
// Compare with basne name.
|
||||
if (!(next = ImageStrings::starts_with(next, base))) return false;
|
||||
// Get extension string.
|
||||
const char* extension = location.get_attribute(ImageLocation::ATTRIBUTE_EXTENSION, strings);
|
||||
// If extension is not empty.
|
||||
if (*extension != '\0') {
|
||||
// Compare '.extension' .
|
||||
if (*next++ != '.') return false;
|
||||
if (!(next = ImageStrings::starts_with(next, extension))) return false;
|
||||
}
|
||||
// True only if complete match and no more characters.
|
||||
return *next == '\0';
|
||||
}
|
||||
|
||||
// Return the resource for the supplied location offset.
|
||||
void ImageFileReader::get_resource(u4 offset, u1* uncompressed_data) const {
|
||||
// Get address of first byte of location attribute stream.
|
||||
u1* data = get_location_offset_data(offset);
|
||||
// Expand location attributes.
|
||||
ImageLocation location(data);
|
||||
// Read the data
|
||||
get_resource(location, uncompressed_data);
|
||||
}
|
||||
|
||||
// Return the resource for the supplied location.
|
||||
void ImageFileReader::get_resource(ImageLocation& location, u1* uncompressed_data) const {
|
||||
// Retrieve the byte offset and size of the resource.
|
||||
u8 offset = location.get_attribute(ImageLocation::ATTRIBUTE_OFFSET);
|
||||
u8 uncompressed_size = location.get_attribute(ImageLocation::ATTRIBUTE_UNCOMPRESSED);
|
||||
u8 compressed_size = location.get_attribute(ImageLocation::ATTRIBUTE_COMPRESSED);
|
||||
// If the resource is compressed.
|
||||
if (compressed_size != 0) {
|
||||
u1* compressed_data;
|
||||
// If not memory mapped read in bytes.
|
||||
if (!MemoryMapImage) {
|
||||
// Allocate buffer for compression.
|
||||
compressed_data = new u1[(u4)compressed_size];
|
||||
// Read bytes from offset beyond the image index.
|
||||
bool is_read = read_at(compressed_data, compressed_size, _index_size + offset);
|
||||
assert(is_read && "error reading from image or short read");
|
||||
} else {
|
||||
compressed_data = get_data_address() + offset;
|
||||
}
|
||||
// Get image string table.
|
||||
const ImageStrings strings = get_strings();
|
||||
// Decompress resource.
|
||||
ImageDecompressor::decompress_resource(compressed_data, uncompressed_data, (u4)uncompressed_size,
|
||||
&strings);
|
||||
// If not memory mapped then release temporary buffer.
|
||||
if (!MemoryMapImage) {
|
||||
delete compressed_data;
|
||||
}
|
||||
} else {
|
||||
// Read bytes from offset beyond the image index.
|
||||
bool is_read = read_at(uncompressed_data, uncompressed_size, _index_size + offset);
|
||||
assert(is_read && "error reading from image or short read");
|
||||
}
|
||||
}
|
||||
|
||||
// Return the ImageModuleData for this image
|
||||
ImageModuleData * ImageFileReader::get_image_module_data() {
|
||||
return module_data;
|
||||
}
|
648
jdk/src/java.base/share/native/libjimage/imageFile.hpp
Normal file
648
jdk/src/java.base/share/native/libjimage/imageFile.hpp
Normal file
@ -0,0 +1,648 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LIBJIMAGE_IMAGEFILE_HPP
|
||||
#define LIBJIMAGE_IMAGEFILE_HPP
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "endian.hpp"
|
||||
#include "inttypes.hpp"
|
||||
|
||||
// Image files are an alternate file format for storing classes and resources. The
|
||||
// goal is to supply file access which is faster and smaller than the jar format.
|
||||
// It should be noted that unlike jars, information stored in an image is in native
|
||||
// endian format. This allows the image to be mapped into memory without endian
|
||||
// translation. This also means that images are platform dependent.
|
||||
//
|
||||
// Image files are structured as three sections;
|
||||
//
|
||||
// +-----------+
|
||||
// | Header |
|
||||
// +-----------+
|
||||
// | |
|
||||
// | Index |
|
||||
// | |
|
||||
// +-----------+
|
||||
// | |
|
||||
// | |
|
||||
// | Resources |
|
||||
// | |
|
||||
// | |
|
||||
// +-----------+
|
||||
//
|
||||
// The header contains information related to identification and description of
|
||||
// contents.
|
||||
//
|
||||
// +-------------------------+
|
||||
// | Magic (0xCAFEDADA) |
|
||||
// +------------+------------+
|
||||
// | Major Vers | Minor Vers |
|
||||
// +------------+------------+
|
||||
// | Flags |
|
||||
// +-------------------------+
|
||||
// | Resource Count |
|
||||
// +-------------------------+
|
||||
// | Table Length |
|
||||
// +-------------------------+
|
||||
// | Attributes Size |
|
||||
// +-------------------------+
|
||||
// | Strings Size |
|
||||
// +-------------------------+
|
||||
//
|
||||
// Magic - means of identifying validity of the file. This avoids requiring a
|
||||
// special file extension.
|
||||
// Major vers, minor vers - differences in version numbers indicate structural
|
||||
// changes in the image.
|
||||
// Flags - various image wide flags (future).
|
||||
// Resource count - number of resources in the file.
|
||||
// Table length - the length of lookup tables used in the index.
|
||||
// Attributes size - number of bytes in the region used to store location attribute
|
||||
// streams.
|
||||
// Strings size - the size of the region used to store strings used by the
|
||||
// index and meta data.
|
||||
//
|
||||
// The index contains information related to resource lookup. The algorithm
|
||||
// used for lookup is "A Practical Minimal Perfect Hashing Method"
|
||||
// (http://homepages.dcc.ufmg.br/~nivio/papers/wea05.pdf). Given a path string
|
||||
// in the form /<module>/<package>/<base>.<extension> return the resource location
|
||||
// information;
|
||||
//
|
||||
// redirectIndex = hash(path, DEFAULT_SEED) % table_length;
|
||||
// redirect = redirectTable[redirectIndex];
|
||||
// if (redirect == 0) return not found;
|
||||
// locationIndex = redirect < 0 ? -1 - redirect : hash(path, redirect) % table_length;
|
||||
// location = locationTable[locationIndex];
|
||||
// if (!verify(location, path)) return not found;
|
||||
// return location;
|
||||
//
|
||||
// Note: The hash function takes an initial seed value. A different seed value
|
||||
// usually returns a different result for strings that would otherwise collide with
|
||||
// other seeds. The verify function guarantees the found resource location is
|
||||
// indeed the resource we are looking for.
|
||||
//
|
||||
// The following is the format of the index;
|
||||
//
|
||||
// +-------------------+
|
||||
// | Redirect Table |
|
||||
// +-------------------+
|
||||
// | Attribute Offsets |
|
||||
// +-------------------+
|
||||
// | Attribute Data |
|
||||
// +-------------------+
|
||||
// | Strings |
|
||||
// +-------------------+
|
||||
//
|
||||
// Redirect Table - Array of 32-bit signed values representing actions that
|
||||
// should take place for hashed strings that map to that
|
||||
// value. Negative values indicate no hash collision and can be
|
||||
// quickly converted to indices into attribute offsets. Positive
|
||||
// values represent a new seed for hashing an index into attribute
|
||||
// offsets. Zero indicates not found.
|
||||
// Attribute Offsets - Array of 32-bit unsigned values representing offsets into
|
||||
// attribute data. Attribute offsets can be iterated to do a
|
||||
// full survey of resources in the image. Offset of zero
|
||||
// indicates no attributes.
|
||||
// Attribute Data - Bytes representing compact attribute data for locations. (See
|
||||
// comments in ImageLocation.)
|
||||
// Strings - Collection of zero terminated UTF-8 strings used by the index and
|
||||
// image meta data. Each string is accessed by offset. Each string is
|
||||
// unique. Offset zero is reserved for the empty string.
|
||||
//
|
||||
// Note that the memory mapped index assumes 32 bit alignment of each component
|
||||
// in the index.
|
||||
//
|
||||
// Endianness of an image.
|
||||
// An image booted by hotspot is always in native endian. However, it is possible
|
||||
// to read (by the JDK) in alternate endian format. Primarily, this is during
|
||||
// cross platform scenarios. Ex, where javac needs to read an embedded image
|
||||
// to access classes for crossing compilation.
|
||||
//
|
||||
|
||||
class ImageFileReader; // forward declaration
|
||||
|
||||
// Manage image file string table.
|
||||
class ImageStrings {
|
||||
private:
|
||||
u1* _data; // Data bytes for strings.
|
||||
u4 _size; // Number of bytes in the string table.
|
||||
public:
|
||||
enum {
|
||||
// Not found result from find routine.
|
||||
NOT_FOUND = -1,
|
||||
// Prime used to generate hash for Perfect Hashing.
|
||||
HASH_MULTIPLIER = 0x01000193
|
||||
};
|
||||
|
||||
ImageStrings(u1* data, u4 size) : _data(data), _size(size) {}
|
||||
|
||||
// Return the UTF-8 string beginning at offset.
|
||||
inline const char* get(u4 offset) const {
|
||||
assert(offset < _size && "offset exceeds string table size");
|
||||
return (const char*)(_data + offset);
|
||||
}
|
||||
|
||||
// Compute the Perfect Hashing hash code for the supplied UTF-8 string.
|
||||
inline static u4 hash_code(const char* string) {
|
||||
return hash_code(string, HASH_MULTIPLIER);
|
||||
}
|
||||
|
||||
// Compute the Perfect Hashing hash code for the supplied string, starting at seed.
|
||||
static s4 hash_code(const char* string, s4 seed);
|
||||
|
||||
// Match up a string in a perfect hash table. Result still needs validation
|
||||
// for precise match.
|
||||
static s4 find(Endian* endian, const char* name, s4* redirect, u4 length);
|
||||
|
||||
// Test to see if UTF-8 string begins with the start UTF-8 string. If so,
|
||||
// return non-NULL address of remaining portion of string. Otherwise, return
|
||||
// NULL. Used to test sections of a path without copying from image string
|
||||
// table.
|
||||
static const char* starts_with(const char* string, const char* start);
|
||||
|
||||
// Test to see if UTF-8 string begins with start char. If so, return non-NULL
|
||||
// address of remaining portion of string. Otherwise, return NULL. Used
|
||||
// to test a character of a path without copying.
|
||||
inline static const char* starts_with(const char* string, const char ch) {
|
||||
return *string == ch ? string + 1 : NULL;
|
||||
}
|
||||
};
|
||||
|
||||
// Manage image file location attribute data. Within an image, a location's
|
||||
// attributes are compressed into a stream of bytes. An attribute stream is
|
||||
// composed of individual attribute sequences. Each attribute sequence begins with
|
||||
// a header byte containing the attribute 'kind' (upper 5 bits of header) and the
|
||||
// 'length' less 1 (lower 3 bits of header) of bytes that follow containing the
|
||||
// attribute value. Attribute values present as most significant byte first.
|
||||
//
|
||||
// Ex. Container offset (ATTRIBUTE_OFFSET) 0x33562 would be represented as 0x22
|
||||
// (kind = 4, length = 3), 0x03, 0x35, 0x62.
|
||||
//
|
||||
// An attribute stream is terminated with a header kind of ATTRIBUTE_END (header
|
||||
// byte of zero.)
|
||||
//
|
||||
// ImageLocation inflates the stream into individual values stored in the long
|
||||
// array _attributes. This allows an attribute value can be quickly accessed by
|
||||
// direct indexing. Unspecified values default to zero.
|
||||
//
|
||||
// Notes:
|
||||
// - Even though ATTRIBUTE_END is used to mark the end of the attribute stream,
|
||||
// streams will contain zero byte values to represent lesser significant bits.
|
||||
// Thus, detecting a zero byte is not sufficient to detect the end of an attribute
|
||||
// stream.
|
||||
// - ATTRIBUTE_OFFSET represents the number of bytes from the beginning of the region
|
||||
// storing the resources. Thus, in an image this represents the number of bytes
|
||||
// after the index.
|
||||
// - Currently, compressed resources are represented by having a non-zero
|
||||
// ATTRIBUTE_COMPRESSED value. This represents the number of bytes stored in the
|
||||
// image, and the value of ATTRIBUTE_UNCOMPRESSED represents number of bytes of the
|
||||
// inflated resource in memory. If the ATTRIBUTE_COMPRESSED is zero then the value
|
||||
// of ATTRIBUTE_UNCOMPRESSED represents both the number of bytes in the image and
|
||||
// in memory. In the future, additional compression techniques will be used and
|
||||
// represented differently.
|
||||
// - Package strings include trailing slash and extensions include prefix period.
|
||||
//
|
||||
class ImageLocation {
|
||||
public:
|
||||
enum {
|
||||
ATTRIBUTE_END, // End of attribute stream marker
|
||||
ATTRIBUTE_MODULE, // String table offset of module name
|
||||
ATTRIBUTE_PARENT, // String table offset of resource path parent
|
||||
ATTRIBUTE_BASE, // String table offset of resource path base
|
||||
ATTRIBUTE_EXTENSION, // String table offset of resource path extension
|
||||
ATTRIBUTE_OFFSET, // Container byte offset of resource
|
||||
ATTRIBUTE_COMPRESSED, // In image byte size of the compressed resource
|
||||
ATTRIBUTE_UNCOMPRESSED, // In memory byte size of the uncompressed resource
|
||||
ATTRIBUTE_COUNT // Number of attribute kinds
|
||||
};
|
||||
|
||||
private:
|
||||
// Values of inflated attributes.
|
||||
u8 _attributes[ATTRIBUTE_COUNT];
|
||||
|
||||
// Return the attribute value number of bytes.
|
||||
inline static u1 attribute_length(u1 data) {
|
||||
return (data & 0x7) + 1;
|
||||
}
|
||||
|
||||
// Return the attribute kind.
|
||||
inline static u1 attribute_kind(u1 data) {
|
||||
u1 kind = data >> 3;
|
||||
assert(kind < ATTRIBUTE_COUNT && "invalid attribute kind");
|
||||
return kind;
|
||||
}
|
||||
|
||||
// Return the attribute length.
|
||||
inline static u8 attribute_value(u1* data, u1 n) {
|
||||
assert(0 < n && n <= 8 && "invalid attribute value length");
|
||||
u8 value = 0;
|
||||
// Most significant bytes first.
|
||||
for (u1 i = 0; i < n; i++) {
|
||||
value <<= 8;
|
||||
value |= data[i];
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public:
|
||||
ImageLocation() {
|
||||
clear_data();
|
||||
}
|
||||
|
||||
ImageLocation(u1* data) {
|
||||
clear_data();
|
||||
set_data(data);
|
||||
}
|
||||
|
||||
// Inflates the attribute stream into individual values stored in the long
|
||||
// array _attributes. This allows an attribute value to be quickly accessed by
|
||||
// direct indexing. Unspecified values default to zero.
|
||||
void set_data(u1* data);
|
||||
|
||||
// Zero all attribute values.
|
||||
void clear_data();
|
||||
|
||||
// Retrieve an attribute value from the inflated array.
|
||||
inline u8 get_attribute(u1 kind) const {
|
||||
assert(ATTRIBUTE_END < kind && kind < ATTRIBUTE_COUNT && "invalid attribute kind");
|
||||
return _attributes[kind];
|
||||
}
|
||||
|
||||
// Retrieve an attribute string value from the inflated array.
|
||||
inline const char* get_attribute(u4 kind, const ImageStrings& strings) const {
|
||||
return strings.get((u4)get_attribute(kind));
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// NOTE: needs revision.
|
||||
// Each loader requires set of module meta data to identify which modules and
|
||||
// packages are managed by that loader. Currently, there is one image file per
|
||||
// builtin loader, so only one module meta data resource per file.
|
||||
//
|
||||
// Each element in the module meta data is a native endian 4 byte integer. Note
|
||||
// that entries with zero offsets for string table entries should be ignored (
|
||||
// padding for hash table lookup.)
|
||||
//
|
||||
// Format:
|
||||
// Count of package to module entries
|
||||
// Count of module to package entries
|
||||
// Perfect Hash redirect table[Count of package to module entries]
|
||||
// Package to module entries[Count of package to module entries]
|
||||
// Offset to package name in string table
|
||||
// Offset to module name in string table
|
||||
// Perfect Hash redirect table[Count of module to package entries]
|
||||
// Module to package entries[Count of module to package entries]
|
||||
// Offset to module name in string table
|
||||
// Count of packages in module
|
||||
// Offset to first package in packages table
|
||||
// Packages[]
|
||||
// Offset to package name in string table
|
||||
//
|
||||
// Manage the image module meta data.
|
||||
class ImageModuleData {
|
||||
class Header {
|
||||
private:
|
||||
u4 _ptm_count; // Count of package to module entries
|
||||
u4 _mtp_count; // Count of module to package entries
|
||||
public:
|
||||
inline u4 ptm_count(Endian* endian) const { return endian->get(_ptm_count); }
|
||||
inline u4 mtp_count(Endian* endian) const { return endian->get(_mtp_count); }
|
||||
};
|
||||
|
||||
// Hashtable entry
|
||||
class HashData {
|
||||
private:
|
||||
u4 _name_offset; // Name offset in string table
|
||||
public:
|
||||
inline s4 name_offset(Endian* endian) const { return endian->get(_name_offset); }
|
||||
};
|
||||
|
||||
// Package to module hashtable entry
|
||||
class PTMData : public HashData {
|
||||
private:
|
||||
u4 _module_name_offset; // Module name offset in string table
|
||||
public:
|
||||
inline s4 module_name_offset(Endian* endian) const { return endian->get(_module_name_offset); }
|
||||
};
|
||||
|
||||
// Module to package hashtable entry
|
||||
class MTPData : public HashData {
|
||||
private:
|
||||
u4 _package_count; // Number of packages in module
|
||||
u4 _package_offset; // Offset in package list
|
||||
public:
|
||||
inline u4 package_count(Endian* endian) const { return endian->get(_package_count); }
|
||||
inline u4 package_offset(Endian* endian) const { return endian->get(_package_offset); }
|
||||
};
|
||||
|
||||
const ImageFileReader* _image_file; // Source image file
|
||||
Endian* _endian; // Endian handler
|
||||
ImageStrings _strings; // Image file strings
|
||||
u1* _data; // Module data resource data
|
||||
u8 _data_size; // Size of resource data
|
||||
Header* _header; // Module data header
|
||||
s4* _ptm_redirect; // Package to module hashtable redirect
|
||||
PTMData* _ptm_data; // Package to module data
|
||||
s4* _mtp_redirect; // Module to packages hashtable redirect
|
||||
MTPData* _mtp_data; // Module to packages data
|
||||
s4* _mtp_packages; // Package data (name offsets)
|
||||
|
||||
// Return a string from the string table.
|
||||
inline const char* get_string(u4 offset) {
|
||||
return _strings.get(offset);
|
||||
}
|
||||
|
||||
inline u4 mtp_package(u4 index) {
|
||||
return _endian->get(_mtp_packages[index]);
|
||||
}
|
||||
|
||||
public:
|
||||
ImageModuleData(const ImageFileReader* image_file, const char* module_data_name);
|
||||
~ImageModuleData();
|
||||
|
||||
// Return the name of the module data resource.
|
||||
static void module_data_name(char* buffer, const char* image_file_name);
|
||||
|
||||
// Return the module in which a package resides. Returns NULL if not found.
|
||||
const char* package_to_module(const char* package_name);
|
||||
|
||||
// Returns all the package names in a module in a NULL terminated array.
|
||||
// Returns NULL if module not found.
|
||||
const char** module_to_packages(const char* module_name);
|
||||
};
|
||||
|
||||
// Image file header, starting at offset 0.
|
||||
class ImageHeader {
|
||||
private:
|
||||
u4 _magic; // Image file marker
|
||||
u4 _version; // Image file major version number
|
||||
u4 _flags; // Image file flags
|
||||
u4 _resource_count; // Number of resources in file
|
||||
u4 _table_length; // Number of slots in index tables
|
||||
u4 _locations_size; // Number of bytes in attribute table
|
||||
u4 _strings_size; // Number of bytes in string table
|
||||
|
||||
public:
|
||||
u4 magic() const { return _magic; }
|
||||
u4 magic(Endian* endian) const { return endian->get(_magic); }
|
||||
void set_magic(Endian* endian, u4 magic) { return endian->set(_magic, magic); }
|
||||
|
||||
u4 major_version(Endian* endian) const { return endian->get(_version) >> 16; }
|
||||
u4 minor_version(Endian* endian) const { return endian->get(_version) & 0xFFFF; }
|
||||
void set_version(Endian* endian, u4 major_version, u4 minor_version) {
|
||||
return endian->set(_version, major_version << 16 | minor_version);
|
||||
}
|
||||
|
||||
u4 flags(Endian* endian) const { return endian->get(_flags); }
|
||||
void set_flags(Endian* endian, u4 value) { return endian->set(_flags, value); }
|
||||
|
||||
u4 resource_count(Endian* endian) const { return endian->get(_resource_count); }
|
||||
void set_resource_count(Endian* endian, u4 count) { return endian->set(_resource_count, count); }
|
||||
|
||||
u4 table_length(Endian* endian) const { return endian->get(_table_length); }
|
||||
void set_table_length(Endian* endian, u4 count) { return endian->set(_table_length, count); }
|
||||
|
||||
u4 locations_size(Endian* endian) const { return endian->get(_locations_size); }
|
||||
void set_locations_size(Endian* endian, u4 size) { return endian->set(_locations_size, size); }
|
||||
|
||||
u4 strings_size(Endian* endian) const { return endian->get(_strings_size); }
|
||||
void set_strings_size(Endian* endian, u4 size) { return endian->set(_strings_size, size); }
|
||||
};
|
||||
|
||||
// Max path length limit independent of platform. Windows max path is 1024,
|
||||
// other platforms use 4096. The JCK fails several tests when 1024 is used.
|
||||
#define IMAGE_MAX_PATH 4096
|
||||
|
||||
class ImageFileReader;
|
||||
|
||||
// Manage a table of open image files. This table allows multiple access points
|
||||
// to share an open image.
|
||||
class ImageFileReaderTable {
|
||||
private:
|
||||
const static u4 _growth = 8; // Growth rate of the table
|
||||
u4 _count; // Number of entries in the table
|
||||
u4 _max; // Maximum number of entries allocated
|
||||
ImageFileReader** _table; // Growable array of entries
|
||||
|
||||
public:
|
||||
ImageFileReaderTable();
|
||||
~ImageFileReaderTable();
|
||||
|
||||
// Return the number of entries.
|
||||
inline u4 count() { return _count; }
|
||||
|
||||
// Return the ith entry from the table.
|
||||
inline ImageFileReader* get(u4 i) { return _table[i]; }
|
||||
|
||||
// Add a new image entry to the table.
|
||||
void add(ImageFileReader* image);
|
||||
|
||||
// Remove an image entry from the table.
|
||||
void remove(ImageFileReader* image);
|
||||
|
||||
// Determine if image entry is in table.
|
||||
bool contains(ImageFileReader* image);
|
||||
};
|
||||
|
||||
// Manage the image file.
|
||||
// ImageFileReader manages the content of an image file.
|
||||
// Initially, the header of the image file is read for validation. If valid,
|
||||
// values in the header are used calculate the size of the image index. The
|
||||
// index is then memory mapped to allow load on demand and sharing. The
|
||||
// -XX:+MemoryMapImage flag determines if the entire file is loaded (server use.)
|
||||
// An image can be used by Hotspot and multiple reference points in the JDK, thus
|
||||
// it is desirable to share a reader. To accomodate sharing, a share table is
|
||||
// defined (see ImageFileReaderTable in imageFile.cpp) To track the number of
|
||||
// uses, ImageFileReader keeps a use count (_use). Use is incremented when
|
||||
// 'opened' by reference point and decremented when 'closed'. Use of zero
|
||||
// leads the ImageFileReader to be actually closed and discarded.
|
||||
class ImageFileReader {
|
||||
private:
|
||||
// Manage a number of image files such that an image can be shared across
|
||||
// multiple uses (ex. loader.)
|
||||
static ImageFileReaderTable _reader_table;
|
||||
|
||||
char* _name; // Name of image
|
||||
s4 _use; // Use count
|
||||
int _fd; // File descriptor
|
||||
Endian* _endian; // Endian handler
|
||||
u8 _file_size; // File size in bytes
|
||||
ImageHeader _header; // Image header
|
||||
size_t _index_size; // Total size of index
|
||||
u1* _index_data; // Raw index data
|
||||
s4* _redirect_table; // Perfect hash redirect table
|
||||
u4* _offsets_table; // Location offset table
|
||||
u1* _location_bytes; // Location attributes
|
||||
u1* _string_bytes; // String table
|
||||
ImageModuleData *module_data; // The ImageModuleData for this image
|
||||
|
||||
ImageFileReader(const char* name, bool big_endian);
|
||||
~ImageFileReader();
|
||||
|
||||
// Compute number of bytes in image file index.
|
||||
inline size_t index_size() {
|
||||
return sizeof(ImageHeader) +
|
||||
table_length() * sizeof(u4) * 2 + locations_size() + strings_size();
|
||||
}
|
||||
|
||||
public:
|
||||
enum {
|
||||
// Image file marker.
|
||||
IMAGE_MAGIC = 0xCAFEDADA,
|
||||
// Endian inverted Image file marker.
|
||||
IMAGE_MAGIC_INVERT = 0xDADAFECA,
|
||||
// Image file major version number.
|
||||
MAJOR_VERSION = 1,
|
||||
// Image file minor version number.
|
||||
MINOR_VERSION = 0
|
||||
};
|
||||
|
||||
// Open an image file, reuse structure if file already open.
|
||||
static ImageFileReader* open(const char* name, bool big_endian = Endian::is_big_endian());
|
||||
|
||||
// Close an image file if the file is not in use elsewhere.
|
||||
static void close(ImageFileReader *reader);
|
||||
|
||||
// Return an id for the specifed ImageFileReader.
|
||||
static u8 readerToID(ImageFileReader *reader);
|
||||
|
||||
// Validate the image id.
|
||||
static bool idCheck(u8 id);
|
||||
|
||||
// Return an id for the specifed ImageFileReader.
|
||||
static ImageFileReader* idToReader(u8 id);
|
||||
|
||||
// Open image file for read access.
|
||||
bool open();
|
||||
|
||||
// Close image file.
|
||||
void close();
|
||||
|
||||
// Read directly from the file.
|
||||
bool read_at(u1* data, u8 size, u8 offset) const;
|
||||
|
||||
inline Endian* endian() const { return _endian; }
|
||||
|
||||
// Retrieve name of image file.
|
||||
inline const char* name() const {
|
||||
return _name;
|
||||
}
|
||||
|
||||
// Retrieve size of image file.
|
||||
inline u8 file_size() const {
|
||||
return _file_size;
|
||||
}
|
||||
|
||||
// Return first address of index data.
|
||||
inline u1* get_index_address() const {
|
||||
return _index_data;
|
||||
}
|
||||
|
||||
// Return first address of resource data.
|
||||
inline u1* get_data_address() const {
|
||||
return _index_data + _index_size;
|
||||
}
|
||||
|
||||
// Get the size of the index data.
|
||||
size_t get_index_size() const {
|
||||
return _index_size;
|
||||
}
|
||||
|
||||
inline u4 table_length() const {
|
||||
return _header.table_length(_endian);
|
||||
}
|
||||
|
||||
inline u4 locations_size() const {
|
||||
return _header.locations_size(_endian);
|
||||
}
|
||||
|
||||
inline u4 strings_size()const {
|
||||
return _header.strings_size(_endian);
|
||||
}
|
||||
|
||||
inline u4* offsets_table() const {
|
||||
return _offsets_table;
|
||||
}
|
||||
|
||||
// Increment use count.
|
||||
inline void inc_use() {
|
||||
_use++;
|
||||
}
|
||||
|
||||
// Decrement use count.
|
||||
inline bool dec_use() {
|
||||
return --_use == 0;
|
||||
}
|
||||
|
||||
// Return a string table accessor.
|
||||
inline const ImageStrings get_strings() const {
|
||||
return ImageStrings(_string_bytes, _header.strings_size(_endian));
|
||||
}
|
||||
|
||||
// Return location attribute stream at offset.
|
||||
inline u1* get_location_offset_data(u4 offset) const {
|
||||
assert((u4)offset < _header.locations_size(_endian) &&
|
||||
"offset exceeds location attributes size");
|
||||
return offset != 0 ? _location_bytes + offset : NULL;
|
||||
}
|
||||
|
||||
// Return location attribute stream for location i.
|
||||
inline u1* get_location_data(u4 index) const {
|
||||
return get_location_offset_data(get_location_offset(index));
|
||||
}
|
||||
|
||||
// Return the location offset for index.
|
||||
inline u4 get_location_offset(u4 index) const {
|
||||
assert((u4)index < _header.table_length(_endian) &&
|
||||
"index exceeds location count");
|
||||
return _endian->get(_offsets_table[index]);
|
||||
}
|
||||
|
||||
// Find the location attributes associated with the path. Returns true if
|
||||
// the location is found, false otherwise.
|
||||
bool find_location(const char* path, ImageLocation& location) const;
|
||||
|
||||
// Find the location index and size associated with the path.
|
||||
// Returns the location index and size if the location is found,
|
||||
// ImageFileReader::NOT_FOUND otherwise.
|
||||
u4 find_location_index(const char* path, u8 *size) const;
|
||||
|
||||
// Assemble the location path.
|
||||
void location_path(ImageLocation& location, char* path, size_t max) const;
|
||||
|
||||
// Verify that a found location matches the supplied path.
|
||||
bool verify_location(ImageLocation& location, const char* path) const;
|
||||
|
||||
// Return the resource for the supplied location index.
|
||||
void get_resource(u4 index, u1* uncompressed_data) const;
|
||||
|
||||
// Return the resource for the supplied path.
|
||||
void get_resource(ImageLocation& location, u1* uncompressed_data) const;
|
||||
|
||||
// Return the ImageModuleData for this image
|
||||
ImageModuleData * get_image_module_data();
|
||||
|
||||
};
|
||||
#endif // LIBJIMAGE_IMAGEFILE_HPP
|
43
jdk/src/java.base/share/native/libjimage/inttypes.hpp
Normal file
43
jdk/src/java.base/share/native/libjimage/inttypes.hpp
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LIBJIMAGE_INTTYPES_HPP
|
||||
#define LIBJIMAGE_INTTYPES_HPP
|
||||
|
||||
typedef unsigned char u1;
|
||||
typedef char s1;
|
||||
typedef unsigned short u2;
|
||||
typedef short s2;
|
||||
typedef unsigned int u4;
|
||||
typedef int s4;
|
||||
#ifdef LP64
|
||||
typedef unsigned long u8;
|
||||
typedef long s8;
|
||||
#else
|
||||
typedef unsigned long long u8;
|
||||
typedef long long s8;
|
||||
#endif
|
||||
|
||||
#endif // LIBJIMAGE_INTTYPES_HPP
|
||||
|
194
jdk/src/java.base/share/native/libjimage/jimage.cpp
Normal file
194
jdk/src/java.base/share/native/libjimage/jimage.cpp
Normal file
@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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 <string.h>
|
||||
|
||||
#include "jimage.hpp"
|
||||
|
||||
#include "imageFile.hpp"
|
||||
|
||||
#define BOOT_VERSION "9.0"
|
||||
|
||||
/*
|
||||
* JImageOpen - Given the supplied full path file name, open an image file. This
|
||||
* function will also initialize tables and retrieve meta-data necessary to
|
||||
* satisfy other functions in the API. If the image file has been previously
|
||||
* open, a new open request will share memory and resources used by the previous
|
||||
* open. A call to JImageOpen should be balanced by a call to JImageClose, to
|
||||
* release memory and resources used. If the image file is not found or cannot
|
||||
* be open, then NULL is returned and error will contain a reason for the
|
||||
* failure; a positive value for a system error number, negative for a jimage
|
||||
* specific error (see JImage Error Codes.)
|
||||
*
|
||||
* Ex.
|
||||
* jint error;
|
||||
* JImageFile* jimage = (*JImageOpen)(JAVA_HOME "lib/modules/bootmodules.jimage", &error);
|
||||
* if (image == NULL) {
|
||||
* tty->print_cr("JImage failed to open: %d", error);
|
||||
* ...
|
||||
* }
|
||||
* ...
|
||||
*/
|
||||
extern "C" JImageFile* JIMAGE_Open(const char *name, jint* error) {
|
||||
// TODO - return a meaningful error code
|
||||
*error = 0;
|
||||
ImageFileReader* jfile = ImageFileReader::open(name);
|
||||
return (JImageFile*) jfile;
|
||||
}
|
||||
|
||||
/*
|
||||
* JImageClose - Given the supplied open image file (see JImageOpen), release
|
||||
* memory and resources used by the open file and close the file. If the image
|
||||
* file is shared by other uses, release and close is deferred until the last use
|
||||
* is also closed.
|
||||
*
|
||||
* Ex.
|
||||
* (*JImageClose)(image);
|
||||
*/
|
||||
extern "C" void JIMAGE_Close(JImageFile* image) {
|
||||
ImageFileReader::close((ImageFileReader*) image);
|
||||
}
|
||||
|
||||
/*
|
||||
* JImagePackageToModule - Given an open image file (see JImageOpen) and the name
|
||||
* of a package, return the name of module where the package resides. If the
|
||||
* package does not exist in the image file, the function returns NULL.
|
||||
* The resulting string does/should not have to be released. All strings are
|
||||
* utf-8, zero byte terminated.
|
||||
*
|
||||
* Ex.
|
||||
* const char* package = (*JImagePackageToModule)(image, "java/lang");
|
||||
* tty->print_cr(package);
|
||||
* —> java.base
|
||||
*/
|
||||
extern "C" const char* JIMAGE_PackageToModule(JImageFile* image, const char* package_name) {
|
||||
return ((ImageFileReader*) image)->get_image_module_data()->package_to_module(package_name);
|
||||
}
|
||||
|
||||
/*
|
||||
* JImageFindResource - Given an open image file (see JImageOpen), a module
|
||||
* name, a version string and the name of a class/resource, return location
|
||||
* information describing the resource and its size. If no resource is found, the
|
||||
* function returns JIMAGE_NOT_FOUND and the value of size is undefined.
|
||||
* The version number should be "9.0" and is not used in locating the resource.
|
||||
* The resulting location does/should not have to be released.
|
||||
* All strings are utf-8, zero byte terminated.
|
||||
*
|
||||
* Ex.
|
||||
* jlong size;
|
||||
* JImageLocationRef location = (*JImageFindResource)(image, "java.base", "9.0", "java/lang/String.class", &size);
|
||||
*/
|
||||
extern "C" JImageLocationRef JIMAGE_FindResource(JImageFile* image,
|
||||
const char* module_name, const char* version, const char* name,
|
||||
jlong* size) {
|
||||
if (strcmp(version, BOOT_VERSION) != 0) {
|
||||
return (JImageLocationRef) 0;
|
||||
}
|
||||
|
||||
ImageLocation location;
|
||||
char fullpath[IMAGE_MAX_PATH];
|
||||
|
||||
// Concatenate to get full path
|
||||
strncpy(fullpath, "/", IMAGE_MAX_PATH - 1);
|
||||
strncat(fullpath, module_name, IMAGE_MAX_PATH - 1);
|
||||
strncat(fullpath, "/", IMAGE_MAX_PATH - 1);
|
||||
strncat(fullpath, name, IMAGE_MAX_PATH - 1);
|
||||
JImageLocationRef loc =
|
||||
(JImageLocationRef) ((ImageFileReader*) image)->find_location_index(fullpath, (u8*) size);
|
||||
return loc;
|
||||
}
|
||||
|
||||
/*
|
||||
* JImageGetResource - Given an open image file (see JImageOpen), a resource’s
|
||||
* location information (see JImageFindResource), a buffer of appropriate
|
||||
* size and the size, retrieve the bytes associated with the
|
||||
* resource. If the size is less than the resource size then the read is truncated.
|
||||
* If the size is greater than the resource size then the remainder of the buffer
|
||||
* is zero filled. The function will return the actual size of the resource.
|
||||
*
|
||||
* Ex.
|
||||
* jlong size;
|
||||
* JImageLocationRef* location = (*JImageFindResource)(image, "java.base", "9.0", "java/lang/String.class", &size);
|
||||
* char* buffer = new char[size];
|
||||
* (*JImageGetResource)(image, location, buffer, size);
|
||||
*/
|
||||
extern "C" jlong JIMAGE_GetResource(JImageFile* image, JImageLocationRef location,
|
||||
char* buffer, jlong size) {
|
||||
((ImageFileReader*) image)->get_resource((u4) location, (u1*) buffer);
|
||||
return size;
|
||||
}
|
||||
|
||||
/*
|
||||
* JImageResourceIterator - Given an open image file (see JImageOpen), a visitor
|
||||
* function and a visitor argument, iterator through each of the image's resources.
|
||||
* The visitor function is called with the image file, the module name, the
|
||||
* package name, the base name, the extension and the visitor argument. The return
|
||||
* value of the visitor function should be true, unless an early iteration exit is
|
||||
* required. All strings are utf-8, zero byte terminated.file.
|
||||
*
|
||||
* Ex.
|
||||
* bool ctw_visitor(JImageFile* jimage, const char* module_name, const char* version, const char* package, const char* name, const char* extension, void* arg) {
|
||||
* if (strcmp(extension, “class”) == 0) {
|
||||
* char path[JIMAGE_MAX_PATH];
|
||||
* Thread* THREAD = Thread::current();
|
||||
* jio_snprintf(path, JIMAGE_MAX_PATH - 1, "/%s/%s", package, name);
|
||||
* ClassLoader::compile_the_world_in(path, (Handle)arg, THREAD);
|
||||
* return !HAS_PENDING_EXCEPTION;
|
||||
* }
|
||||
* return true;
|
||||
* }
|
||||
* (*JImageResourceIterator)(image, ctw_visitor, loader);
|
||||
*/
|
||||
extern "C" void JIMAGE_ResourceIterator(JImageFile* image,
|
||||
JImageResourceVisitor_t visitor, void* arg) {
|
||||
ImageFileReader* imageFile = (ImageFileReader*) image;
|
||||
u4 nEntries = imageFile->table_length();
|
||||
const ImageStrings strings = imageFile->get_strings();
|
||||
for (u4 i = 0; i < nEntries; i++) {
|
||||
ImageLocation location(imageFile->get_location_data(i));
|
||||
|
||||
u4 moduleOffset = (u4) location.get_attribute(ImageLocation::ATTRIBUTE_MODULE);
|
||||
if (moduleOffset == 0) {
|
||||
continue; // skip non-modules
|
||||
}
|
||||
const char *module = strings.get(moduleOffset);
|
||||
if (strcmp(module, "modules") == 0
|
||||
|| strcmp(module, "packages") == 0) {
|
||||
continue; // always skip
|
||||
}
|
||||
|
||||
u4 parentOffset = (u4) location.get_attribute(ImageLocation::ATTRIBUTE_PARENT);
|
||||
const char *parent = strings.get(parentOffset);
|
||||
u4 baseOffset = (u4) location.get_attribute(ImageLocation::ATTRIBUTE_BASE);
|
||||
const char *base = strings.get(baseOffset);
|
||||
u4 extOffset = (u4) location.get_attribute(ImageLocation::ATTRIBUTE_EXTENSION);
|
||||
const char *extension = strings.get(extOffset);
|
||||
|
||||
if (!(*visitor)(image, module, "9", parent, base, extension, arg)) {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
176
jdk/src/java.base/share/native/libjimage/jimage.hpp
Normal file
176
jdk/src/java.base/share/native/libjimage/jimage.hpp
Normal file
@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "jni.h"
|
||||
|
||||
// Opaque reference to a JImage file.
|
||||
class JImageFile;
|
||||
// Opaque reference to an image file resource location.
|
||||
typedef jlong JImageLocationRef;
|
||||
|
||||
// Max path length limit independent of platform. Windows max path is 1024,
|
||||
// other platforms use 4096. The JCK fails several tests when 1024 is used.
|
||||
#define JIMAGE_MAX_PATH 4096
|
||||
|
||||
// JImage Error Codes
|
||||
|
||||
// The image file is not prefixed with 0xCAFEDADA
|
||||
#define JIMAGE_BAD_MAGIC (-1)
|
||||
// The image file does not have a compatible (translatable) version
|
||||
#define JIMAGE_BAD_VERSION (-2)
|
||||
// The image file content is malformed
|
||||
#define JIMAGE_CORRUPTED (-3)
|
||||
|
||||
/*
|
||||
* JImageOpen - Given the supplied full path file name, open an image file. This
|
||||
* function will also initialize tables and retrieve meta-data necessary to
|
||||
* satisfy other functions in the API. If the image file has been previously
|
||||
* open, a new open request will share memory and resources used by the previous
|
||||
* open. A call to JImageOpen should be balanced by a call to JImageClose, to
|
||||
* release memory and resources used. If the image file is not found or cannot
|
||||
* be open, then NULL is returned and error will contain a reason for the
|
||||
* failure; a positive value for a system error number, negative for a jimage
|
||||
* specific error (see JImage Error Codes.)
|
||||
*
|
||||
* Ex.
|
||||
* jint error;
|
||||
* JImageFile* jimage = (*JImageOpen)(JAVA_HOME "lib/modules/bootmodules.jimage", &error);
|
||||
* if (image == NULL) {
|
||||
* tty->print_cr("JImage failed to open: %d", error);
|
||||
* ...
|
||||
* }
|
||||
* ...
|
||||
*/
|
||||
|
||||
extern "C" JImageFile* JIMAGE_Open(const char *name, jint* error);
|
||||
|
||||
typedef JImageFile* (*JImageOpen_t)(const char *name, jint* error);
|
||||
|
||||
/*
|
||||
* JImageClose - Given the supplied open image file (see JImageOpen), release
|
||||
* memory and resources used by the open file and close the file. If the image
|
||||
* file is shared by other uses, release and close is deferred until the last use
|
||||
* is also closed.
|
||||
*
|
||||
* Ex.
|
||||
* (*JImageClose)(image);
|
||||
*/
|
||||
|
||||
extern "C" void JIMAGE_Close(JImageFile* jimage);
|
||||
|
||||
typedef void (*JImageClose_t)(JImageFile* jimage);
|
||||
|
||||
|
||||
/*
|
||||
* JImagePackageToModule - Given an open image file (see JImageOpen) and the name
|
||||
* of a package, return the name of module where the package resides. If the
|
||||
* package does not exist in the image file, the function returns NULL.
|
||||
* The resulting string does/should not have to be released. All strings are
|
||||
* utf-8, zero byte terminated.
|
||||
*
|
||||
* Ex.
|
||||
* const char* package = (*JImagePackageToModule)(image, "java/lang");
|
||||
* tty->print_cr(package);
|
||||
* —> java.base
|
||||
*/
|
||||
|
||||
extern "C" const char * JIMAGE_PackageToModule(JImageFile* jimage, const char* package_name);
|
||||
|
||||
typedef const char* (*JImagePackageToModule_t)(JImageFile* jimage, const char* package_name);
|
||||
|
||||
|
||||
/*
|
||||
* JImageFindResource - Given an open image file (see JImageOpen), a module
|
||||
* name, a version string and the name of a class/resource, return location
|
||||
* information describing the resource and its size. If no resource is found, the
|
||||
* function returns JIMAGE_NOT_FOUND and the value of size is undefined.
|
||||
* The version number should be "9.0" and is not used in locating the resource.
|
||||
* The resulting location does/should not have to be released.
|
||||
* All strings are utf-8, zero byte terminated.
|
||||
*
|
||||
* Ex.
|
||||
* jlong size;
|
||||
* JImageLocationRef location = (*JImageFindResource)(image, "java.base", "9.0", "java/lang/String.class", &size);
|
||||
*/
|
||||
extern "C" JImageLocationRef JIMAGE_FindResource(JImageFile* jimage,
|
||||
const char* module_name, const char* version, const char* name,
|
||||
jlong* size);
|
||||
|
||||
typedef JImageLocationRef(*JImageFindResource_t)(JImageFile* jimage,
|
||||
const char* module_name, const char* version, const char* name,
|
||||
jlong* size);
|
||||
|
||||
|
||||
/*
|
||||
* JImageGetResource - Given an open image file (see JImageOpen), a resource’s
|
||||
* location information (see JImageFindResource), a buffer of appropriate
|
||||
* size and the size, retrieve the bytes associated with the
|
||||
* resource. If the size is less than the resource size then the read is truncated.
|
||||
* If the size is greater than the resource size then the remainder of the buffer
|
||||
* is zero filled. The function will return the actual size of the resource.
|
||||
*
|
||||
* Ex.
|
||||
* jlong size;
|
||||
* JImageLocationRef location = (*JImageFindResource)(image, "java.base", "9.0", "java/lang/String.class", &size);
|
||||
* char* buffer = new char[size];
|
||||
* (*JImageGetResource)(image, location, buffer, size);
|
||||
*/
|
||||
extern "C" jlong JIMAGE_GetResource(JImageFile* jimage, JImageLocationRef location,
|
||||
char* buffer, jlong size);
|
||||
|
||||
typedef jlong(*JImageGetResource_t)(JImageFile* jimage, JImageLocationRef location,
|
||||
char* buffer, jlong size);
|
||||
|
||||
|
||||
/*
|
||||
* JImageResourceIterator - Given an open image file (see JImageOpen), a visitor
|
||||
* function and a visitor argument, iterator through each of the image's resources.
|
||||
* The visitor function is called with the image file, the module name, the
|
||||
* package name, the base name, the extension and the visitor argument. The return
|
||||
* value of the visitor function should be true, unless an early iteration exit is
|
||||
* required. All strings are utf-8, zero byte terminated.file.
|
||||
*
|
||||
* Ex.
|
||||
* bool ctw_visitor(JImageFile* jimage, const char* module_name, const char* version, const char* package, const char* name, const char* extension, void* arg) {
|
||||
* if (strcmp(extension, “class”) == 0) {
|
||||
* char path[JIMAGE_MAX_PATH];
|
||||
* Thread* THREAD = Thread::current();
|
||||
* jio_snprintf(path, JIMAGE_MAX_PATH - 1, "/%s/%s", package, name);
|
||||
* ClassLoader::compile_the_world_in(path, (Handle)arg, THREAD);
|
||||
* return !HAS_PENDING_EXCEPTION;
|
||||
* }
|
||||
* return true;
|
||||
* }
|
||||
* (*JImageResourceIterator)(image, ctw_visitor, loader);
|
||||
*/
|
||||
|
||||
typedef bool (*JImageResourceVisitor_t)(JImageFile* jimage,
|
||||
const char* module_name, const char* version, const char* package,
|
||||
const char* name, const char* extension, void* arg);
|
||||
|
||||
extern "C" void JIMAGE_ResourceIterator(JImageFile* jimage,
|
||||
JImageResourceVisitor_t visitor, void *arg);
|
||||
|
||||
typedef void (*JImageResourceIterator_t)(JImageFile* jimage,
|
||||
JImageResourceVisitor_t visitor, void* arg);
|
109
jdk/src/java.base/share/native/libjimage/osSupport.hpp
Normal file
109
jdk/src/java.base/share/native/libjimage/osSupport.hpp
Normal file
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LIBJIMAGE_OSSUPPORT_HPP
|
||||
#define LIBJIMAGE_OSSUPPORT_HPP
|
||||
|
||||
#ifdef WIN32
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
class osSupport {
|
||||
public:
|
||||
/**
|
||||
* Open a regular file read-only.
|
||||
* Return the file descriptor.
|
||||
*/
|
||||
static jint openReadOnly(const char *path);
|
||||
|
||||
/**
|
||||
* Close a file descriptor.
|
||||
*/
|
||||
static jint close(jint fd);
|
||||
|
||||
/**
|
||||
* Return the size of a regular file.
|
||||
*/
|
||||
static jlong size(const char *path);
|
||||
|
||||
/**
|
||||
* Read nBytes at offset into a buffer.
|
||||
*/
|
||||
static jlong read(jint fd, char *buf, jlong nBytes, jlong offset);
|
||||
|
||||
/**
|
||||
* Map nBytes at offset into memory and return the address.
|
||||
* The system chooses the address.
|
||||
*/
|
||||
static void* map_memory(jint fd, const char *filename, size_t file_offset, size_t bytes);
|
||||
|
||||
/**
|
||||
* Unmap nBytes of memory at address.
|
||||
*/
|
||||
static int unmap_memory(void* addr, size_t bytes);
|
||||
};
|
||||
|
||||
/**
|
||||
* A CriticalSection to protect a small section of code.
|
||||
*/
|
||||
class SimpleCriticalSection {
|
||||
friend class SimpleCriticalSectionLock;
|
||||
private:
|
||||
void enter();
|
||||
void exit();
|
||||
public:
|
||||
SimpleCriticalSection();
|
||||
//~SimpleCriticalSection(); // Cretes a dependency on Solaris on a C++ exit registration
|
||||
|
||||
private:
|
||||
#ifdef WIN32
|
||||
CRITICAL_SECTION critical_section;
|
||||
#else
|
||||
pthread_mutex_t mutex;
|
||||
#endif // WIN32
|
||||
};
|
||||
|
||||
/**
|
||||
* SimpleCriticalSectionLock instance.
|
||||
* The constructor locks a SimpleCriticalSection and the
|
||||
* destructor does the unlock.
|
||||
*/
|
||||
class SimpleCriticalSectionLock {
|
||||
private:
|
||||
SimpleCriticalSection *lock;
|
||||
public:
|
||||
|
||||
SimpleCriticalSectionLock(SimpleCriticalSection *cslock) {
|
||||
this->lock = cslock;
|
||||
lock->enter();
|
||||
}
|
||||
|
||||
~SimpleCriticalSectionLock() {
|
||||
lock->exit();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // LIBJIMAGE_OSSUPPORT_HPP
|
111
jdk/src/java.base/unix/native/libjimage/osSupport_unix.cpp
Normal file
111
jdk/src/java.base/unix/native/libjimage/osSupport_unix.cpp
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "osSupport.hpp"
|
||||
|
||||
/**
|
||||
* Open a regular file read-only.
|
||||
* Return the file descriptor.
|
||||
*/
|
||||
jint osSupport::openReadOnly(const char *path) {
|
||||
return ::open(path, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close a file descriptor.
|
||||
*/
|
||||
jint osSupport::close(jint fd) {
|
||||
return ::close(fd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size of a regular file.
|
||||
*/
|
||||
jlong osSupport::size(const char *path) {
|
||||
struct stat statbuf;
|
||||
if (stat(path, &statbuf) < 0 ||
|
||||
(statbuf.st_mode & S_IFREG) != S_IFREG) {
|
||||
return -1;
|
||||
}
|
||||
return (jsize) statbuf.st_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read nBytes at offset into a buffer.
|
||||
*/
|
||||
jlong osSupport::read(jint fd, char *buf, jlong nBytes, jlong offset) {
|
||||
return ::pread(fd, buf, nBytes, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map nBytes at offset into memory and return the address.
|
||||
* The system chooses the address.
|
||||
*/
|
||||
void* osSupport::map_memory(int fd, const char *filename, size_t file_offset, size_t bytes) {
|
||||
void* mapped_address = NULL;
|
||||
mapped_address = (void*) mmap(NULL,
|
||||
bytes, PROT_READ, MAP_SHARED,
|
||||
fd, file_offset);
|
||||
if (mapped_address == MAP_FAILED) {
|
||||
return NULL;
|
||||
}
|
||||
return mapped_address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmap nBytes of memory at address.
|
||||
*/
|
||||
int osSupport::unmap_memory(void *addr, size_t bytes) {
|
||||
return munmap((char *) addr, bytes) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* A CriticalSection to protect a small section of code.
|
||||
*/
|
||||
void SimpleCriticalSection::enter() {
|
||||
pthread_mutex_lock(&mutex);
|
||||
}
|
||||
|
||||
void SimpleCriticalSection::exit() {
|
||||
pthread_mutex_unlock(&mutex);
|
||||
|
||||
}
|
||||
|
||||
SimpleCriticalSection::SimpleCriticalSection() {
|
||||
pthread_mutex_init(&mutex, NULL);
|
||||
}
|
||||
|
||||
//SimpleCriticalSection::~SimpleCriticalSection() {
|
||||
// pthread_mutex_destroy(&mutex);
|
||||
//}
|
||||
|
133
jdk/src/java.base/windows/native/libjimage/osSupport_windows.cpp
Normal file
133
jdk/src/java.base/windows/native/libjimage/osSupport_windows.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <io.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "osSupport.hpp"
|
||||
|
||||
/**
|
||||
* Open a regular file read-only.
|
||||
* Return the file descriptor.
|
||||
*/
|
||||
jint osSupport::openReadOnly(const char *path) {
|
||||
return ::open(path, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close a file descriptor.
|
||||
*/
|
||||
jint osSupport::close(jint fd) {
|
||||
return ::close(fd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size of a regular file.
|
||||
*/
|
||||
jlong osSupport::size(const char *path) {
|
||||
struct stat statbuf;
|
||||
if (stat(path, &statbuf) < 0 ||
|
||||
(statbuf.st_mode & S_IFREG) != S_IFREG) {
|
||||
return -1;
|
||||
}
|
||||
return (jlong) statbuf.st_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read nBytes at offset into a buffer.
|
||||
*/
|
||||
jlong osSupport::read(jint fd, char *buf, jlong nBytes, jlong offset) {
|
||||
OVERLAPPED ov;
|
||||
DWORD nread;
|
||||
BOOL result;
|
||||
|
||||
ZeroMemory(&ov, sizeof (ov));
|
||||
ov.Offset = (DWORD) offset;
|
||||
ov.OffsetHigh = (DWORD) (offset >> 32);
|
||||
|
||||
HANDLE h = (HANDLE)::_get_osfhandle(fd);
|
||||
|
||||
result = ReadFile(h, (LPVOID) buf, (DWORD) nBytes, &nread, &ov);
|
||||
|
||||
return result ? nread : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map nBytes at offset into memory and return the address.
|
||||
* The system chooses the address.
|
||||
*/
|
||||
void* osSupport::map_memory(jint fd, const char *file_name, size_t file_offset, size_t bytes) {
|
||||
HANDLE hFile;
|
||||
char* base = NULL;
|
||||
|
||||
// Get a handle to the file
|
||||
hFile = CreateFile(file_name, GENERIC_READ, FILE_SHARE_READ, NULL,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile != NULL) {
|
||||
// Create a file mapping handle
|
||||
HANDLE hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0,
|
||||
NULL /* file_name */);
|
||||
if (hMap != NULL) {
|
||||
// Map the file into the address space at the offset
|
||||
base = (char*) MapViewOfFileEx(hMap, FILE_MAP_READ, 0, (DWORD) file_offset,
|
||||
(DWORD) bytes, NULL);
|
||||
CloseHandle(hMap); // The mapping is no longer needed
|
||||
}
|
||||
CloseHandle(hFile); // The file handle is no longer needed
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmap nBytes of memory at address.
|
||||
*/
|
||||
int osSupport::unmap_memory(void* addr, size_t bytes) {
|
||||
BOOL result = UnmapViewOfFile(addr);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* A CriticalSection to protect a small section of code.
|
||||
*/
|
||||
void SimpleCriticalSection::enter() {
|
||||
EnterCriticalSection(&critical_section);
|
||||
}
|
||||
|
||||
void SimpleCriticalSection::exit() {
|
||||
LeaveCriticalSection(&critical_section);
|
||||
}
|
||||
|
||||
SimpleCriticalSection::SimpleCriticalSection() {
|
||||
InitializeCriticalSection(&critical_section);
|
||||
}
|
||||
|
||||
//SimpleCriticalSection::~SimpleCriticalSection() {
|
||||
// DeleteCriticalSection(&critical_section);
|
||||
//}
|
||||
|
@ -1,190 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jmx.remote.internal;
|
||||
|
||||
import java.util.Properties;
|
||||
import java.io.IOException;
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.NoSuchObjectException;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
/**
|
||||
* A helper class for RMI-IIOP and CORBA APIs.
|
||||
*/
|
||||
|
||||
public final class IIOPHelper {
|
||||
private IIOPHelper() { }
|
||||
|
||||
// loads IIOPProxy implementation class if available
|
||||
private static final String IMPL_CLASS =
|
||||
"com.sun.jmx.remote.protocol.iiop.IIOPProxyImpl";
|
||||
private static final IIOPProxy proxy =
|
||||
AccessController.doPrivileged(new PrivilegedAction<IIOPProxy>() {
|
||||
public IIOPProxy run() {
|
||||
try {
|
||||
Class<?> c = Class.forName(IMPL_CLASS, true,
|
||||
IIOPHelper.class.getClassLoader());
|
||||
return (IIOPProxy)c.newInstance();
|
||||
} catch (ClassNotFoundException cnf) {
|
||||
return null;
|
||||
} catch (InstantiationException e) {
|
||||
throw new AssertionError(e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}});
|
||||
|
||||
/**
|
||||
* Returns true if RMI-IIOP and CORBA is available.
|
||||
*/
|
||||
public static boolean isAvailable() {
|
||||
return proxy != null;
|
||||
}
|
||||
|
||||
private static void ensureAvailable() {
|
||||
if (proxy == null)
|
||||
throw new AssertionError("Should not here");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given object is a Stub.
|
||||
*/
|
||||
public static boolean isStub(Object obj) {
|
||||
return (proxy == null) ? false : proxy.isStub(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Delegate to which the given Stub delegates.
|
||||
*/
|
||||
public static Object getDelegate(Object stub) {
|
||||
ensureAvailable();
|
||||
return proxy.getDelegate(stub);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Delegate for a given Stub.
|
||||
*/
|
||||
public static void setDelegate(Object stub, Object delegate) {
|
||||
ensureAvailable();
|
||||
proxy.setDelegate(stub, delegate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ORB associated with the given stub
|
||||
*
|
||||
* @throws UnsupportedOperationException
|
||||
* if the object does not support the operation that
|
||||
* was invoked
|
||||
*/
|
||||
public static Object getOrb(Object stub) {
|
||||
ensureAvailable();
|
||||
return proxy.getOrb(stub);
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects the Stub to the given ORB.
|
||||
*/
|
||||
public static void connect(Object stub, Object orb)
|
||||
throws IOException
|
||||
{
|
||||
if (proxy == null)
|
||||
throw new IOException("Connection to ORB failed, RMI/IIOP not available");
|
||||
proxy.connect(stub, orb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given object is an ORB.
|
||||
*/
|
||||
public static boolean isOrb(Object obj) {
|
||||
return (proxy == null) ? false : proxy.isOrb(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates, and returns, a new ORB instance.
|
||||
*/
|
||||
public static Object createOrb(String[] args, Properties props)
|
||||
throws IOException
|
||||
{
|
||||
if (proxy == null)
|
||||
throw new IOException("ORB initialization failed, RMI/IIOP not available");
|
||||
return proxy.createOrb(args, props);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a string, produced by the object_to_string method, back
|
||||
* to a CORBA object reference.
|
||||
*/
|
||||
public static Object stringToObject(Object orb, String str) {
|
||||
ensureAvailable();
|
||||
return proxy.stringToObject(orb, str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given CORBA object reference to a string.
|
||||
*/
|
||||
public static String objectToString(Object orb, Object obj) {
|
||||
ensureAvailable();
|
||||
return proxy.objectToString(orb, obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to ensure that an object of a remote or abstract interface
|
||||
* type can be cast to a desired type.
|
||||
*/
|
||||
public static <T> T narrow(Object narrowFrom, Class<T> narrowTo) {
|
||||
ensureAvailable();
|
||||
return proxy.narrow(narrowFrom, narrowTo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a server object ready to receive remote calls
|
||||
*/
|
||||
public static void exportObject(Remote obj) throws IOException {
|
||||
if (proxy == null)
|
||||
throw new IOException("RMI object cannot be exported, RMI/IIOP not available");
|
||||
proxy.exportObject(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deregisters a server object from the runtime.
|
||||
*/
|
||||
public static void unexportObject(Remote obj) throws IOException {
|
||||
if (proxy == null)
|
||||
throw new NoSuchObjectException("Object not exported");
|
||||
proxy.unexportObject(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a stub for the given server object.
|
||||
*/
|
||||
public static Remote toStub(Remote obj) throws IOException {
|
||||
if (proxy == null)
|
||||
throw new NoSuchObjectException("Object not exported");
|
||||
return proxy.toStub(obj);
|
||||
}
|
||||
}
|
@ -1,110 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jmx.remote.internal;
|
||||
|
||||
import java.util.Properties;
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.RemoteException;
|
||||
import java.rmi.NoSuchObjectException;
|
||||
|
||||
/**
|
||||
* An interface to a subset of the RMI-IIOP and CORBA APIs to avoid a
|
||||
* static dependencies on the types defined by these APIs.
|
||||
*/
|
||||
|
||||
public interface IIOPProxy {
|
||||
|
||||
/**
|
||||
* Returns true if the given object is a Stub.
|
||||
*/
|
||||
boolean isStub(Object obj);
|
||||
|
||||
/**
|
||||
* Returns the Delegate to which the given Stub delegates.
|
||||
*/
|
||||
Object getDelegate(Object stub);
|
||||
|
||||
/**
|
||||
* Sets the Delegate for a given Stub.
|
||||
*/
|
||||
void setDelegate(Object stub, Object delegate);
|
||||
|
||||
/**
|
||||
* Returns the ORB associated with the given stub
|
||||
*
|
||||
* @throws UnsupportedOperationException
|
||||
* if the object does not support the operation that
|
||||
* was invoked
|
||||
*/
|
||||
Object getOrb(Object stub);
|
||||
|
||||
/**
|
||||
* Connects the Stub to the given ORB.
|
||||
*/
|
||||
void connect(Object stub, Object orb) throws RemoteException;
|
||||
|
||||
/**
|
||||
* Returns true if the given object is an ORB.
|
||||
*/
|
||||
boolean isOrb(Object obj);
|
||||
|
||||
/**
|
||||
* Creates, and returns, a new ORB instance.
|
||||
*/
|
||||
Object createOrb(String[] args, Properties props);
|
||||
|
||||
/**
|
||||
* Converts a string, produced by the object_to_string method, back
|
||||
* to a CORBA object reference.
|
||||
*/
|
||||
Object stringToObject(Object orb, String str);
|
||||
|
||||
/**
|
||||
* Converts the given CORBA object reference to a string.
|
||||
*/
|
||||
String objectToString(Object orb, Object obj);
|
||||
|
||||
/**
|
||||
* Checks to ensure that an object of a remote or abstract interface
|
||||
* type can be cast to a desired type.
|
||||
*/
|
||||
<T> T narrow(Object narrowFrom, Class<T> narrowTo);
|
||||
|
||||
/**
|
||||
* Makes a server object ready to receive remote calls
|
||||
*/
|
||||
void exportObject(Remote obj) throws RemoteException;
|
||||
|
||||
/**
|
||||
* Deregisters a server object from the runtime.
|
||||
*/
|
||||
void unexportObject(Remote obj) throws NoSuchObjectException;
|
||||
|
||||
/**
|
||||
* Returns a stub for the given server object.
|
||||
*/
|
||||
Remote toStub(Remote obj) throws NoSuchObjectException;
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jmx.remote.protocol.iiop;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.management.remote.JMXConnectorProvider;
|
||||
import javax.management.remote.JMXConnector;
|
||||
import javax.management.remote.JMXServiceURL;
|
||||
import javax.management.remote.rmi.RMIConnector;
|
||||
|
||||
public class ClientProvider implements JMXConnectorProvider {
|
||||
|
||||
public JMXConnector newJMXConnector(JMXServiceURL serviceURL,
|
||||
Map<String,?> environment)
|
||||
throws IOException {
|
||||
if (!serviceURL.getProtocol().equals("iiop")) {
|
||||
throw new MalformedURLException("Protocol not iiop: " +
|
||||
serviceURL.getProtocol());
|
||||
}
|
||||
return new RMIConnector(serviceURL, environment);
|
||||
}
|
||||
}
|
@ -1,157 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2009,2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jmx.remote.protocol.iiop;
|
||||
|
||||
import org.omg.CORBA.ORB;
|
||||
import org.omg.CORBA.portable.Delegate;
|
||||
import javax.rmi.PortableRemoteObject;
|
||||
import javax.rmi.CORBA.Stub;
|
||||
|
||||
import java.util.Properties;
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.RemoteException;
|
||||
import java.rmi.NoSuchObjectException;
|
||||
|
||||
import com.sun.jmx.remote.internal.IIOPProxy;
|
||||
import java.io.SerializablePermission;
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.AccessController;
|
||||
import java.security.Permissions;
|
||||
import java.security.PrivilegedActionException;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.security.ProtectionDomain;
|
||||
|
||||
/**
|
||||
* An implementation of IIOPProxy that simply delegates to the appropriate
|
||||
* RMI-IIOP and CORBA APIs.
|
||||
*/
|
||||
|
||||
public class IIOPProxyImpl implements IIOPProxy {
|
||||
// special ACC used to initialize the IIOP stub
|
||||
// the only allowed privilege is SerializablePermission("enableSubclassImplementation")
|
||||
private static final AccessControlContext STUB_ACC;
|
||||
|
||||
static {
|
||||
Permissions p = new Permissions();
|
||||
p.add(new SerializablePermission("enableSubclassImplementation"));
|
||||
STUB_ACC = new AccessControlContext(
|
||||
new ProtectionDomain[]{
|
||||
new ProtectionDomain(null, p)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public IIOPProxyImpl() { }
|
||||
|
||||
@Override
|
||||
public boolean isStub(Object obj) {
|
||||
return (obj instanceof Stub);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getDelegate(Object stub) {
|
||||
return ((Stub)stub)._get_delegate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDelegate(Object stub, Object delegate) {
|
||||
((Stub)stub)._set_delegate((Delegate)delegate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getOrb(Object stub) {
|
||||
try {
|
||||
return ((Stub)stub)._orb();
|
||||
} catch (org.omg.CORBA.BAD_OPERATION x) {
|
||||
throw new UnsupportedOperationException(x);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect(Object stub, Object orb)
|
||||
throws RemoteException
|
||||
{
|
||||
((Stub)stub).connect((ORB)orb);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOrb(Object obj) {
|
||||
return (obj instanceof ORB);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object createOrb(String[] args, Properties props) {
|
||||
return ORB.init(args, props);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object stringToObject(Object orb, String str) {
|
||||
return ((ORB)orb).string_to_object(str);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String objectToString(Object orb, Object obj) {
|
||||
return ((ORB)orb).object_to_string((org.omg.CORBA.Object)obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T narrow(Object narrowFrom, Class<T> narrowTo) {
|
||||
return (T)PortableRemoteObject.narrow(narrowFrom, narrowTo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exportObject(Remote obj) throws RemoteException {
|
||||
PortableRemoteObject.exportObject(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unexportObject(Remote obj) throws NoSuchObjectException {
|
||||
PortableRemoteObject.unexportObject(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Remote toStub(final Remote obj) throws NoSuchObjectException {
|
||||
if (System.getSecurityManager() == null) {
|
||||
return PortableRemoteObject.toStub(obj);
|
||||
} else {
|
||||
try {
|
||||
return AccessController.doPrivileged(new PrivilegedExceptionAction<Remote>() {
|
||||
|
||||
@Override
|
||||
public Remote run() throws Exception {
|
||||
return PortableRemoteObject.toStub(obj);
|
||||
}
|
||||
}, STUB_ACC);
|
||||
} catch (PrivilegedActionException e) {
|
||||
if (e.getException() instanceof NoSuchObjectException) {
|
||||
throw (NoSuchObjectException)e.getException();
|
||||
}
|
||||
throw new RuntimeException("Unexpected exception type", e.getException());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,241 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jmx.remote.protocol.iiop;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.omg.CORBA.Any;
|
||||
import org.omg.CORBA.Context;
|
||||
import org.omg.CORBA.NO_IMPLEMENT;
|
||||
import org.omg.CORBA.ORB;
|
||||
import org.omg.CORBA.TypeCode;
|
||||
import org.omg.CORBA.portable.BoxedValueHelper;
|
||||
|
||||
@SuppressWarnings({"deprecation", "rawtypes"})
|
||||
public class ProxyInputStream extends org.omg.CORBA_2_3.portable.InputStream {
|
||||
public ProxyInputStream(org.omg.CORBA.portable.InputStream in) {
|
||||
this.in = in;
|
||||
}
|
||||
|
||||
public boolean read_boolean() {
|
||||
return in.read_boolean();
|
||||
}
|
||||
|
||||
public char read_char() {
|
||||
return in.read_char();
|
||||
}
|
||||
|
||||
public char read_wchar() {
|
||||
return in.read_wchar();
|
||||
}
|
||||
|
||||
public byte read_octet() {
|
||||
return in.read_octet();
|
||||
}
|
||||
|
||||
public short read_short() {
|
||||
return in.read_short();
|
||||
}
|
||||
|
||||
public short read_ushort() {
|
||||
return in.read_ushort();
|
||||
}
|
||||
|
||||
public int read_long() {
|
||||
return in.read_long();
|
||||
}
|
||||
|
||||
public int read_ulong() {
|
||||
return in.read_ulong();
|
||||
}
|
||||
|
||||
public long read_longlong() {
|
||||
return in.read_longlong();
|
||||
}
|
||||
|
||||
public long read_ulonglong() {
|
||||
return in.read_ulonglong();
|
||||
}
|
||||
|
||||
public float read_float() {
|
||||
return in.read_float();
|
||||
}
|
||||
|
||||
public double read_double() {
|
||||
return in.read_double();
|
||||
}
|
||||
|
||||
public String read_string() {
|
||||
return in.read_string();
|
||||
}
|
||||
|
||||
public String read_wstring() {
|
||||
return in.read_wstring();
|
||||
}
|
||||
|
||||
public void read_boolean_array(boolean[] value, int offset, int length) {
|
||||
in.read_boolean_array(value, offset, length);
|
||||
}
|
||||
|
||||
public void read_char_array(char[] value, int offset, int length) {
|
||||
in.read_char_array(value, offset, length);
|
||||
}
|
||||
|
||||
public void read_wchar_array(char[] value, int offset, int length) {
|
||||
in.read_wchar_array(value, offset, length);
|
||||
}
|
||||
|
||||
public void read_octet_array(byte[] value, int offset, int length) {
|
||||
in.read_octet_array(value, offset, length);
|
||||
}
|
||||
|
||||
public void read_short_array(short[] value, int offset, int length) {
|
||||
in.read_short_array(value, offset, length);
|
||||
}
|
||||
|
||||
public void read_ushort_array(short[] value, int offset, int length) {
|
||||
in.read_ushort_array(value, offset, length);
|
||||
}
|
||||
|
||||
public void read_long_array(int[] value, int offset, int length) {
|
||||
in.read_long_array(value, offset, length);
|
||||
}
|
||||
|
||||
public void read_ulong_array(int[] value, int offset, int length) {
|
||||
in.read_ulong_array(value, offset, length);
|
||||
}
|
||||
|
||||
public void read_longlong_array(long[] value, int offset, int length) {
|
||||
in.read_longlong_array(value, offset, length);
|
||||
}
|
||||
|
||||
public void read_ulonglong_array(long[] value, int offset, int length) {
|
||||
in.read_ulonglong_array(value, offset, length);
|
||||
}
|
||||
|
||||
public void read_float_array(float[] value, int offset, int length) {
|
||||
in.read_float_array(value, offset, length);
|
||||
}
|
||||
|
||||
public void read_double_array(double[] value, int offset, int length) {
|
||||
in.read_double_array(value, offset, length);
|
||||
}
|
||||
|
||||
public org.omg.CORBA.Object read_Object() {
|
||||
return in.read_Object();
|
||||
}
|
||||
|
||||
public TypeCode read_TypeCode() {
|
||||
return in.read_TypeCode();
|
||||
}
|
||||
|
||||
public Any read_any() {
|
||||
return in.read_any();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public org.omg.CORBA.Principal read_Principal() {
|
||||
return in.read_Principal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return in.read();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal read_fixed() {
|
||||
return in.read_fixed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Context read_Context() {
|
||||
return in.read_Context();
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.omg.CORBA.Object read_Object(java.lang.Class clz) {
|
||||
return in.read_Object(clz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ORB orb() {
|
||||
return in.orb();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Serializable read_value() {
|
||||
return narrow().read_value();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Serializable read_value(Class clz) {
|
||||
return narrow().read_value(clz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Serializable read_value(BoxedValueHelper factory) {
|
||||
return narrow().read_value(factory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Serializable read_value(String rep_id) {
|
||||
return narrow().read_value(rep_id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Serializable read_value(Serializable value) {
|
||||
return narrow().read_value(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object read_abstract_interface() {
|
||||
return narrow().read_abstract_interface();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object read_abstract_interface(Class clz) {
|
||||
return narrow().read_abstract_interface(clz);
|
||||
}
|
||||
|
||||
protected org.omg.CORBA_2_3.portable.InputStream narrow() {
|
||||
if (in instanceof org.omg.CORBA_2_3.portable.InputStream)
|
||||
return (org.omg.CORBA_2_3.portable.InputStream) in;
|
||||
throw new NO_IMPLEMENT();
|
||||
}
|
||||
|
||||
public org.omg.CORBA.portable.InputStream getProxiedInputStream() {
|
||||
return in;
|
||||
}
|
||||
|
||||
protected final org.omg.CORBA.portable.InputStream in;
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jmx.remote.protocol.iiop;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.remote.JMXConnectorServer;
|
||||
import javax.management.remote.JMXConnectorServerProvider;
|
||||
import javax.management.remote.JMXServiceURL;
|
||||
import javax.management.remote.rmi.RMIConnectorServer;
|
||||
|
||||
public class ServerProvider implements JMXConnectorServerProvider {
|
||||
|
||||
public JMXConnectorServer newJMXConnectorServer(JMXServiceURL serviceURL,
|
||||
Map<String,?> environment,
|
||||
MBeanServer mbeanServer)
|
||||
throws IOException {
|
||||
if (!serviceURL.getProtocol().equals("iiop")) {
|
||||
throw new MalformedURLException("Protocol not iiop: " +
|
||||
serviceURL.getProtocol());
|
||||
}
|
||||
return new RMIConnectorServer(serviceURL, environment, mbeanServer);
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -140,9 +140,7 @@ import sun.reflect.misc.ReflectUtil;
|
||||
*
|
||||
* <p>Every implementation must support the RMI connector protocol with
|
||||
* the default RMI transport, specified with string <code>rmi</code>.
|
||||
* An implementation may optionally support the RMI connector protocol
|
||||
* with the RMI/IIOP transport, specified with the string
|
||||
* <code>iiop</code>.</p>
|
||||
* </p>
|
||||
*
|
||||
* <p>Once a provider is found, the result of the
|
||||
* <code>newJMXConnector</code> method is the result of calling {@link
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -131,9 +131,7 @@ import javax.management.MBeanServer;
|
||||
*
|
||||
* <p>Every implementation must support the RMI connector protocol with
|
||||
* the default RMI transport, specified with string <code>rmi</code>.
|
||||
* An implementation may optionally support the RMI connector protocol
|
||||
* with the RMI/IIOP transport, specified with the string
|
||||
* <code>iiop</code>.</p>
|
||||
* </p>
|
||||
*
|
||||
* <p>Once a provider is found, the result of the
|
||||
* <code>newJMXConnectorServer</code> method is the result of calling
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -31,12 +31,11 @@ import java.security.ProtectionDomain;
|
||||
<p>A class loader that only knows how to define a limited number
|
||||
of classes, and load a limited number of other classes through
|
||||
delegation to another loader. It is used to get around a problem
|
||||
with Serialization, in particular as used by RMI (including
|
||||
RMI/IIOP). The JMX Remote API defines exactly what class loader
|
||||
must be used to deserialize arguments on the server, and return
|
||||
values on the client. We communicate this class loader to RMI by
|
||||
setting it as the context class loader. RMI uses the context
|
||||
class loader to load classes as it deserializes, which is what we
|
||||
with Serialization, in particular as used by RMI. The JMX Remote API
|
||||
defines exactly what class loader must be used to deserialize arguments on
|
||||
the server, and return values on the client. We communicate this class
|
||||
loader to RMI by setting it as the context class loader. RMI uses the
|
||||
context class loader to load classes as it deserializes, which is what we
|
||||
want. However, before consulting the context class loader, it
|
||||
looks up the call stack for a class with a non-null class loader,
|
||||
and uses that if it finds one. So, in the standalone version of
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -76,11 +76,10 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced {
|
||||
|
||||
/**
|
||||
* Constructs a new {@link RMIConnection}. This connection can be
|
||||
* used with either the JRMP or IIOP transport. This object does
|
||||
* used with the JRMP transport. This object does
|
||||
* not export itself: it is the responsibility of the caller to
|
||||
* export it appropriately (see {@link
|
||||
* RMIJRMPServerImpl#makeClient(String,Subject)} and {@link
|
||||
* RMIIIOPServerImpl#makeClient(String,Subject)}.
|
||||
* RMIJRMPServerImpl#makeClient(String,Subject)}).
|
||||
*
|
||||
* @param rmiServer The RMIServerImpl object for which this
|
||||
* connection is created. The behavior is unspecified if this
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -30,25 +30,21 @@ import com.sun.jmx.remote.internal.ClientCommunicatorAdmin;
|
||||
import com.sun.jmx.remote.internal.ClientListenerInfo;
|
||||
import com.sun.jmx.remote.internal.ClientNotifForwarder;
|
||||
import com.sun.jmx.remote.internal.ProxyRef;
|
||||
import com.sun.jmx.remote.internal.IIOPHelper;
|
||||
import com.sun.jmx.remote.util.ClassLogger;
|
||||
import com.sun.jmx.remote.util.EnvHelp;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.NotSerializableException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectStreamClass;
|
||||
import java.io.Serializable;
|
||||
import java.io.WriteAbortedException;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.net.MalformedURLException;
|
||||
import java.rmi.MarshalException;
|
||||
import java.rmi.MarshalledObject;
|
||||
import java.rmi.NoSuchObjectException;
|
||||
import java.rmi.Remote;
|
||||
@ -61,13 +57,12 @@ import java.rmi.server.RemoteRef;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.security.PrivilegedActionException;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
import javax.management.Attribute;
|
||||
@ -146,22 +141,20 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable
|
||||
* the RMI connector server with the given address.</p>
|
||||
*
|
||||
* <p>The address can refer directly to the connector server,
|
||||
* using one of the following syntaxes:</p>
|
||||
* using the following syntax:</p>
|
||||
*
|
||||
* <pre>
|
||||
* service:jmx:rmi://<em>[host[:port]]</em>/stub/<em>encoded-stub</em>
|
||||
* service:jmx:iiop://<em>[host[:port]]</em>/ior/<em>encoded-IOR</em>
|
||||
* </pre>
|
||||
*
|
||||
* <p>(Here, the square brackets {@code []} are not part of the
|
||||
* address but indicate that the host and port are optional.)</p>
|
||||
*
|
||||
* <p>The address can instead indicate where to find an RMI stub
|
||||
* through JNDI, using one of the following syntaxes:</p>
|
||||
* through JNDI, using the following syntax:</p>
|
||||
*
|
||||
* <pre>
|
||||
* service:jmx:rmi://<em>[host[:port]]</em>/jndi/<em>jndi-name</em>
|
||||
* service:jmx:iiop://<em>[host[:port]]</em>/jndi/<em>jndi-name</em>
|
||||
* </pre>
|
||||
*
|
||||
* <p>An implementation may also recognize additional address
|
||||
@ -242,8 +235,7 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable
|
||||
|
||||
/**
|
||||
* @throws IOException if the connection could not be made because of a
|
||||
* communication problem, or in the case of the {@code iiop} protocol,
|
||||
* that RMI/IIOP is not supported
|
||||
* communication problem
|
||||
*/
|
||||
public void connect() throws IOException {
|
||||
connect(null);
|
||||
@ -251,8 +243,7 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable
|
||||
|
||||
/**
|
||||
* @throws IOException if the connection could not be made because of a
|
||||
* communication problem, or in the case of the {@code iiop} protocol,
|
||||
* that RMI/IIOP is not supported
|
||||
* communication problem
|
||||
*/
|
||||
public synchronized void connect(Map<String,?> environment)
|
||||
throws IOException {
|
||||
@ -294,9 +285,7 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable
|
||||
|
||||
if (checkStub) checkStub(stub, rmiServerImplStubClass);
|
||||
|
||||
// Connect IIOP Stub if needed.
|
||||
if (tracing) logger.trace("connect",idstr + " connecting stub...");
|
||||
stub = connectStub(stub,usemap);
|
||||
idstr = (tracing?"["+this.toString()+"]":null);
|
||||
|
||||
// Calling newClient on the RMIServer stub.
|
||||
@ -307,18 +296,6 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable
|
||||
try {
|
||||
connection = getConnection(stub, credentials, checkStub);
|
||||
} catch (java.rmi.RemoteException re) {
|
||||
if (jmxServiceURL != null) {
|
||||
final String pro = jmxServiceURL.getProtocol();
|
||||
final String path = jmxServiceURL.getURLPath();
|
||||
|
||||
if ("rmi".equals(pro) &&
|
||||
path.startsWith("/jndi/iiop:")) {
|
||||
MalformedURLException mfe = new MalformedURLException(
|
||||
"Protocol is rmi but JNDI scheme is iiop: " + jmxServiceURL);
|
||||
mfe.initCause(re);
|
||||
throw mfe;
|
||||
}
|
||||
}
|
||||
throw re;
|
||||
}
|
||||
|
||||
@ -1413,13 +1390,6 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable
|
||||
if (ioe instanceof UnmarshalException) {
|
||||
throw ioe; // the fix of 6937053 made ClientNotifForwarder.fetchNotifs
|
||||
// fetch one by one with UnmarshalException
|
||||
} else if (ioe instanceof MarshalException) {
|
||||
// IIOP will throw MarshalException wrapping a NotSerializableException
|
||||
// when a server fails to serialize a response.
|
||||
MarshalException me = (MarshalException)ioe;
|
||||
if (me.detail instanceof NotSerializableException) {
|
||||
throw (NotSerializableException)me.detail;
|
||||
}
|
||||
}
|
||||
|
||||
// Not serialization problem, return.
|
||||
@ -1654,9 +1624,6 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable
|
||||
throw new IOException("Failed to get a RMI stub: "+ne);
|
||||
}
|
||||
|
||||
// Connect IIOP Stub if needed.
|
||||
stub = connectStub(stub,env);
|
||||
|
||||
// Calling newClient on the RMIServer stub.
|
||||
Object credentials = env.get(CREDENTIALS);
|
||||
connection = stub.newClient(credentials);
|
||||
@ -1693,103 +1660,6 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable
|
||||
//--------------------------------------------------------------------
|
||||
// Private stuff - Serialization
|
||||
//--------------------------------------------------------------------
|
||||
/**
|
||||
* <p>In order to be usable, an IIOP stub must be connected to an ORB.
|
||||
* The stub is automatically connected to the ORB if:
|
||||
* <ul>
|
||||
* <li> It was returned by the COS naming</li>
|
||||
* <li> Its server counterpart has been registered in COS naming
|
||||
* through JNDI.</li>
|
||||
* </ul>
|
||||
* Otherwise, it is not connected. A stub which is deserialized
|
||||
* from Jini is not connected. A stub which is obtained from a
|
||||
* non registered RMIIIOPServerImpl is not a connected.<br>
|
||||
* A stub which is not connected can't be serialized, and thus
|
||||
* can't be registered in Jini. A stub which is not connected can't
|
||||
* be used to invoke methods on the server.
|
||||
* <p>
|
||||
* In order to palliate this, this method will connect the
|
||||
* given stub if it is not yet connected. If the given
|
||||
* <var>RMIServer</var> is not an instance of
|
||||
* {@link javax.rmi.CORBA.Stub javax.rmi.CORBA.Stub}, then the
|
||||
* method do nothing and simply returns that stub. Otherwise,
|
||||
* this method will attempt to connect the stub to an ORB as
|
||||
* follows:
|
||||
* <ul>
|
||||
* <li>This method looks in the provided <var>environment</var> for
|
||||
* the "java.naming.corba.orb" property. If it is found, the
|
||||
* referenced object (an {@link org.omg.CORBA.ORB ORB}) is used to
|
||||
* connect the stub. Otherwise, a new org.omg.CORBA.ORB is created
|
||||
* by calling {@link
|
||||
* org.omg.CORBA.ORB#init(String[], Properties)
|
||||
* org.omg.CORBA.ORB.init((String[])null,(Properties)null)}</li>
|
||||
* <li>The new created ORB is kept in a static
|
||||
* {@link WeakReference} and can be reused for connecting other
|
||||
* stubs. However, no reference is ever kept on the ORB provided
|
||||
* in the <var>environment</var> map, if any.</li>
|
||||
* </ul>
|
||||
* @param rmiServer A RMI Server Stub.
|
||||
* @param environment An environment map, possibly containing an ORB.
|
||||
* @return the given stub.
|
||||
* @exception IllegalArgumentException if the
|
||||
* {@code java.naming.corba.orb} property is specified and
|
||||
* does not point to an {@link org.omg.CORBA.ORB ORB}.
|
||||
* @exception IOException if the connection to the ORB failed.
|
||||
**/
|
||||
static RMIServer connectStub(RMIServer rmiServer,
|
||||
Map<String, ?> environment)
|
||||
throws IOException {
|
||||
if (IIOPHelper.isStub(rmiServer)) {
|
||||
try {
|
||||
IIOPHelper.getOrb(rmiServer);
|
||||
} catch (UnsupportedOperationException x) {
|
||||
// BAD_OPERATION
|
||||
IIOPHelper.connect(rmiServer, resolveOrb(environment));
|
||||
}
|
||||
}
|
||||
return rmiServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ORB specified by <var>environment</var>, or create a
|
||||
* new one.
|
||||
* <p>This method looks in the provided <var>environment</var> for
|
||||
* the "java.naming.corba.orb" property. If it is found, the
|
||||
* referenced object (an {@link org.omg.CORBA.ORB ORB}) is
|
||||
* returned. Otherwise, a new org.omg.CORBA.ORB is created
|
||||
* by calling {@link
|
||||
* org.omg.CORBA.ORB#init(String[], java.util.Properties)
|
||||
* org.omg.CORBA.ORB.init((String[])null,(Properties)null)}
|
||||
* <p>The new created ORB is kept in a static
|
||||
* {@link WeakReference} and can be reused for connecting other
|
||||
* stubs. However, no reference is ever kept on the ORB provided
|
||||
* in the <var>environment</var> map, if any.
|
||||
* @param environment An environment map, possibly containing an ORB.
|
||||
* @return An ORB.
|
||||
* @exception IllegalArgumentException if the
|
||||
* {@code java.naming.corba.orb} property is specified and
|
||||
* does not point to an {@link org.omg.CORBA.ORB ORB}.
|
||||
* @exception IOException if the ORB initialization failed.
|
||||
**/
|
||||
static Object resolveOrb(Map<String, ?> environment)
|
||||
throws IOException {
|
||||
if (environment != null) {
|
||||
final Object orb = environment.get(EnvHelp.DEFAULT_ORB);
|
||||
if (orb != null && !(IIOPHelper.isOrb(orb)))
|
||||
throw new IllegalArgumentException(EnvHelp.DEFAULT_ORB +
|
||||
" must be an instance of org.omg.CORBA.ORB.");
|
||||
if (orb != null) return orb;
|
||||
}
|
||||
final Object orb =
|
||||
(RMIConnector.orb==null)?null:RMIConnector.orb.get();
|
||||
if (orb != null) return orb;
|
||||
|
||||
final Object newOrb =
|
||||
IIOPHelper.createOrb((String[])null, (Properties)null);
|
||||
RMIConnector.orb = new WeakReference<Object>(newOrb);
|
||||
return newOrb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read RMIConnector fields from an {@link java.io.ObjectInputStream
|
||||
* ObjectInputStream}.
|
||||
@ -1846,7 +1716,6 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable
|
||||
throws IOException {
|
||||
if (rmiServer == null && jmxServiceURL == null) throw new
|
||||
InvalidObjectException("rmiServer and jmxServiceURL both null.");
|
||||
connectStub(this.rmiServer,env);
|
||||
s.defaultWriteObject();
|
||||
}
|
||||
|
||||
@ -1911,24 +1780,15 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable
|
||||
private RMIServer findRMIServer(JMXServiceURL directoryURL,
|
||||
Map<String, Object> environment)
|
||||
throws NamingException, IOException {
|
||||
final boolean isIiop = RMIConnectorServer.isIiopURL(directoryURL,true);
|
||||
if (isIiop) {
|
||||
// Make sure java.naming.corba.orb is in the Map.
|
||||
environment.put(EnvHelp.DEFAULT_ORB,resolveOrb(environment));
|
||||
}
|
||||
|
||||
String path = directoryURL.getURLPath();
|
||||
int end = path.indexOf(';');
|
||||
if (end < 0) end = path.length();
|
||||
if (path.startsWith("/jndi/"))
|
||||
return findRMIServerJNDI(path.substring(6,end), environment, isIiop);
|
||||
return findRMIServerJNDI(path.substring(6,end), environment);
|
||||
else if (path.startsWith("/stub/"))
|
||||
return findRMIServerJRMP(path.substring(6,end), environment, isIiop);
|
||||
else if (path.startsWith("/ior/")) {
|
||||
if (!IIOPHelper.isAvailable())
|
||||
throw new IOException("iiop protocol not available");
|
||||
return findRMIServerIIOP(path.substring(5,end), environment, isIiop);
|
||||
} else {
|
||||
return findRMIServerJRMP(path.substring(6,end), environment);
|
||||
else {
|
||||
final String msg = "URL path must begin with /jndi/ or /stub/ " +
|
||||
"or /ior/: " + path;
|
||||
throw new MalformedURLException(msg);
|
||||
@ -1940,16 +1800,13 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable
|
||||
* @param jndiURL A JNDI URL indicating the location of the Stub
|
||||
* (see {@link javax.management.remote.rmi}), e.g.:
|
||||
* <ul><li>{@code rmi://registry-host:port/rmi-stub-name}</li>
|
||||
* <li>or {@code iiop://cosnaming-host:port/iiop-stub-name}</li>
|
||||
* <li>or {@code ldap://ldap-host:port/java-container-dn}</li>
|
||||
* </ul>
|
||||
* @param env the environment Map passed to the connector.
|
||||
* @param isIiop true if the stub is expected to be an IIOP stub.
|
||||
* @return The retrieved RMIServer stub.
|
||||
* @exception NamingException if the stub couldn't be found.
|
||||
**/
|
||||
private RMIServer findRMIServerJNDI(String jndiURL, Map<String, ?> env,
|
||||
boolean isIiop)
|
||||
private RMIServer findRMIServerJNDI(String jndiURL, Map<String, ?> env)
|
||||
throws NamingException {
|
||||
|
||||
InitialContext ctx = new InitialContext(EnvHelp.mapToHashtable(env));
|
||||
@ -1957,10 +1814,7 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable
|
||||
Object objref = ctx.lookup(jndiURL);
|
||||
ctx.close();
|
||||
|
||||
if (isIiop)
|
||||
return narrowIIOPServer(objref);
|
||||
else
|
||||
return narrowJRMPServer(objref);
|
||||
return narrowJRMPServer(objref);
|
||||
}
|
||||
|
||||
private static RMIServer narrowJRMPServer(Object objref) {
|
||||
@ -1968,28 +1822,8 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable
|
||||
return (RMIServer) objref;
|
||||
}
|
||||
|
||||
private static RMIServer narrowIIOPServer(Object objref) {
|
||||
try {
|
||||
return IIOPHelper.narrow(objref, RMIServer.class);
|
||||
} catch (ClassCastException e) {
|
||||
if (logger.traceOn())
|
||||
logger.trace("narrowIIOPServer","Failed to narrow objref=" +
|
||||
objref + ": " + e);
|
||||
if (logger.debugOn()) logger.debug("narrowIIOPServer",e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private RMIServer findRMIServerIIOP(String ior, Map<String, ?> env, boolean isIiop) {
|
||||
// could forbid "rmi:" URL here -- but do we need to?
|
||||
final Object orb = env.get(EnvHelp.DEFAULT_ORB);
|
||||
final Object stub = IIOPHelper.stringToObject(orb, ior);
|
||||
return IIOPHelper.narrow(stub, RMIServer.class);
|
||||
}
|
||||
|
||||
private RMIServer findRMIServerJRMP(String base64, Map<String, ?> env, boolean isIiop)
|
||||
private RMIServer findRMIServerJRMP(String base64, Map<String, ?> env)
|
||||
throws IOException {
|
||||
// could forbid "iiop:" URL here -- but do we need to?
|
||||
final byte[] serialized;
|
||||
try {
|
||||
serialized = base64ToByteArray(base64);
|
||||
@ -2203,228 +2037,6 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable
|
||||
return proxyStub;
|
||||
}
|
||||
|
||||
/*
|
||||
The following code performs a similar trick for RMI/IIOP to the
|
||||
one described above for RMI/JRMP. Unlike JRMP, though, we
|
||||
can't easily insert an object between the RMIConnection stub
|
||||
and the RMI/IIOP deserialization code, as explained below.
|
||||
|
||||
A method in an RMI/IIOP stub does the following. It makes an
|
||||
org.omg.CORBA_2_3.portable.OutputStream for each request, and
|
||||
writes the parameters to it. Then it calls
|
||||
_invoke(OutputStream) which it inherits from CORBA's
|
||||
ObjectImpl. That returns an
|
||||
org.omg.CORBA_2_3.portable.InputStream. The return value is
|
||||
read from this InputStream. So the stack during
|
||||
deserialization looks like this:
|
||||
|
||||
MBeanServerConnection.getAttribute (or whatever)
|
||||
-> _RMIConnection_Stub.getAttribute
|
||||
-> Util.readAny (a CORBA method)
|
||||
-> InputStream.read_any
|
||||
-> internal CORBA stuff
|
||||
|
||||
What we would have *liked* to have done would be the same thing
|
||||
as for RMI/JRMP. We create a "ProxyDelegate" that is an
|
||||
org.omg.CORBA.portable.Delegate that simply forwards every
|
||||
operation to the real original Delegate from the RMIConnection
|
||||
stub, except that the InputStream returned by _invoke is
|
||||
wrapped by a "ProxyInputStream" that is loaded by our
|
||||
NoCallStackClassLoader.
|
||||
|
||||
Unfortunately, this doesn't work, at least with Sun's J2SE
|
||||
1.4.2, because the CORBA code is not designed to allow you to
|
||||
change Delegates arbitrarily. You get a ClassCastException
|
||||
from code that expects the Delegate to implement an internal
|
||||
interface.
|
||||
|
||||
So instead we do the following. We create a subclass of the
|
||||
stub that overrides the _invoke method so as to wrap the
|
||||
returned InputStream in a ProxyInputStream. We create a
|
||||
subclass of ProxyInputStream using the NoCallStackClassLoader
|
||||
and override its read_any and read_value(Class) methods.
|
||||
(These are the only methods called during deserialization of
|
||||
MBeanServerConnection return values.) We extract the Delegate
|
||||
from the original stub and insert it into our subclass stub,
|
||||
and away we go. The state of a stub consists solely of its
|
||||
Delegate.
|
||||
|
||||
We also need to catch ApplicationException, which will encode
|
||||
any exceptions declared in the throws clause of the called
|
||||
method. Its InputStream needs to be wrapped in a
|
||||
ProxyInputSteam too.
|
||||
|
||||
We override _releaseReply in the stub subclass so that it
|
||||
replaces a ProxyInputStream argument with the original
|
||||
InputStream. This avoids problems if the implementation of
|
||||
_releaseReply ends up casting this InputStream to an
|
||||
implementation-specific interface (which in Sun's J2SE 5 it
|
||||
does).
|
||||
|
||||
It is not strictly necessary for the stub subclass to be loaded
|
||||
by a NoCallStackClassLoader, since the call-stack search stops
|
||||
at the ProxyInputStream subclass. However, it is convenient
|
||||
for two reasons. One is that it means that the
|
||||
ProxyInputStream subclass can be accessed directly, without
|
||||
using reflection. The other is that it avoids build problems,
|
||||
since usually stubs are created after other classes are
|
||||
compiled, so we can't access them from this class without,
|
||||
again, using reflection.
|
||||
|
||||
The strings below encode the following two Java classes,
|
||||
compiled using javac -g:none.
|
||||
|
||||
package com.sun.jmx.remote.protocol.iiop;
|
||||
|
||||
import org.omg.stub.javax.management.remote.rmi._RMIConnection_Stub;
|
||||
|
||||
import org.omg.CORBA.portable.ApplicationException;
|
||||
import org.omg.CORBA.portable.InputStream;
|
||||
import org.omg.CORBA.portable.OutputStream;
|
||||
import org.omg.CORBA.portable.RemarshalException;
|
||||
|
||||
public class ProxyStub extends _RMIConnection_Stub {
|
||||
public InputStream _invoke(OutputStream out)
|
||||
throws ApplicationException, RemarshalException {
|
||||
try {
|
||||
return new PInputStream(super._invoke(out));
|
||||
} catch (ApplicationException e) {
|
||||
InputStream pis = new PInputStream(e.getInputStream());
|
||||
throw new ApplicationException(e.getId(), pis);
|
||||
}
|
||||
}
|
||||
|
||||
public void _releaseReply(InputStream in) {
|
||||
if (in != null)
|
||||
in = ((PInputStream)in).getProxiedInputStream();
|
||||
super._releaseReply(in);
|
||||
}
|
||||
}
|
||||
|
||||
package com.sun.jmx.remote.protocol.iiop;
|
||||
|
||||
public class PInputStream extends ProxyInputStream {
|
||||
public PInputStream(org.omg.CORBA.portable.InputStream in) {
|
||||
super(in);
|
||||
}
|
||||
|
||||
public org.omg.CORBA.Any read_any() {
|
||||
return in.read_any();
|
||||
}
|
||||
|
||||
public java.io.Serializable read_value(Class clz) {
|
||||
return narrow().read_value(clz);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
*/
|
||||
private static final String iiopConnectionStubClassName =
|
||||
"org.omg.stub.javax.management.remote.rmi._RMIConnection_Stub";
|
||||
private static final String proxyStubClassName =
|
||||
"com.sun.jmx.remote.protocol.iiop.ProxyStub";
|
||||
private static final String ProxyInputStreamClassName =
|
||||
"com.sun.jmx.remote.protocol.iiop.ProxyInputStream";
|
||||
private static final String pInputStreamClassName =
|
||||
"com.sun.jmx.remote.protocol.iiop.PInputStream";
|
||||
private static final Class<?> proxyStubClass;
|
||||
static {
|
||||
final String proxyStubByteCodeString =
|
||||
"\312\376\272\276\0\0\0\63\0+\12\0\14\0\30\7\0\31\12\0\14\0\32\12"+
|
||||
"\0\2\0\33\7\0\34\12\0\5\0\35\12\0\5\0\36\12\0\5\0\37\12\0\2\0 "+
|
||||
"\12\0\14\0!\7\0\"\7\0#\1\0\6<init>\1\0\3()V\1\0\4Code\1\0\7_in"+
|
||||
"voke\1\0K(Lorg/omg/CORBA/portable/OutputStream;)Lorg/omg/CORBA"+
|
||||
"/portable/InputStream;\1\0\15StackMapTable\7\0\34\1\0\12Except"+
|
||||
"ions\7\0$\1\0\15_releaseReply\1\0'(Lorg/omg/CORBA/portable/Inp"+
|
||||
"utStream;)V\14\0\15\0\16\1\0-com/sun/jmx/remote/protocol/iiop/"+
|
||||
"PInputStream\14\0\20\0\21\14\0\15\0\27\1\0+org/omg/CORBA/porta"+
|
||||
"ble/ApplicationException\14\0%\0&\14\0'\0(\14\0\15\0)\14\0*\0&"+
|
||||
"\14\0\26\0\27\1\0*com/sun/jmx/remote/protocol/iiop/ProxyStub\1"+
|
||||
"\0<org/omg/stub/javax/management/remote/rmi/_RMIConnection_Stu"+
|
||||
"b\1\0)org/omg/CORBA/portable/RemarshalException\1\0\16getInput"+
|
||||
"Stream\1\0&()Lorg/omg/CORBA/portable/InputStream;\1\0\5getId\1"+
|
||||
"\0\24()Ljava/lang/String;\1\09(Ljava/lang/String;Lorg/omg/CORB"+
|
||||
"A/portable/InputStream;)V\1\0\25getProxiedInputStream\0!\0\13\0"+
|
||||
"\14\0\0\0\0\0\3\0\1\0\15\0\16\0\1\0\17\0\0\0\21\0\1\0\1\0\0\0\5"+
|
||||
"*\267\0\1\261\0\0\0\0\0\1\0\20\0\21\0\2\0\17\0\0\0G\0\4\0\4\0\0"+
|
||||
"\0'\273\0\2Y*+\267\0\3\267\0\4\260M\273\0\2Y,\266\0\6\267\0\4N"+
|
||||
"\273\0\5Y,\266\0\7-\267\0\10\277\0\1\0\0\0\14\0\15\0\5\0\1\0\22"+
|
||||
"\0\0\0\6\0\1M\7\0\23\0\24\0\0\0\6\0\2\0\5\0\25\0\1\0\26\0\27\0"+
|
||||
"\1\0\17\0\0\0'\0\2\0\2\0\0\0\22+\306\0\13+\300\0\2\266\0\11L*+"+
|
||||
"\267\0\12\261\0\0\0\1\0\22\0\0\0\3\0\1\14\0\0";
|
||||
final String pInputStreamByteCodeString =
|
||||
"\312\376\272\276\0\0\0\63\0\36\12\0\7\0\17\11\0\6\0\20\12\0\21"+
|
||||
"\0\22\12\0\6\0\23\12\0\24\0\25\7\0\26\7\0\27\1\0\6<init>\1\0'("+
|
||||
"Lorg/omg/CORBA/portable/InputStream;)V\1\0\4Code\1\0\10read_an"+
|
||||
"y\1\0\25()Lorg/omg/CORBA/Any;\1\0\12read_value\1\0)(Ljava/lang"+
|
||||
"/Class;)Ljava/io/Serializable;\14\0\10\0\11\14\0\30\0\31\7\0\32"+
|
||||
"\14\0\13\0\14\14\0\33\0\34\7\0\35\14\0\15\0\16\1\0-com/sun/jmx"+
|
||||
"/remote/protocol/iiop/PInputStream\1\0\61com/sun/jmx/remote/pr"+
|
||||
"otocol/iiop/ProxyInputStream\1\0\2in\1\0$Lorg/omg/CORBA/portab"+
|
||||
"le/InputStream;\1\0\"org/omg/CORBA/portable/InputStream\1\0\6n"+
|
||||
"arrow\1\0*()Lorg/omg/CORBA_2_3/portable/InputStream;\1\0&org/o"+
|
||||
"mg/CORBA_2_3/portable/InputStream\0!\0\6\0\7\0\0\0\0\0\3\0\1\0"+
|
||||
"\10\0\11\0\1\0\12\0\0\0\22\0\2\0\2\0\0\0\6*+\267\0\1\261\0\0\0"+
|
||||
"\0\0\1\0\13\0\14\0\1\0\12\0\0\0\24\0\1\0\1\0\0\0\10*\264\0\2\266"+
|
||||
"\0\3\260\0\0\0\0\0\1\0\15\0\16\0\1\0\12\0\0\0\25\0\2\0\2\0\0\0"+
|
||||
"\11*\266\0\4+\266\0\5\260\0\0\0\0\0\0";
|
||||
final byte[] proxyStubByteCode =
|
||||
NoCallStackClassLoader.stringToBytes(proxyStubByteCodeString);
|
||||
final byte[] pInputStreamByteCode =
|
||||
NoCallStackClassLoader.stringToBytes(pInputStreamByteCodeString);
|
||||
final String[] classNames={proxyStubClassName, pInputStreamClassName};
|
||||
final byte[][] byteCodes = {proxyStubByteCode, pInputStreamByteCode};
|
||||
final String[] otherClassNames = {
|
||||
iiopConnectionStubClassName,
|
||||
ProxyInputStreamClassName,
|
||||
};
|
||||
if (IIOPHelper.isAvailable()) {
|
||||
PrivilegedExceptionAction<Class<?>> action =
|
||||
new PrivilegedExceptionAction<Class<?>>() {
|
||||
public Class<?> run() throws Exception {
|
||||
Class<RMIConnector> thisClass = RMIConnector.class;
|
||||
ClassLoader thisLoader = thisClass.getClassLoader();
|
||||
ProtectionDomain thisProtectionDomain =
|
||||
thisClass.getProtectionDomain();
|
||||
ClassLoader cl =
|
||||
new NoCallStackClassLoader(classNames,
|
||||
byteCodes,
|
||||
otherClassNames,
|
||||
thisLoader,
|
||||
thisProtectionDomain);
|
||||
return cl.loadClass(proxyStubClassName);
|
||||
}
|
||||
};
|
||||
Class<?> stubClass;
|
||||
try {
|
||||
stubClass = AccessController.doPrivileged(action);
|
||||
} catch (Exception e) {
|
||||
logger.error("<clinit>",
|
||||
"Unexpected exception making shadow IIOP stub class: "+e);
|
||||
logger.debug("<clinit>",e);
|
||||
stubClass = null;
|
||||
}
|
||||
proxyStubClass = stubClass;
|
||||
} else {
|
||||
proxyStubClass = null;
|
||||
}
|
||||
}
|
||||
|
||||
private static RMIConnection shadowIiopStub(Object stub)
|
||||
throws InstantiationException, IllegalAccessException {
|
||||
Object proxyStub = null;
|
||||
try {
|
||||
proxyStub = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
|
||||
public Object run() throws Exception {
|
||||
return proxyStubClass.newInstance();
|
||||
}
|
||||
});
|
||||
} catch (PrivilegedActionException e) {
|
||||
throw new InternalError();
|
||||
}
|
||||
IIOPHelper.setDelegate(proxyStub, IIOPHelper.getDelegate(stub));
|
||||
return (RMIConnection) proxyStub;
|
||||
}
|
||||
private static RMIConnection getConnection(RMIServer server,
|
||||
Object credentials,
|
||||
boolean checkStub)
|
||||
@ -2434,8 +2046,6 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable
|
||||
try {
|
||||
if (c.getClass() == rmiConnectionImplStubClass)
|
||||
return shadowJrmpStub((RemoteObject) c);
|
||||
if (c.getClass().getName().equals(iiopConnectionStubClassName))
|
||||
return shadowIiopStub(c);
|
||||
logger.trace("getConnection",
|
||||
"Did not wrap " + c.getClass() + " to foil " +
|
||||
"stack search for classes: class loading semantics " +
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -27,7 +27,6 @@ package javax.management.remote.rmi;
|
||||
|
||||
|
||||
import com.sun.jmx.remote.security.MBeanServerFileAccessController;
|
||||
import com.sun.jmx.remote.internal.IIOPHelper;
|
||||
import com.sun.jmx.remote.util.ClassLogger;
|
||||
import com.sun.jmx.remote.util.EnvHelp;
|
||||
|
||||
@ -117,8 +116,8 @@ public class RMIConnectorServer extends JMXConnectorServer {
|
||||
*
|
||||
* @exception MalformedURLException if <code>url</code> does not
|
||||
* conform to the syntax for an RMI connector, or if its protocol
|
||||
* is not recognized by this implementation. Only "rmi" and "iiop"
|
||||
* are valid when this constructor is used.
|
||||
* is not recognized by this implementation. Only "rmi" is valid when
|
||||
* this constructor is used.
|
||||
*
|
||||
* @exception IOException if the connector server cannot be created
|
||||
* for some reason or if it is inevitable that its {@link #start()
|
||||
@ -151,8 +150,8 @@ public class RMIConnectorServer extends JMXConnectorServer {
|
||||
*
|
||||
* @exception MalformedURLException if <code>url</code> does not
|
||||
* conform to the syntax for an RMI connector, or if its protocol
|
||||
* is not recognized by this implementation. Only "rmi" and "iiop"
|
||||
* are valid when this constructor is used.
|
||||
* is not recognized by this implementation. Only "rmi" is valid
|
||||
* when this constructor is used.
|
||||
*
|
||||
* @exception IOException if the connector server cannot be created
|
||||
* for some reason or if it is inevitable that its {@link #start()
|
||||
@ -179,7 +178,7 @@ public class RMIConnectorServer extends JMXConnectorServer {
|
||||
* consistent with the protocol type specified in <var>url</var>.
|
||||
* If this parameter is non null, the protocol type specified by
|
||||
* <var>url</var> is not constrained, and is assumed to be valid.
|
||||
* Otherwise, only "rmi" and "iiop" will be recognized.
|
||||
* Otherwise, only "rmi" will be recognized.
|
||||
*
|
||||
* @param mbeanServer the MBean server to which the new connector
|
||||
* server is attached, or null if it will be attached by being
|
||||
@ -189,8 +188,8 @@ public class RMIConnectorServer extends JMXConnectorServer {
|
||||
*
|
||||
* @exception MalformedURLException if <code>url</code> does not
|
||||
* conform to the syntax for an RMI connector, or if its protocol
|
||||
* is not recognized by this implementation. Only "rmi" and "iiop"
|
||||
* are recognized when <var>rmiServerImpl</var> is null.
|
||||
* is not recognized by this implementation. Only "rmi" is recognized
|
||||
* when <var>rmiServerImpl</var> is null.
|
||||
*
|
||||
* @exception IOException if the connector server cannot be created
|
||||
* for some reason or if it is inevitable that its {@link #start()
|
||||
@ -208,7 +207,7 @@ public class RMIConnectorServer extends JMXConnectorServer {
|
||||
IllegalArgumentException("Null JMXServiceURL");
|
||||
if (rmiServerImpl == null) {
|
||||
final String prt = url.getProtocol();
|
||||
if (prt == null || !(prt.equals("rmi") || prt.equals("iiop"))) {
|
||||
if (prt == null || !(prt.equals("rmi"))) {
|
||||
final String msg = "Invalid protocol type: " + prt;
|
||||
throw new MalformedURLException(msg);
|
||||
}
|
||||
@ -298,11 +297,6 @@ public class RMIConnectorServer extends JMXConnectorServer {
|
||||
* <li>If an <code>RMIServerImpl</code> was supplied to the
|
||||
* constructor, it is used.
|
||||
*
|
||||
* <li>Otherwise, if the protocol part of the
|
||||
* <code>JMXServiceURL</code> supplied to the constructor was
|
||||
* <code>iiop</code>, an object of type {@link RMIIIOPServerImpl}
|
||||
* is created.
|
||||
*
|
||||
* <li>Otherwise, if the <code>JMXServiceURL</code>
|
||||
* was null, or its protocol part was <code>rmi</code>, an object
|
||||
* of type {@link RMIJRMPServerImpl} is created.
|
||||
@ -324,21 +318,19 @@ public class RMIConnectorServer extends JMXConnectorServer {
|
||||
* will not be bound to a directory. Instead, a reference to it
|
||||
* will be encoded in the URL path of the RMIConnectorServer
|
||||
* address (returned by {@link #getAddress()}). The encodings for
|
||||
* <code>rmi</code> and <code>iiop</code> are described in the
|
||||
* package documentation for {@link
|
||||
* javax.management.remote.rmi}.</p>
|
||||
* <code>rmi</code> are described in the package documentation for
|
||||
* {@link javax.management.remote.rmi}.</p>
|
||||
*
|
||||
* <p>The behavior when the URL path is neither empty nor a JNDI
|
||||
* directory URL, or when the protocol is neither <code>rmi</code>
|
||||
* nor <code>iiop</code>, is implementation defined, and may
|
||||
* include throwing {@link MalformedURLException} when the
|
||||
* connector server is created or when it is started.</p>
|
||||
* directory URL, or when the protocol is not <code>rmi</code>,
|
||||
* is implementation defined, and may include throwing
|
||||
* {@link MalformedURLException} when the connector server is created
|
||||
* or when it is started.</p>
|
||||
*
|
||||
* @exception IllegalStateException if the connector server has
|
||||
* not been attached to an MBean server.
|
||||
* @exception IOException if the connector server cannot be
|
||||
* started, or in the case of the {@code iiop} protocol, that
|
||||
* RMI/IIOP is not supported.
|
||||
* started.
|
||||
*/
|
||||
public synchronized void start() throws IOException {
|
||||
final boolean tracing = logger.traceOn();
|
||||
@ -649,16 +641,13 @@ public class RMIConnectorServer extends JMXConnectorServer {
|
||||
* Creates a new RMIServerImpl.
|
||||
**/
|
||||
RMIServerImpl newServer() throws IOException {
|
||||
final boolean iiop = isIiopURL(address,true);
|
||||
final int port;
|
||||
if (address == null)
|
||||
port = 0;
|
||||
else
|
||||
port = address.getPort();
|
||||
if (iiop)
|
||||
return newIIOPServer(attributes);
|
||||
else
|
||||
return newJRMPServer(attributes, port);
|
||||
|
||||
return newJRMPServer(attributes, port);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -675,10 +664,7 @@ public class RMIConnectorServer extends JMXConnectorServer {
|
||||
final int port;
|
||||
|
||||
if (address == null) {
|
||||
if (IIOPHelper.isStub(rmiServer))
|
||||
protocol = "iiop";
|
||||
else
|
||||
protocol = "rmi";
|
||||
protocol = "rmi";
|
||||
host = null; // will default to local host name
|
||||
port = 0;
|
||||
} else {
|
||||
@ -692,31 +678,12 @@ public class RMIConnectorServer extends JMXConnectorServer {
|
||||
address = new JMXServiceURL(protocol, host, port, urlPath);
|
||||
}
|
||||
|
||||
static boolean isIiopURL(JMXServiceURL directoryURL, boolean strict)
|
||||
throws MalformedURLException {
|
||||
String protocol = directoryURL.getProtocol();
|
||||
if (protocol.equals("rmi"))
|
||||
return false;
|
||||
else if (protocol.equals("iiop"))
|
||||
return true;
|
||||
else if (strict) {
|
||||
|
||||
throw new MalformedURLException("URL must have protocol " +
|
||||
"\"rmi\" or \"iiop\": \"" +
|
||||
protocol + "\"");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the IOR of the given rmiServer.
|
||||
**/
|
||||
static String encodeStub(
|
||||
RMIServer rmiServer, Map<String, ?> env) throws IOException {
|
||||
if (IIOPHelper.isStub(rmiServer))
|
||||
return "/ior/" + encodeIIOPStub(rmiServer, env);
|
||||
else
|
||||
return "/stub/" + encodeJRMPStub(rmiServer, env);
|
||||
return "/stub/" + encodeJRMPStub(rmiServer, env);
|
||||
}
|
||||
|
||||
static String encodeJRMPStub(
|
||||
@ -730,17 +697,6 @@ public class RMIConnectorServer extends JMXConnectorServer {
|
||||
return byteArrayToBase64(bytes);
|
||||
}
|
||||
|
||||
static String encodeIIOPStub(
|
||||
RMIServer rmiServer, Map<String, ?> env)
|
||||
throws IOException {
|
||||
try {
|
||||
Object orb = IIOPHelper.getOrb(rmiServer);
|
||||
return IIOPHelper.objectToString(orb, rmiServer);
|
||||
} catch (RuntimeException x) {
|
||||
throw newIOException(x.getMessage(), x);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Object that we will bind to the registry.
|
||||
* This object is a stub connected to our RMIServerImpl.
|
||||
@ -748,8 +704,7 @@ public class RMIConnectorServer extends JMXConnectorServer {
|
||||
private static RMIServer objectToBind(
|
||||
RMIServerImpl rmiServer, Map<String, ?> env)
|
||||
throws IOException {
|
||||
return RMIConnector.
|
||||
connectStub((RMIServer)rmiServer.toStub(),env);
|
||||
return (RMIServer)rmiServer.toStub();
|
||||
}
|
||||
|
||||
private static RMIServerImpl newJRMPServer(Map<String, ?> env, int port)
|
||||
@ -761,11 +716,6 @@ public class RMIConnectorServer extends JMXConnectorServer {
|
||||
return new RMIJRMPServerImpl(port, csf, ssf, env);
|
||||
}
|
||||
|
||||
private static RMIServerImpl newIIOPServer(Map<String, ?> env)
|
||||
throws IOException {
|
||||
return new RMIIIOPServerImpl(env);
|
||||
}
|
||||
|
||||
private static String byteArrayToBase64(byte[] a) {
|
||||
int aLen = a.length;
|
||||
int numFullGroups = aLen/3;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -27,16 +27,9 @@ package javax.management.remote.rmi;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.rmi.Remote;
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedActionException;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.util.Map;
|
||||
import java.util.Collections;
|
||||
import javax.security.auth.Subject;
|
||||
|
||||
import com.sun.jmx.remote.internal.IIOPHelper;
|
||||
|
||||
/**
|
||||
* <p>An {@link RMIServerImpl} that is exported through IIOP and that
|
||||
* creates client connections as RMI objects exported through IIOP.
|
||||
@ -45,120 +38,59 @@ import com.sun.jmx.remote.internal.IIOPHelper;
|
||||
* @see RMIServerImpl
|
||||
*
|
||||
* @since 1.5
|
||||
* @deprecated This transport is no longer supported.
|
||||
*/
|
||||
@Deprecated
|
||||
public class RMIIIOPServerImpl extends RMIServerImpl {
|
||||
/**
|
||||
* <p>Creates a new {@link RMIServerImpl}.</p>
|
||||
* Throws {@linkplain UnsupportedOperationException}
|
||||
*
|
||||
* @param env the environment containing attributes for the new
|
||||
* <code>RMIServerImpl</code>. Can be null, which is equivalent
|
||||
* to an empty Map.
|
||||
*
|
||||
* @exception IOException if the RMI object cannot be created.
|
||||
* @throws IOException if the RMI object cannot be created.
|
||||
*/
|
||||
public RMIIIOPServerImpl(Map<String,?> env)
|
||||
throws IOException {
|
||||
super(env);
|
||||
|
||||
this.env = (env == null) ? Collections.<String, Object>emptyMap() : env;
|
||||
|
||||
callerACC = AccessController.getContext();
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void export() throws IOException {
|
||||
IIOPHelper.exportObject(this);
|
||||
throw new UnsupportedOperationException("Method not supported. JMX RMI-IIOP is deprecated");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getProtocol() {
|
||||
return "iiop";
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns an IIOP stub.</p>
|
||||
* The stub might not yet be connected to the ORB. The stub will
|
||||
* be serializable only if it is connected to the ORB.
|
||||
* @return an IIOP stub.
|
||||
* @exception IOException if the stub cannot be created - e.g the
|
||||
* RMIIIOPServerImpl has not been exported yet.
|
||||
**/
|
||||
@Override
|
||||
public Remote toStub() throws IOException {
|
||||
// javax.rmi.CORBA.Stub stub =
|
||||
// (javax.rmi.CORBA.Stub) PortableRemoteObject.toStub(this);
|
||||
final Remote stub = IIOPHelper.toStub(this);
|
||||
// java.lang.System.out.println("NON CONNECTED STUB " + stub);
|
||||
// org.omg.CORBA.ORB orb =
|
||||
// org.omg.CORBA.ORB.init((String[])null, (Properties)null);
|
||||
// stub.connect(orb);
|
||||
// java.lang.System.out.println("CONNECTED STUB " + stub);
|
||||
return stub;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Creates a new client connection as an RMI object exported
|
||||
* through IIOP.
|
||||
*
|
||||
* @param connectionId the ID of the new connection. Every
|
||||
* connection opened by this connector server will have a
|
||||
* different ID. The behavior is unspecified if this parameter is
|
||||
* null.
|
||||
*
|
||||
* @param subject the authenticated subject. Can be null.
|
||||
*
|
||||
* @return the newly-created <code>RMIConnection</code>.
|
||||
*
|
||||
* @exception IOException if the new client object cannot be
|
||||
* created or exported.
|
||||
*/
|
||||
@Override
|
||||
protected RMIConnection makeClient(String connectionId, Subject subject)
|
||||
throws IOException {
|
||||
|
||||
if (connectionId == null)
|
||||
throw new NullPointerException("Null connectionId");
|
||||
|
||||
RMIConnection client =
|
||||
new RMIConnectionImpl(this, connectionId, getDefaultClassLoader(),
|
||||
subject, env);
|
||||
IIOPHelper.exportObject(client);
|
||||
return client;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void closeClient(RMIConnection client) throws IOException {
|
||||
IIOPHelper.unexportObject(client);
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Called by {@link #close()} to close the connector server by
|
||||
* unexporting this object. After returning from this method, the
|
||||
* connector server must not accept any new connections.</p>
|
||||
*
|
||||
* @exception IOException if the attempt to close the connector
|
||||
* server failed.
|
||||
*/
|
||||
@Override
|
||||
protected void closeServer() throws IOException {
|
||||
IIOPHelper.unexportObject(this);
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
RMIConnection doNewClient(final Object credentials) throws IOException {
|
||||
if (callerACC == null) {
|
||||
throw new SecurityException("AccessControlContext cannot be null");
|
||||
}
|
||||
try {
|
||||
return AccessController.doPrivileged(
|
||||
new PrivilegedExceptionAction<RMIConnection>() {
|
||||
public RMIConnection run() throws IOException {
|
||||
return superDoNewClient(credentials);
|
||||
}
|
||||
}, callerACC);
|
||||
} catch (PrivilegedActionException pae) {
|
||||
throw (IOException) pae.getCause();
|
||||
}
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
RMIConnection superDoNewClient(Object credentials) throws IOException {
|
||||
return super.doNewClient(credentials);
|
||||
}
|
||||
|
||||
private final Map<String, ?> env;
|
||||
private final AccessControlContext callerACC;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -61,8 +61,7 @@ import javax.security.auth.Subject;
|
||||
* or by instantiating {@link RMIConnector}.</p>
|
||||
*
|
||||
* <p>This is an abstract class. Concrete subclasses define the
|
||||
* details of the client connection objects, such as whether they use
|
||||
* JRMP or IIOP.</p>
|
||||
* details of the client connection objects.</p>
|
||||
*
|
||||
* @since 1.5
|
||||
*/
|
||||
@ -307,7 +306,7 @@ public abstract class RMIServerImpl implements Closeable, RMIServer {
|
||||
|
||||
/**
|
||||
* <p>Returns the protocol string for this object. The string is
|
||||
* <code>rmi</code> for RMI/JRMP and <code>iiop</code> for RMI/IIOP.
|
||||
* <code>rmi</code> for RMI/JRMP.
|
||||
*
|
||||
* @return the protocol string for this object.
|
||||
*/
|
||||
|
@ -2,7 +2,7 @@
|
||||
<head>
|
||||
<title>RMI connector</title>
|
||||
<!--
|
||||
Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
|
||||
This code is free software; you can redistribute it and/or modify it
|
||||
@ -36,16 +36,14 @@ questions.
|
||||
that different implementations of the RMI connector can
|
||||
interoperate.</p>
|
||||
|
||||
<p>The RMI connector supports the JRMP transport for RMI, and
|
||||
optionally the IIOP transport.</p>
|
||||
<p>The RMI connector supports the JRMP transport for RMI.</p>
|
||||
|
||||
<p>Like most connectors in the JMX Remote API, an RMI connector
|
||||
usually has an address, which
|
||||
is a {@link javax.management.remote.JMXServiceURL
|
||||
JMXServiceURL}. The protocol part of this address is
|
||||
<code>rmi</code> for a connector that uses the default RMI
|
||||
transport (JRMP), or <code>iiop</code> for a connector that
|
||||
uses RMI/IIOP.</p>
|
||||
transport (JRMP).</p>
|
||||
|
||||
<p>There are two forms for RMI connector addresses:</p>
|
||||
|
||||
@ -65,10 +63,9 @@ questions.
|
||||
information needed to connect to the connector server. When
|
||||
using RMI/JRMP, the encoded form is the serialized RMI stub
|
||||
for the server object, encoded using BASE64 without embedded
|
||||
newlines. When using RMI/IIOP, the encoded form is the CORBA
|
||||
IOR for the server object.
|
||||
newlines.
|
||||
</ul>
|
||||
|
||||
|
||||
<p>Addresses are covered in more detail below.</p>
|
||||
|
||||
|
||||
@ -91,9 +88,8 @@ questions.
|
||||
|
||||
<h4>Choosing the RMI transport</h4>
|
||||
|
||||
<p>You can choose the RMI transport (JRMP or IIOP) by specifying
|
||||
<code>rmi</code> or <code>iiop</code> in the
|
||||
<code><em>protocol</em></code> part of the
|
||||
<p>You can choose the RMI transport by specifying
|
||||
<code>rmi</code> in the <code><em>protocol</em></code> part of the
|
||||
<code>serviceURL</code> when creating the connector server. You
|
||||
can also create specialized connector servers by instantiating
|
||||
an appropriate subclass of {@link
|
||||
@ -132,33 +128,9 @@ questions.
|
||||
stub for the generated object, encoded in BASE64 without
|
||||
newlines.</p>
|
||||
|
||||
<li><p>If the <code>serviceURL</code> looks like:</p>
|
||||
|
||||
<pre>
|
||||
<code>service:jmx:iiop://<em>host</em>:<em>port</em></code>
|
||||
</pre>
|
||||
|
||||
<p>then the connector server will generate an {@link
|
||||
javax.management.remote.rmi.RMIIIOPServerImpl
|
||||
RMIIIOPServerImpl} and the returned
|
||||
<code>JMXServiceURL</code> looks like:</p>
|
||||
|
||||
<pre>
|
||||
<code>service:jmx:iiop://<em>host</em>:<em>port</em>/ior/IOR:<em>XXXX</em></code>
|
||||
</pre>
|
||||
|
||||
<p>where <code>IOR:<em>XXXX</em></code> is the standard CORBA
|
||||
encoding of the Interoperable Object Reference for the
|
||||
generated object.</p>
|
||||
|
||||
<li><p>If there is no <code>serviceURL</code>, there must be a
|
||||
user-provided <code>RMIServerImpl</code>. If the {@link
|
||||
javax.management.remote.rmi.RMIServerImpl#toStub toStub}
|
||||
method on this object returns an instance of {@link
|
||||
javax.rmi.CORBA.Stub}, then the connector server will generate
|
||||
a <code>JMXServiceURL</code> using the <code>iiop</code>
|
||||
form above. Otherwise, it will generate a
|
||||
<code>JMXServiceURL</code> using the <code>rmi</code>
|
||||
user-provided <code>RMIServerImpl</code>. The connector server
|
||||
will generate a <code>JMXServiceURL</code> using the <code>rmi</code>
|
||||
form.</p>
|
||||
|
||||
</ul>
|
||||
@ -195,12 +167,10 @@ questions.
|
||||
stub. This directory address is then used by both client and
|
||||
server.</p>
|
||||
|
||||
<p>In this case, the <code>serviceURL</code> has one of these two
|
||||
forms:</p>
|
||||
<p>In this case, the <code>serviceURL</code> has the following form:</p>
|
||||
|
||||
<pre>
|
||||
<code>service:jmx:rmi://<em>host</em>:<em>port</em>/jndi/<em>jndi-name</em></code>
|
||||
<code>service:jmx:iiop://<em>host</em>:<em>port</em>/jndi/<em>jndi-name</em></code>
|
||||
</pre>
|
||||
|
||||
<p>Here, <code><em>jndi-name</em></code> is a string that can be
|
||||
@ -212,8 +182,7 @@ questions.
|
||||
|
||||
<p>The connector server will generate an
|
||||
<code>RMIServerImpl</code> based on the protocol
|
||||
(<code>rmi</code> or <code>iiop</code>) and, for
|
||||
<code>rmi</code>, the <code><em>port</em></code> if any. When
|
||||
(<code>rmi</code>) and the <code><em>port</em></code> if any. When
|
||||
the connector server is started, it will derive a stub from this
|
||||
object using its {@link
|
||||
javax.management.remote.rmi.RMIServerImpl#toStub toStub} method
|
||||
@ -250,11 +219,11 @@ questions.
|
||||
<p>As another example, if the <code>JMXServiceURL</code> is:
|
||||
|
||||
<pre>
|
||||
<code>service:jmx:iiop://ignoredhost/jndi/ldap://dirhost:9999/cn=this,ou=that</code>
|
||||
<code>service:jmx:rmi://ignoredhost/jndi/ldap://dirhost:9999/cn=this,ou=that</code>
|
||||
</pre>
|
||||
|
||||
then the connector server will generate an
|
||||
<code>RMIIIOPServerImpl</code> and store its stub using the JNDI
|
||||
<code>RMIJRMPServerImpl</code> and store its stub using the JNDI
|
||||
name
|
||||
|
||||
<pre>
|
||||
@ -267,11 +236,11 @@ questions.
|
||||
<p>If the <code>JMXServiceURL</code> is:
|
||||
|
||||
<pre>
|
||||
<code>service:jmx:iiop://ignoredhost/jndi/cn=this,ou=that</code>
|
||||
<code>service:jmx:rmi://ignoredhost/jndi/cn=this,ou=that</code>
|
||||
</pre>
|
||||
|
||||
then the connector server will generate an
|
||||
<code>RMIIIOPServerImpl</code> and store its stub using the JNDI
|
||||
<code>RMIJRMPServerImpl</code> and store its stub using the JNDI
|
||||
name
|
||||
|
||||
<pre>
|
||||
@ -287,7 +256,7 @@ questions.
|
||||
omitted, for example:</p>
|
||||
|
||||
<pre>
|
||||
<code>service:jmx:iiop:///jndi/cn=this,ou=that</code>
|
||||
<code>service:jmx:rmi:///jndi/cn=this,ou=that</code>
|
||||
</pre>
|
||||
|
||||
<p>However, it is good practice to use the name of the host
|
||||
@ -313,8 +282,7 @@ questions.
|
||||
|
||||
<p>An RMI connector client is usually constructed using {@link
|
||||
javax.management.remote.JMXConnectorFactory}, with a
|
||||
<code>JMXServiceURL</code> that has <code>rmi</code> or
|
||||
<code>iiop</code> as its protocol.</p>
|
||||
<code>JMXServiceURL</code> that has <code>rmi</code> as its protocol.</p>
|
||||
|
||||
<p>If the <code>JMXServiceURL</code> was generated by the server,
|
||||
as described above under <a href="#servergen">"connector
|
||||
@ -343,37 +311,6 @@ questions.
|
||||
constructor of {@link javax.management.remote.rmi.RMIConnector
|
||||
RMIConnector}.</p>
|
||||
|
||||
|
||||
<h3>Specifying an ORB for the RMI/IIOP connector</h3>
|
||||
|
||||
<p>When using the IIOP transport, the client and server can
|
||||
specify what ORB to use
|
||||
with the attribute <code>java.naming.corba.orb</code>.
|
||||
Connection to the ORB happens at {@link
|
||||
javax.management.remote.rmi.RMIConnectorServer#start() start} time
|
||||
for the connector server, and at {@link
|
||||
javax.management.remote.rmi.RMIConnector#connect(java.util.Map)
|
||||
connect} time for the connector client.
|
||||
If the <code>java.naming.corba.orb</code> attribute is contained
|
||||
in the environment Map, then its value (an {@link
|
||||
org.omg.CORBA.ORB ORB}), is used to connect the IIOP Stubs.
|
||||
Otherwise, a new org.omg.CORBA.ORB is created by calling {@link
|
||||
org.omg.CORBA.ORB
|
||||
org.omg.CORBA.ORB.init((String[])null,(Properties)null)}. A
|
||||
later RMI connector client or server in the same JVM can reuse
|
||||
this ORB, or it can create another one in the same way.</p>
|
||||
|
||||
<p>If the <code>java.naming.corba.orb</code> attribute is
|
||||
specified and does not point to an {@link org.omg.CORBA.ORB ORB},
|
||||
then an <code>{@link java.lang.IllegalArgumentException}</code>
|
||||
will be thrown.</p>
|
||||
|
||||
<p>The mechanism described here does not apply when the IIOP
|
||||
Remote objects (Stubs or Servers) are created and connected to
|
||||
an ORB manually before being passed to the RMIConnector and
|
||||
RMIConnectorServer.</p>
|
||||
|
||||
|
||||
<h3>Dynamic code downloading</h3>
|
||||
|
||||
<p>If an RMI connector client or server receives from its peer an
|
||||
@ -385,7 +322,7 @@ questions.
|
||||
code downloading using Java RMI</em></a> explains this in more
|
||||
detail.</p>
|
||||
|
||||
|
||||
|
||||
@see <a href="{@docRoot}/../technotes/guides/rmi/index.html">
|
||||
Java™ Remote Method
|
||||
Invocation (RMI)</a>
|
||||
|
@ -67,6 +67,7 @@ jdk_lang = \
|
||||
sun/misc \
|
||||
sun/reflect \
|
||||
jdk/lambda \
|
||||
jdk/internal/jimage \
|
||||
vm
|
||||
|
||||
# All of the java.util package
|
||||
@ -210,13 +211,13 @@ jdk_native_sanity = \
|
||||
|
||||
# java launcher specific tests, Note: do not include this group into any groups
|
||||
# that potentially could be included into a jprt test rule, as the complementary
|
||||
# closed group includes awt SplashScreen and these tests may not run
|
||||
# satisfacotorily on all platforms and profiles thus this group must always
|
||||
# closed group includes awt SplashScreen and these tests may not run
|
||||
# satisfactorily on all platforms and profiles thus this group must always
|
||||
# be a stand-alone group
|
||||
jdk_launcher = \
|
||||
tools/launcher \
|
||||
sun/tools
|
||||
|
||||
|
||||
#
|
||||
# Tool (and tool API) tests are split into core and svc groups
|
||||
#
|
||||
@ -473,7 +474,7 @@ needs_jdk = \
|
||||
sun/reflect/CallerSensitive/MissingCallerSensitive.java \
|
||||
sun/security/util/Resources/NewNamesFormat.java \
|
||||
vm/verifier/defaultMethods/DefaultMethodRegressionTestsRun.java \
|
||||
javax/xml/ws/clientjar/TestWsImport.java
|
||||
javax/xml/ws/clientjar/TestWsImport.java
|
||||
|
||||
# JRE adds further tests to compact3
|
||||
#
|
||||
|
@ -40,7 +40,6 @@ import javax.management.remote.rmi.RMIConnection;
|
||||
import javax.management.remote.rmi.RMIConnectionImpl;
|
||||
import javax.management.remote.rmi.RMIConnectionImpl_Stub;
|
||||
import javax.management.remote.rmi.RMIConnector;
|
||||
import javax.management.remote.rmi.RMIIIOPServerImpl;
|
||||
import javax.management.remote.rmi.RMIJRMPServerImpl;
|
||||
import javax.management.remote.rmi.RMIServerImpl;
|
||||
|
||||
@ -52,7 +51,6 @@ public class CloseableTest {
|
||||
RMIConnectionImpl.class,
|
||||
RMIConnectionImpl_Stub.class,
|
||||
RMIServerImpl.class,
|
||||
RMIIIOPServerImpl.class,
|
||||
RMIJRMPServerImpl.class
|
||||
};
|
||||
|
||||
|
@ -1,142 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/* @test
|
||||
* @bug 8004502
|
||||
* @summary Sanity check that attempts to use the IIOP transport or
|
||||
* RMIIIOPServerImpl when RMI/IIOP not present throws the expected exceptions
|
||||
* @modules java.management
|
||||
*/
|
||||
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.MBeanServerFactory;
|
||||
import javax.management.remote.*;
|
||||
import javax.management.remote.rmi.*;
|
||||
import java.net.MalformedURLException;
|
||||
import java.io.IOException;
|
||||
import javax.security.auth.Subject;
|
||||
import java.rmi.NoSuchObjectException;
|
||||
import javax.management.remote.JMXConnectorFactory;
|
||||
import javax.management.remote.JMXConnectorServerFactory;
|
||||
|
||||
public class NoIIOP {
|
||||
|
||||
/**
|
||||
* RMIIIOPServerImpl implementation for testing purposes (methods are
|
||||
* overridden to be public to allow for testing)
|
||||
*/
|
||||
static class MyRMIIIOPServerImpl extends RMIIIOPServerImpl {
|
||||
MyRMIIIOPServerImpl() throws IOException {
|
||||
super(null);
|
||||
}
|
||||
@Override
|
||||
public void export() throws IOException {
|
||||
super.export();
|
||||
}
|
||||
@Override
|
||||
public String getProtocol() {
|
||||
return super.getProtocol();
|
||||
}
|
||||
@Override
|
||||
public RMIConnection makeClient(String connectionId, Subject subject)
|
||||
throws IOException
|
||||
{
|
||||
return super.makeClient(connectionId, subject);
|
||||
}
|
||||
@Override
|
||||
public void closeClient(RMIConnection client) throws IOException {
|
||||
super.closeClient(client);
|
||||
}
|
||||
@Override
|
||||
public void closeServer() throws IOException {
|
||||
super.closeServer();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
try {
|
||||
Class.forName("javax.management.remote.rmi._RMIConnectionImpl_Tie");
|
||||
System.out.println("RMI/IIOP appears to be supported, test skipped");
|
||||
return;
|
||||
} catch (ClassNotFoundException okay) { }
|
||||
|
||||
JMXServiceURL url = new JMXServiceURL("service:jmx:iiop://");
|
||||
MBeanServer mbs = MBeanServerFactory.createMBeanServer();
|
||||
|
||||
|
||||
// test JMXConnectorFactory/JMXConnectorServerFactory
|
||||
|
||||
try {
|
||||
JMXConnectorFactory.connect(url);
|
||||
throw new RuntimeException("connect did not throw MalformedURLException");
|
||||
} catch (MalformedURLException expected) { }
|
||||
|
||||
try {
|
||||
JMXConnectorServerFactory.newJMXConnectorServer(url, null, null);
|
||||
throw new RuntimeException("newJMXConnectorServer did not throw MalformedURLException");
|
||||
} catch (MalformedURLException expected) { }
|
||||
|
||||
|
||||
// test RMIConnector/RMIConnectorServer
|
||||
|
||||
RMIConnector connector = new RMIConnector(url, null);
|
||||
try {
|
||||
connector.connect();
|
||||
throw new RuntimeException("connect did not throw IOException");
|
||||
} catch (IOException expected) { }
|
||||
|
||||
RMIConnectorServer server = new RMIConnectorServer(url, null, mbs);
|
||||
try {
|
||||
server.start();
|
||||
throw new RuntimeException("start did not throw IOException");
|
||||
} catch (IOException expected) { }
|
||||
|
||||
|
||||
// test RMIIIOPServerImpl
|
||||
|
||||
MyRMIIIOPServerImpl impl = new MyRMIIIOPServerImpl();
|
||||
impl.setMBeanServer(mbs);
|
||||
System.out.println(impl.getProtocol());
|
||||
|
||||
try {
|
||||
impl.export();
|
||||
throw new RuntimeException("export did not throw IOException");
|
||||
} catch (IOException expected) { }
|
||||
|
||||
try {
|
||||
impl.newClient(null);
|
||||
throw new RuntimeException("newClient did not throw IOException");
|
||||
} catch (IOException expected) { }
|
||||
|
||||
try {
|
||||
impl.toStub();
|
||||
throw new RuntimeException("toStub did not throw NoSuchObjectException");
|
||||
} catch (NoSuchObjectException expected) { }
|
||||
|
||||
try {
|
||||
impl.closeServer();
|
||||
throw new RuntimeException("closeServer did not throw NoSuchObjectException");
|
||||
} catch (NoSuchObjectException expected) { }
|
||||
}
|
||||
}
|
377
jdk/test/jdk/internal/jimage/JImageReadTest.java
Normal file
377
jdk/test/jdk/internal/jimage/JImageReadTest.java
Normal file
@ -0,0 +1,377 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @modules java.base/jdk.internal.jimage
|
||||
* @summary Unit test for libjimage JIMAGE_Open/Read/Close
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
|
||||
import jdk.internal.jimage.BasicImageReader;
|
||||
import jdk.internal.jimage.ImageNativeSubstrate;
|
||||
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Optional;
|
||||
import org.testng.annotations.Parameters;
|
||||
import org.testng.annotations.Test;
|
||||
import org.testng.Assert;
|
||||
import org.testng.TestNG;
|
||||
|
||||
@Test
|
||||
public class JImageReadTest {
|
||||
|
||||
static String javaHome = System.getProperty("java.home");
|
||||
static String imageFile = javaHome + File.separator + "lib"
|
||||
+ File.separator + "modules" + File.separator
|
||||
+ "bootmodules.jimage";
|
||||
|
||||
@DataProvider(name="classes")
|
||||
static Object[][] loadClasses() {
|
||||
return new Object[][] {
|
||||
{"java.base", "java/lang/String.class"},
|
||||
{"java.base", "java/lang/Object.class"},
|
||||
{"java.base", "sun/reflect/generics/tree/TypeArgument.class"},
|
||||
{"jdk.jdeps", "com/sun/tools/javap/StackMapWriter$StackMapBuilder.class"},
|
||||
{"jdk.hotspot.agent", "sa.properties"},
|
||||
{"java.logging", "java/util/logging/Logger.class"},
|
||||
{"java.base", "java/NOSUCHCLASS/yyy.class"}, // non-existent
|
||||
{"NOSUCHMODULE", "java/lang/Class.class"}, // non-existent
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@DataProvider(name="packages")
|
||||
static Object[][] loadPackages() {
|
||||
return new Object[][] {
|
||||
{"java.base", "java/lang"},
|
||||
{"java.base", "java/io"},
|
||||
{"java.logging", "java/util/logging"},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a class is correctly accessible from the image in a module.
|
||||
*
|
||||
* @param moduleName the module name
|
||||
* @param className the classname
|
||||
* @throws Exception is thrown if there is a test error
|
||||
*/
|
||||
@Test(dataProvider="classes")
|
||||
public static void test1_ReadClasses(String moduleName, String className) throws Exception {
|
||||
final int classMagic = 0xCAFEBABE;
|
||||
final long NOT_FOUND = 0L;
|
||||
|
||||
if (!(new File(imageFile)).exists()) {
|
||||
System.out.printf("Test skipped; no jimage file");
|
||||
return;
|
||||
}
|
||||
|
||||
long jimageHandle = ImageNativeSubstrate.JIMAGE_Open(imageFile);
|
||||
Assert.assertTrue(jimageHandle != 0, "JIMAGE_Open failed: id: " + jimageHandle);
|
||||
|
||||
long[] sizeArray = new long[1];
|
||||
long locationHandle =
|
||||
ImageNativeSubstrate.JIMAGE_FindResource(jimageHandle,
|
||||
moduleName, "9.0", className, sizeArray);
|
||||
long size = sizeArray[0];
|
||||
System.out.printf("reading: module: %s, path: %s, handle: %16x, " +
|
||||
"location: %d, size: %d%n",
|
||||
moduleName, className, jimageHandle, locationHandle, size);
|
||||
if (moduleName.contains("NOSUCH") || className.contains("NOSUCH")) {
|
||||
Assert.assertEquals(locationHandle, NOT_FOUND,
|
||||
"location found for non-existing module: "
|
||||
+ moduleName
|
||||
+ ", or class: " + className);
|
||||
return; // no more to test for non-existing class
|
||||
} else {
|
||||
Assert.assertTrue(locationHandle != NOT_FOUND, "location not found: " + className);
|
||||
Assert.assertTrue(size > 0, "size of should be > 0: " + className);
|
||||
}
|
||||
|
||||
// positive: read whole class
|
||||
ByteBuffer buffer = ByteBuffer.allocate((int)size);
|
||||
long actual = ImageNativeSubstrate.JIMAGE_GetResource(jimageHandle,
|
||||
locationHandle, buffer.array(), size);
|
||||
Assert.assertEquals(actual, size, "bytes read not equal bytes requested");
|
||||
|
||||
if (className.endsWith(".class")) {
|
||||
int m = buffer.getInt();
|
||||
Assert.assertEquals(m, classMagic, "Classfile has bad magic number");
|
||||
}
|
||||
|
||||
// Read less than the size of the artifact
|
||||
buffer.rewind();
|
||||
Arrays.fill(buffer.array(), (byte)0xc0);
|
||||
long sizeExpected = size - 10;
|
||||
actual = ImageNativeSubstrate.JIMAGE_GetResource(jimageHandle,
|
||||
locationHandle, buffer.array(), sizeExpected);
|
||||
Assert.assertEquals(actual, sizeExpected, "bytes read not equal bytes requested");
|
||||
|
||||
if (className.endsWith(".class")) {
|
||||
int m1 = buffer.getInt();
|
||||
Assert.assertEquals(m1, classMagic, "Read operation succeeded but has bad magic number");
|
||||
}
|
||||
|
||||
ImageNativeSubstrate.JIMAGE_Close(jimageHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* For all the resource names, check the name and approximate count.
|
||||
*
|
||||
* @throws IOException thrown if an error occurs
|
||||
*/
|
||||
@Test
|
||||
static void test2_ImageResources() throws IOException {
|
||||
if (!(new File(imageFile)).exists()) {
|
||||
System.out.printf("Test skipped; no jimage file");
|
||||
return;
|
||||
}
|
||||
|
||||
long jimageHandle = ImageNativeSubstrate.JIMAGE_Open(imageFile);
|
||||
Assert.assertTrue(jimageHandle != 0, "JIMAGE_Open failed: id: " + jimageHandle);
|
||||
|
||||
String[] names = new String[4096];
|
||||
int max = ImageNativeSubstrate.JIMAGE_Resources(jimageHandle,
|
||||
names);
|
||||
|
||||
// Repeat with count available
|
||||
names = new String[max + 1];
|
||||
int count = ImageNativeSubstrate.JIMAGE_Resources(jimageHandle,
|
||||
names);
|
||||
System.out.printf(" count: %d, a class: %s\n", count, names[0]);
|
||||
Assert.assertTrue(max > 31000,
|
||||
"missing entries, should be more than 31000, reported: " + count);
|
||||
Assert.assertTrue(count == max,
|
||||
"unexpected count of entries, count: " + count
|
||||
+ ", max: " + max);
|
||||
for (int i = 0; i < count; i++) {
|
||||
checkFullName(names[i]);
|
||||
}
|
||||
|
||||
ImageNativeSubstrate.JIMAGE_Close(jimageHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that a package exists and correctly mapped to the module.
|
||||
*
|
||||
* @param moduleName the module name
|
||||
* @param packageName the package name
|
||||
* @throws IOException thrown if an error occurs
|
||||
*/
|
||||
@Test(dataProvider="packages")
|
||||
static void test3_PackageToModule(String moduleName, String packageName) throws IOException {
|
||||
if (!(new File(imageFile)).exists()) {
|
||||
System.out.printf("Test skipped; no jimage file");
|
||||
return;
|
||||
}
|
||||
|
||||
long jimageHandle = ImageNativeSubstrate.JIMAGE_Open(imageFile);
|
||||
Assert.assertTrue(jimageHandle != 0, "JIMAGE_Open failed: id: " + jimageHandle);
|
||||
|
||||
String result = ImageNativeSubstrate.JIMAGE_PackageToModule(jimageHandle, packageName);
|
||||
System.out.printf(" package: %s, module: %s%n", packageName, result);
|
||||
Assert.assertEquals(result, moduleName, "wrong module for package: " + packageName);
|
||||
|
||||
ImageNativeSubstrate.JIMAGE_Close(jimageHandle);
|
||||
}
|
||||
|
||||
|
||||
static void checkFullName(String path) {
|
||||
int next = 0;
|
||||
String m = null;
|
||||
String p = null;
|
||||
String b = null;
|
||||
String e = null;
|
||||
if (path.startsWith("/")) {
|
||||
next = path.indexOf('/', 1);
|
||||
m = path.substring(1, next);
|
||||
next = next + 1;
|
||||
}
|
||||
int lastSlash = path.lastIndexOf('/');
|
||||
if (lastSlash > next) {
|
||||
// has a parent
|
||||
p = path.substring(next, lastSlash);
|
||||
next = lastSlash + 1;
|
||||
}
|
||||
int period = path.indexOf('.', next);
|
||||
if (period > next) {
|
||||
b = path.substring(next, period);
|
||||
e = path.substring(period + 1);
|
||||
} else {
|
||||
b = path.substring(next);
|
||||
}
|
||||
Assert.assertNotNull(m, "module must be non-empty");
|
||||
Assert.assertNotNull(b, "base name must be non-empty");
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that all of the resource names from BasicImageReader
|
||||
* match those returned from the native JIMAGE_Resources iterator.
|
||||
* Names that start with /modules, /packages, and bootmodules.jdata
|
||||
* must appear in the names from JIMAGE_Resource iterator;
|
||||
* from the BasicImageReader they are ignored.
|
||||
*/
|
||||
@Test
|
||||
static void test4_verifyNames() {
|
||||
if (!(new File(imageFile)).exists()) {
|
||||
System.out.printf("Test skipped; no jimage file");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
String[] names = BasicImageReader_Names();
|
||||
//writeNames("/tmp/basic-names.txt", names); // debug
|
||||
|
||||
// Read all the names from the native JIMAGE API
|
||||
String[] nativeNames = JIMAGE_Names();
|
||||
//writeNames("/tmp/native-names.txt", nativeNames); // debug
|
||||
|
||||
|
||||
int modCount = 0;
|
||||
int pkgCount = 0;
|
||||
int otherCount = 0;
|
||||
for (String n : nativeNames) {
|
||||
if (n.startsWith("/modules/")) {
|
||||
modCount++;
|
||||
} else if (n.startsWith("/packages/")) {
|
||||
pkgCount++;
|
||||
} else {
|
||||
otherCount++;
|
||||
}
|
||||
}
|
||||
System.out.printf("native name count: %d, modCount: %d, pkgCount: %d, otherCount: %d%n",
|
||||
names.length, modCount, pkgCount, otherCount);
|
||||
|
||||
Assert.assertEquals(modCount, 0, "JIMAGE_ResourceIterator should not return any '/modules' paths");
|
||||
Assert.assertEquals(pkgCount, 0, "JIMAGE_ResourceIterator should not return any '/packages' paths");
|
||||
|
||||
// Sort and merge the two arrays. Every name should appear exactly twice.
|
||||
Arrays.sort(names);
|
||||
Arrays.sort(nativeNames);
|
||||
String[] combined = Arrays.copyOf(names, nativeNames.length + names.length);
|
||||
System.arraycopy(nativeNames,0, combined, names.length, nativeNames.length);
|
||||
Arrays.sort(combined);
|
||||
int missing = 0;
|
||||
for (int i = 0; i < combined.length; i++) {
|
||||
String s = combined[i];
|
||||
if (isMetaName(s)) {
|
||||
// Ignore /modules and /packages in BasicImageReader names
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i < combined.length - 1 && s.equals(combined[i + 1])) {
|
||||
i++; // string appears in both java and native
|
||||
continue;
|
||||
}
|
||||
|
||||
missing++;
|
||||
int ndx = Arrays.binarySearch(names, s);
|
||||
String which = (ndx >= 0) ? "java BasicImageReader" : "native JIMAGE_Resources";
|
||||
System.out.printf("Missing Resource: %s found only via %s%n", s, which);
|
||||
}
|
||||
Assert.assertEquals(missing, 0, "Resources missing");
|
||||
|
||||
} catch (IOException ioe) {
|
||||
Assert.fail("I/O exception", ioe);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the name is one of the meta-data names
|
||||
* @param name a name
|
||||
* @return return true if starts with either /packages or /modules
|
||||
*/
|
||||
static boolean isMetaName(String name) {
|
||||
return name.startsWith("/modules")
|
||||
|| name.startsWith("/packages")
|
||||
|| name.equals("bootmodules.jdata");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all of the names from BasicImageReader.
|
||||
* @return the names returned from BasicImageReader
|
||||
*/
|
||||
static String[] BasicImageReader_Names() throws IOException {
|
||||
String[] names = null;
|
||||
try (BasicImageReader reader = BasicImageReader.open(imageFile)) {
|
||||
names = reader.getEntryNames();
|
||||
} catch (IOException ioe) {
|
||||
Assert.fail("I/O exception", ioe);
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all of the names returned from JIMAGE_Resources
|
||||
*/
|
||||
static String[] JIMAGE_Names() throws IOException {
|
||||
|
||||
long jimageHandle = ImageNativeSubstrate.JIMAGE_Open(imageFile);
|
||||
Assert.assertTrue(jimageHandle != 0, "JIMAGE_Open failed: id: " + jimageHandle);
|
||||
|
||||
String[] names = new String[50000];
|
||||
int max = ImageNativeSubstrate.JIMAGE_Resources(jimageHandle, names);
|
||||
|
||||
if (max > names.length) {
|
||||
// Not all names fit, repeat with correct size
|
||||
names = new String[max];
|
||||
max = ImageNativeSubstrate.JIMAGE_Resources(jimageHandle, names);
|
||||
} else {
|
||||
names = Arrays.copyOf(names, max);
|
||||
}
|
||||
|
||||
ImageNativeSubstrate.JIMAGE_Close(jimageHandle);
|
||||
return names;
|
||||
}
|
||||
|
||||
// Write an array of names to a file for debugging
|
||||
static void writeNames(String fname, String[] names) throws IOException {
|
||||
try (FileWriter wr = new FileWriter(new File(fname))) {
|
||||
for (String s : names) {
|
||||
wr.write(s);
|
||||
wr.write("\n");
|
||||
}
|
||||
|
||||
}
|
||||
System.out.printf(" %s: %d names%n", fname, names.length);
|
||||
}
|
||||
|
||||
// main method to run standalone from jtreg
|
||||
|
||||
@Test(enabled=false)
|
||||
@Parameters({"x"})
|
||||
@SuppressWarnings("raw_types")
|
||||
public static void main(@Optional String[] args) {
|
||||
Class<?>[] testclass = { JImageReadTest.class};
|
||||
TestNG testng = new TestNG();
|
||||
testng.setTestClasses(testclass);
|
||||
testng.run();
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user