提交 0b5ba35e 编写于 作者: X xdono

Merge

37a05a11f281b4d238e2f9e7ebb67c63f64d0e77 jdk7-b24 37a05a11f281b4d238e2f9e7ebb67c63f64d0e77 jdk7-b24
75fca0b0ab83ab1392e615910cea020f66535390 jdk7-b25
# #
# Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. # Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # This code is free software; you can redistribute it and/or modify it
...@@ -87,8 +87,7 @@ ...@@ -87,8 +87,7 @@
# sign Alias for sign-jar # sign Alias for sign-jar
# sign-jar Builds/signs sunjce_provider.jar (no install) # sign-jar Builds/signs sunjce_provider.jar (no install)
# #
# obfus Builds/obfuscates/signs/installs # obfus Builds/obfuscates/signs sunjce_provider.jar
# sunjce_provider.jar
# #
# release Builds all targets in preparation # release Builds all targets in preparation
# for workspace integration. # for workspace integration.
...@@ -101,8 +100,25 @@ ...@@ -101,8 +100,25 @@
BUILDDIR = ../../../.. BUILDDIR = ../../../..
PACKAGE = com.sun.crypto.provider PACKAGE = com.sun.crypto.provider
PRODUCT = sun PRODUCT = sun
#
# The following is for when we need to do postprocessing
# (signing/obfuscation) against a read-only build. If the OUTPUTDIR
# isn't writable, the build currently crashes out.
#
ifndef OPENJDK
ifdef ALT_JCE_BUILD_DIR
# =====================================================
# Where to place the output, in case we're building from a read-only
# build area. (e.g. a release engineering build.)
JCE_BUILD_DIR=${ALT_JCE_BUILD_DIR}
IGNORE_WRITABLE_OUTPUTDIR_TEST=true
else
JCE_BUILD_DIR=${TEMPDIR}
endif
endif
include $(BUILDDIR)/common/Defs.gmk include $(BUILDDIR)/common/Defs.gmk
include $(BUILDDIR)/javax/crypto/Defs-jce.gmk
# #
# Location for the newly built classfiles. # Location for the newly built classfiles.
...@@ -147,6 +163,8 @@ endif # OPENJDK ...@@ -147,6 +163,8 @@ endif # OPENJDK
# #
UNSIGNED_DIR = $(TEMPDIR)/unsigned UNSIGNED_DIR = $(TEMPDIR)/unsigned
include $(BUILDDIR)/javax/crypto/Defs-jce.gmk
# ===================================================== # =====================================================
# Build the unsigned sunjce_provider.jar file. # Build the unsigned sunjce_provider.jar file.
...@@ -184,44 +202,66 @@ ifndef OPENJDK ...@@ -184,44 +202,66 @@ ifndef OPENJDK
# Sign the provider jar file. Not needed for OpenJDK. # Sign the provider jar file. Not needed for OpenJDK.
# #
SIGNED_DIR = $(TEMPDIR)/signed SIGNED_DIR = $(JCE_BUILD_DIR)/signed
sign: sign-jar sign: sign-jar
sign-jar: $(SIGNED_DIR)/sunjce_provider.jar sign-jar: $(SIGNED_DIR)/sunjce_provider.jar
ifndef ALT_JCE_BUILD_DIR
$(SIGNED_DIR)/sunjce_provider.jar: $(UNSIGNED_DIR)/sunjce_provider.jar $(SIGNED_DIR)/sunjce_provider.jar: $(UNSIGNED_DIR)/sunjce_provider.jar
$(sign-file) else
#
# We have to remove the build dependency, otherwise, we'll try to rebuild it
# which we can't do on a read-only filesystem.
#
$(SIGNED_DIR)/sunjce_provider.jar:
@if [ ! -r $(UNSIGNED_DIR)/sunjce_provider.jar ] ; then \
$(ECHO) "Couldn't find $(UNSIGNED_DIR)/sunjce_provider.jar"; \
exit 1; \
fi
endif
$(call sign-file, $(UNSIGNED_DIR)/sunjce_provider.jar)
# ===================================================== # =====================================================
# Obfuscate/sign/install the JDK build. Not needed for OpenJDK. # Obfuscate/sign/install the JDK build. Not needed for OpenJDK.
# #
OBFUS_DIR = $(TEMPDIR)/obfus OBFUS_DIR = $(JCE_BUILD_DIR)/obfus/sunjce
CLOSED_DIR = $(BUILDDIR)/closed/com/sun/crypto/provider CLOSED_DIR = $(BUILDDIR)/closed/com/sun/crypto/provider
obfus: $(OBFUS_DIR)/sunjce_provider.jar obfus: $(OBFUS_DIR)/sunjce_provider.jar
$(release-warning) $(release-warning)
$(OBFUS_DIR)/sunjce_provider.jar: build-jar $(JCE_MANIFEST_FILE) ifndef ALT_JCE_BUILD_DIR
$(OBFUS_DIR)/sunjce_provider.jar: build-jar $(JCE_MANIFEST_FILE) \
$(OBFUS_DIR)/sunjce.dox
else
$(OBFUS_DIR)/sunjce_provider.jar: $(JCE_MANIFEST_FILE) $(OBFUS_DIR)/sunjce.dox
@if [ ! -d $(CLASSDESTDIR) ] ; then \
$(ECHO) "Couldn't find $(CLASSDESTDIR)"; \
exit 1; \
fi
endif
@$(ECHO) ">>>Obfuscating SunJCE Provider..."
$(presign) $(presign)
$(preobfus) $(preobfus)
@$(ECHO) ">>>Obfuscating Sun JCE Provider..."
$(prep-target) $(prep-target)
$(CD) $(OBFUS_DIR); \ $(CD) $(OBFUS_DIR); \
$(OBFUSCATOR) -fv \ $(OBFUSCATOR) -fv sunjce.dox
$(CURRENT_DIRECTORY)/$(CLOSED_DIR)/obfus/sunjce.dox
@$(CD) $(OBFUS_DIR); $(java-vm-cleanup) @$(CD) $(OBFUS_DIR); $(java-vm-cleanup)
$(BOOT_JAR_CMD) cmf $(JCE_MANIFEST_FILE) $@ \ $(BOOT_JAR_CMD) cmf $(JCE_MANIFEST_FILE) $@ \
-C $(OBFUS_DIR)/build com \ -C $(OBFUS_DIR)/build com \
$(JAR_JFLAGS) $(JAR_JFLAGS)
$(sign-target) $(sign-target)
$(MKDIR) -p $(dir $(JAR_DESTFILE))
$(RM) $(JAR_DESTFILE)
$(CP) $@ $(JAR_DESTFILE)
@$(java-vm-cleanup) @$(java-vm-cleanup)
$(OBFUS_DIR)/sunjce.dox: $(CLOSED_DIR)/obfus/sunjce.dox
@$(ECHO) ">>>Creating sunjce.dox"
$(prep-target)
$(SED) "s:@@TEMPDIR@@:$(ABS_TEMPDIR):" $< > $@
# #
# The current obfuscator has a limitation in that it currently only # The current obfuscator has a limitation in that it currently only
# supports up to v49 class file format. Force v49 classfiles in our # supports up to v49 class file format. Force v49 classfiles in our
...@@ -235,9 +275,9 @@ TARGET_CLASS_VERSION = 5 ...@@ -235,9 +275,9 @@ TARGET_CLASS_VERSION = 5
# #
release: $(OBFUS_DIR)/sunjce_provider.jar release: $(OBFUS_DIR)/sunjce_provider.jar
$(RM) $(RELEASE_DIR)/sunjce_provider.jar $(RM) $(JCE_BUILD_DIR)/release/sunjce_provider.jar
$(MKDIR) -p $(RELEASE_DIR) $(MKDIR) -p $(JCE_BUILD_DIR)/release
$(CP) $(OBFUS_DIR)/sunjce_provider.jar $(RELEASE_DIR) $(CP) $(OBFUS_DIR)/sunjce_provider.jar $(JCE_BUILD_DIR)/release
$(release-warning) $(release-warning)
endif # OPENJDK endif # OPENJDK
...@@ -275,7 +315,7 @@ endif ...@@ -275,7 +315,7 @@ endif
# #
clobber clean:: clobber clean::
$(RM) -r $(JAR_DESTFILE) $(TEMPDIR) $(RM) -r $(JAR_DESTFILE) $(TEMPDIR) $(JCE_BUILD_DIR)
.PHONY: build-jar jar install-jar .PHONY: build-jar jar install-jar
ifndef OPENJDK ifndef OPENJDK
......
# #
# Copyright 2005-2007 Sun Microsystems, Inc. All Rights Reserved. # Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # This code is free software; you can redistribute it and/or modify it
...@@ -451,11 +451,20 @@ endif ...@@ -451,11 +451,20 @@ endif
# Check for spaces and null value # Check for spaces and null value
OUTPUTDIR:=$(call AltCheckSpaces,OUTPUTDIR) OUTPUTDIR:=$(call AltCheckSpaces,OUTPUTDIR)
OUTPUTDIR:=$(call AltCheckValue,OUTPUTDIR) OUTPUTDIR:=$(call AltCheckValue,OUTPUTDIR)
#
# When signing the JCE framework and provider, we could be using built
# bits on a read-only filesystem. If so, this test will fail and crash
# the build.
#
ifndef IGNORE_WRITABLE_OUTPUTDIR_TEST
# Create the output directory and make sure it exists and is writable # Create the output directory and make sure it exists and is writable
_create_outputdir:=$(shell $(MKDIR) -p "$(OUTPUTDIR)" > $(DEV_NULL) 2>&1) _create_outputdir:=$(shell $(MKDIR) -p "$(OUTPUTDIR)" > $(DEV_NULL) 2>&1)
ifeq ($(call WriteDirExists,$(OUTPUTDIR),/dev/null),/dev/null) ifeq ($(call WriteDirExists,$(OUTPUTDIR),/dev/null),/dev/null)
_outputdir_error:=$(error "ERROR: OUTPUTDIR '$(OUTPUTDIR)' not created or not writable") _outputdir_error:=$(error "ERROR: OUTPUTDIR '$(OUTPUTDIR)' not created or not writable")
endif endif
endif
# Define absolute path if needed and check for spaces and null value # Define absolute path if needed and check for spaces and null value
ifndef ABS_OUTPUTDIR ifndef ABS_OUTPUTDIR
ABS_OUTPUTDIR:=$(call FullPath,$(OUTPUTDIR)) ABS_OUTPUTDIR:=$(call FullPath,$(OUTPUTDIR))
......
# #
# Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. # Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # This code is free software; you can redistribute it and/or modify it
...@@ -31,7 +31,7 @@ include $(BUILDDIR)/common/Release.gmk ...@@ -31,7 +31,7 @@ include $(BUILDDIR)/common/Release.gmk
JCE_MANIFEST_FILE = $(TEMPDIR)/manifest.mf JCE_MANIFEST_FILE = $(TEMPDIR)/manifest.mf
$(JCE_MANIFEST_FILE): $(MAINMANIFEST) $(JCE_MANIFEST_FILE): $(MAINMANIFEST)
$(prep-target) $(prep-target)
( $(SED) "s/@@RELEASE@@/$(RELEASE)/" $(MAINMANIFEST); \ ( $(SED) "s/@@RELEASE@@/$(RELEASE)/" $<; \
$(ECHO) "Extension-Name: javax.crypto"; \ $(ECHO) "Extension-Name: javax.crypto"; \
$(ECHO) "Implementation-Vendor-Id: com.sun"; ) > $@ $(ECHO) "Implementation-Vendor-Id: com.sun"; ) > $@
...@@ -75,6 +75,7 @@ endef ...@@ -75,6 +75,7 @@ endef
define sign-target define sign-target
$(BOOT_JARSIGNER_CMD) -keystore $(SIGNING_KEYSTORE) \ $(BOOT_JARSIGNER_CMD) -keystore $(SIGNING_KEYSTORE) \
$@ $(SIGNING_ALIAS) < $(SIGNING_PASSPHRASE) $@ $(SIGNING_ALIAS) < $(SIGNING_PASSPHRASE)
@$(java-vm-cleanup)
@$(ECHO) "\nJar codesigning finished." @$(ECHO) "\nJar codesigning finished."
endef endef
...@@ -88,13 +89,15 @@ define release-warning ...@@ -88,13 +89,15 @@ define release-warning
endef endef
# #
# Convenience macro for steps needed to sign a jar file. # Convenience macros for signing a jar file.
#
# Call through $(call sign-file, target file)
# #
define sign-file define sign-file
$(presign) $(presign)
$(install-file) $(prep-target)
$(CP) $1 $@
$(sign-target) $(sign-target)
@$(java-vm-cleanup)
endef endef
# #
......
# #
# Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. # Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # This code is free software; you can redistribute it and/or modify it
...@@ -96,7 +96,7 @@ ...@@ -96,7 +96,7 @@
# sign-jar Builds/signs jce.jar file (no install) # sign-jar Builds/signs jce.jar file (no install)
# sign-policy Builds/signs policy files (no install) # sign-policy Builds/signs policy files (no install)
# #
# obfus Builds/obfuscates/signs/installs jce.jar # obfus Builds/obfuscates/signs jce.jar
# #
# release Builds all targets in preparation # release Builds all targets in preparation
# for workspace integration. # for workspace integration.
...@@ -110,8 +110,24 @@ BUILDDIR = ../.. ...@@ -110,8 +110,24 @@ BUILDDIR = ../..
PACKAGE = javax.crypto PACKAGE = javax.crypto
PRODUCT = sun PRODUCT = sun
#
# The following is for when we need to do postprocessing
# (signing/obfuscation) against a read-only build. If the OUTPUTDIR
# isn't writable, the build currently crashes out.
#
ifndef OPENJDK
ifdef ALT_JCE_BUILD_DIR
# =====================================================
# Where to place the output, in case we're building from a read-only
# build area. (e.g. a release engineering build.)
JCE_BUILD_DIR=${ALT_JCE_BUILD_DIR}
IGNORE_WRITABLE_OUTPUTDIR_TEST=true
else
JCE_BUILD_DIR=${TEMPDIR}
endif
endif
include $(BUILDDIR)/common/Defs.gmk include $(BUILDDIR)/common/Defs.gmk
include Defs-jce.gmk
# #
# Location for the newly built classfiles. # Location for the newly built classfiles.
...@@ -158,6 +174,8 @@ endif # OPENJDK ...@@ -158,6 +174,8 @@ endif # OPENJDK
# #
UNSIGNED_DIR = $(TEMPDIR)/unsigned UNSIGNED_DIR = $(TEMPDIR)/unsigned
include Defs-jce.gmk
# ===================================================== # =====================================================
# Build the unsigned jce.jar file. Signing/obfuscation comes later. # Build the unsigned jce.jar file. Signing/obfuscation comes later.
...@@ -299,7 +317,7 @@ ifndef OPENJDK ...@@ -299,7 +317,7 @@ ifndef OPENJDK
# Sign the various jar files. Not needed for OpenJDK. # Sign the various jar files. Not needed for OpenJDK.
# #
SIGNED_DIR = $(TEMPDIR)/signed SIGNED_DIR = $(JCE_BUILD_DIR)/signed
SIGNED_POLICY_BUILDDIR = $(SIGNED_DIR)/policy SIGNED_POLICY_BUILDDIR = $(SIGNED_DIR)/policy
SIGNED_POLICY_FILES = \ SIGNED_POLICY_FILES = \
...@@ -312,61 +330,87 @@ sign-jar: $(SIGNED_DIR)/jce.jar ...@@ -312,61 +330,87 @@ sign-jar: $(SIGNED_DIR)/jce.jar
sign-policy: $(SIGNED_POLICY_FILES) sign-policy: $(SIGNED_POLICY_FILES)
ifndef ALT_JCE_BUILD_DIR
$(SIGNED_DIR)/jce.jar: $(UNSIGNED_DIR)/jce.jar $(SIGNED_DIR)/jce.jar: $(UNSIGNED_DIR)/jce.jar
$(sign-file) else
#
# We have to remove the build dependency, otherwise, we'll try to rebuild it
# which we can't do on a read-only filesystem.
#
$(SIGNED_DIR)/jce.jar:
@if [ ! -r $(UNSIGNED_DIR)/jce.jar ] ; then \
$(ECHO) "Couldn't find $(UNSIGNED_DIR)/jce.jar"; \
exit 1; \
fi
endif
$(call sign-file, $(UNSIGNED_DIR)/jce.jar)
$(SIGNED_POLICY_BUILDDIR)/unlimited/US_export_policy.jar: \ $(SIGNED_POLICY_BUILDDIR)/unlimited/US_export_policy.jar: \
$(UNSIGNED_POLICY_BUILDDIR)/unlimited/US_export_policy.jar $(UNSIGNED_POLICY_BUILDDIR)/unlimited/US_export_policy.jar
$(sign-file) $(call sign-file, $<)
$(SIGNED_POLICY_BUILDDIR)/unlimited/local_policy.jar: \ $(SIGNED_POLICY_BUILDDIR)/unlimited/local_policy.jar: \
$(UNSIGNED_POLICY_BUILDDIR)/unlimited/local_policy.jar $(UNSIGNED_POLICY_BUILDDIR)/unlimited/local_policy.jar
$(sign-file) $(call sign-file, $<)
$(SIGNED_POLICY_BUILDDIR)/limited/US_export_policy.jar: \ $(SIGNED_POLICY_BUILDDIR)/limited/US_export_policy.jar: \
$(UNSIGNED_POLICY_BUILDDIR)/limited/US_export_policy.jar $(UNSIGNED_POLICY_BUILDDIR)/limited/US_export_policy.jar
$(sign-file) $(call sign-file, $<)
$(SIGNED_POLICY_BUILDDIR)/limited/local_policy.jar: \ $(SIGNED_POLICY_BUILDDIR)/limited/local_policy.jar: \
$(UNSIGNED_POLICY_BUILDDIR)/limited/local_policy.jar $(UNSIGNED_POLICY_BUILDDIR)/limited/local_policy.jar
$(sign-file) $(call sign-file, $<)
# ===================================================== # =====================================================
# Obfuscate/sign/install the JDK build. Not needed for OpenJDK. # Obfuscate/sign/install the JDK build. Not needed for OpenJDK.
# #
OBFUS_DIR = $(TEMPDIR)/obfus OBFUS_DIR = $(JCE_BUILD_DIR)/obfus/jce
CLOSED_DIR = $(BUILDDIR)/closed/javax/crypto CLOSED_DIR = $(BUILDDIR)/closed/javax/crypto
obfus: $(OBFUS_DIR)/jce.jar obfus: $(OBFUS_DIR)/jce.jar
$(release-warning) $(release-warning)
$(OBFUS_DIR)/jce.jar: build-jar $(JCE_MANIFEST_FILE) ifndef ALT_JCE_BUILD_DIR
$(OBFUS_DIR)/jce.jar: build-jar $(JCE_MANIFEST_FILE) $(OBFUS_DIR)/framework.dox
else
#
# We have to remove the build dependency, otherwise, we'll try to rebuild it
# which we can't do on a read-only filesystem.
#
$(OBFUS_DIR)/jce.jar: $(JCE_MANIFEST_FILE) $(OBFUS_DIR)/framework.dox
@if [ ! -d $(CLASSDESTDIR) ] ; then \
$(ECHO) "Couldn't find $(CLASSDESTDIR)"; \
exit 1; \
fi
endif
@$(ECHO) ">>>Obfuscating JCE framework..."
$(presign) $(presign)
$(preobfus) $(preobfus)
@$(ECHO) ">>>Obfuscating JCE framework..."
$(prep-target) $(prep-target)
$(CD) $(OBFUS_DIR); \ $(CD) $(OBFUS_DIR); \
$(OBFUSCATOR) -fv \ $(OBFUSCATOR) -fv framework.dox
$(CURRENT_DIRECTORY)/$(CLOSED_DIR)/obfus/framework.dox
@$(CD) $(OBFUS_DIR); $(java-vm-cleanup) @$(CD) $(OBFUS_DIR); $(java-vm-cleanup)
@#
@# The sun.security.internal classes are currently not obfuscated @# The sun.security.internal classes are currently not obfuscated
@# due to an obfus problem. Manually copy them to the build directory @# due to an obfus problem. Manually copy them to the build directory
@# so that they are included in the jce.jar file. @# so that they are included in the jce.jar file.
@#
$(CP) -r $(CLASSDESTDIR)/sun $(OBFUS_DIR)/build $(CP) -r $(CLASSDESTDIR)/sun $(OBFUS_DIR)/build
$(RM) $(UNSIGNED_DIR)/jce.jar
$(BOOT_JAR_CMD) cmf $(JCE_MANIFEST_FILE) $@ \ $(BOOT_JAR_CMD) cmf $(JCE_MANIFEST_FILE) $@ \
-C $(OBFUS_DIR)/build javax \ -C $(OBFUS_DIR)/build javax \
-C $(OBFUS_DIR)/build sun \ -C $(OBFUS_DIR)/build sun \
$(JAR_JFLAGS) $(JAR_JFLAGS)
$(sign-target) $(sign-target)
$(MKDIR) -p $(dir $(JAR_DESTFILE))
$(RM) $(JAR_DESTFILE)
$(CP) $@ $(JAR_DESTFILE)
@$(java-vm-cleanup) @$(java-vm-cleanup)
$(OBFUS_DIR)/framework.dox: $(CLOSED_DIR)/obfus/framework.dox
@$(ECHO) ">>>Creating framework.dox"
$(prep-target)
$(SED) "s:@@TEMPDIR@@:$(ABS_TEMPDIR):" $< > $@
# #
# The current obfuscator has a limitation in that it currently only # The current obfuscator has a limitation in that it currently only
# supports up to v49 class file format. Force v49 classfiles in our # supports up to v49 class file format. Force v49 classfiles in our
...@@ -380,26 +424,27 @@ TARGET_CLASS_VERSION = 5 ...@@ -380,26 +424,27 @@ TARGET_CLASS_VERSION = 5
# unlimited policy file distribution, etc. # unlimited policy file distribution, etc.
# #
release: $(OBFUS_DIR)/jce.jar sign-policy release: $(OBFUS_DIR)/jce.jar sign-policy $(CLOSED_DIR)/doc/COPYRIGHT.html \
$(CLOSED_DIR)/doc/README.txt
$(RM) -r \ $(RM) -r \
$(RELEASE_DIR)/UnlimitedJCEPolicy \ $(JCE_BUILD_DIR)/release/UnlimitedJCEPolicy \
$(RELEASE_DIR)/jce.jar \ $(JCE_BUILD_DIR)/release/jce.jar \
$(RELEASE_DIR)/US_export_policy.jar \ $(JCE_BUILD_DIR)/release/US_export_policy.jar \
$(RELEASE_DIR)/local_policy.jar \ $(JCE_BUILD_DIR)/release/local_policy.jar \
$(RELEASE_DIR)/UnlimitedJCEPolicy.zip $(JCE_BUILD_DIR)/release/UnlimitedJCEPolicy.zip
$(MKDIR) -p $(RELEASE_DIR)/UnlimitedJCEPolicy $(MKDIR) -p $(JCE_BUILD_DIR)/release/UnlimitedJCEPolicy
$(CP) $(OBFUS_DIR)/jce.jar $(RELEASE_DIR) $(CP) $(OBFUS_DIR)/jce.jar $(JCE_BUILD_DIR)/release
$(CP) -r \ $(CP) \
$(SIGNED_POLICY_BUILDDIR)/limited/US_export_policy.jar \ $(SIGNED_POLICY_BUILDDIR)/limited/US_export_policy.jar \
$(SIGNED_POLICY_BUILDDIR)/limited/local_policy.jar \ $(SIGNED_POLICY_BUILDDIR)/limited/local_policy.jar \
$(RELEASE_DIR) $(JCE_BUILD_DIR)/release
$(CP) \ $(CP) \
$(SIGNED_POLICY_BUILDDIR)/unlimited/US_export_policy.jar \ $(SIGNED_POLICY_BUILDDIR)/unlimited/US_export_policy.jar \
$(SIGNED_POLICY_BUILDDIR)/unlimited/local_policy.jar \ $(SIGNED_POLICY_BUILDDIR)/unlimited/local_policy.jar \
$(RELEASE_DIR)/UnlimitedJCEPolicy $(CLOSED_DIR)/doc/COPYRIGHT.html \
$(CP) $(CLOSED_DIR)/doc/COPYRIGHT.html \ $(CLOSED_DIR)/doc/README.txt \
$(CLOSED_DIR)/doc/README.txt $(RELEASE_DIR)/UnlimitedJCEPolicy $(JCE_BUILD_DIR)/release/UnlimitedJCEPolicy
cd $(RELEASE_DIR) ; \ cd $(JCE_BUILD_DIR)/release ; \
$(ZIPEXE) -qr UnlimitedJCEPolicy.zip UnlimitedJCEPolicy $(ZIPEXE) -qr UnlimitedJCEPolicy.zip UnlimitedJCEPolicy
$(release-warning) $(release-warning)
...@@ -478,7 +523,8 @@ endif ...@@ -478,7 +523,8 @@ endif
clobber clean:: clobber clean::
$(RM) -r $(JAR_DESTFILE) $(POLICY_DESTDIR)/US_export_policy.jar \ $(RM) -r $(JAR_DESTFILE) $(POLICY_DESTDIR)/US_export_policy.jar \
$(POLICY_DESTDIR)/local_policy.jar $(DELETE_DIRS) $(TEMPDIR) $(POLICY_DESTDIR)/local_policy.jar $(DELETE_DIRS) $(TEMPDIR) \
$(JCE_BUILD_DIR)
.PHONY: build-jar jar build-policy unlimited limited install-jar \ .PHONY: build-jar jar build-policy unlimited limited install-jar \
install-limited install-unlimited install-limited install-unlimited
......
# #
# Copyright 2005-2007 Sun Microsystems, Inc. All Rights Reserved. # Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # This code is free software; you can redistribute it and/or modify it
...@@ -92,8 +92,25 @@ BUILDDIR = ../../.. ...@@ -92,8 +92,25 @@ BUILDDIR = ../../..
PACKAGE = sun.security.mscapi PACKAGE = sun.security.mscapi
LIBRARY = sunmscapi LIBRARY = sunmscapi
PRODUCT = sun PRODUCT = sun
#
# The following is for when we need to do postprocessing
# (signing/obfuscation) against a read-only build. If the OUTPUTDIR
# isn't writable, the build currently crashes out.
#
ifndef OPENJDK
ifdef ALT_JCE_BUILD_DIR
# =====================================================
# Where to place the output, in case we're building from a read-only
# build area. (e.g. a release engineering build.)
JCE_BUILD_DIR=${ALT_JCE_BUILD_DIR}
IGNORE_WRITABLE_OUTPUTDIR_TEST=true
else
JCE_BUILD_DIR=${TEMPDIR}
endif
endif
include $(BUILDDIR)/common/Defs.gmk include $(BUILDDIR)/common/Defs.gmk
include $(BUILDDIR)/javax/crypto/Defs-jce.gmk
CPLUSPLUSLIBRARY=true CPLUSPLUSLIBRARY=true
...@@ -163,6 +180,8 @@ all: build-jar install-prebuilt ...@@ -163,6 +180,8 @@ all: build-jar install-prebuilt
$(build-warning) $(build-warning)
endif endif
include $(BUILDDIR)/javax/crypto/Defs-jce.gmk
# ===================================================== # =====================================================
# Build the unsigned sunmscapi.jar file. # Build the unsigned sunmscapi.jar file.
...@@ -200,14 +219,26 @@ ifndef OPENJDK ...@@ -200,14 +219,26 @@ ifndef OPENJDK
# Sign the provider jar file. Not needed for OpenJDK. # Sign the provider jar file. Not needed for OpenJDK.
# #
SIGNED_DIR = $(TEMPDIR)/signed SIGNED_DIR = $(JCE_BUILD_DIR)/signed
sign: sign-jar sign: sign-jar
sign-jar: $(SIGNED_DIR)/sunmscapi.jar sign-jar: $(SIGNED_DIR)/sunmscapi.jar
ifndef ALT_JCE_BUILD_DIR
$(SIGNED_DIR)/sunmscapi.jar: $(UNSIGNED_DIR)/sunmscapi.jar $(SIGNED_DIR)/sunmscapi.jar: $(UNSIGNED_DIR)/sunmscapi.jar
$(sign-file) else
#
# We have to remove the build dependency, otherwise, we'll try to rebuild it
# which we can't do on a read-only filesystem.
#
$(SIGNED_DIR)/sunmscapi.jar:
@if [ ! -r $(UNSIGNED_DIR)/sunmscapi.jar ] ; then \
$(ECHO) "Couldn't find $(UNSIGNED_DIR)/sunmscapi.jar"; \
exit 1; \
fi
endif
$(call sign-file, $(UNSIGNED_DIR)/sunmscapi.jar)
# ===================================================== # =====================================================
...@@ -215,9 +246,9 @@ $(SIGNED_DIR)/sunmscapi.jar: $(UNSIGNED_DIR)/sunmscapi.jar ...@@ -215,9 +246,9 @@ $(SIGNED_DIR)/sunmscapi.jar: $(UNSIGNED_DIR)/sunmscapi.jar
# #
release: $(SIGNED_DIR)/sunmscapi.jar release: $(SIGNED_DIR)/sunmscapi.jar
$(RM) $(RELEASE_DIR)/sunmscapi.jar $(RM) $(JCE_BUILD_DIR)/release/sunmscapi.jar
$(MKDIR) -p $(RELEASE_DIR) $(MKDIR) -p $(JCE_BUILD_DIR)/release
$(CP) $(SIGNED_DIR)/sunmscapi.jar $(RELEASE_DIR) $(CP) $(SIGNED_DIR)/sunmscapi.jar $(JCE_BUILD_DIR)/release
$(release-warning) $(release-warning)
endif # OPENJDK endif # OPENJDK
...@@ -255,7 +286,7 @@ endif ...@@ -255,7 +286,7 @@ endif
# #
clobber clean:: clobber clean::
$(RM) -r $(JAR_DESTFILE) $(TEMPDIR) $(RM) -r $(JAR_DESTFILE) $(TEMPDIR) $(JCE_BUILD_DIR)
.PHONY: build-jar jar install-jar .PHONY: build-jar jar install-jar
ifndef OPENJDK ifndef OPENJDK
......
# #
# Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. # Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # This code is free software; you can redistribute it and/or modify it
...@@ -92,8 +92,25 @@ BUILDDIR = ../../.. ...@@ -92,8 +92,25 @@ BUILDDIR = ../../..
PACKAGE = sun.security.pkcs11 PACKAGE = sun.security.pkcs11
LIBRARY = j2pkcs11 LIBRARY = j2pkcs11
PRODUCT = sun PRODUCT = sun
#
# The following is for when we need to do postprocessing
# (signing/obfuscation) against a read-only build. If the OUTPUTDIR
# isn't writable, the build currently crashes out.
#
ifndef OPENJDK
ifdef ALT_JCE_BUILD_DIR
# =====================================================
# Where to place the output, in case we're building from a read-only
# build area. (e.g. a release engineering build.)
JCE_BUILD_DIR=${ALT_JCE_BUILD_DIR}
IGNORE_WRITABLE_OUTPUTDIR_TEST=true
else
JCE_BUILD_DIR=${TEMPDIR}
endif
endif
include $(BUILDDIR)/common/Defs.gmk include $(BUILDDIR)/common/Defs.gmk
include $(BUILDDIR)/javax/crypto/Defs-jce.gmk
# #
# C and Java Files # C and Java Files
...@@ -163,6 +180,8 @@ all: build-jar install-prebuilt ...@@ -163,6 +180,8 @@ all: build-jar install-prebuilt
$(build-warning) $(build-warning)
endif endif
include $(BUILDDIR)/javax/crypto/Defs-jce.gmk
# ===================================================== # =====================================================
# Build the unsigned sunpkcs11.jar file. # Build the unsigned sunpkcs11.jar file.
...@@ -200,14 +219,26 @@ ifndef OPENJDK ...@@ -200,14 +219,26 @@ ifndef OPENJDK
# Sign the provider jar file. Not needed for OpenJDK. # Sign the provider jar file. Not needed for OpenJDK.
# #
SIGNED_DIR = $(TEMPDIR)/signed SIGNED_DIR = $(JCE_BUILD_DIR)/signed
sign: sign-jar sign: sign-jar
sign-jar: $(SIGNED_DIR)/sunpkcs11.jar sign-jar: $(SIGNED_DIR)/sunpkcs11.jar
ifndef ALT_JCE_BUILD_DIR
$(SIGNED_DIR)/sunpkcs11.jar: $(UNSIGNED_DIR)/sunpkcs11.jar $(SIGNED_DIR)/sunpkcs11.jar: $(UNSIGNED_DIR)/sunpkcs11.jar
$(sign-file) else
#
# We have to remove the build dependency, otherwise, we'll try to rebuild it
# which we can't do on a read-only filesystem.
#
$(SIGNED_DIR)/sunpkcs11.jar:
@if [ ! -r $(UNSIGNED_DIR)/sunpkcs11.jar ] ; then \
$(ECHO) "Couldn't find $(UNSIGNED_DIR)/sunpkcs11.jar"; \
exit 1; \
fi
endif
$(call sign-file, $(UNSIGNED_DIR)/sunpkcs11.jar)
# ===================================================== # =====================================================
...@@ -215,9 +246,9 @@ $(SIGNED_DIR)/sunpkcs11.jar: $(UNSIGNED_DIR)/sunpkcs11.jar ...@@ -215,9 +246,9 @@ $(SIGNED_DIR)/sunpkcs11.jar: $(UNSIGNED_DIR)/sunpkcs11.jar
# #
release: $(SIGNED_DIR)/sunpkcs11.jar release: $(SIGNED_DIR)/sunpkcs11.jar
$(RM) $(RELEASE_DIR)/sunpkcs11.jar $(RM) $(JCE_BUILD_DIR)/release/sunpkcs11.jar
$(MKDIR) -p $(RELEASE_DIR) $(MKDIR) -p $(JCE_BUILD_DIR)/release
$(CP) $(SIGNED_DIR)/sunpkcs11.jar $(RELEASE_DIR) $(CP) $(SIGNED_DIR)/sunpkcs11.jar $(JCE_BUILD_DIR)/release
$(release-warning) $(release-warning)
endif # OPENJDK endif # OPENJDK
...@@ -255,7 +286,7 @@ endif ...@@ -255,7 +286,7 @@ endif
# #
clobber clean:: clobber clean::
$(RM) -r $(JAR_DESTFILE) $(TEMPDIR) $(RM) -r $(JAR_DESTFILE) $(TEMPDIR) $(JCE_BUILD_DIR)
.PHONY: build-jar jar install-jar .PHONY: build-jar jar install-jar
ifndef OPENJDK ifndef OPENJDK
......
...@@ -34,8 +34,6 @@ import java.util.Set; ...@@ -34,8 +34,6 @@ import java.util.Set;
import java.util.HashSet; import java.util.HashSet;
import java.util.WeakHashMap; import java.util.WeakHashMap;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.security.AccessControlContext; import java.security.AccessControlContext;
import java.security.Permission; import java.security.Permission;
import java.security.ProtectionDomain; import java.security.ProtectionDomain;
...@@ -51,7 +49,6 @@ import javax.management.InstanceAlreadyExistsException; ...@@ -51,7 +49,6 @@ import javax.management.InstanceAlreadyExistsException;
import javax.management.InstanceNotFoundException; import javax.management.InstanceNotFoundException;
import javax.management.IntrospectionException; import javax.management.IntrospectionException;
import javax.management.InvalidAttributeValueException; import javax.management.InvalidAttributeValueException;
import javax.management.JMException;
import javax.management.JMRuntimeException; import javax.management.JMRuntimeException;
import javax.management.ListenerNotFoundException; import javax.management.ListenerNotFoundException;
import javax.management.MalformedObjectNameException; import javax.management.MalformedObjectNameException;
...@@ -84,11 +81,10 @@ import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER; ...@@ -84,11 +81,10 @@ import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER;
import com.sun.jmx.mbeanserver.DynamicMBean2; import com.sun.jmx.mbeanserver.DynamicMBean2;
import com.sun.jmx.mbeanserver.ModifiableClassLoaderRepository; import com.sun.jmx.mbeanserver.ModifiableClassLoaderRepository;
import com.sun.jmx.mbeanserver.MBeanInstantiator; import com.sun.jmx.mbeanserver.MBeanInstantiator;
import com.sun.jmx.mbeanserver.MXBeanSupport;
import com.sun.jmx.mbeanserver.Repository; import com.sun.jmx.mbeanserver.Repository;
import com.sun.jmx.mbeanserver.NamedObject; import com.sun.jmx.mbeanserver.NamedObject;
import com.sun.jmx.defaults.ServiceName;
import com.sun.jmx.mbeanserver.Introspector; import com.sun.jmx.mbeanserver.Introspector;
import com.sun.jmx.mbeanserver.Util;
import com.sun.jmx.remote.util.EnvHelp; import com.sun.jmx.remote.util.EnvHelp;
/** /**
...@@ -623,18 +619,9 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { ...@@ -623,18 +619,9 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor {
List<String> result = new ArrayList<String>(domains.length); List<String> result = new ArrayList<String>(domains.length);
for (int i = 0; i < domains.length; i++) { for (int i = 0; i < domains.length; i++) {
try { try {
ObjectName domain = new ObjectName(domains[i] + ":x=x"); ObjectName domain = Util.newObjectName(domains[i] + ":x=x");
checkMBeanPermission((String) null, null, domain, "getDomains"); checkMBeanPermission((String) null, null, domain, "getDomains");
result.add(domains[i]); result.add(domains[i]);
} catch (MalformedObjectNameException e) {
// Should never occur... But let's log it just in case.
if (MBEANSERVER_LOGGER.isLoggable(Level.SEVERE)) {
MBEANSERVER_LOGGER.logp(Level.SEVERE,
DefaultMBeanServerInterceptor.class.getName(),
"getDomains",
"Failed to check permission for domain = " +
domains[i], e);
}
} catch (SecurityException e) { } catch (SecurityException e) {
// OK: Do not add this domain to the list // OK: Do not add this domain to the list
} }
......
...@@ -107,10 +107,7 @@ class MBeanAnalyzer<M> { ...@@ -107,10 +107,7 @@ class MBeanAnalyzer<M> {
private MBeanAnalyzer(Class<?> mbeanInterface, private MBeanAnalyzer(Class<?> mbeanInterface,
MBeanIntrospector<M> introspector) MBeanIntrospector<M> introspector)
throws NotCompliantMBeanException { throws NotCompliantMBeanException {
if (!mbeanInterface.isInterface()) { introspector.checkCompliance(mbeanInterface);
throw new NotCompliantMBeanException("Not an interface: " +
mbeanInterface.getName());
}
try { try {
initMaps(mbeanInterface, introspector); initMaps(mbeanInterface, introspector);
...@@ -121,11 +118,10 @@ class MBeanAnalyzer<M> { ...@@ -121,11 +118,10 @@ class MBeanAnalyzer<M> {
// Introspect the mbeanInterface and initialize this object's maps. // Introspect the mbeanInterface and initialize this object's maps.
// //
private void initMaps(Class<?> mbeanInterface, private void initMaps(Class<?> mbeanType,
MBeanIntrospector<M> introspector) throws Exception { MBeanIntrospector<M> introspector) throws Exception {
final Method[] methodArray = mbeanInterface.getMethods(); final List<Method> methods1 = introspector.getMethods(mbeanType);
final List<Method> methods = eliminateCovariantMethods(methods1);
final List<Method> methods = eliminateCovariantMethods(methodArray);
/* Run through the methods to detect inconsistencies and to enable /* Run through the methods to detect inconsistencies and to enable
us to give getter and setter together to visitAttribute. */ us to give getter and setter together to visitAttribute. */
...@@ -234,13 +230,13 @@ class MBeanAnalyzer<M> { ...@@ -234,13 +230,13 @@ class MBeanAnalyzer<M> {
but existing code may depend on it and users may be used to seeing but existing code may depend on it and users may be used to seeing
operations or attributes appear in a particular order. */ operations or attributes appear in a particular order. */
static List<Method> static List<Method>
eliminateCovariantMethods(Method[] methodArray) { eliminateCovariantMethods(List<Method> startMethods) {
// We are assuming that you never have very many methods with the // We are assuming that you never have very many methods with the
// same name, so it is OK to use algorithms that are quadratic // same name, so it is OK to use algorithms that are quadratic
// in the number of methods with the same name. // in the number of methods with the same name.
final int len = methodArray.length; final int len = startMethods.size();
final Method[] sorted = methodArray.clone(); final Method[] sorted = startMethods.toArray(new Method[len]);
Arrays.sort(sorted,MethodOrder.instance); Arrays.sort(sorted,MethodOrder.instance);
final Set<Method> overridden = newSet(); final Set<Method> overridden = newSet();
for (int i=1;i<len;i++) { for (int i=1;i<len;i++) {
...@@ -259,7 +255,7 @@ class MBeanAnalyzer<M> { ...@@ -259,7 +255,7 @@ class MBeanAnalyzer<M> {
} }
} }
final List<Method> methods = newList(Arrays.asList(methodArray)); final List<Method> methods = newList(startMethods);
methods.removeAll(overridden); methods.removeAll(overridden);
return methods; return methods;
} }
......
...@@ -34,6 +34,7 @@ import java.lang.reflect.Constructor; ...@@ -34,6 +34,7 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.WeakHashMap; import java.util.WeakHashMap;
...@@ -169,6 +170,19 @@ abstract class MBeanIntrospector<M> { ...@@ -169,6 +170,19 @@ abstract class MBeanIntrospector<M> {
*/ */
abstract Descriptor getMBeanDescriptor(Class<?> resourceClass); abstract Descriptor getMBeanDescriptor(Class<?> resourceClass);
void checkCompliance(Class<?> mbeanType) throws NotCompliantMBeanException {
if (!mbeanType.isInterface()) {
throw new NotCompliantMBeanException("Not an interface: " +
mbeanType.getName());
}
}
/**
* Get the methods to be analyzed to build the MBean interface.
*/
List<Method> getMethods(final Class<?> mbeanType) throws Exception {
return Arrays.asList(mbeanType.getMethods());
}
final PerInterface<M> getPerInterface(Class<?> mbeanInterface) final PerInterface<M> getPerInterface(Class<?> mbeanInterface)
throws NotCompliantMBeanException { throws NotCompliantMBeanException {
......
/*
* Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package com.sun.jmx.mbeanserver;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import javax.management.NotCompliantMBeanException;
import javax.management.Notification;
/**
* <p>A variant of {@code StandardMBeanSupport} where the only
* methods included are public getters. This is used by
* {@code QueryNotificationFilter} to pretend that a Notification is
* an MBean so it can have a query evaluated on it. Standard queries
* never set attributes or invoke methods but custom queries could and
* we don't want to allow that. Also we don't want to fail if a
* Notification happens to have inconsistent types in a pair of getX and
* setX methods, and we want to include the Object.getClass() method.
*/
public class NotificationMBeanSupport extends StandardMBeanSupport {
public <T extends Notification> NotificationMBeanSupport(T n)
throws NotCompliantMBeanException {
super(n, Util.<Class<T>>cast(n.getClass()));
}
@Override
MBeanIntrospector<Method> getMBeanIntrospector() {
return introspector;
}
private static class Introspector extends StandardMBeanIntrospector {
@Override
void checkCompliance(Class<?> mbeanType) {}
@Override
List<Method> getMethods(final Class<?> mbeanType)
throws Exception {
List<Method> methods = new ArrayList<Method>();
for (Method m : mbeanType.getMethods()) {
String name = m.getName();
Class<?> ret = m.getReturnType();
if (m.getParameterTypes().length == 0) {
if ((name.startsWith("is") && name.length() > 2 &&
ret == boolean.class) ||
(name.startsWith("get") && name.length() > 3 &&
ret != void.class)) {
methods.add(m);
}
}
}
return methods;
}
}
private static final MBeanIntrospector<Method> introspector =
new Introspector();
}
...@@ -438,7 +438,7 @@ public abstract class OpenConverter { ...@@ -438,7 +438,7 @@ public abstract class OpenConverter {
c.getClassLoader() == null); c.getClassLoader() == null);
final List<Method> methods = final List<Method> methods =
MBeanAnalyzer.eliminateCovariantMethods(c.getMethods()); MBeanAnalyzer.eliminateCovariantMethods(Arrays.asList(c.getMethods()));
final SortedMap<String,Method> getterMap = newSortedMap(); final SortedMap<String,Method> getterMap = newSortedMap();
/* Select public methods that look like "T getX()" or "boolean /* Select public methods that look like "T getX()" or "boolean
...@@ -1118,11 +1118,11 @@ public abstract class OpenConverter { ...@@ -1118,11 +1118,11 @@ public abstract class OpenConverter {
final Class<ConstructorProperties> propertyNamesClass = ConstructorProperties.class; final Class<ConstructorProperties> propertyNamesClass = ConstructorProperties.class;
Class targetClass = getTargetClass(); Class targetClass = getTargetClass();
Constructor[] constrs = targetClass.getConstructors(); Constructor<?>[] constrs = targetClass.getConstructors();
// Applicable if and only if there are any annotated constructors // Applicable if and only if there are any annotated constructors
List<Constructor> annotatedConstrList = newList(); List<Constructor<?>> annotatedConstrList = newList();
for (Constructor constr : constrs) { for (Constructor<?> constr : constrs) {
if (Modifier.isPublic(constr.getModifiers()) if (Modifier.isPublic(constr.getModifiers())
&& constr.getAnnotation(propertyNamesClass) != null) && constr.getAnnotation(propertyNamesClass) != null)
annotatedConstrList.add(constr); annotatedConstrList.add(constr);
...@@ -1152,7 +1152,7 @@ public abstract class OpenConverter { ...@@ -1152,7 +1152,7 @@ public abstract class OpenConverter {
// Also remember the set of properties in that constructor // Also remember the set of properties in that constructor
// so we can test unambiguity. // so we can test unambiguity.
Set<BitSet> getterIndexSets = newSet(); Set<BitSet> getterIndexSets = newSet();
for (Constructor constr : annotatedConstrList) { for (Constructor<?> constr : annotatedConstrList) {
String[] propertyNames = String[] propertyNames =
constr.getAnnotation(propertyNamesClass).value(); constr.getAnnotation(propertyNamesClass).value();
...@@ -1309,10 +1309,10 @@ public abstract class OpenConverter { ...@@ -1309,10 +1309,10 @@ public abstract class OpenConverter {
} }
private static class Constr { private static class Constr {
final Constructor constructor; final Constructor<?> constructor;
final int[] paramIndexes; final int[] paramIndexes;
final BitSet presentParams; final BitSet presentParams;
Constr(Constructor constructor, int[] paramIndexes, Constr(Constructor<?> constructor, int[] paramIndexes,
BitSet presentParams) { BitSet presentParams) {
this.constructor = constructor; this.constructor = constructor;
this.paramIndexes = paramIndexes; this.paramIndexes = paramIndexes;
......
...@@ -415,17 +415,8 @@ public class Repository { ...@@ -415,17 +415,8 @@ public class Repository {
boolean to_default_domain = false; boolean to_default_domain = false;
// Set domain to default if domain is empty and not already set // Set domain to default if domain is empty and not already set
if (dom.length() == 0) { if (dom.length() == 0)
try { name = Util.newObjectName(domain + name.toString());
name = new ObjectName(domain + name.toString());
} catch (MalformedObjectNameException e) {
if (MBEANSERVER_LOGGER.isLoggable(Level.FINEST)) {
MBEANSERVER_LOGGER.logp(Level.FINEST,
Repository.class.getName(), "addMBean",
"Unexpected MalformedObjectNameException", e);
}
}
}
// Do we have default domain ? // Do we have default domain ?
if (dom == domain) { if (dom == domain) {
......
...@@ -38,6 +38,8 @@ import java.util.Map; ...@@ -38,6 +38,8 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.SortedMap; import java.util.SortedMap;
import java.util.TreeMap; import java.util.TreeMap;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
public class Util { public class Util {
static <K, V> Map<K, V> newMap() { static <K, V> Map<K, V> newMap() {
...@@ -85,6 +87,14 @@ public class Util { ...@@ -85,6 +87,14 @@ public class Util {
return new ArrayList<E>(c); return new ArrayList<E>(c);
} }
public static ObjectName newObjectName(String s) {
try {
return new ObjectName(s);
} catch (MalformedObjectNameException e) {
throw new IllegalArgumentException(e);
}
}
/* This method can be used by code that is deliberately violating the /* This method can be used by code that is deliberately violating the
* allowed checked casts. Rather than marking the whole method containing * allowed checked casts. Rather than marking the whole method containing
* the code with @SuppressWarnings, you can use a call to this method for * the code with @SuppressWarnings, you can use a call to this method for
......
CTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html> <html>
<head> <head>
<!-- <!--
......
...@@ -1553,7 +1553,7 @@ class MetaData { ...@@ -1553,7 +1553,7 @@ class MetaData {
private static String[] getConstructorProperties(Class type) { private static String[] getConstructorProperties(Class type) {
String[] names = null; String[] names = null;
int length = 0; int length = 0;
for (Constructor constructor : type.getConstructors()) { for (Constructor<?> constructor : type.getConstructors()) {
String[] value = getAnnotationValue(constructor); String[] value = getAnnotationValue(constructor);
if ((value != null) && (length < value.length) && isValid(constructor, value)) { if ((value != null) && (length < value.length) && isValid(constructor, value)) {
names = value; names = value;
...@@ -1563,14 +1563,14 @@ class MetaData { ...@@ -1563,14 +1563,14 @@ class MetaData {
return names; return names;
} }
private static String[] getAnnotationValue(Constructor constructor) { private static String[] getAnnotationValue(Constructor<?> constructor) {
ConstructorProperties annotation = constructor.getAnnotation(ConstructorProperties.class); ConstructorProperties annotation = constructor.getAnnotation(ConstructorProperties.class);
return (annotation != null) return (annotation != null)
? annotation.value() ? annotation.value()
: null; : null;
} }
private static boolean isValid(Constructor constructor, String[] names) { private static boolean isValid(Constructor<?> constructor, String[] names) {
Class[] parameters = constructor.getParameterTypes(); Class[] parameters = constructor.getParameterTypes();
if (names.length != parameters.length) { if (names.length != parameters.length) {
return false; return false;
......
...@@ -636,7 +636,11 @@ public interface Instrumentation { ...@@ -636,7 +636,11 @@ public interface Instrumentation {
* @param transformer * @param transformer
* The ClassFileTransformer which wraps using this prefix. * The ClassFileTransformer which wraps using this prefix.
* @param prefix * @param prefix
* The prefix which has been applied to wrapped native methods. * The prefix to apply to wrapped native methods when
* retrying a failed native method resolution. If prefix
* is either <code>null</code> or the empty string, then
* failed native method resolutions are not retried for
* this transformer.
* @throws java.lang.NullPointerException if passed a <code>null</code> transformer. * @throws java.lang.NullPointerException if passed a <code>null</code> transformer.
* @throws java.lang.UnsupportedOperationException if the current configuration of * @throws java.lang.UnsupportedOperationException if the current configuration of
* the JVM does not allow setting a native method prefix * the JVM does not allow setting a native method prefix
......
...@@ -50,7 +50,7 @@ import javax.management.loading.ClassLoaderRepository; ...@@ -50,7 +50,7 @@ import javax.management.loading.ClassLoaderRepository;
* server. A Java object cannot be registered in the MBean server * server. A Java object cannot be registered in the MBean server
* unless it is a JMX compliant MBean.</p> * unless it is a JMX compliant MBean.</p>
* *
* <p>When an MBean is registered or unregistered in the MBean server * <p id="notif">When an MBean is registered or unregistered in the MBean server
* a {@link javax.management.MBeanServerNotification * a {@link javax.management.MBeanServerNotification
* MBeanServerNotification} Notification is emitted. To register an * MBeanServerNotification} Notification is emitted. To register an
* object as listener to MBeanServerNotifications you should call the * object as listener to MBeanServerNotifications you should call the
...@@ -258,27 +258,43 @@ import javax.management.loading.ClassLoaderRepository; ...@@ -258,27 +258,43 @@ import javax.management.loading.ClassLoaderRepository;
*/ */
public interface MBeanServer extends MBeanServerConnection { public interface MBeanServer extends MBeanServerConnection {
// doc comment inherited from MBeanServerConnection /**
* {@inheritDoc}
* <p>If this method successfully creates an MBean, a notification
* is sent as described <a href="#notif">above</a>.</p>
*/
public ObjectInstance createMBean(String className, ObjectName name) public ObjectInstance createMBean(String className, ObjectName name)
throws ReflectionException, InstanceAlreadyExistsException, throws ReflectionException, InstanceAlreadyExistsException,
MBeanRegistrationException, MBeanException, MBeanRegistrationException, MBeanException,
NotCompliantMBeanException; NotCompliantMBeanException;
// doc comment inherited from MBeanServerConnection /**
* {@inheritDoc}
* <p>If this method successfully creates an MBean, a notification
* is sent as described <a href="#notif">above</a>.</p>
*/
public ObjectInstance createMBean(String className, ObjectName name, public ObjectInstance createMBean(String className, ObjectName name,
ObjectName loaderName) ObjectName loaderName)
throws ReflectionException, InstanceAlreadyExistsException, throws ReflectionException, InstanceAlreadyExistsException,
MBeanRegistrationException, MBeanException, MBeanRegistrationException, MBeanException,
NotCompliantMBeanException, InstanceNotFoundException; NotCompliantMBeanException, InstanceNotFoundException;
// doc comment inherited from MBeanServerConnection /**
* {@inheritDoc}
* <p>If this method successfully creates an MBean, a notification
* is sent as described <a href="#notif">above</a>.</p>
*/
public ObjectInstance createMBean(String className, ObjectName name, public ObjectInstance createMBean(String className, ObjectName name,
Object params[], String signature[]) Object params[], String signature[])
throws ReflectionException, InstanceAlreadyExistsException, throws ReflectionException, InstanceAlreadyExistsException,
MBeanRegistrationException, MBeanException, MBeanRegistrationException, MBeanException,
NotCompliantMBeanException; NotCompliantMBeanException;
// doc comment inherited from MBeanServerConnection /**
* {@inheritDoc}
* <p>If this method successfully creates an MBean, a notification
* is sent as described <a href="#notif">above</a>.</p>
*/
public ObjectInstance createMBean(String className, ObjectName name, public ObjectInstance createMBean(String className, ObjectName name,
ObjectName loaderName, Object params[], ObjectName loaderName, Object params[],
String signature[]) String signature[])
...@@ -287,12 +303,15 @@ public interface MBeanServer extends MBeanServerConnection { ...@@ -287,12 +303,15 @@ public interface MBeanServer extends MBeanServerConnection {
NotCompliantMBeanException, InstanceNotFoundException; NotCompliantMBeanException, InstanceNotFoundException;
/** /**
* Registers a pre-existing object as an MBean with the MBean * <p>Registers a pre-existing object as an MBean with the MBean
* server. If the object name given is null, the MBean must * server. If the object name given is null, the MBean must
* provide its own name by implementing the {@link * provide its own name by implementing the {@link
* javax.management.MBeanRegistration MBeanRegistration} interface * javax.management.MBeanRegistration MBeanRegistration} interface
* and returning the name from the {@link * and returning the name from the {@link
* MBeanRegistration#preRegister preRegister} method. * MBeanRegistration#preRegister preRegister} method.</p>
*
* <p>If this method successfully registers an MBean, a notification
* is sent as described <a href="#notif">above</a>.</p>
* *
* @param object The MBean to be registered as an MBean. * @param object The MBean to be registered as an MBean.
* @param name The object name of the MBean. May be null. * @param name The object name of the MBean. May be null.
...@@ -319,7 +338,12 @@ public interface MBeanServer extends MBeanServerConnection { ...@@ -319,7 +338,12 @@ public interface MBeanServer extends MBeanServerConnection {
throws InstanceAlreadyExistsException, MBeanRegistrationException, throws InstanceAlreadyExistsException, MBeanRegistrationException,
NotCompliantMBeanException; NotCompliantMBeanException;
// doc comment inherited from MBeanServerConnection /**
* {@inheritDoc}
*
* <p>If this method successfully unregisters an MBean, a notification
* is sent as described <a href="#notif">above</a>.</p>
*/
public void unregisterMBean(ObjectName name) public void unregisterMBean(ObjectName name)
throws InstanceNotFoundException, MBeanRegistrationException; throws InstanceNotFoundException, MBeanRegistrationException;
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
package javax.management; package javax.management;
import com.sun.jmx.mbeanserver.GetPropertyAction; import com.sun.jmx.mbeanserver.GetPropertyAction;
import com.sun.jmx.mbeanserver.Util;
import java.io.IOException; import java.io.IOException;
import java.io.InvalidObjectException; import java.io.InvalidObjectException;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
...@@ -1386,12 +1387,7 @@ public class ObjectName extends ToQueryString ...@@ -1386,12 +1387,7 @@ public class ObjectName extends ToQueryString
throws NullPointerException { throws NullPointerException {
if (name.getClass().equals(ObjectName.class)) if (name.getClass().equals(ObjectName.class))
return name; return name;
try { return Util.newObjectName(name.getSerializedNameString());
return new ObjectName(name.getSerializedNameString());
} catch (MalformedObjectNameException e) {
throw new IllegalArgumentException("Unexpected: " + e);
// can't happen
}
} }
/** /**
...@@ -1950,14 +1946,7 @@ public class ObjectName extends ToQueryString ...@@ -1950,14 +1946,7 @@ public class ObjectName extends ToQueryString
* *
* @since 1.6 * @since 1.6
*/ */
public static final ObjectName WILDCARD; public static final ObjectName WILDCARD = Util.newObjectName("*:*");
static {
try {
WILDCARD = new ObjectName("*:*");
} catch (MalformedObjectNameException e) {
throw new Error("Can't initialize wildcard name", e);
}
}
// Category : Utilities <=================================== // Category : Utilities <===================================
......
/*
* Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package javax.management;
import com.sun.jmx.mbeanserver.NotificationMBeanSupport;
import com.sun.jmx.mbeanserver.Util;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Collections;
import java.util.Set;
/**
* <p>General-purpose notification filter. This filter can be used to
* filter notifications from a possibly-remote MBean. Most filtering
* decisions can be coded using this filter, which avoids having to
* write a custom implementation of the {@link NotificationFilter}
* class. Writing a custom implementation requires you to deploy it
* on both the client and the server in the remote case, so using this class
* instead is recommended where possible.</p>
*
* <!-- <p>Because this class was introduced in version 2.0 of the JMX API,
* it may not be present on a remote JMX agent that is running an earlier
* version. The method {@link JMX#addListenerWithFilter JMX.addListenerWithFilter}
* can be used when you cannot be sure whether this class is present in the
* agent you are connecting to.</p> -->
*
* <p>This class uses the {@linkplain Query Query API} to specify the
* filtering logic. For example, to select only notifications where the
* {@linkplain Notification#getType() type} is {@code "com.example.mytype"},
* you could use</p>
*
* <pre>
* NotificationFilter filter =
* new QueryNotificationFilter("Type = 'com.example.mytype'");
* </pre>
*
* <p>or equivalently</p>
*
* <pre>
* NotificationFilter filter =
* new QueryNotificationFilter(
* Query.eq(Query.attr("Type"), Query.value("com.example.mytype")));
* </pre>
*
* <p>(This particular example could also use
* {@link NotificationFilterSupport}.)</p>
*
* <p>Here are some other examples of filters you can specify with this class.</p>
*
* <dl>
*
* <dt>{@code QueryNotificationFilter("Type = 'com.example.type1' or
* Type = 'com.example.type2'")}
* <dd>Notifications where the type is either of the given strings.
*
* <dt>{@code QueryNotificationFilter("Type in ('com.example.type1',
* 'com.example.type2')")}
* <dd>Another way to write the previous example.
*
* <dt>{@code QueryNotificationFilter("SequenceNumber > 1000")}
* <dd>Notifications where the {@linkplain Notification#getSequenceNumber()
* sequence number} is greater than 1000.
*
* <dt>{@code QueryNotificationFilter(AttributeChangeNotification.class, null)}
* <dd>Notifications where the notification class is
* {@link AttributeChangeNotification} or a subclass of it.
*
* <dt>{@code QueryNotificationFilter(AttributeChangeNotification.class,
* "AttributeName = 'Size'")}
* <dd>Notifications where the notification class is
* {@link AttributeChangeNotification} or a subclass, and where the
* {@linkplain AttributeChangeNotification#getAttributeName() name of the
* changed attribute} is {@code Size}.
*
* <dt>{@code QueryNotificationFilter(AttributeChangeNotification.class,
* "AttributeName = 'Size' and NewValue - OldValue > 100")}
* <dd>As above, but the difference between the
* {@linkplain AttributeChangeNotification#getNewValue() new value} and the
* {@linkplain AttributeChangeNotification#getOldValue() old value} must be
* greater than 100.
*
* <dt>{@code QueryNotificationFilter("like 'com.example.mydomain:*'")}
* <dd>Notifications where the {@linkplain Notification#getSource() source}
* is an ObjectName that matches the pattern.
*
* <dt>{@code QueryNotificationFilter("Source.canonicalName like
* 'com.example.mydomain:%'")}
* <dd>Another way to write the previous example.
*
* <dt>{@code QueryNotificationFilter(MBeanServerNotification.class,
* "Type = 'JMX.mbean.registered' and MBeanName.canonicalName like
* 'com.example.mydomain:%'")}
* <dd>Notifications of class {@link MBeanServerNotification} representing
* an object registered in the domain {@code com.example.mydomain}.
*
* </dl>
*
* <h4>How it works</h4>
*
* <p>Although the examples above are clear, looking closely at the
* Query API reveals a subtlety. A {@link QueryExp} is evaluated on
* an {@link ObjectName}, not a {@code Notification}.</p>
*
* <p>Every time a {@code Notification} is to be filtered by a
* {@code QueryNotificationFilter}, a special {@link MBeanServer} is created.
* This {@code MBeanServer} contains exactly one MBean, which represents the
* {@code Notification}. If the {@linkplain Notification#getSource()
* source} of the notification is an {@code ObjectName}, which is
* recommended practice, then the name of the MBean representing the
* {@code Notification} will be this {@code ObjectName}. Otherwise the
* name is unspecified.</p>
*
* <p>The query specified in the {@code QueryNotificationFilter} constructor
* is evaluated against this {@code MBeanServer} and {@code ObjectName},
* and the filter returns true if and only if the query does. If the
* query throws an exception, then the filter will return false.</p>
*
* <p>The MBean representing the {@code Notification} has one attribute for
* every property of the {@code Notification}. Specifically, for every public
* method {@code T getX()} in the {@code NotificationClass}, the MBean will
* have an attribute called {@code X} of type {@code T}. For example, if the
* {@code Notification} is an {@code AttributeChangeNotification}, then the
* MBean will have an attribute called {@code AttributeName} of type
* {@code "java.lang.String"}, corresponding to the method {@link
* AttributeChangeNotification#getAttributeName}.</p>
*
* <p>Query evaluation usually involves calls to the methods of {@code
* MBeanServer}. The methods have the following behavior:</p>
*
* <ul>
* <li>The {@link MBeanServer#getAttribute getAttribute} method returns the
* value of the corresponding property.
* <li>The {@link MBeanServer#getObjectInstance getObjectInstance}
* method returns an {@link ObjectInstance} where the {@link
* ObjectInstance#getObjectName ObjectName} is the name of the MBean and the
* {@link ObjectInstance#getClassName ClassName} is the class name of the
* {@code Notification}.
* <li>The {@link MBeanServer#isInstanceOf isInstanceOf} method returns true
* if and only if the {@code Notification}'s {@code ClassLoader} can load the
* named class, and the {@code Notification} is an {@linkplain Class#isInstance
* instance} of that class.
* </ul>
*
* <p>These are the only {@code MBeanServer} methods that are needed to
* evaluate standard queries. The behavior of the other {@code MBeanServer}
* methods is unspecified.</p>
*
* @since 1.7
*/
public class QueryNotificationFilter implements NotificationFilter {
private static final long serialVersionUID = -8408613922660635231L;
private static final ObjectName DEFAULT_NAME =
Util.newObjectName(":type=Notification");
private static final QueryExp trueQuery;
static {
ValueExp zero = Query.value(0);
trueQuery = Query.eq(zero, zero);
}
private final QueryExp query;
/**
* Construct a {@code QueryNotificationFilter} that evaluates the given
* {@code QueryExp} to determine whether to accept a notification.
*
* @param query the {@code QueryExp} to evaluate. Can be null,
* in which case all notifications are accepted.
*/
public QueryNotificationFilter(QueryExp query) {
if (query == null)
this.query = trueQuery;
else
this.query = query;
}
/**
* Construct a {@code QueryNotificationFilter} that evaluates the query
* in the given string to determine whether to accept a notification.
* The string is converted into a {@code QueryExp} using
* {@link Query#fromString Query.fromString}.
*
* @param query the string specifying the query to evaluate. Can be null,
* in which case all notifications are accepted.
*
* @throws IllegalArgumentException if the string is not a valid
* query string.
*/
public QueryNotificationFilter(String query) {
this(Query.fromString(query));
}
/**
* <p>Construct a {@code QueryNotificationFilter} that evaluates the query
* in the given string to determine whether to accept a notification,
* and where the notification must also be an instance of the given class.
* The string is converted into a {@code QueryExp} using
* {@link Query#fromString Query.fromString}.</p>
*
* @param notifClass the class that the notification must be an instance of.
* Cannot be null.
*
* @param query the string specifying the query to evaluate. Can be null,
* in which case all notifications are accepted.
*
* @throws IllegalArgumentException if the string is not a valid
* query string, or if {@code notifClass} is null.
*/
public QueryNotificationFilter(
Class<? extends Notification> notifClass, String query) {
this(Query.and(Query.isInstanceOf(Query.value(notNull(notifClass).getName())),
Query.fromString(query)));
}
private static <T> T notNull(T x) {
if (x == null)
throw new IllegalArgumentException("Null argument");
return x;
}
/**
* Retrieve the query that this notification filter will evaluate for
* each notification.
*
* @return the query.
*/
public QueryExp getQuery() {
return query;
}
public boolean isNotificationEnabled(Notification notification) {
ObjectName name;
Object source = notification.getSource();
if (source instanceof ObjectName)
name = (ObjectName) source;
else
name = DEFAULT_NAME;
MBS mbsImpl = new MBS(notification, name);
MBeanServer mbs = (MBeanServer) Proxy.newProxyInstance(
MBeanServer.class.getClassLoader(),
new Class<?>[] {MBeanServer.class},
new ForwardIH(mbsImpl));
return evalQuery(query, mbs, name);
}
private static boolean evalQuery(
QueryExp query, MBeanServer mbs, ObjectName name) {
MBeanServer oldMBS = QueryEval.getMBeanServer();
try {
if (mbs != null)
query.setMBeanServer(mbs);
return query.apply(name);
} catch (Exception e) {
return false;
} finally {
query.setMBeanServer(oldMBS);
}
}
private static class ForwardIH implements InvocationHandler {
private final MBS mbs;
ForwardIH(MBS mbs) {
this.mbs = mbs;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Method forward;
try {
forward = MBS.class.getMethod(
method.getName(), method.getParameterTypes());
} catch (NoSuchMethodException e) {
throw new UnsupportedOperationException(method.getName());
}
try {
return forward.invoke(mbs, args);
} catch (InvocationTargetException e) {
throw e.getCause();
}
}
}
private static class MBS {
private final Notification notification;
private final ObjectName objectName;
private final ObjectInstance objectInstance;
private volatile DynamicMBean mbean;
MBS(Notification n, ObjectName name) {
this.notification = n;
this.objectName = name;
this.objectInstance = new ObjectInstance(name, n.getClass().getName());
}
private void checkName(ObjectName name) throws InstanceNotFoundException {
if (!objectName.equals(name))
throw new InstanceNotFoundException(String.valueOf(name));
}
private DynamicMBean mbean(ObjectName name)
throws InstanceNotFoundException, ReflectionException {
if (mbean == null) {
try {
mbean = new NotificationMBeanSupport(notification);
} catch (NotCompliantMBeanException e) {
throw new ReflectionException(e);
}
}
return mbean;
}
public ObjectInstance getObjectInstance(ObjectName name)
throws InstanceNotFoundException {
checkName(name);
return objectInstance;
}
public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) {
Set<ObjectName> names = queryNames(name, query);
switch (names.size()) {
case 0:
return Collections.emptySet();
case 1:
return Collections.singleton(objectInstance);
default:
throw new UnsupportedOperationException("Internal error");
}
}
public Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
if ((name != null && !name.apply(objectName)) ||
(query != null && !evalQuery(query, null, name)))
return Collections.emptySet();
return Collections.singleton(objectName);
}
public boolean isRegistered(ObjectName name) {
return objectName.equals(name);
}
public Integer getMBeanCount() {
return 1;
}
public Object getAttribute(ObjectName name, String attribute)
throws MBeanException, AttributeNotFoundException,
InstanceNotFoundException, ReflectionException {
return mbean(name).getAttribute(attribute);
}
public AttributeList getAttributes(ObjectName name, String[] attributes)
throws InstanceNotFoundException, ReflectionException {
return mbean(name).getAttributes(attributes);
}
public String getDefaultDomain() {
return objectName.getDomain();
}
public String[] getDomains() {
return new String[] {objectName.getDomain()};
}
public MBeanInfo getMBeanInfo(ObjectName name)
throws InstanceNotFoundException, ReflectionException {
return mbean(name).getMBeanInfo();
}
public boolean isInstanceOf(ObjectName name, String className)
throws InstanceNotFoundException {
try {
mbean(name);
ClassLoader loader = notification.getClass().getClassLoader();
Class<?> c = Class.forName(className, false, loader);
return c.isInstance(notification);
} catch (ReflectionException e) {
return false;
} catch (ClassNotFoundException e) {
return false;
}
}
public ClassLoader getClassLoaderFor(ObjectName mbeanName)
throws InstanceNotFoundException {
checkName(mbeanName);
return notification.getClass().getClassLoader();
}
}
}
...@@ -48,6 +48,7 @@ import java.util.logging.Level; ...@@ -48,6 +48,7 @@ import java.util.logging.Level;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.Vector;
import javax.management.Attribute; import javax.management.Attribute;
import javax.management.AttributeChangeNotification; import javax.management.AttributeChangeNotification;
import javax.management.AttributeChangeNotificationFilter; import javax.management.AttributeChangeNotificationFilter;
...@@ -132,8 +133,6 @@ public class RequiredModelMBean ...@@ -132,8 +133,6 @@ public class RequiredModelMBean
* and operations will be executed */ * and operations will be executed */
private Object managedResource = null; private Object managedResource = null;
private static final String currClass = "RequiredModelMBean";
/* records the registering in MBeanServer */ /* records the registering in MBeanServer */
private boolean registered = false; private boolean registered = false;
private transient MBeanServer server = null; private transient MBeanServer server = null;
...@@ -2488,10 +2487,13 @@ public class RequiredModelMBean ...@@ -2488,10 +2487,13 @@ public class RequiredModelMBean
} }
if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
Vector<String> enabledAttrs = currFilter.getEnabledAttributes();
String s = (enabledAttrs.size() > 1) ?
"[" + enabledAttrs.firstElement() + ", ...]" :
enabledAttrs.toString();
MODELMBEAN_LOGGER.logp(Level.FINER, MODELMBEAN_LOGGER.logp(Level.FINER,
RequiredModelMBean.class.getName(), mth, RequiredModelMBean.class.getName(), mth,
"Set attribute change filter to " + "Set attribute change filter to " + s);
currFilter.getEnabledAttributes().firstElement());
} }
attributeBroadcaster.addNotificationListener(inlistener,currFilter, attributeBroadcaster.addNotificationListener(inlistener,currFilter,
......
...@@ -303,39 +303,78 @@ public class InstrumentationImpl implements Instrumentation { ...@@ -303,39 +303,78 @@ public class InstrumentationImpl implements Instrumentation {
NoSuchMethodException firstExc = null; NoSuchMethodException firstExc = null;
boolean twoArgAgent = false; boolean twoArgAgent = false;
// The agent class has a premain or agentmain method that has 1 or 2 // The agent class must have a premain or agentmain method that
// arguments. We first check for a signature of (String, Instrumentation), // has 1 or 2 arguments. We check in the following order:
// and if not found we check for (String). If neither is found then we //
// throw the NoSuchMethodException from the first attempt so that the // 1) declared with a signature of (String, Instrumentation)
// exception text indicates the lookup failed for the 2-arg method // 2) declared with a signature of (String)
// (same as JDK5.0). // 3) inherited with a signature of (String, Instrumentation)
// 4) inherited with a signature of (String)
//
// So the declared version of either 1-arg or 2-arg always takes
// primary precedence over an inherited version. After that, the
// 2-arg version takes precedence over the 1-arg version.
//
// If no method is found then we throw the NoSuchMethodException
// from the first attempt so that the exception text indicates
// the lookup failed for the 2-arg method (same as JDK5.0).
try { try {
m = javaAgentClass.getMethod( methodname, m = javaAgentClass.getDeclaredMethod( methodname,
new Class[] { new Class[] {
String.class, String.class,
java.lang.instrument.Instrumentation.class java.lang.instrument.Instrumentation.class
} }
); );
twoArgAgent = true; twoArgAgent = true;
} catch (NoSuchMethodException x) { } catch (NoSuchMethodException x) {
// remember the NoSuchMethodException // remember the NoSuchMethodException
firstExc = x; firstExc = x;
} }
// check for the 1-arg method
if (m == null) { if (m == null) {
// now try the declared 1-arg method
try { try {
m = javaAgentClass.getMethod(methodname, new Class[] { String.class }); m = javaAgentClass.getDeclaredMethod(methodname,
new Class[] { String.class });
} catch (NoSuchMethodException x) { } catch (NoSuchMethodException x) {
// Neither method exists so we throw the first NoSuchMethodException // ignore this exception because we'll try
// as per 5.0 // two arg inheritance next
}
}
if (m == null) {
// now try the inherited 2-arg method
try {
m = javaAgentClass.getMethod( methodname,
new Class[] {
String.class,
java.lang.instrument.Instrumentation.class
}
);
twoArgAgent = true;
} catch (NoSuchMethodException x) {
// ignore this exception because we'll try
// one arg inheritance next
}
}
if (m == null) {
// finally try the inherited 1-arg method
try {
m = javaAgentClass.getMethod(methodname,
new Class[] { String.class });
} catch (NoSuchMethodException x) {
// none of the methods exists so we throw the
// first NoSuchMethodException as per 5.0
throw firstExc; throw firstExc;
} }
} }
// the premain method should not be required to be public, // the premain method should not be required to be public,
// make it accessible so we can call it // make it accessible so we can call it
// Note: The spec says the following:
// The agent class must implement a public static premain method...
setAccessible(m, true); setAccessible(m, true);
// invoke the 1 or 2-arg method // invoke the 1 or 2-arg method
......
...@@ -64,7 +64,8 @@ class Flag { ...@@ -64,7 +64,8 @@ class Flag {
} }
VMOption getVMOption() { VMOption getVMOption() {
return new VMOption(name, value.toString(), writeable, origin); String val = value == null ? "" : value.toString();
return new VMOption(name, val, writeable, origin);
} }
static Flag getFlag(String name) { static Flag getFlag(String name) {
......
...@@ -91,9 +91,10 @@ public class NegotiatorImpl extends Negotiator { ...@@ -91,9 +91,10 @@ public class NegotiatorImpl extends Negotiator {
GSSManagerImpl manager = new GSSManagerImpl( GSSManagerImpl manager = new GSSManagerImpl(
GSSUtil.CALLER_HTTP_NEGOTIATE); GSSUtil.CALLER_HTTP_NEGOTIATE);
String peerName = "HTTP/" + hostname; String peerName = "HTTP@" + hostname;
GSSName serverName = manager.createName(peerName, null); GSSName serverName = manager.createName(peerName,
GSSName.NT_HOSTBASED_SERVICE);
context = manager.createContext(serverName, context = manager.createContext(serverName,
oid, oid,
null, null,
......
/* /*
* Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -65,10 +65,86 @@ final class P11KeyGenerator extends KeyGeneratorSpi { ...@@ -65,10 +65,86 @@ final class P11KeyGenerator extends KeyGeneratorSpi {
// are supported. // are supported.
private boolean supportBothKeySizes; private boolean supportBothKeySizes;
// min and max key sizes (in bits) for variable-key-length /**
// algorithms, e.g. RC4 and Blowfish * Utility method for checking if the specified key size is valid
private int minKeySize; * and within the supported range. Return the significant key size
private int maxKeySize; * upon successful validation.
* @param keyGenMech the PKCS#11 key generation mechanism.
* @param keySize the to-be-checked key size for this mechanism.
* @param token token which provides this mechanism.
* @return the significant key size (in bits) corresponding to the
* specified key size.
* @throws InvalidParameterException if the specified key size is invalid.
* @throws ProviderException if this mechanism isn't supported by SunPKCS11
* or underlying native impl.
*/
static int checkKeySize(long keyGenMech, int keySize, Token token)
throws InvalidAlgorithmParameterException, ProviderException {
int sigKeySize;
switch ((int)keyGenMech) {
case (int)CKM_DES_KEY_GEN:
if ((keySize != 64) && (keySize != 56)) {
throw new InvalidAlgorithmParameterException
("DES key length must be 56 bits");
}
sigKeySize = 56;
break;
case (int)CKM_DES2_KEY_GEN:
case (int)CKM_DES3_KEY_GEN:
if ((keySize == 112) || (keySize == 128)) {
sigKeySize = 112;
} else if ((keySize == 168) || (keySize == 192)) {
sigKeySize = 168;
} else {
throw new InvalidAlgorithmParameterException
("DESede key length must be 112, or 168 bits");
}
break;
default:
// Handle all variable-key-length algorithms here
CK_MECHANISM_INFO info = null;
try {
info = token.getMechanismInfo(keyGenMech);
} catch (PKCS11Exception p11e) {
// Should never happen
throw new ProviderException
("Cannot retrieve mechanism info", p11e);
}
if (info == null) {
// XXX Unable to retrieve the supported key length from
// the underlying native impl. Skip the checking for now.
return keySize;
}
// PKCS#11 defines these to be in number of bytes except for
// RC4 which is in bits. However, some PKCS#11 impls still use
// bytes for all mechs, e.g. NSS. We try to detect this
// inconsistency if the minKeySize seems unreasonably small.
int minKeySize = (int)info.ulMinKeySize;
int maxKeySize = (int)info.ulMaxKeySize;
if (keyGenMech != CKM_RC4_KEY_GEN || minKeySize < 8) {
minKeySize = (int)info.ulMinKeySize << 3;
maxKeySize = (int)info.ulMaxKeySize << 3;
}
// Explicitly disallow keys shorter than 40-bits for security
if (minKeySize < 40) minKeySize = 40;
if (keySize < minKeySize || keySize > maxKeySize) {
throw new InvalidAlgorithmParameterException
("Key length must be between " + minKeySize +
" and " + maxKeySize + " bits");
}
if (keyGenMech == CKM_AES_KEY_GEN) {
if ((keySize != 128) && (keySize != 192) &&
(keySize != 256)) {
throw new InvalidAlgorithmParameterException
("AES key length must be " + minKeySize +
(maxKeySize >= 192? ", 192":"") +
(maxKeySize >= 256? ", or 256":"") + " bits");
}
}
sigKeySize = keySize;
}
return sigKeySize;
}
P11KeyGenerator(Token token, String algorithm, long mechanism) P11KeyGenerator(Token token, String algorithm, long mechanism)
throws PKCS11Exception { throws PKCS11Exception {
...@@ -85,72 +161,44 @@ final class P11KeyGenerator extends KeyGeneratorSpi { ...@@ -85,72 +161,44 @@ final class P11KeyGenerator extends KeyGeneratorSpi {
supportBothKeySizes = supportBothKeySizes =
(token.provider.config.isEnabled(CKM_DES2_KEY_GEN) && (token.provider.config.isEnabled(CKM_DES2_KEY_GEN) &&
(token.getMechanismInfo(CKM_DES2_KEY_GEN) != null)); (token.getMechanismInfo(CKM_DES2_KEY_GEN) != null));
} else if (this.mechanism == CKM_RC4_KEY_GEN) {
CK_MECHANISM_INFO info = token.getMechanismInfo(mechanism);
// Although PKCS#11 spec documented that these are in bits,
// NSS, for one, uses bytes. Multiple by 8 if the number seems
// unreasonably small.
if (info.ulMinKeySize < 8) {
minKeySize = (int)info.ulMinKeySize << 3;
maxKeySize = (int)info.ulMaxKeySize << 3;
} else {
minKeySize = (int)info.ulMinKeySize;
maxKeySize = (int)info.ulMaxKeySize;
}
// Explicitly disallow keys shorter than 40-bits for security
if (minKeySize < 40) minKeySize = 40;
} else if (this.mechanism == CKM_BLOWFISH_KEY_GEN) {
CK_MECHANISM_INFO info = token.getMechanismInfo(mechanism);
maxKeySize = (int)info.ulMaxKeySize << 3;
minKeySize = (int)info.ulMinKeySize << 3;
// Explicitly disallow keys shorter than 40-bits for security
if (minKeySize < 40) minKeySize = 40;
} }
setDefaultKeySize(); setDefaultKeySize();
} }
// set default keysize and also initialize keyType // set default keysize and also initialize keyType
private void setDefaultKeySize() { private void setDefaultKeySize() {
// whether to check default key size against the min and max value
boolean validateKeySize = false;
switch ((int)mechanism) { switch ((int)mechanism) {
case (int)CKM_DES_KEY_GEN: case (int)CKM_DES_KEY_GEN:
keySize = 64; keySize = 64;
significantKeySize = 56;
keyType = CKK_DES; keyType = CKK_DES;
break; break;
case (int)CKM_DES2_KEY_GEN: case (int)CKM_DES2_KEY_GEN:
keySize = 128; keySize = 128;
significantKeySize = 112;
keyType = CKK_DES2; keyType = CKK_DES2;
break; break;
case (int)CKM_DES3_KEY_GEN: case (int)CKM_DES3_KEY_GEN:
keySize = 192; keySize = 192;
significantKeySize = 168;
keyType = CKK_DES3; keyType = CKK_DES3;
break; break;
case (int)CKM_AES_KEY_GEN: case (int)CKM_AES_KEY_GEN:
keyType = CKK_AES;
keySize = 128; keySize = 128;
significantKeySize = 128; keyType = CKK_AES;
break; break;
case (int)CKM_RC4_KEY_GEN: case (int)CKM_RC4_KEY_GEN:
keyType = CKK_RC4;
keySize = 128; keySize = 128;
validateKeySize = true; keyType = CKK_RC4;
break; break;
case (int)CKM_BLOWFISH_KEY_GEN: case (int)CKM_BLOWFISH_KEY_GEN:
keyType = CKK_BLOWFISH;
keySize = 128; keySize = 128;
validateKeySize = true; keyType = CKK_BLOWFISH;
break; break;
default: default:
throw new ProviderException("Unknown mechanism " + mechanism); throw new ProviderException("Unknown mechanism " + mechanism);
} }
if (validateKeySize && try {
((keySize > maxKeySize) || (keySize < minKeySize))) { significantKeySize = checkKeySize(mechanism, keySize, token);
throw new ProviderException("Unsupported key size"); } catch (InvalidAlgorithmParameterException iape) {
throw new ProviderException("Unsupported default key size", iape);
} }
} }
...@@ -170,57 +218,32 @@ final class P11KeyGenerator extends KeyGeneratorSpi { ...@@ -170,57 +218,32 @@ final class P11KeyGenerator extends KeyGeneratorSpi {
// see JCE spec // see JCE spec
protected void engineInit(int keySize, SecureRandom random) { protected void engineInit(int keySize, SecureRandom random) {
token.ensureValid(); token.ensureValid();
switch ((int)mechanism) { int newSignificantKeySize;
case (int)CKM_DES_KEY_GEN: try {
if ((keySize != this.keySize) && newSignificantKeySize = checkKeySize(mechanism, keySize, token);
(keySize != this.significantKeySize)) { } catch (InvalidAlgorithmParameterException iape) {
throw new InvalidParameterException throw (InvalidParameterException)
("DES key length must be 56 bits"); (new InvalidParameterException().initCause(iape));
} }
break; if ((mechanism == CKM_DES2_KEY_GEN) ||
case (int)CKM_DES2_KEY_GEN: (mechanism == CKM_DES3_KEY_GEN)) {
case (int)CKM_DES3_KEY_GEN: long newMechanism = (newSignificantKeySize == 112 ?
long newMechanism; CKM_DES2_KEY_GEN : CKM_DES3_KEY_GEN);
if ((keySize == 112) || (keySize == 128)) {
newMechanism = CKM_DES2_KEY_GEN;
} else if ((keySize == 168) || (keySize == 192)) {
newMechanism = CKM_DES3_KEY_GEN;
} else {
throw new InvalidParameterException
("DESede key length must be 112, or 168 bits");
}
if (mechanism != newMechanism) { if (mechanism != newMechanism) {
if (supportBothKeySizes) { if (supportBothKeySizes) {
mechanism = newMechanism; mechanism = newMechanism;
setDefaultKeySize(); // Adjust keyType to reflect the mechanism change
keyType = (mechanism == CKM_DES2_KEY_GEN ?
CKK_DES2 : CKK_DES3);
} else { } else {
throw new InvalidParameterException throw new InvalidParameterException
("Only " + significantKeySize + ("Only " + significantKeySize +
"-bit DESede key length is supported"); "-bit DESede is supported");
} }
} }
break;
case (int)CKM_AES_KEY_GEN:
if ((keySize != 128) && (keySize != 192) && (keySize != 256)) {
throw new InvalidParameterException
("AES key length must be 128, 192, or 256 bits");
}
this.keySize = keySize;
significantKeySize = keySize;
break;
case (int)CKM_RC4_KEY_GEN:
case (int)CKM_BLOWFISH_KEY_GEN:
if ((keySize < minKeySize) || (keySize > maxKeySize)) {
throw new InvalidParameterException
(algorithm + " key length must be between " +
minKeySize + " and " + maxKeySize + " bits");
}
this.keySize = keySize;
this.significantKeySize = keySize;
break;
default:
throw new ProviderException("Unknown mechanism " + mechanism);
} }
this.keySize = keySize;
this.significantKeySize = newSignificantKeySize;
} }
// see JCE spec // see JCE spec
......
/* /*
* Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -156,10 +156,10 @@ final class P11KeyStore extends KeyStoreSpi { ...@@ -156,10 +156,10 @@ final class P11KeyStore extends KeyStoreSpi {
// CKA_CLASS - entry type // CKA_CLASS - entry type
private CK_ATTRIBUTE type = null; private CK_ATTRIBUTE type = null;
// CKA_LABEL of cert // CKA_LABEL of cert and secret key
private String label = null; private String label = null;
// CKA_ID - of private key/cert // CKA_ID of the private key/cert pair
private byte[] id = null; private byte[] id = null;
// CKA_TRUSTED - true if cert is trusted // CKA_TRUSTED - true if cert is trusted
...@@ -871,10 +871,8 @@ final class P11KeyStore extends KeyStoreSpi { ...@@ -871,10 +871,8 @@ final class P11KeyStore extends KeyStoreSpi {
if ((token.tokenInfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH) == 0) { if ((token.tokenInfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH) == 0) {
token.provider.login(null, handler); token.provider.login(null, handler);
} else { } else {
// token supports protected authentication path // token supports protected authentication path
// (external pin-pad, for example) // (external pin-pad, for example)
if (handler != null && if (handler != null &&
!token.config.getKeyStoreCompatibilityMode()) { !token.config.getKeyStoreCompatibilityMode()) {
throw new LoginException("can not specify password if token " + throw new LoginException("can not specify password if token " +
...@@ -1130,19 +1128,14 @@ final class P11KeyStore extends KeyStoreSpi { ...@@ -1130,19 +1128,14 @@ final class P11KeyStore extends KeyStoreSpi {
SecretKey skey = ske.getSecretKey(); SecretKey skey = ske.getSecretKey();
try { try {
// first see if the key already exists. // first check if the key already exists
// if so, update the CKA_LABEL AliasInfo aliasInfo = aliasMap.get(alias);
if (!updateSkey(alias)) {
// key entry does not exist.
// delete existing entry for alias and
// create new secret key entry
// (new entry might be a secret key
// session object converted into a token object)
if (aliasInfo != null) {
engineDeleteEntry(alias); engineDeleteEntry(alias);
storeSkey(alias, ske);
} }
storeSkey(alias, ske);
} catch (PKCS11Exception pe) { } catch (PKCS11Exception pe) {
throw new KeyStoreException(pe); throw new KeyStoreException(pe);
} }
...@@ -1396,41 +1389,6 @@ final class P11KeyStore extends KeyStoreSpi { ...@@ -1396,41 +1389,6 @@ final class P11KeyStore extends KeyStoreSpi {
} }
} }
/**
* return true if update occurred
*/
private boolean updateSkey(String alias)
throws KeyStoreException, PKCS11Exception {
Session session = null;
try {
session = token.getOpSession();
// first update existing secret key CKA_LABEL
THandle h = getTokenObject(session, ATTR_CLASS_SKEY, null, alias);
if (h.type != ATTR_CLASS_SKEY) {
if (debug != null) {
debug.println("did not find secret key " +
"with CKA_LABEL [" + alias + "]");
}
return false;
}
CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] {
new CK_ATTRIBUTE(CKA_LABEL, alias) };
token.p11.C_SetAttributeValue(session.id(), h.handle, attrs);
if (debug != null) {
debug.println("updateSkey set new alias [" +
alias +
"] for secret key entry");
}
return true;
} finally {
token.releaseSession(session);
}
}
/** /**
* XXX On ibutton, when you C_SetAttribute(CKA_ID) for a private key * XXX On ibutton, when you C_SetAttribute(CKA_ID) for a private key
...@@ -1532,30 +1490,6 @@ final class P11KeyStore extends KeyStoreSpi { ...@@ -1532,30 +1490,6 @@ final class P11KeyStore extends KeyStoreSpi {
} }
} }
private void updateP11Skey(String alias, P11Key key)
throws PKCS11Exception {
Session session = null;
try {
session = token.getOpSession();
// session key - convert to token key and set CKA_LABEL
CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] {
ATTR_TOKEN_TRUE,
new CK_ATTRIBUTE(CKA_LABEL, alias) };
token.p11.C_CopyObject(session.id(), key.keyID, attrs);
if (debug != null) {
debug.println("updateP11Skey copied secret session key " +
"for [" +
alias +
"] to token entry");
}
} finally {
token.releaseSession(session);
}
}
private void updateP11Pkey(String alias, CK_ATTRIBUTE attribute, P11Key key) private void updateP11Pkey(String alias, CK_ATTRIBUTE attribute, P11Key key)
throws PKCS11Exception { throws PKCS11Exception {
...@@ -1689,48 +1623,26 @@ final class P11KeyStore extends KeyStoreSpi { ...@@ -1689,48 +1623,26 @@ final class P11KeyStore extends KeyStoreSpi {
throws PKCS11Exception, KeyStoreException { throws PKCS11Exception, KeyStoreException {
SecretKey skey = ske.getSecretKey(); SecretKey skey = ske.getSecretKey();
long keyType = CKK_GENERIC_SECRET; // No need to specify CKA_CLASS, CKA_KEY_TYPE, CKA_VALUE since
// they are handled in P11SecretKeyFactory.createKey() method.
if (skey instanceof P11Key && this.token == ((P11Key)skey).token) { CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] {
updateP11Skey(alias, (P11Key)skey); ATTR_SKEY_TOKEN_TRUE,
return; ATTR_PRIVATE_TRUE,
} new CK_ATTRIBUTE(CKA_LABEL, alias),
};
if ("AES".equalsIgnoreCase(skey.getAlgorithm())) { try {
keyType = CKK_AES; P11SecretKeyFactory.convertKey(token, skey, null, attrs);
} else if ("Blowfish".equalsIgnoreCase(skey.getAlgorithm())) { } catch (InvalidKeyException ike) {
keyType = CKK_BLOWFISH; // re-throw KeyStoreException to match javadoc
} else if ("DES".equalsIgnoreCase(skey.getAlgorithm())) { throw new KeyStoreException("Cannot convert to PKCS11 keys", ike);
keyType = CKK_DES;
} else if ("DESede".equalsIgnoreCase(skey.getAlgorithm())) {
keyType = CKK_DES3;
} else if ("RC4".equalsIgnoreCase(skey.getAlgorithm()) ||
"ARCFOUR".equalsIgnoreCase(skey.getAlgorithm())) {
keyType = CKK_RC4;
} }
CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { // update global alias map
ATTR_SKEY_TOKEN_TRUE, aliasMap.put(alias, new AliasInfo(alias));
ATTR_CLASS_SKEY,
ATTR_PRIVATE_TRUE,
new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType),
new CK_ATTRIBUTE(CKA_LABEL, alias),
new CK_ATTRIBUTE(CKA_VALUE, skey.getEncoded()) };
attrs = token.getAttributes
(TemplateManager.O_IMPORT, CKO_SECRET_KEY, keyType, attrs);
// create the new entry if (debug != null) {
Session session = null; debug.println("storeSkey created token secret key for [" +
try { alias + "]");
session = token.getOpSession();
token.p11.C_CreateObject(session.id(), attrs);
if (debug != null) {
debug.println("storeSkey created token secret key for [" +
alias +
"]");
}
} finally {
token.releaseSession(session);
} }
} }
...@@ -2492,7 +2404,8 @@ final class P11KeyStore extends KeyStoreSpi { ...@@ -2492,7 +2404,8 @@ final class P11KeyStore extends KeyStoreSpi {
// if there are duplicates (either between secret keys, // if there are duplicates (either between secret keys,
// or between a secret key and another object), // or between a secret key and another object),
// throw an exception // throw an exception
HashSet<String> sKeySet = new HashSet<String>(); HashMap<String, AliasInfo> sKeyMap =
new HashMap<String, AliasInfo>();
attrs = new CK_ATTRIBUTE[] { attrs = new CK_ATTRIBUTE[] {
ATTR_SKEY_TOKEN_TRUE, ATTR_SKEY_TOKEN_TRUE,
...@@ -2507,8 +2420,8 @@ final class P11KeyStore extends KeyStoreSpi { ...@@ -2507,8 +2420,8 @@ final class P11KeyStore extends KeyStoreSpi {
// there is a CKA_LABEL // there is a CKA_LABEL
String cka_label = new String(attrs[0].getCharArray()); String cka_label = new String(attrs[0].getCharArray());
if (!sKeySet.contains(cka_label)) { if (sKeyMap.get(cka_label) == null) {
sKeySet.add(cka_label); sKeyMap.put(cka_label, new AliasInfo(cka_label));
} else { } else {
throw new KeyStoreException("invalid KeyStore state: " + throw new KeyStoreException("invalid KeyStore state: " +
"found multiple secret keys sharing same " + "found multiple secret keys sharing same " +
...@@ -2523,7 +2436,7 @@ final class P11KeyStore extends KeyStoreSpi { ...@@ -2523,7 +2436,7 @@ final class P11KeyStore extends KeyStoreSpi {
ArrayList<AliasInfo> matchedCerts = ArrayList<AliasInfo> matchedCerts =
mapPrivateKeys(pkeyIDs, certMap); mapPrivateKeys(pkeyIDs, certMap);
boolean sharedLabel = mapCerts(matchedCerts, certMap); boolean sharedLabel = mapCerts(matchedCerts, certMap);
mapSecretKeys(sKeySet); mapSecretKeys(sKeyMap);
return sharedLabel; return sharedLabel;
...@@ -2547,7 +2460,7 @@ final class P11KeyStore extends KeyStoreSpi { ...@@ -2547,7 +2460,7 @@ final class P11KeyStore extends KeyStoreSpi {
HashMap<String, HashSet<AliasInfo>> certMap) HashMap<String, HashSet<AliasInfo>> certMap)
throws PKCS11Exception, CertificateException { throws PKCS11Exception, CertificateException {
// global alias map // reset global alias map
aliasMap = new HashMap<String, AliasInfo>(); aliasMap = new HashMap<String, AliasInfo>();
// list of matched certs that we will return // list of matched certs that we will return
...@@ -2722,18 +2635,17 @@ final class P11KeyStore extends KeyStoreSpi { ...@@ -2722,18 +2635,17 @@ final class P11KeyStore extends KeyStoreSpi {
* If the secret key shares a CKA_LABEL with another entry, * If the secret key shares a CKA_LABEL with another entry,
* throw an exception * throw an exception
*/ */
private void mapSecretKeys(HashSet<String> sKeySet) private void mapSecretKeys(HashMap<String, AliasInfo> sKeyMap)
throws KeyStoreException { throws KeyStoreException {
for (String label : sKeySet) { for (String label : sKeyMap.keySet()) {
if (!aliasMap.containsKey(label)) { if (aliasMap.containsKey(label)) {
aliasMap.put(label, new AliasInfo(label));
} else {
throw new KeyStoreException("invalid KeyStore state: " + throw new KeyStoreException("invalid KeyStore state: " +
"found secret key sharing CKA_LABEL [" + "found secret key sharing CKA_LABEL [" +
label + label +
"] with another token object"); "] with another token object");
} }
} }
aliasMap.putAll(sKeyMap);
} }
private void dumpTokenMap() { private void dumpTokenMap() {
......
/* /*
* Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -98,7 +98,6 @@ final class P11RSACipher extends CipherSpi { ...@@ -98,7 +98,6 @@ final class P11RSACipher extends CipherSpi {
this.token = token; this.token = token;
this.algorithm = "RSA"; this.algorithm = "RSA";
this.mechanism = mechanism; this.mechanism = mechanism;
session = token.getOpSession();
} }
// modes do not make sense for RSA, but allow ECB // modes do not make sense for RSA, but allow ECB
...@@ -184,7 +183,8 @@ final class P11RSACipher extends CipherSpi { ...@@ -184,7 +183,8 @@ final class P11RSACipher extends CipherSpi {
throw new InvalidKeyException throw new InvalidKeyException
("Wrap has to be used with public keys"); ("Wrap has to be used with public keys");
} }
// No further setup needed for C_Wrap(). We remain uninitialized. // No further setup needed for C_Wrap(). We'll initialize later if
// we can't use C_Wrap().
return; return;
} else if (opmode == Cipher.UNWRAP_MODE) { } else if (opmode == Cipher.UNWRAP_MODE) {
if (p11Key.isPrivate() == false) { if (p11Key.isPrivate() == false) {
...@@ -383,7 +383,8 @@ final class P11RSACipher extends CipherSpi { ...@@ -383,7 +383,8 @@ final class P11RSACipher extends CipherSpi {
return implDoFinal(out, outOfs, out.length - outOfs); return implDoFinal(out, outOfs, out.length - outOfs);
} }
private byte[] doFinal() throws BadPaddingException, IllegalBlockSizeException { private byte[] doFinal() throws BadPaddingException,
IllegalBlockSizeException {
byte[] t = new byte[2048]; byte[] t = new byte[2048];
int n = implDoFinal(t, 0, t.length); int n = implDoFinal(t, 0, t.length);
byte[] out = new byte[n]; byte[] out = new byte[n];
...@@ -394,20 +395,37 @@ final class P11RSACipher extends CipherSpi { ...@@ -394,20 +395,37 @@ final class P11RSACipher extends CipherSpi {
// see JCE spec // see JCE spec
protected byte[] engineWrap(Key key) throws InvalidKeyException, protected byte[] engineWrap(Key key) throws InvalidKeyException,
IllegalBlockSizeException { IllegalBlockSizeException {
// XXX Note that if we cannot convert key to a key on this token,
// we will fail. For example, trying a wrap an AES key on a token that
// does not support AES.
// We could implement a fallback that just encrypts the encoding
// (assuming the key is not sensitive). For now, we are operating under
// the assumption that this is not necessary.
String keyAlg = key.getAlgorithm(); String keyAlg = key.getAlgorithm();
P11Key secretKey = P11SecretKeyFactory.convertKey(token, key, keyAlg); P11Key sKey = null;
try {
// The conversion may fail, e.g. trying to wrap an AES key on
// a token that does not support AES, or when the key size is
// not within the range supported by the token.
sKey = P11SecretKeyFactory.convertKey(token, key, keyAlg);
} catch (InvalidKeyException ike) {
byte[] toBeWrappedKey = key.getEncoded();
if (toBeWrappedKey == null) {
throw new InvalidKeyException
("wrap() failed, no encoding available", ike);
}
// Directly encrypt the key encoding when key conversion failed
implInit(Cipher.ENCRYPT_MODE, p11Key);
implUpdate(toBeWrappedKey, 0, toBeWrappedKey.length);
try {
return doFinal();
} catch (BadPaddingException bpe) {
// should not occur
throw new InvalidKeyException("wrap() failed", bpe);
} finally {
// Restore original mode
implInit(Cipher.WRAP_MODE, p11Key);
}
}
Session s = null; Session s = null;
try { try {
s = token.getOpSession(); s = token.getOpSession();
byte[] b = token.p11.C_WrapKey(s.id(), new CK_MECHANISM(mechanism), return token.p11.C_WrapKey(s.id(), new CK_MECHANISM(mechanism),
p11Key.keyID, secretKey.keyID); p11Key.keyID, sKey.keyID);
return b;
} catch (PKCS11Exception e) { } catch (PKCS11Exception e) {
throw new InvalidKeyException("wrap() failed", e); throw new InvalidKeyException("wrap() failed", e);
} finally { } finally {
...@@ -431,11 +449,13 @@ final class P11RSACipher extends CipherSpi { ...@@ -431,11 +449,13 @@ final class P11RSACipher extends CipherSpi {
}; };
attributes = token.getAttributes attributes = token.getAttributes
(O_IMPORT, CKO_SECRET_KEY, keyType, attributes); (O_IMPORT, CKO_SECRET_KEY, keyType, attributes);
long keyID = token.p11.C_UnwrapKey(s.id(), new CK_MECHANISM(mechanism), long keyID = token.p11.C_UnwrapKey(s.id(),
p11Key.keyID, wrappedKey, attributes); new CK_MECHANISM(mechanism), p11Key.keyID, wrappedKey,
return P11Key.secretKey(session, keyID, algorithm, 48 << 3, attributes); attributes);
return P11Key.secretKey(session, keyID, algorithm, 48 << 3,
attributes);
} catch (PKCS11Exception e) { } catch (PKCS11Exception e) {
throw new InvalidKeyException("wrap() failed", e); throw new InvalidKeyException("unwrap() failed", e);
} finally { } finally {
token.releaseSession(s); token.releaseSession(s);
} }
......
/* /*
* Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -104,9 +104,20 @@ final class P11SecretKeyFactory extends SecretKeyFactorySpi { ...@@ -104,9 +104,20 @@ final class P11SecretKeyFactory extends SecretKeyFactorySpi {
/** /**
* Convert an arbitrary key of algorithm into a P11Key of provider. * Convert an arbitrary key of algorithm into a P11Key of provider.
* Used engineTranslateKey(), P11Cipher.init(), and P11Mac.init(). * Used in engineTranslateKey(), P11Cipher.init(), and P11Mac.init().
*/ */
static P11Key convertKey(Token token, Key key, String algorithm) static P11Key convertKey(Token token, Key key, String algo)
throws InvalidKeyException {
return convertKey(token, key, algo, null);
}
/**
* Convert an arbitrary key of algorithm w/ custom attributes into a
* P11Key of provider.
* Used in P11KeyStore.storeSkey.
*/
static P11Key convertKey(Token token, Key key, String algo,
CK_ATTRIBUTE[] extraAttrs)
throws InvalidKeyException { throws InvalidKeyException {
token.ensureValid(); token.ensureValid();
if (key == null) { if (key == null) {
...@@ -115,25 +126,41 @@ final class P11SecretKeyFactory extends SecretKeyFactorySpi { ...@@ -115,25 +126,41 @@ final class P11SecretKeyFactory extends SecretKeyFactorySpi {
if (key instanceof SecretKey == false) { if (key instanceof SecretKey == false) {
throw new InvalidKeyException("Key must be a SecretKey"); throw new InvalidKeyException("Key must be a SecretKey");
} }
long algorithmType; long algoType;
if (algorithm == null) { if (algo == null) {
algorithm = key.getAlgorithm(); algo = key.getAlgorithm();
algorithmType = getKeyType(algorithm); algoType = getKeyType(algo);
} else { } else {
algorithmType = getKeyType(algorithm); algoType = getKeyType(algo);
long keyAlgorithmType = getKeyType(key.getAlgorithm()); long keyAlgorithmType = getKeyType(key.getAlgorithm());
if (algorithmType != keyAlgorithmType) { if (algoType != keyAlgorithmType) {
if ((algorithmType == PCKK_HMAC) || (algorithmType == PCKK_SSLMAC)) { if ((algoType == PCKK_HMAC) || (algoType == PCKK_SSLMAC)) {
// ignore key algorithm for MACs // ignore key algorithm for MACs
} else { } else {
throw new InvalidKeyException throw new InvalidKeyException
("Key algorithm must be " + algorithm); ("Key algorithm must be " + algo);
} }
} }
} }
if (key instanceof P11Key) { if (key instanceof P11Key) {
P11Key p11Key = (P11Key)key; P11Key p11Key = (P11Key)key;
if (p11Key.token == token) { if (p11Key.token == token) {
if (extraAttrs != null) {
Session session = null;
try {
session = token.getObjSession();
long newKeyID = token.p11.C_CopyObject(session.id(),
p11Key.keyID, extraAttrs);
p11Key = (P11Key) (P11Key.secretKey(p11Key.session,
newKeyID, p11Key.algorithm, p11Key.keyLength,
extraAttrs));
} catch (PKCS11Exception p11e) {
throw new InvalidKeyException
("Cannot duplicate the PKCS11 key", p11e);
} finally {
token.releaseSession(session);
}
}
return p11Key; return p11Key;
} }
} }
...@@ -141,11 +168,11 @@ final class P11SecretKeyFactory extends SecretKeyFactorySpi { ...@@ -141,11 +168,11 @@ final class P11SecretKeyFactory extends SecretKeyFactorySpi {
if (p11Key != null) { if (p11Key != null) {
return p11Key; return p11Key;
} }
if ("RAW".equals(key.getFormat()) == false) { if ("RAW".equalsIgnoreCase(key.getFormat()) == false) {
throw new InvalidKeyException("Encoded format must be RAW"); throw new InvalidKeyException("Encoded format must be RAW");
} }
byte[] encoded = key.getEncoded(); byte[] encoded = key.getEncoded();
p11Key = createKey(token, encoded, algorithm, algorithmType); p11Key = createKey(token, encoded, algo, algoType, extraAttrs);
token.secretCache.put(key, p11Key); token.secretCache.put(key, p11Key);
return p11Key; return p11Key;
} }
...@@ -159,79 +186,79 @@ final class P11SecretKeyFactory extends SecretKeyFactorySpi { ...@@ -159,79 +186,79 @@ final class P11SecretKeyFactory extends SecretKeyFactorySpi {
} }
private static P11Key createKey(Token token, byte[] encoded, private static P11Key createKey(Token token, byte[] encoded,
String algorithm, long keyType) throws InvalidKeyException { String algorithm, long keyType, CK_ATTRIBUTE[] extraAttrs)
int n = encoded.length; throws InvalidKeyException {
int keyLength; int n = encoded.length << 3;
switch ((int)keyType) { int keyLength = n;
case (int)CKK_RC4: try {
if ((n < 5) || (n > 128)) { switch ((int)keyType) {
throw new InvalidKeyException case (int)CKK_DES:
("ARCFOUR key length must be between 5 and 128 bytes"); keyLength =
} P11KeyGenerator.checkKeySize(CKM_DES_KEY_GEN, n, token);
keyLength = n << 3; fixDESParity(encoded, 0);
break; break;
case (int)CKK_DES: case (int)CKK_DES3:
if (n != 8) { keyLength =
throw new InvalidKeyException P11KeyGenerator.checkKeySize(CKM_DES3_KEY_GEN, n, token);
("DES key length must be 8 bytes"); fixDESParity(encoded, 0);
} fixDESParity(encoded, 8);
keyLength = 56; if (keyLength == 112) {
fixDESParity(encoded, 0); keyType = CKK_DES2;
break; } else {
case (int)CKK_DES3: keyType = CKK_DES3;
if (n == 16) { fixDESParity(encoded, 16);
keyType = CKK_DES2; }
} else if (n == 24) { break;
keyType = CKK_DES3; case (int)CKK_AES:
fixDESParity(encoded, 16); keyLength =
} else { P11KeyGenerator.checkKeySize(CKM_AES_KEY_GEN, n, token);
throw new InvalidKeyException break;
("DESede key length must be 16 or 24 bytes"); case (int)CKK_RC4:
} keyLength =
fixDESParity(encoded, 0); P11KeyGenerator.checkKeySize(CKM_RC4_KEY_GEN, n, token);
fixDESParity(encoded, 8); break;
keyLength = n * 7; case (int)CKK_BLOWFISH:
break; keyLength =
case (int)CKK_AES: P11KeyGenerator.checkKeySize(CKM_BLOWFISH_KEY_GEN, n,
if ((n != 16) && (n != 24) && (n != 32)) { token);
throw new InvalidKeyException break;
("AES key length must be 16, 24, or 32 bytes"); case (int)CKK_GENERIC_SECRET:
} case (int)PCKK_TLSPREMASTER:
keyLength = n << 3; case (int)PCKK_TLSRSAPREMASTER:
break; case (int)PCKK_TLSMASTER:
case (int)CKK_BLOWFISH: keyType = CKK_GENERIC_SECRET;
if ((n < 5) || (n > 56)) { break;
throw new InvalidKeyException case (int)PCKK_SSLMAC:
("Blowfish key length must be between 5 and 56 bytes"); case (int)PCKK_HMAC:
} if (n == 0) {
keyLength = n << 3; throw new InvalidKeyException
break; ("MAC keys must not be empty");
case (int)CKK_GENERIC_SECRET: }
case (int)PCKK_TLSPREMASTER: keyType = CKK_GENERIC_SECRET;
case (int)PCKK_TLSRSAPREMASTER: break;
case (int)PCKK_TLSMASTER: default:
keyType = CKK_GENERIC_SECRET; throw new InvalidKeyException("Unknown algorithm " +
keyLength = n << 3; algorithm);
break;
case (int)PCKK_SSLMAC:
case (int)PCKK_HMAC:
if (n == 0) {
throw new InvalidKeyException
("MAC keys must not be empty");
} }
keyType = CKK_GENERIC_SECRET; } catch (InvalidAlgorithmParameterException iape) {
keyLength = n << 3; throw new InvalidKeyException("Invalid key for " + algorithm,
break; iape);
default: } catch (ProviderException pe) {
throw new InvalidKeyException("Unknown algorithm " + algorithm); throw new InvalidKeyException("Could not create key", pe);
} }
Session session = null; Session session = null;
try { try {
CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { CK_ATTRIBUTE[] attributes;
new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY), if (extraAttrs != null) {
new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType), attributes = new CK_ATTRIBUTE[3 + extraAttrs.length];
new CK_ATTRIBUTE(CKA_VALUE, encoded), System.arraycopy(extraAttrs, 0, attributes, 3,
}; extraAttrs.length);
} else {
attributes = new CK_ATTRIBUTE[3];
}
attributes[0] = new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY);
attributes[1] = new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType);
attributes[2] = new CK_ATTRIBUTE(CKA_VALUE, encoded);
attributes = token.getAttributes attributes = token.getAttributes
(O_IMPORT, CKO_SECRET_KEY, keyType, attributes); (O_IMPORT, CKO_SECRET_KEY, keyType, attributes);
session = token.getObjSession(); session = token.getObjSession();
...@@ -280,7 +307,7 @@ final class P11SecretKeyFactory extends SecretKeyFactorySpi { ...@@ -280,7 +307,7 @@ final class P11SecretKeyFactory extends SecretKeyFactorySpi {
private byte[] getKeyBytes(SecretKey key) throws InvalidKeySpecException { private byte[] getKeyBytes(SecretKey key) throws InvalidKeySpecException {
try { try {
key = engineTranslateKey(key); key = engineTranslateKey(key);
if ("RAW".equals(key.getFormat()) == false) { if ("RAW".equalsIgnoreCase(key.getFormat()) == false) {
throw new InvalidKeySpecException throw new InvalidKeySpecException
("Could not obtain key bytes"); ("Could not obtain key bytes");
} }
......
/* /*
* Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -601,14 +601,26 @@ public final class SunPKCS11 extends AuthProvider { ...@@ -601,14 +601,26 @@ public final class SunPKCS11 extends AuthProvider {
// XXX attributes for Ciphers (supported modes, padding) // XXX attributes for Ciphers (supported modes, padding)
d(CIP, "ARCFOUR", P11Cipher, s("RC4"), d(CIP, "ARCFOUR", P11Cipher, s("RC4"),
m(CKM_RC4)); m(CKM_RC4));
// XXX only CBC/NoPadding for block ciphers
d(CIP, "DES/CBC/NoPadding", P11Cipher, d(CIP, "DES/CBC/NoPadding", P11Cipher,
m(CKM_DES_CBC)); m(CKM_DES_CBC));
d(CIP, "DES/CBC/PKCS5Padding", P11Cipher,
m(CKM_DES_CBC_PAD, CKM_DES_CBC));
d(CIP, "DES/ECB", P11Cipher, s("DES"),
m(CKM_DES_ECB));
d(CIP, "DESede/CBC/NoPadding", P11Cipher, d(CIP, "DESede/CBC/NoPadding", P11Cipher,
m(CKM_DES3_CBC)); m(CKM_DES3_CBC));
d(CIP, "DESede/CBC/PKCS5Padding", P11Cipher,
m(CKM_DES3_CBC_PAD, CKM_DES3_CBC));
d(CIP, "DESede/ECB", P11Cipher, s("DESede"),
m(CKM_DES3_ECB));
d(CIP, "AES/CBC/NoPadding", P11Cipher, d(CIP, "AES/CBC/NoPadding", P11Cipher,
m(CKM_AES_CBC)); m(CKM_AES_CBC));
d(CIP, "Blowfish/CBC/NoPadding", P11Cipher, d(CIP, "AES/CBC/PKCS5Padding", P11Cipher,
m(CKM_AES_CBC_PAD, CKM_AES_CBC));
d(CIP, "AES/ECB", P11Cipher, s("AES"),
m(CKM_AES_ECB));
d(CIP, "Blowfish/CBC", P11Cipher,
m(CKM_BLOWFISH_CBC)); m(CKM_BLOWFISH_CBC));
// XXX RSA_X_509, RSA_OAEP not yet supported // XXX RSA_X_509, RSA_OAEP not yet supported
......
...@@ -87,6 +87,9 @@ class EndEntityChecker { ...@@ -87,6 +87,9 @@ class EndEntityChecker {
// the Microsoft Server-Gated-Cryptography EKU extension OID // the Microsoft Server-Gated-Cryptography EKU extension OID
private final static String OID_EKU_MS_SGC = "1.3.6.1.4.1.311.10.3.3"; private final static String OID_EKU_MS_SGC = "1.3.6.1.4.1.311.10.3.3";
// the recognized extension OIDs
private final static String OID_SUBJECT_ALT_NAME = "2.5.29.17";
private final static String NSCT_SSL_CLIENT = private final static String NSCT_SSL_CLIENT =
NetscapeCertTypeExtension.SSL_CLIENT; NetscapeCertTypeExtension.SSL_CLIENT;
...@@ -171,6 +174,13 @@ class EndEntityChecker { ...@@ -171,6 +174,13 @@ class EndEntityChecker {
throws CertificateException { throws CertificateException {
// basic constraints irrelevant in EE certs // basic constraints irrelevant in EE certs
exts.remove(SimpleValidator.OID_BASIC_CONSTRAINTS); exts.remove(SimpleValidator.OID_BASIC_CONSTRAINTS);
// If the subject field contains an empty sequence, the subjectAltName
// extension MUST be marked critical.
// We do not check the validity of the critical extension, just mark
// it recognizable here.
exts.remove(OID_SUBJECT_ALT_NAME);
if (!exts.isEmpty()) { if (!exts.isEmpty()) {
throw new CertificateException("Certificate contains unsupported " throw new CertificateException("Certificate contains unsupported "
+ "critical extensions: " + exts); + "critical extensions: " + exts);
......
...@@ -626,6 +626,7 @@ appendClassPath( JPLISAgent* agent, ...@@ -626,6 +626,7 @@ appendClassPath( JPLISAgent* agent,
jvmtiError jvmtierr; jvmtiError jvmtierr;
jvmtierr = (*jvmtienv)->AddToSystemClassLoaderSearch(jvmtienv, jarfile); jvmtierr = (*jvmtienv)->AddToSystemClassLoaderSearch(jvmtienv, jarfile);
check_phase_ret_1(jvmtierr);
if (jvmtierr == JVMTI_ERROR_NONE) { if (jvmtierr == JVMTI_ERROR_NONE) {
return 0; return 0;
...@@ -634,6 +635,7 @@ appendClassPath( JPLISAgent* agent, ...@@ -634,6 +635,7 @@ appendClassPath( JPLISAgent* agent,
jvmtiError err; jvmtiError err;
err = (*jvmtienv)->GetPhase(jvmtienv, &phase); err = (*jvmtienv)->GetPhase(jvmtienv, &phase);
/* can be called from any phase */
jplis_assert(err == JVMTI_ERROR_NONE); jplis_assert(err == JVMTI_ERROR_NONE);
if (phase == JVMTI_PHASE_LIVE) { if (phase == JVMTI_PHASE_LIVE) {
...@@ -805,6 +807,8 @@ appendBootClassPath( JPLISAgent* agent, ...@@ -805,6 +807,8 @@ appendBootClassPath( JPLISAgent* agent,
/* print warning if boot class path not updated */ /* print warning if boot class path not updated */
if (jvmtierr != JVMTI_ERROR_NONE) { if (jvmtierr != JVMTI_ERROR_NONE) {
check_phase_blob_ret(jvmtierr, free(path));
fprintf(stderr, "WARNING: %s not added to bootstrap class loader search: ", path); fprintf(stderr, "WARNING: %s not added to bootstrap class loader search: ", path);
switch (jvmtierr) { switch (jvmtierr) {
case JVMTI_ERROR_ILLEGAL_ARGUMENT : case JVMTI_ERROR_ILLEGAL_ARGUMENT :
......
...@@ -179,6 +179,7 @@ getJPLISEnvironment(jvmtiEnv * jvmtienv) { ...@@ -179,6 +179,7 @@ getJPLISEnvironment(jvmtiEnv * jvmtienv) {
jvmtierror = (*jvmtienv)->GetEnvironmentLocalStorage( jvmtierror = (*jvmtienv)->GetEnvironmentLocalStorage(
jvmtienv, jvmtienv,
(void**)&environment); (void**)&environment);
/* can be called from any phase */
jplis_assert(jvmtierror == JVMTI_ERROR_NONE); jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
if (jvmtierror == JVMTI_ERROR_NONE) { if (jvmtierror == JVMTI_ERROR_NONE) {
...@@ -230,6 +231,7 @@ createNewJPLISAgent(JavaVM * vm, JPLISAgent **agent_ptr) { ...@@ -230,6 +231,7 @@ createNewJPLISAgent(JavaVM * vm, JPLISAgent **agent_ptr) {
/* don't leak envs */ /* don't leak envs */
if ( initerror != JPLIS_INIT_ERROR_NONE ) { if ( initerror != JPLIS_INIT_ERROR_NONE ) {
jvmtiError jvmtierror = (*jvmtienv)->DisposeEnvironment(jvmtienv); jvmtiError jvmtierror = (*jvmtienv)->DisposeEnvironment(jvmtienv);
/* can be called from any phase */
jplis_assert(jvmtierror == JVMTI_ERROR_NONE); jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
} }
} }
...@@ -259,7 +261,7 @@ initializeJPLISAgent( JPLISAgent * agent, ...@@ -259,7 +261,7 @@ initializeJPLISAgent( JPLISAgent * agent,
agent->mNormalEnvironment.mIsRetransformer = JNI_FALSE; agent->mNormalEnvironment.mIsRetransformer = JNI_FALSE;
agent->mRetransformEnvironment.mJVMTIEnv = NULL; /* NULL until needed */ agent->mRetransformEnvironment.mJVMTIEnv = NULL; /* NULL until needed */
agent->mRetransformEnvironment.mAgent = agent; agent->mRetransformEnvironment.mAgent = agent;
agent->mRetransformEnvironment.mIsRetransformer = JNI_TRUE; agent->mRetransformEnvironment.mIsRetransformer = JNI_FALSE; /* JNI_FALSE until mJVMTIEnv is set */
agent->mAgentmainCaller = NULL; agent->mAgentmainCaller = NULL;
agent->mInstrumentationImpl = NULL; agent->mInstrumentationImpl = NULL;
agent->mPremainCaller = NULL; agent->mPremainCaller = NULL;
...@@ -277,18 +279,25 @@ initializeJPLISAgent( JPLISAgent * agent, ...@@ -277,18 +279,25 @@ initializeJPLISAgent( JPLISAgent * agent,
jvmtierror = (*jvmtienv)->SetEnvironmentLocalStorage( jvmtierror = (*jvmtienv)->SetEnvironmentLocalStorage(
jvmtienv, jvmtienv,
&(agent->mNormalEnvironment)); &(agent->mNormalEnvironment));
/* can be called from any phase */
jplis_assert(jvmtierror == JVMTI_ERROR_NONE); jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
/* check what capabilities are available */ /* check what capabilities are available */
checkCapabilities(agent); checkCapabilities(agent);
/* check phase - if live phase then we don't need the VMInit event */ /* check phase - if live phase then we don't need the VMInit event */
jvmtierror == (*jvmtienv)->GetPhase(jvmtienv, &phase); jvmtierror = (*jvmtienv)->GetPhase(jvmtienv, &phase);
/* can be called from any phase */
jplis_assert(jvmtierror == JVMTI_ERROR_NONE); jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
if (phase == JVMTI_PHASE_LIVE) { if (phase == JVMTI_PHASE_LIVE) {
return JPLIS_INIT_ERROR_NONE; return JPLIS_INIT_ERROR_NONE;
} }
if (phase != JVMTI_PHASE_ONLOAD) {
/* called too early or called too late; either way bail out */
return JPLIS_INIT_ERROR_FAILURE;
}
/* now turn on the VMInit event */ /* now turn on the VMInit event */
if ( jvmtierror == JVMTI_ERROR_NONE ) { if ( jvmtierror == JVMTI_ERROR_NONE ) {
jvmtiEventCallbacks callbacks; jvmtiEventCallbacks callbacks;
...@@ -298,6 +307,7 @@ initializeJPLISAgent( JPLISAgent * agent, ...@@ -298,6 +307,7 @@ initializeJPLISAgent( JPLISAgent * agent,
jvmtierror = (*jvmtienv)->SetEventCallbacks( jvmtienv, jvmtierror = (*jvmtienv)->SetEventCallbacks( jvmtienv,
&callbacks, &callbacks,
sizeof(callbacks)); sizeof(callbacks));
check_phase_ret_blob(jvmtierror, JPLIS_INIT_ERROR_FAILURE);
jplis_assert(jvmtierror == JVMTI_ERROR_NONE); jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
} }
...@@ -307,6 +317,7 @@ initializeJPLISAgent( JPLISAgent * agent, ...@@ -307,6 +317,7 @@ initializeJPLISAgent( JPLISAgent * agent,
JVMTI_ENABLE, JVMTI_ENABLE,
JVMTI_EVENT_VM_INIT, JVMTI_EVENT_VM_INIT,
NULL /* all threads */); NULL /* all threads */);
check_phase_ret_blob(jvmtierror, JPLIS_INIT_ERROR_FAILURE);
jplis_assert(jvmtierror == JVMTI_ERROR_NONE); jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
} }
...@@ -622,6 +633,7 @@ setLivePhaseEventHandlers( JPLISAgent * agent) { ...@@ -622,6 +633,7 @@ setLivePhaseEventHandlers( JPLISAgent * agent) {
jvmtierror = (*jvmtienv)->SetEventCallbacks( jvmtienv, jvmtierror = (*jvmtienv)->SetEventCallbacks( jvmtienv,
&callbacks, &callbacks,
sizeof(callbacks)); sizeof(callbacks));
check_phase_ret_false(jvmtierror);
jplis_assert(jvmtierror == JVMTI_ERROR_NONE); jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
...@@ -632,6 +644,7 @@ setLivePhaseEventHandlers( JPLISAgent * agent) { ...@@ -632,6 +644,7 @@ setLivePhaseEventHandlers( JPLISAgent * agent) {
JVMTI_DISABLE, JVMTI_DISABLE,
JVMTI_EVENT_VM_INIT, JVMTI_EVENT_VM_INIT,
NULL /* all threads */); NULL /* all threads */);
check_phase_ret_false(jvmtierror);
jplis_assert(jvmtierror == JVMTI_ERROR_NONE); jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
} }
...@@ -642,6 +655,7 @@ setLivePhaseEventHandlers( JPLISAgent * agent) { ...@@ -642,6 +655,7 @@ setLivePhaseEventHandlers( JPLISAgent * agent) {
JVMTI_ENABLE, JVMTI_ENABLE,
JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK,
NULL /* all threads */); NULL /* all threads */);
check_phase_ret_false(jvmtierror);
jplis_assert(jvmtierror == JVMTI_ERROR_NONE); jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
} }
...@@ -660,6 +674,7 @@ checkCapabilities(JPLISAgent * agent) { ...@@ -660,6 +674,7 @@ checkCapabilities(JPLISAgent * agent) {
memset(&potentialCapabilities, 0, sizeof(potentialCapabilities)); memset(&potentialCapabilities, 0, sizeof(potentialCapabilities));
jvmtierror = (*jvmtienv)->GetPotentialCapabilities(jvmtienv, &potentialCapabilities); jvmtierror = (*jvmtienv)->GetPotentialCapabilities(jvmtienv, &potentialCapabilities);
check_phase_ret(jvmtierror);
jplis_assert(jvmtierror == JVMTI_ERROR_NONE); jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
if ( jvmtierror == JVMTI_ERROR_NONE ) { if ( jvmtierror == JVMTI_ERROR_NONE ) {
...@@ -681,9 +696,11 @@ enableNativeMethodPrefixCapability(jvmtiEnv * jvmtienv) { ...@@ -681,9 +696,11 @@ enableNativeMethodPrefixCapability(jvmtiEnv * jvmtienv) {
jvmtiError jvmtierror; jvmtiError jvmtierror;
jvmtierror = (*jvmtienv)->GetCapabilities(jvmtienv, &desiredCapabilities); jvmtierror = (*jvmtienv)->GetCapabilities(jvmtienv, &desiredCapabilities);
/* can be called from any phase */
jplis_assert(jvmtierror == JVMTI_ERROR_NONE); jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
desiredCapabilities.can_set_native_method_prefix = 1; desiredCapabilities.can_set_native_method_prefix = 1;
jvmtierror = (*jvmtienv)->AddCapabilities(jvmtienv, &desiredCapabilities); jvmtierror = (*jvmtienv)->AddCapabilities(jvmtienv, &desiredCapabilities);
check_phase_ret(jvmtierror);
jplis_assert(jvmtierror == JVMTI_ERROR_NONE); jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
} }
...@@ -715,9 +732,11 @@ addOriginalMethodOrderCapability(JPLISAgent * agent) { ...@@ -715,9 +732,11 @@ addOriginalMethodOrderCapability(JPLISAgent * agent) {
jvmtiError jvmtierror; jvmtiError jvmtierror;
jvmtierror = (*jvmtienv)->GetCapabilities(jvmtienv, &desiredCapabilities); jvmtierror = (*jvmtienv)->GetCapabilities(jvmtienv, &desiredCapabilities);
/* can be called from any phase */
jplis_assert(jvmtierror == JVMTI_ERROR_NONE); jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
desiredCapabilities.can_maintain_original_method_order = 1; desiredCapabilities.can_maintain_original_method_order = 1;
jvmtierror = (*jvmtienv)->AddCapabilities(jvmtienv, &desiredCapabilities); jvmtierror = (*jvmtienv)->AddCapabilities(jvmtienv, &desiredCapabilities);
check_phase_ret(jvmtierror);
jplis_assert(jvmtierror == JVMTI_ERROR_NONE); jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
} }
...@@ -732,9 +751,11 @@ addRedefineClassesCapability(JPLISAgent * agent) { ...@@ -732,9 +751,11 @@ addRedefineClassesCapability(JPLISAgent * agent) {
if (agent->mRedefineAvailable && !agent->mRedefineAdded) { if (agent->mRedefineAvailable && !agent->mRedefineAdded) {
jvmtierror = (*jvmtienv)->GetCapabilities(jvmtienv, &desiredCapabilities); jvmtierror = (*jvmtienv)->GetCapabilities(jvmtienv, &desiredCapabilities);
/* can be called from any phase */
jplis_assert(jvmtierror == JVMTI_ERROR_NONE); jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
desiredCapabilities.can_redefine_classes = 1; desiredCapabilities.can_redefine_classes = 1;
jvmtierror = (*jvmtienv)->AddCapabilities(jvmtienv, &desiredCapabilities); jvmtierror = (*jvmtienv)->AddCapabilities(jvmtienv, &desiredCapabilities);
check_phase_ret(jvmtierror);
/* /*
* With mixed premain/agentmain agents then it's possible that the * With mixed premain/agentmain agents then it's possible that the
...@@ -998,6 +1019,7 @@ retransformableEnvironment(JPLISAgent * agent) { ...@@ -998,6 +1019,7 @@ retransformableEnvironment(JPLISAgent * agent) {
if (jvmtierror == JVMTI_ERROR_NONE) { if (jvmtierror == JVMTI_ERROR_NONE) {
// install the retransforming environment // install the retransforming environment
agent->mRetransformEnvironment.mJVMTIEnv = retransformerEnv; agent->mRetransformEnvironment.mJVMTIEnv = retransformerEnv;
agent->mRetransformEnvironment.mIsRetransformer = JNI_TRUE;
// Make it for ClassFileLoadHook handling // Make it for ClassFileLoadHook handling
jvmtierror = (*retransformerEnv)->SetEnvironmentLocalStorage( jvmtierror = (*retransformerEnv)->SetEnvironmentLocalStorage(
...@@ -1025,6 +1047,7 @@ isModifiableClass(JNIEnv * jnienv, JPLISAgent * agent, jclass clazz) { ...@@ -1025,6 +1047,7 @@ isModifiableClass(JNIEnv * jnienv, JPLISAgent * agent, jclass clazz) {
jvmtierror = (*jvmtienv)->IsModifiableClass( jvmtienv, jvmtierror = (*jvmtienv)->IsModifiableClass( jvmtienv,
clazz, clazz,
&is_modifiable); &is_modifiable);
check_phase_ret_false(jvmtierror);
jplis_assert(jvmtierror == JVMTI_ERROR_NONE); jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
return is_modifiable; return is_modifiable;
...@@ -1032,7 +1055,7 @@ isModifiableClass(JNIEnv * jnienv, JPLISAgent * agent, jclass clazz) { ...@@ -1032,7 +1055,7 @@ isModifiableClass(JNIEnv * jnienv, JPLISAgent * agent, jclass clazz) {
jboolean jboolean
isRetransformClassesSupported(JNIEnv * jnienv, JPLISAgent * agent) { isRetransformClassesSupported(JNIEnv * jnienv, JPLISAgent * agent) {
return retransformableEnvironment(agent) != NULL; return agent->mRetransformEnvironment.mIsRetransformer;
} }
void void
...@@ -1075,6 +1098,12 @@ retransformClasses(JNIEnv * jnienv, JPLISAgent * agent, jobjectArray classes) { ...@@ -1075,6 +1098,12 @@ retransformClasses(JNIEnv * jnienv, JPLISAgent * agent, jobjectArray classes) {
numClasses = (*jnienv)->GetArrayLength(jnienv, classes); numClasses = (*jnienv)->GetArrayLength(jnienv, classes);
errorOccurred = checkForThrowable(jnienv); errorOccurred = checkForThrowable(jnienv);
jplis_assert(!errorOccurred); jplis_assert(!errorOccurred);
if (!errorOccurred && numClasses == 0) {
jplis_assert(numClasses != 0);
errorOccurred = JNI_TRUE;
errorCode = JVMTI_ERROR_NULL_POINTER;
}
} }
if (!errorOccurred) { if (!errorOccurred) {
...@@ -1096,6 +1125,13 @@ retransformClasses(JNIEnv * jnienv, JPLISAgent * agent, jobjectArray classes) { ...@@ -1096,6 +1125,13 @@ retransformClasses(JNIEnv * jnienv, JPLISAgent * agent, jobjectArray classes) {
if (errorOccurred) { if (errorOccurred) {
break; break;
} }
if (classArray[index] == NULL) {
jplis_assert(classArray[index] != NULL);
errorOccurred = JNI_TRUE;
errorCode = JVMTI_ERROR_NULL_POINTER;
break;
}
} }
} }
...@@ -1217,6 +1253,7 @@ redefineClasses(JNIEnv * jnienv, JPLISAgent * agent, jobjectArray classDefinitio ...@@ -1217,6 +1253,7 @@ redefineClasses(JNIEnv * jnienv, JPLISAgent * agent, jobjectArray classDefinitio
if (!errorOccurred) { if (!errorOccurred) {
jvmtiError errorCode = JVMTI_ERROR_NONE; jvmtiError errorCode = JVMTI_ERROR_NONE;
errorCode = (*jvmtienv)->RedefineClasses(jvmtienv, numDefs, classDefs); errorCode = (*jvmtienv)->RedefineClasses(jvmtienv, numDefs, classDefs);
check_phase_blob_ret(errorCode, deallocate(jvmtienv, (void*)classDefs));
errorOccurred = (errorCode != JVMTI_ERROR_NONE); errorOccurred = (errorCode != JVMTI_ERROR_NONE);
if ( errorOccurred ) { if ( errorOccurred ) {
createAndThrowThrowableFromJVMTIErrorCode(jnienv, errorCode); createAndThrowThrowableFromJVMTIErrorCode(jnienv, errorCode);
...@@ -1250,6 +1287,7 @@ commonGetClassList( JNIEnv * jnienv, ...@@ -1250,6 +1287,7 @@ commonGetClassList( JNIEnv * jnienv,
classLoader, classLoader,
&classCount, &classCount,
&classes); &classes);
check_phase_ret_blob(jvmtierror, localArray);
errorOccurred = (jvmtierror != JVMTI_ERROR_NONE); errorOccurred = (jvmtierror != JVMTI_ERROR_NONE);
jplis_assert(!errorOccurred); jplis_assert(!errorOccurred);
...@@ -1311,6 +1349,7 @@ getObjectSize(JNIEnv * jnienv, JPLISAgent * agent, jobject objectToSize) { ...@@ -1311,6 +1349,7 @@ getObjectSize(JNIEnv * jnienv, JPLISAgent * agent, jobject objectToSize) {
jvmtiError jvmtierror = JVMTI_ERROR_NONE; jvmtiError jvmtierror = JVMTI_ERROR_NONE;
jvmtierror = (*jvmtienv)->GetObjectSize(jvmtienv, objectToSize, &objectSize); jvmtierror = (*jvmtienv)->GetObjectSize(jvmtienv, objectToSize, &objectSize);
check_phase_ret_0(jvmtierror);
jplis_assert(jvmtierror == JVMTI_ERROR_NONE); jplis_assert(jvmtierror == JVMTI_ERROR_NONE);
if ( jvmtierror != JVMTI_ERROR_NONE ) { if ( jvmtierror != JVMTI_ERROR_NONE ) {
createAndThrowThrowableFromJVMTIErrorCode(jnienv, jvmtierror); createAndThrowThrowableFromJVMTIErrorCode(jnienv, jvmtierror);
...@@ -1360,6 +1399,7 @@ appendToClassLoaderSearch(JNIEnv * jnienv, JPLISAgent * agent, jstring jarFile, ...@@ -1360,6 +1399,7 @@ appendToClassLoaderSearch(JNIEnv * jnienv, JPLISAgent * agent, jstring jarFile,
} else { } else {
jvmtierror = (*jvmtienv)->AddToSystemClassLoaderSearch(jvmtienv, platformChars); jvmtierror = (*jvmtienv)->AddToSystemClassLoaderSearch(jvmtienv, platformChars);
} }
check_phase_ret(jvmtierror);
if ( jvmtierror != JVMTI_ERROR_NONE ) { if ( jvmtierror != JVMTI_ERROR_NONE ) {
createAndThrowThrowableFromJVMTIErrorCode(jnienv, jvmtierror); createAndThrowThrowableFromJVMTIErrorCode(jnienv, jvmtierror);
...@@ -1450,6 +1490,7 @@ setNativeMethodPrefixes(JNIEnv * jnienv, JPLISAgent * agent, jobjectArray prefix ...@@ -1450,6 +1490,7 @@ setNativeMethodPrefixes(JNIEnv * jnienv, JPLISAgent * agent, jobjectArray prefix
} }
err = (*jvmtienv)->SetNativeMethodPrefixes(jvmtienv, inx, (char**)prefixes); err = (*jvmtienv)->SetNativeMethodPrefixes(jvmtienv, inx, (char**)prefixes);
/* can be called from any phase */
jplis_assert(err == JVMTI_ERROR_NONE); jplis_assert(err == JVMTI_ERROR_NONE);
for (i = 0; i < inx; i++) { for (i = 0; i < inx; i++) {
......
...@@ -266,6 +266,48 @@ setNativeMethodPrefixes(JNIEnv * jnienv, JPLISAgent * agent, jobjectArray prefix ...@@ -266,6 +266,48 @@ setNativeMethodPrefixes(JNIEnv * jnienv, JPLISAgent * agent, jobjectArray prefix
#define jvmti(a) a->mNormalEnvironment.mJVMTIEnv #define jvmti(a) a->mNormalEnvironment.mJVMTIEnv
/*
* A set of macros for insulating the JLI method callers from
* JVMTI_ERROR_WRONG_PHASE return codes.
*/
/* for a JLI method where "blob" is executed before simply returning */
#define check_phase_blob_ret(ret, blob) \
if ((ret) == JVMTI_ERROR_WRONG_PHASE) { \
blob; \
return; \
}
/* for a JLI method where simply returning is benign */
#define check_phase_ret(ret) \
if ((ret) == JVMTI_ERROR_WRONG_PHASE) { \
return; \
}
/* for a JLI method where returning zero (0) is benign */
#define check_phase_ret_0(ret) \
if ((ret) == JVMTI_ERROR_WRONG_PHASE) { \
return 0; \
}
/* for a JLI method where returning one (1) is benign */
#define check_phase_ret_1(ret) \
if ((ret) == JVMTI_ERROR_WRONG_PHASE) { \
return 1; \
}
/* for a case where a specific "blob" must be returned */
#define check_phase_ret_blob(ret, blob) \
if ((ret) == JVMTI_ERROR_WRONG_PHASE) { \
return (blob); \
}
/* for a JLI method where returning false is benign */
#define check_phase_ret_false(ret) \
if ((ret) == JVMTI_ERROR_WRONG_PHASE) { \
return (jboolean) 0; \
}
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */
#endif /* __cplusplus */ #endif /* __cplusplus */
......
...@@ -23,6 +23,14 @@ ...@@ -23,6 +23,14 @@
* have any questions. * have any questions.
*/ */
#ifdef _WIN32
/*
* Win* needs this include. However, Linux and Solaris do not.
* Having this include on Solaris SPARC breaks having non US-ASCII
* characters in the value of the Premain-Class attribute.
*/
#include <ctype.h>
#endif /* _WIN32 */
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
...@@ -45,11 +53,37 @@ doAttribute(const char* name, const char* value, void* user_data) { ...@@ -45,11 +53,37 @@ doAttribute(const char* name, const char* value, void* user_data) {
if (attribute->name == NULL) { if (attribute->name == NULL) {
free(attribute); free(attribute);
} else { } else {
attribute->value = strdup(value); char *begin = (char *)value;
char *end;
size_t value_len;
/* skip any leading white space */
while (isspace(*begin)) {
begin++;
}
/* skip any trailing white space */
end = &begin[strlen(begin)];
while (end > begin && isspace(end[-1])) {
end--;
}
if (begin == end) {
/* no value so skip this attribute */
free(attribute->name);
free(attribute);
return;
}
value_len = (size_t)(end - begin);
attribute->value = malloc(value_len + 1);
if (attribute->value == NULL) { if (attribute->value == NULL) {
free(attribute->name); free(attribute->name);
free(attribute); free(attribute);
} else { } else {
/* save the value without leading or trailing whitespace */
strncpy(attribute->value, begin, value_len);
attribute->value[value_len] = '\0';
attribute->next = NULL; attribute->next = NULL;
if (context->head == NULL) { if (context->head == NULL) {
context->head = attribute; context->head = attribute;
......
...@@ -74,6 +74,7 @@ confirmingTLSSet( jvmtiEnv * jvmtienv, ...@@ -74,6 +74,7 @@ confirmingTLSSet( jvmtiEnv * jvmtienv,
jvmtienv, jvmtienv,
thread, thread,
newValue); newValue);
check_phase_ret_blob(error, error);
#if JPLISASSERT_ENABLEASSERTIONS #if JPLISASSERT_ENABLEASSERTIONS
assertTLSValue( jvmtienv, assertTLSValue( jvmtienv,
...@@ -96,6 +97,7 @@ assertTLSValue( jvmtiEnv * jvmtienv, ...@@ -96,6 +97,7 @@ assertTLSValue( jvmtiEnv * jvmtienv,
jvmtienv, jvmtienv,
thread, thread,
&test); &test);
check_phase_ret(error);
jplis_assert(error == JVMTI_ERROR_NONE); jplis_assert(error == JVMTI_ERROR_NONE);
jplis_assert(test == expected); jplis_assert(test == expected);
} }
...@@ -111,6 +113,7 @@ tryToAcquireReentrancyToken( jvmtiEnv * jvmtienv, ...@@ -111,6 +113,7 @@ tryToAcquireReentrancyToken( jvmtiEnv * jvmtienv,
jvmtienv, jvmtienv,
thread, thread,
&storedValue); &storedValue);
check_phase_ret_false(error);
jplis_assert(error == JVMTI_ERROR_NONE); jplis_assert(error == JVMTI_ERROR_NONE);
if ( error == JVMTI_ERROR_NONE ) { if ( error == JVMTI_ERROR_NONE ) {
/* if this thread is already inside, just return false and short-circuit */ /* if this thread is already inside, just return false and short-circuit */
......
...@@ -46,6 +46,7 @@ allocate(jvmtiEnv * jvmtienv, size_t bytecount) { ...@@ -46,6 +46,7 @@ allocate(jvmtiEnv * jvmtienv, size_t bytecount) {
error = (*jvmtienv)->Allocate(jvmtienv, error = (*jvmtienv)->Allocate(jvmtienv,
bytecount, bytecount,
(unsigned char**) &resultBuffer); (unsigned char**) &resultBuffer);
/* may be called from any phase */
jplis_assert(error == JVMTI_ERROR_NONE); jplis_assert(error == JVMTI_ERROR_NONE);
if ( error != JVMTI_ERROR_NONE ) { if ( error != JVMTI_ERROR_NONE ) {
resultBuffer = NULL; resultBuffer = NULL;
...@@ -66,6 +67,7 @@ deallocate(jvmtiEnv * jvmtienv, void * buffer) { ...@@ -66,6 +67,7 @@ deallocate(jvmtiEnv * jvmtienv, void * buffer) {
error = (*jvmtienv)->Deallocate(jvmtienv, error = (*jvmtienv)->Deallocate(jvmtienv,
(unsigned char*)buffer); (unsigned char*)buffer);
/* may be called from any phase */
jplis_assert_msg(error == JVMTI_ERROR_NONE, "Can't deallocate memory"); jplis_assert_msg(error == JVMTI_ERROR_NONE, "Can't deallocate memory");
return; return;
} }
......
...@@ -123,7 +123,10 @@ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_connect ...@@ -123,7 +123,10 @@ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_connect
C_GetFunctionList = (CK_C_GetFunctionList) dlsym(hModule, getFunctionListStr); C_GetFunctionList = (CK_C_GetFunctionList) dlsym(hModule, getFunctionListStr);
(*env)->ReleaseStringUTFChars(env, jGetFunctionList, getFunctionListStr); (*env)->ReleaseStringUTFChars(env, jGetFunctionList, getFunctionListStr);
} }
if ((C_GetFunctionList == NULL) || ((systemErrorMessage = dlerror()) != NULL)){ if (C_GetFunctionList == NULL) {
throwIOException(env, "ERROR: C_GetFunctionList == NULL");
return;
} else if ( (systemErrorMessage = dlerror()) != NULL ){
throwIOException(env, systemErrorMessage); throwIOException(env, systemErrorMessage);
return; return;
} }
......
/*
* Copyright 2005 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/*
* @test
* @bug 6658779
* @summary Basic Test for HotSpotDiagnosticMXBean.getDiagnosticOptions()
* @author Daniel Fuchs
*
* @run main GetDiagnosticOptions
*/
import com.sun.management.HotSpotDiagnosticMXBean;
import com.sun.management.VMOption;
import java.lang.management.ManagementFactory;
import java.util.List;
import javax.management.MBeanServer;
public class GetDiagnosticOptions {
private static String HOTSPOT_DIAGNOSTIC_MXBEAN_NAME =
"com.sun.management:type=HotSpotDiagnostic";
public static void main(String[] args) throws Exception {
HotSpotDiagnosticMXBean mbean =
sun.management.ManagementFactory.getDiagnosticMXBean();
checkDiagnosticOptions(mbean);
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
mbean = ManagementFactory.newPlatformMXBeanProxy(mbs,
HOTSPOT_DIAGNOSTIC_MXBEAN_NAME,
HotSpotDiagnosticMXBean.class);
checkDiagnosticOptions(mbean);
}
private static void checkDiagnosticOptions(HotSpotDiagnosticMXBean mbean) {
List<VMOption> options = mbean.getDiagnosticOptions();
for (VMOption opt : options) {
System.out.println("option: "+opt.getName()+"="+opt.getValue());
}
}
}
...@@ -23,8 +23,10 @@ ...@@ -23,8 +23,10 @@
# @test # @test
# @bug 5055293 # @bug 5055293
# @summary Test non US-ASCII characters in the value of the Boot-Class-Path # @summary Test non US-ASCII characters in the value of the Boot-Class-Path
# attribute. # attribute.
#
# @run shell/timeout=240 BootClassPathTest.sh
if [ "${TESTJAVA}" = "" ] if [ "${TESTJAVA}" = "" ]
then then
...@@ -72,7 +74,7 @@ echo "Creating agent jar file..." ...@@ -72,7 +74,7 @@ echo "Creating agent jar file..."
echo "Running test..." echo "Running test..."
"${JAVA}" -javaagent:"${TESTCLASSES}"/Agent.jar -classpath "${TESTCLASSES}" DummyMain "${JAVA}" ${TESTVMOPTS} -javaagent:"${TESTCLASSES}"/Agent.jar -classpath "${TESTCLASSES}" DummyMain
result=$? result=$?
echo "Cleanup..." echo "Cleanup..."
......
...@@ -70,9 +70,11 @@ JAR="${TESTJAVA}/bin/jar" ...@@ -70,9 +70,11 @@ JAR="${TESTJAVA}/bin/jar"
cp ${TESTSRC}/${AGENT}.java . cp ${TESTSRC}/${AGENT}.java .
cp ${TESTSRC}/${APP}.java . cp ${TESTSRC}/${APP}.java .
rm -rf ilib rm -rf ilib
cp -r ${TESTSRC}/ilib . mkdir ilib
mkdir bootpath cp ${TESTSRC}/ilib/*.java ilib
cp -r ${TESTSRC}/bootreporter bootpath rm -rf bootpath
mkdir -p bootpath/bootreporter
cp ${TESTSRC}/bootreporter/*.java bootpath/bootreporter
cd bootpath cd bootpath
${JAVAC} bootreporter/*.java ${JAVAC} bootreporter/*.java
......
#
# Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
# CA 95054 USA or visit www.sun.com if you need additional information or
# have any questions.
#
# @test
# @bug 6274276
# @summary JLI JAR manifest processing should ignore leading and trailing white space.
# @author Daniel D. Daugherty
#
# @run build ManifestTestApp
# @run shell/timeout=900 ManifestTest.sh
#
make_a_JAR() {
# version_line and premain_line are required
version_line="Manifest-Version: 1.0"
premain_line="Premain-Class: ${AGENT}"
boot_cp_line=""
expect_boot_cp_line="ExampleForBootClassPath was not loaded."
can_redef_line=""
expect_redef_line="isRedefineClassesSupported()=false"
can_retrans_line=""
expect_retrans_line="isRetransformClassesSupported()=false"
can_set_nmp_line=""
expect_set_nmp_line="isNativeMethodPrefixSupported()=false"
while [ $# != 0 ] ; do
case "$1" in
defaults)
# just use the defaults for the test
;;
boot_cp_line1)
boot_cp_line="Boot-Class-Path: no_white_space"
expect_boot_cp_line="ExampleForBootClassPath was loaded."
mkdir -p no_white_space
cp -p $OUT_OF_THE_WAY/ExampleForBootClassPath.class no_white_space
;;
boot_cp_line2)
boot_cp_line="Boot-Class-Path: has_leading_blank"
expect_boot_cp_line="ExampleForBootClassPath was loaded."
mkdir -p has_leading_blank " has_leading_blank"
# the good class is in the directory without the blank
cp -p $OUT_OF_THE_WAY/ExampleForBootClassPath.class \
has_leading_blank
# the bad class is in the directory with the blank
cp -p $OUT_OF_THE_WAY/ExampleForBootClassPath.class.bad \
" has_leading_blank"/ExampleForBootClassPath.class
;;
boot_cp_line3)
boot_cp_line="Boot-Class-Path: has_trailing_blank "
expect_boot_cp_line="ExampleForBootClassPath was loaded."
mkdir -p has_trailing_blank "has_trailing_blank "
# the good class is in the directory without the blank
cp -p $OUT_OF_THE_WAY/ExampleForBootClassPath.class \
has_trailing_blank
# the bad class is in the directory with the blank
cp -p $OUT_OF_THE_WAY/ExampleForBootClassPath.class.bad \
"has_trailing_blank "/ExampleForBootClassPath.class
;;
boot_cp_line4)
boot_cp_line="Boot-Class-Path: has_leading_and_trailing_blank "
expect_boot_cp_line="ExampleForBootClassPath was loaded."
mkdir -p has_leading_and_trailing_blank \
" has_leading_and_trailing_blank "
# the good class is in the directory without the blanks
cp -p $OUT_OF_THE_WAY/ExampleForBootClassPath.class \
has_leading_and_trailing_blank
# the bad class is in the directory with the blanks
cp -p $OUT_OF_THE_WAY/ExampleForBootClassPath.class.bad \
" has_leading_and_trailing_blank "/ExampleForBootClassPath.class
;;
boot_cp_line5)
boot_cp_line="Boot-Class-Path: has_embedded blank"
expect_boot_cp_line="ExampleForBootClassPath was loaded."
mkdir -p has_embedded "has_embedded blank"
# the good class is in the first blank separated word
cp -p $OUT_OF_THE_WAY/ExampleForBootClassPath.class has_embedded
# the bad class is in the directory with the blank
cp -p $OUT_OF_THE_WAY/ExampleForBootClassPath.class.bad \
"has_embedded blank"/ExampleForBootClassPath.class
;;
can_redef_line1)
can_redef_line="Can-Redefine-Classes: true"
expect_redef_line="isRedefineClassesSupported()=true"
;;
can_redef_line2)
can_redef_line="Can-Redefine-Classes: true"
expect_redef_line="isRedefineClassesSupported()=true"
;;
can_redef_line3)
can_redef_line="Can-Redefine-Classes: true "
expect_redef_line="isRedefineClassesSupported()=true"
;;
can_redef_line4)
can_redef_line="Can-Redefine-Classes: true "
expect_redef_line="isRedefineClassesSupported()=true"
;;
can_redef_line5)
can_redef_line="Can-Redefine-Classes: false"
;;
can_redef_line6)
can_redef_line="Can-Redefine-Classes: false"
;;
can_redef_line7)
can_redef_line="Can-Redefine-Classes: false "
;;
can_redef_line8)
can_redef_line="Can-Redefine-Classes: false "
;;
can_redef_line9)
# this line makes the jar command unhappy and that's
# not what we're testing so skip this case
can_redef_line="Can-Redefine-Classes:"
;;
can_redef_line10)
can_redef_line="Can-Redefine-Classes: "
;;
can_redef_line11)
can_redef_line="Can-Redefine-Classes: "
;;
can_retrans_line1)
can_retrans_line="Can-Retransform-Classes: true"
expect_retrans_line="isRetransformClassesSupported()=true"
;;
can_retrans_line2)
can_retrans_line="Can-Retransform-Classes: true"
expect_retrans_line="isRetransformClassesSupported()=true"
;;
can_retrans_line3)
can_retrans_line="Can-Retransform-Classes: true "
expect_retrans_line="isRetransformClassesSupported()=true"
;;
can_retrans_line4)
can_retrans_line="Can-Retransform-Classes: true "
expect_retrans_line="isRetransformClassesSupported()=true"
;;
can_retrans_line5)
can_retrans_line="Can-Retransform-Classes: false"
;;
can_retrans_line6)
can_retrans_line="Can-Retransform-Classes: false"
;;
can_retrans_line7)
can_retrans_line="Can-Retransform-Classes: false "
;;
can_retrans_line8)
can_retrans_line="Can-Retransform-Classes: false "
;;
can_retrans_line9)
# this line makes the jar command unhappy and that's
# not what we're testing so skip this case
can_retrans_line="Can-Retransform-Classes:"
;;
can_retrans_line10)
can_retrans_line="Can-Retransform-Classes: "
;;
can_retrans_line11)
can_retrans_line="Can-Retransform-Classes: "
;;
can_set_nmp_line1)
can_set_nmp_line="Can-Set-Native-Method-Prefix: true"
expect_set_nmp_line="isNativeMethodPrefixSupported()=true"
;;
can_set_nmp_line2)
can_set_nmp_line="Can-Set-Native-Method-Prefix: true"
expect_set_nmp_line="isNativeMethodPrefixSupported()=true"
;;
can_set_nmp_line3)
can_set_nmp_line="Can-Set-Native-Method-Prefix: true "
expect_set_nmp_line="isNativeMethodPrefixSupported()=true"
;;
can_set_nmp_line4)
can_set_nmp_line="Can-Set-Native-Method-Prefix: true "
expect_set_nmp_line="isNativeMethodPrefixSupported()=true"
;;
can_set_nmp_line5)
can_set_nmp_line="Can-Set-Native-Method-Prefix: false"
;;
can_set_nmp_line6)
can_set_nmp_line="Can-Set-Native-Method-Prefix: false"
;;
can_set_nmp_line7)
can_set_nmp_line="Can-Set-Native-Method-Prefix: false "
;;
can_set_nmp_line8)
can_set_nmp_line="Can-Set-Native-Method-Prefix: false "
;;
can_set_nmp_line9)
# this line makes the jar command unhappy and that's
# not what we're testing so skip this case
can_set_nmp_line="Can-Set-Native-Method-Prefix:"
;;
can_set_nmp_line10)
can_set_nmp_line="Can-Set-Native-Method-Prefix: "
;;
can_set_nmp_line11)
can_set_nmp_line="Can-Set-Native-Method-Prefix: "
;;
premain_line1)
premain_line="Premain-Class: ${AGENT}"
;;
premain_line2)
premain_line="Premain-Class: ${AGENT} "
;;
premain_line3)
premain_line="Premain-Class: ${AGENT} "
;;
version_line1)
version_line="Manifest-Version: 1.0"
;;
version_line2)
version_line="Manifest-Version: 1.0 "
;;
version_line3)
version_line="Manifest-Version: 1.0 "
;;
*)
echo "ERROR: invalid test token"
exit 1
esac
shift
done
echo "${version_line}" > ${AGENT}.mf
echo "${premain_line}" >> ${AGENT}.mf
if [ -n "$boot_cp_line" ]; then
echo "${boot_cp_line}" >> ${AGENT}.mf
fi
if [ -n "$can_redef_line" ]; then
echo "${can_redef_line}" >> ${AGENT}.mf
fi
if [ -n "$can_retrans_line" ]; then
echo "${can_retrans_line}" >> ${AGENT}.mf
fi
if [ -n "$can_set_nmp_line" ]; then
echo "${can_set_nmp_line}" >> ${AGENT}.mf
fi
rm -f ${AGENT}.jar
${JAR} cvfm ${AGENT}.jar ${AGENT}.mf ${AGENT}.class
echo "$expect_boot_cp_line" > expect_boot_cp_line
echo "$expect_redef_line" > expect_redef_line
echo "$expect_retrans_line" > expect_retrans_line
echo "$expect_set_nmp_line" > expect_set_nmp_line
}
if [ "${TESTJAVA}" = "" ]
then
echo "TESTJAVA not set. Test cannot execute. Failed."
exit 1
fi
if [ "${TESTSRC}" = "" ]
then
echo "TESTSRC not set. Test cannot execute. Failed."
exit 1
fi
if [ "${TESTCLASSES}" = "" ]
then
echo "TESTCLASSES not set. Test cannot execute. Failed."
exit 1
fi
JAR="${TESTJAVA}/bin/jar"
JAVAC="${TESTJAVA}"/bin/javac
JAVA="${TESTJAVA}"/bin/java
# Now that ManifestTestApp.class is built, we move
# ExampleForBootClassPath.class so that it cannot be found
# by default
OUT_OF_THE_WAY=out_of_the_way
mkdir $OUT_OF_THE_WAY
mv "${TESTCLASSES}/ExampleForBootClassPath.class" $OUT_OF_THE_WAY
# create a bad version of ExampleForBootClassPath.class
# so we can tell when the wrong version is run
sed 's/return 15/return 42/' "${TESTSRC}"/ExampleForBootClassPath.java \
> ExampleForBootClassPath.java
"$JAVAC" ExampleForBootClassPath.java
mv ExampleForBootClassPath.class \
$OUT_OF_THE_WAY/ExampleForBootClassPath.class.bad
mv ExampleForBootClassPath.java \
$OUT_OF_THE_WAY/ExampleForBootClassPath.java.bad
AGENT=ManifestTestAgent
# We compile the agent in the working directory instead of with
# a build task because we construct a different agent JAR file
# for each test case.
${JAVAC} -d . ${TESTSRC}/${AGENT}.java
FAIL_MARKER=fail_marker
rm -f $FAIL_MARKER
while read token; do
echo
echo "===== begin test case: $token ====="
make_a_JAR "$token"
"${JAVA}" ${TESTVMOPTS} -javaagent:${AGENT}.jar \
-classpath "${TESTCLASSES}" ManifestTestApp > output.log 2>&1
result=$?
cat output.log
if [ "$result" = 0 ]; then
echo "PASS: ManifestTestApp exited with status of 0."
else
echo "FAIL: ManifestTestApp exited with status of $result"
touch $FAIL_MARKER
fi
MESG="Hello from ${AGENT}!"
grep -s "$MESG" output.log > /dev/null
result=$?
if [ "$result" = 0 ]; then
echo "PASS: found '$MESG' in the test output"
else
echo "FAIL: did NOT find '$MESG' in the test output"
touch $FAIL_MARKER
fi
MESG=`cat expect_boot_cp_line`
grep -s "$MESG" output.log > /dev/null
result=$?
if [ "$result" = 0 ]; then
echo "PASS: found '$MESG' in the test output"
else
echo "FAIL: did NOT find '$MESG' in the test output"
touch $FAIL_MARKER
fi
MESG=`cat expect_redef_line`
grep -s "$MESG" output.log > /dev/null
result=$?
if [ "$result" = 0 ]; then
echo "PASS: found '$MESG' in the test output"
else
echo "FAIL: did NOT find '$MESG' in the test output"
touch $FAIL_MARKER
fi
MESG=`cat expect_retrans_line`
grep -s "$MESG" output.log > /dev/null
result=$?
if [ "$result" = 0 ]; then
echo "PASS: found '$MESG' in the test output"
else
echo "FAIL: did NOT find '$MESG' in the test output"
touch $FAIL_MARKER
fi
MESG=`cat expect_set_nmp_line`
grep -s "$MESG" output.log > /dev/null
result=$?
if [ "$result" = 0 ]; then
echo "PASS: found '$MESG' in the test output"
else
echo "FAIL: did NOT find '$MESG' in the test output"
touch $FAIL_MARKER
fi
echo "===== end test case: $token ====="
echo
done << EOF
defaults
version_line1
version_line2
version_line3
premain_line1
premain_line2
premain_line3
boot_cp_line1
boot_cp_line2
boot_cp_line3
boot_cp_line4
boot_cp_line5
can_redef_line1
can_redef_line2
can_redef_line3
can_redef_line4
can_redef_line5
can_redef_line6
can_redef_line7
can_redef_line8
can_redef_line10
can_redef_line11
can_retrans_line1
can_retrans_line2
can_retrans_line3
can_retrans_line4
can_retrans_line5
can_retrans_line6
can_retrans_line7
can_retrans_line8
can_retrans_line10
can_retrans_line11
can_set_nmp_line1
can_set_nmp_line2
can_set_nmp_line3
can_set_nmp_line4
can_set_nmp_line5
can_set_nmp_line6
can_set_nmp_line7
can_set_nmp_line8
can_set_nmp_line10
can_set_nmp_line11
EOF
if [ -f $FAIL_MARKER ]; then
exit 1
else
exit 0
fi
/*
* Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
import java.lang.instrument.Instrumentation;
public class ManifestTestAgent {
private static Instrumentation instrumentation;
private ManifestTestAgent() {
}
public static void premain(String agentArgs, Instrumentation inst) {
System.out.println("Hello from ManifestTestAgent!");
System.out.println("isNativeMethodPrefixSupported()=" +
inst.isNativeMethodPrefixSupported());
System.out.println("isRedefineClassesSupported()=" +
inst.isRedefineClassesSupported());
System.out.println("isRetransformClassesSupported()=" +
inst.isRetransformClassesSupported());
}
}
/*
* Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
public class ManifestTestApp {
public static void main(String args[]) {
System.out.println("Hello from ManifestTestApp!");
new ManifestTestApp().doTest();
System.exit(0);
}
private void doTest() {
try {
// load the class only found via the Boot-Class-Path attribute
Object instance = loadExampleClass();
if (instance.getClass().getClassLoader() == null) {
System.out.println("PASS: ExampleForBootClassPath was loaded" +
" by the boot class path loader.");
} else {
System.out.println("FAIL: ExampleForBootClassPath was loaded" +
" by a non-boot class path loader.");
System.exit(1);
}
} catch (NoClassDefFoundError ncdfe) {
// This message just lets ManifestTest.sh know whether or
// not ExampleForBootClassPath was loaded. Depending on
// the current test case, that will be either a PASSing
// condition or a FAILing condition as determined by
// ManifestTest.sh.
System.out.println("ExampleForBootClassPath was not loaded.");
}
}
Object loadExampleClass() {
ExampleForBootClassPath instance = new ExampleForBootClassPath();
System.out.println("ExampleForBootClassPath was loaded.");
if (instance.fifteen() == 15) {
System.out.println("PASS: the correct" +
" ExampleForBootClassPath was loaded.");
} else {
System.out.println("FAIL: the wrong ExampleForBootClassPath" +
" was loaded.");
System.out.println("FAIL: instance.fifteen()=" +
instance.fifteen());
System.exit(1);
}
return instance;
}
}
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
* @summary test setNativeMethodPrefix * @summary test setNativeMethodPrefix
* @author Robert Field, Sun Microsystems * @author Robert Field, Sun Microsystems
* *
* @run shell MakeJAR2.sh NativeMethodPrefixAgent NativeMethodPrefixApp 'Can-Retransform-Classes: true' 'Can-Set-Native-Method-Prefix: true' * @run shell/timeout=240 MakeJAR2.sh NativeMethodPrefixAgent NativeMethodPrefixApp 'Can-Retransform-Classes: true' 'Can-Set-Native-Method-Prefix: true'
* @run main/othervm -javaagent:NativeMethodPrefixAgent.jar NativeMethodPrefixApp * @run main/othervm -javaagent:NativeMethodPrefixAgent.jar NativeMethodPrefixApp
*/ */
......
#
# Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
# CA 95054 USA or visit www.sun.com if you need additional information or
# have any questions.
#
# @test
# @bug 5088398
# @summary Test parallel class loading by parallel transformers.
# @author Daniel D. Daugherty as modified from the code of Daryl Puryear @ Wily
#
# @run shell MakeJAR3.sh ParallelTransformerLoaderAgent
# @run build ParallelTransformerLoaderApp
# @run shell/timeout=240 ParallelTransformerLoader.sh
#
if [ "${TESTJAVA}" = "" ]
then
echo "TESTJAVA not set. Test cannot execute. Failed."
exit 1
fi
if [ "${TESTSRC}" = "" ]
then
echo "TESTSRC not set. Test cannot execute. Failed."
exit 1
fi
if [ "${TESTCLASSES}" = "" ]
then
echo "TESTCLASSES not set. Test cannot execute. Failed."
exit 1
fi
JAR="${TESTJAVA}"/bin/jar
JAVAC="${TESTJAVA}"/bin/javac
JAVA="${TESTJAVA}"/bin/java
"${JAVAC}" -d . \
"${TESTSRC}"/TestClass1.java \
"${TESTSRC}"/TestClass2.java \
"${TESTSRC}"/TestClass3.java
"${JAR}" cvf Test.jar Test*.class
# Removing the test class files is important. If these
# .class files are available on the classpath other
# than via Test.jar, then the deadlock will not reproduce.
rm -f Test*.class
"${JAVA}" ${TESTVMOPTS} -javaagent:ParallelTransformerLoaderAgent.jar=Test.jar \
-classpath "${TESTCLASSES}" ParallelTransformerLoaderApp
result=$?
echo "result=$result"
exit $result
/*
* Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
import java.lang.instrument.*;
import java.net.*;
import java.io.*;
import java.security.*;
/**
* Test Java Agent
*
* @author Daryl Puryear
* @copyright 1999-2004 Wily Technology, Inc. All rights reserved.
*/
public class ParallelTransformerLoaderAgent
{
private static URL sURL;
private static ClassLoader sClassLoader;
public static synchronized ClassLoader
getClassLoader()
{
return sClassLoader;
}
public static synchronized void
generateNewClassLoader()
{
sClassLoader = new URLClassLoader(new URL[] {sURL});
}
public static void
premain( String agentArgs,
Instrumentation instrumentation)
throws Exception
{
if (agentArgs == null || agentArgs == "")
{
System.err.println("Error: No jar file name provided, test will not run.");
return;
}
sURL = (new File(agentArgs)).toURL();
System.out.println("Using jar file: " + sURL);
generateNewClassLoader();
instrumentation.addTransformer(new TestTransformer());
}
private static class TestTransformer
implements ClassFileTransformer
{
public byte[]
transform( ClassLoader loader,
String className,
Class classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer)
throws IllegalClassFormatException
{
String tName = Thread.currentThread().getName();
// In 160_03 and older, transform() is called
// with the "system_loader_lock" held and that
// prevents the bootstrap class loaded from
// running in parallel. If we add a slight sleep
// delay here when the transform() call is not
// main or TestThread, then the deadlock in
// 160_03 and older is much more reproducible.
if (!tName.equals("main") && !tName.equals("TestThread")) {
System.out.println("Thread '" + tName +
"' has called transform()");
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
}
}
// load additional classes when called from other threads
if (!tName.equals("main"))
{
loadClasses(3);
}
return null;
}
public static void
loadClasses( int index)
{
ClassLoader loader = ParallelTransformerLoaderAgent.getClassLoader();
try
{
Class.forName("TestClass" + index, true, loader);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
}
/*
* Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/**
* Test Java Program
*
* @author Daryl Puryear
* @copyright 1999-2004 Wily Technology, Inc. All rights reserved.
*/
public class ParallelTransformerLoaderApp
{
private static final int kNumIterations = 1000;
public static void
main( String[] args)
throws Exception
{
System.out.println();
System.out.print("Starting test with " + kNumIterations + " iterations");
for (int i = 0; i < kNumIterations; i++)
{
// load some classes from multiple threads (this thread and one other)
Thread testThread = new TestThread(2);
testThread.start();
loadClasses(1);
// log that it completed and reset for the next iteration
testThread.join();
System.out.print(".");
ParallelTransformerLoaderAgent.generateNewClassLoader();
}
System.out.println();
System.out.println("Test completed successfully");
}
private static class TestThread
extends Thread
{
private final int fIndex;
public
TestThread( int index)
{
super("TestThread");
fIndex = index;
}
public void
run()
{
loadClasses(fIndex);
}
}
public static void
loadClasses( int index)
{
ClassLoader loader = ParallelTransformerLoaderAgent.getClassLoader();
try
{
Class.forName("TestClass" + index, true, loader);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
...@@ -22,11 +22,10 @@ ...@@ -22,11 +22,10 @@
*/ */
/* /*
* * dummy "Hello World"ish application for "premain" tests
*
* Used by PremainClassTest.sh - dummy "main application" which doesn't do anything
*/ */
public class DummyMain { public class DummyMain {
public static void main(String[] args) { public static void main(String[] args) {
System.out.println("Hello from DummyMain!");
} }
} }
/*
* Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/**
* @test
* @bug 6289149
* @summary test config (0,0,0,1): declared 1-arg in agent class
* @author Daniel D. Daugherty, Sun Microsystems
*
* @run shell ../MakeJAR3.sh InheritAgent0001
* @run main/othervm -javaagent:InheritAgent0001.jar DummyMain
*/
import java.lang.instrument.*;
class InheritAgent0001 extends InheritAgent0001Super {
//
// This agent has a single argument premain() method which
// is the one that should be called.
//
public static void premain (String agentArgs) {
System.out.println("Hello from Single-Arg InheritAgent0001!");
}
// This agent does NOT have a double argument premain() method.
}
class InheritAgent0001Super {
// This agent does NOT have a single argument premain() method.
// This agent does NOT have a double argument premain() method.
}
/*
* Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/**
* @test
* @bug 6289149
* @summary test config (0,0,1,0): declared 2-arg in agent class
* @author Daniel D. Daugherty, Sun Microsystems
*
* @run shell ../MakeJAR3.sh InheritAgent0010
* @run main/othervm -javaagent:InheritAgent0010.jar DummyMain
*/
import java.lang.instrument.*;
class InheritAgent0010 extends InheritAgent0010Super {
// This agent does NOT have a single argument premain() method.
//
// This agent has a double argument premain() method which
// is the one that should be called.
//
public static void premain (String agentArgs, Instrumentation instArg) {
System.out.println("Hello from Double-Arg InheritAgent0010!");
}
}
class InheritAgent0010Super {
// This agent does NOT have a single argument premain() method.
// This agent does NOT have a double argument premain() method.
}
/*
* Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/**
* @test
* @bug 6289149
* @summary test config (0,0,1,1): declared 2-arg and declared 1-arg in agent class
* @author Daniel D. Daugherty, Sun Microsystems
*
* @run shell ../MakeJAR3.sh InheritAgent0011
* @run main/othervm -javaagent:InheritAgent0011.jar DummyMain
*/
import java.lang.instrument.*;
class InheritAgent0011 extends InheritAgent0011Super {
//
// This agent has a single argument premain() method which
// is NOT the one that should be called.
//
public static void premain (String agentArgs) {
System.out.println("Hello from Single-Arg InheritAgent0011!");
throw new Error("ERROR: THIS AGENT SHOULD NOT HAVE BEEN CALLED.");
}
//
// This agent has a double argument premain() method which
// is the one that should be called.
//
public static void premain (String agentArgs, Instrumentation instArg) {
System.out.println("Hello from Double-Arg InheritAgent0011!");
}
}
class InheritAgent0011Super {
// This agent does NOT have a single argument premain() method.
// This agent does NOT have a double argument premain() method.
}
/*
* Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/**
* @test
* @bug 6289149
* @summary test config (0,1,0,0): inherited 1-arg in agent class
* @author Daniel D. Daugherty, Sun Microsystems
*
* @run shell ../MakeJAR3.sh InheritAgent0100
* @run main/othervm -javaagent:InheritAgent0100.jar DummyMain
*/
import java.lang.instrument.*;
class InheritAgent0100 extends InheritAgent0100Super {
// This agent does NOT have a single argument premain() method.
// This agent does NOT have a double argument premain() method.
}
class InheritAgent0100Super {
//
// This agent has a single argument premain() method which
// is the one that should be called.
//
public static void premain (String agentArgs) {
System.out.println("Hello from Single-Arg InheritAgent0100Super!");
}
// This agent does NOT have a double argument premain() method.
}
/*
* Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/**
* @test
* @bug 6289149
* @summary test config (0,1,0,1): inherited 1-arg and declared 1-arg in agent class
* @author Daniel D. Daugherty, Sun Microsystems
*
* @run shell ../MakeJAR3.sh InheritAgent0101
* @run main/othervm -javaagent:InheritAgent0101.jar DummyMain
*/
import java.lang.instrument.*;
class InheritAgent0101 extends InheritAgent0101Super {
//
// This agent has a single argument premain() method which
// is the one that should be called.
//
public static void premain (String agentArgs) {
System.out.println("Hello from Single-Arg InheritAgent0101!");
}
// This agent does NOT have a double argument premain() method.
}
class InheritAgent0101Super {
//
// This agent has a single argument premain() method which
// is NOT the one that should be called.
//
public static void premain (String agentArgs) {
System.out.println("Hello from Single-Arg InheritAgent0101Super!");
throw new Error("ERROR: THIS AGENT SHOULD NOT HAVE BEEN CALLED.");
}
// This agent does NOT have a double argument premain() method.
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册