This commit is contained in:
Alejandro Murillo 2015-09-10 14:55:20 -07:00
commit 556157743b
45 changed files with 4036 additions and 1919 deletions

View File

@ -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)

View File

@ -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;

View 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:
*;
};

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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"/>

View File

@ -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

View File

@ -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);
}

View File

@ -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;

View File

@ -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);

View File

@ -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
*/

View File

@ -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;
}

View File

@ -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();
}

View 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();
}

View 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

View 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

View 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

View 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;
}

View 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

View 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

View 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 resources
* 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;
}
}
}

View 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 resources
* 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);

View 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

View 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);
//}

View 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);
//}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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());
}
}
}
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 " +

View File

@ -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;

View File

@ -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;
}

View File

@ -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.
*/

View File

@ -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&trade; Remote Method
Invocation (RMI)</a>

View File

@ -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
#

View File

@ -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
};

View File

@ -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) { }
}
}

View 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();
}
}