changeset 13901:b2a69d66dc65 jdk-9+111

8142968: Module System implementation Summary: Initial integration of JEP 200, JEP 260, JEP 261, and JEP 282 Reviewed-by: alanb, mchung, naoto, rriggs, psandoz, plevart, mullan, ascarpino, vinnie, prr, sherman, dfuchs, mhaupt Contributed-by: alan.bateman@oracle.com, alex.buckley@oracle.com, jonathan.gibbons@oracle.com, karen.kinnear@oracle.com, mandy.chung@oracle.com, mark.reinhold@oracle.com, chris.hegarty@oracle.com, alexandr.scherbatiy@oracle.com, amy.lu@oracle.com, calvin.cheung@oracle.com, daniel.fuchs@oracle.com, erik.joelsson@oracle.com, harold.seigel@oracle.com, jaroslav.bachorik@oracle.com, jean-francois.denise@oracle.com, jan.lahoda@oracle.com, james.laskey@oracle.com, lois.foltan@oracle.com, miroslav.kos@oracle.com, huaming.li@oracle.com, sean.mullan@oracle.com, naoto.sato@oracle.com, masayoshi.okutsu@oracle.com, peter.levart@gmail.com, philip.race@oracle.com, claes.redestad@oracle.com, sergey.bylokhov@oracle.com, alexandre.iline@oracle.com, volker.simonis@gmail.com, staffan.larsen@oracle.com, stuart.marks@oracle.com, semyon.sadetsky@oracle.com, serguei.spitsyn@oracle.com, sundararajan.athijegannathan@oracle.com, valerie.peng@oracle.com, vincent.x.ryan@oracle.com, weijun.wang@oracle.com, yuri.nesterenko@oracle.com, yekaterina.kantserova@oracle.com, alexander.kulyakhtin@oracle.com, felix.yang@oracle.com, andrei.eremeev@oracle.com, frank.yuan@oracle.com, sergei.pikalev@oracle.com, sibabrata.sahoo@oracle.com, tiantian.du@oracle.com, sha.jiang@oracle.com
author alanb
date Thu, 17 Mar 2016 19:04:16 +0000
parents edb95a70985f
children 589795e4cd38 fbe70dc61f3b
files make/CompileInterimRmic.gmk make/CompileTools.gmk make/GenerateModuleSummary.gmk make/ModuleTools.gmk make/Tools.gmk make/copy/Copy-java.base.gmk make/data/jdwp/jdwp.spec make/gendata/Gendata-jdk.jdeps.gmk make/gendata/GendataBreakIterator.gmk make/gensrc/Gensrc-java.base.gmk make/gensrc/Gensrc-jdk.dev.gmk make/gensrc/Gensrc-jdk.jdi.gmk make/gensrc/Gensrc-jdk.jlink.gmk make/gensrc/Gensrc-jdk.jvmstat.gmk make/gensrc/GensrcLocaleData.gmk make/gensrc/GensrcModuleLoaderMap.gmk make/launcher/Launcher-java.desktop.gmk make/launcher/Launcher-jdk.dev.gmk make/launcher/Launcher-jdk.jlink.gmk make/launcher/Launcher-jdk.pack200.gmk make/launcher/Launcher-jdk.rmic.gmk make/launcher/LauncherCommon.gmk make/lib/CoreLibraries.gmk make/lib/Lib-java.instrument.gmk make/mapfiles/libjava/mapfile-vers make/mapfiles/libjimage/mapfile-vers make/rmic/Rmic-java.management.gmk make/rmic/RmicCommon.gmk make/scripts/localelist.sh make/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java make/src/classes/build/tools/generatebreakiteratordata/GenerateBreakIteratorData.java make/src/classes/build/tools/jdwpgen/ModuleTypeNode.java make/src/classes/build/tools/jdwpgen/Parse.java make/src/classes/build/tools/jigsaw/GenGraphs.java make/src/classes/build/tools/jigsaw/Graph.java make/src/classes/build/tools/jigsaw/ModuleSummary.java make/src/classes/build/tools/jigsaw/technology-summary.html make/src/classes/build/tools/module/GenJdepsModulesXml.java make/src/classes/build/tools/module/GenModuleInfoSource.java make/src/classes/build/tools/module/GenModuleLoaderMap.java make/src/classes/build/tools/module/GenModulesList.java make/src/classes/build/tools/module/ImageBuilder.java make/src/classes/build/tools/module/Module.java make/src/classes/build/tools/module/ModuleArchive.java make/src/classes/build/tools/module/ModuleInfoReader.java make/src/classes/build/tools/module/boot.modules make/src/classes/build/tools/module/ext.modules src/demo/share/java2d/J2DBench/src/j2dbench/ResultSet.java src/java.base/macosx/classes/module-info.java.extra src/java.base/share/classes/com/sun/java/util/jar/pack/intrinsic.properties src/java.base/share/classes/java/io/ObjectInputStream.java src/java.base/share/classes/java/lang/Class.java src/java.base/share/classes/java/lang/ClassLoader.java src/java.base/share/classes/java/lang/NamedPackage.java src/java.base/share/classes/java/lang/Package.java src/java.base/share/classes/java/lang/StackFrameInfo.java src/java.base/share/classes/java/lang/StackTraceElement.java src/java.base/share/classes/java/lang/StackWalker.java src/java.base/share/classes/java/lang/System.java src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java src/java.base/share/classes/java/lang/invoke/MemberName.java src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java src/java.base/share/classes/java/lang/invoke/MethodHandles.java src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java src/java.base/share/classes/java/lang/module/Configuration.java src/java.base/share/classes/java/lang/module/Dependence.java src/java.base/share/classes/java/lang/module/FindException.java src/java.base/share/classes/java/lang/module/InvalidModuleDescriptorException.java src/java.base/share/classes/java/lang/module/ModuleDescriptor.java src/java.base/share/classes/java/lang/module/ModuleFinder.java src/java.base/share/classes/java/lang/module/ModuleInfo.java src/java.base/share/classes/java/lang/module/ModulePath.java src/java.base/share/classes/java/lang/module/ModuleReader.java src/java.base/share/classes/java/lang/module/ModuleReference.java src/java.base/share/classes/java/lang/module/ModuleReferences.java src/java.base/share/classes/java/lang/module/ResolutionException.java src/java.base/share/classes/java/lang/module/ResolvedModule.java src/java.base/share/classes/java/lang/module/Resolver.java src/java.base/share/classes/java/lang/module/SystemModuleFinder.java src/java.base/share/classes/java/lang/module/package-info.java src/java.base/share/classes/java/lang/ref/Finalizer.java src/java.base/share/classes/java/lang/reflect/AccessibleObject.java src/java.base/share/classes/java/lang/reflect/Constructor.java src/java.base/share/classes/java/lang/reflect/Field.java src/java.base/share/classes/java/lang/reflect/InaccessibleObjectException.java src/java.base/share/classes/java/lang/reflect/Layer.java src/java.base/share/classes/java/lang/reflect/LayerInstantiationException.java src/java.base/share/classes/java/lang/reflect/Method.java src/java.base/share/classes/java/lang/reflect/Module.java src/java.base/share/classes/java/lang/reflect/Proxy.java src/java.base/share/classes/java/lang/reflect/package-info.java src/java.base/share/classes/java/net/URL.java src/java.base/share/classes/java/net/URLClassLoader.java src/java.base/share/classes/java/nio/Bits.java src/java.base/share/classes/java/nio/file/FileSystems.java src/java.base/share/classes/java/nio/file/Files.java src/java.base/share/classes/java/util/ResourceBundle.java src/java.base/share/classes/java/util/ServiceLoader.java src/java.base/share/classes/java/util/spi/AbstractResourceBundleProvider.java src/java.base/share/classes/java/util/spi/ResourceBundleControlProvider.java src/java.base/share/classes/java/util/spi/ResourceBundleProvider.java src/java.base/share/classes/javax/crypto/JceSecurity.java src/java.base/share/classes/javax/crypto/SealedObject.java src/java.base/share/classes/jdk/internal/jimage/Archive.java src/java.base/share/classes/jdk/internal/jimage/BasicImageReader.java src/java.base/share/classes/jdk/internal/jimage/BasicImageWriter.java src/java.base/share/classes/jdk/internal/jimage/ExternalFilesWriter.java src/java.base/share/classes/jdk/internal/jimage/ImageBufferCache.java src/java.base/share/classes/jdk/internal/jimage/ImageFileCreator.java src/java.base/share/classes/jdk/internal/jimage/ImageHeader.java src/java.base/share/classes/jdk/internal/jimage/ImageJavaSubstrate.java src/java.base/share/classes/jdk/internal/jimage/ImageLocation.java src/java.base/share/classes/jdk/internal/jimage/ImageLocationBase.java src/java.base/share/classes/jdk/internal/jimage/ImageLocationWriter.java src/java.base/share/classes/jdk/internal/jimage/ImageModuleData.java src/java.base/share/classes/jdk/internal/jimage/ImageModuleDataWriter.java src/java.base/share/classes/jdk/internal/jimage/ImageNativeSubstrate.java src/java.base/share/classes/jdk/internal/jimage/ImageReader.java src/java.base/share/classes/jdk/internal/jimage/ImageReaderFactory.java src/java.base/share/classes/jdk/internal/jimage/ImageResourcesTree.java src/java.base/share/classes/jdk/internal/jimage/ImageStream.java src/java.base/share/classes/jdk/internal/jimage/ImageStrings.java src/java.base/share/classes/jdk/internal/jimage/ImageStringsReader.java src/java.base/share/classes/jdk/internal/jimage/ImageStringsWriter.java src/java.base/share/classes/jdk/internal/jimage/ImageSubstrate.java src/java.base/share/classes/jdk/internal/jimage/NativeImageBuffer.java src/java.base/share/classes/jdk/internal/jimage/PerfectHashBuilder.java src/java.base/share/classes/jdk/internal/jimage/ResourcePool.java src/java.base/share/classes/jdk/internal/jimage/ResourcePoolImpl.java src/java.base/share/classes/jdk/internal/jimage/StringTable.java src/java.base/share/classes/jdk/internal/jimage/UTF8String.java src/java.base/share/classes/jdk/internal/jimage/decompressor/CompressIndexes.java src/java.base/share/classes/jdk/internal/jimage/decompressor/CompressedResourceHeader.java src/java.base/share/classes/jdk/internal/jimage/decompressor/Decompressor.java src/java.base/share/classes/jdk/internal/jimage/decompressor/ResourceDecompressor.java src/java.base/share/classes/jdk/internal/jimage/decompressor/ResourceDecompressorFactory.java src/java.base/share/classes/jdk/internal/jimage/decompressor/ResourceDecompressorRepository.java src/java.base/share/classes/jdk/internal/jimage/decompressor/SignatureParser.java src/java.base/share/classes/jdk/internal/jimage/decompressor/StringSharingDecompressor.java src/java.base/share/classes/jdk/internal/jimage/decompressor/StringSharingDecompressorFactory.java src/java.base/share/classes/jdk/internal/jimage/decompressor/ZipDecompressor.java src/java.base/share/classes/jdk/internal/jimage/decompressor/ZipDecompressorFactory.java src/java.base/share/classes/jdk/internal/jrtfs/AbstractJrtFileAttributes.java src/java.base/share/classes/jdk/internal/jrtfs/AbstractJrtFileSystem.java src/java.base/share/classes/jdk/internal/jrtfs/AbstractJrtPath.java src/java.base/share/classes/jdk/internal/jrtfs/JrtDirectoryStream.java src/java.base/share/classes/jdk/internal/jrtfs/JrtExplodedFileAttributes.java src/java.base/share/classes/jdk/internal/jrtfs/JrtExplodedFileSystem.java src/java.base/share/classes/jdk/internal/jrtfs/JrtExplodedPath.java src/java.base/share/classes/jdk/internal/jrtfs/JrtFileAttributeView.java src/java.base/share/classes/jdk/internal/jrtfs/JrtFileAttributes.java src/java.base/share/classes/jdk/internal/jrtfs/JrtFileStore.java src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystem.java src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java src/java.base/share/classes/jdk/internal/jrtfs/JrtPath.java src/java.base/share/classes/jdk/internal/jrtfs/JrtUtils.java src/java.base/share/classes/jdk/internal/jrtfs/SystemImages.java src/java.base/share/classes/jdk/internal/jrtfs/jrtfsviewer.js src/java.base/share/classes/jdk/internal/jrtfs/jrtls.js src/java.base/share/classes/jdk/internal/loader/BootLoader.java src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java src/java.base/share/classes/jdk/internal/loader/Loader.java src/java.base/share/classes/jdk/internal/loader/LoaderPool.java src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java src/java.base/share/classes/jdk/internal/misc/JavaLangReflectModuleAccess.java src/java.base/share/classes/jdk/internal/misc/JavaUtilResourceBundleAccess.java src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java src/java.base/share/classes/jdk/internal/misc/VM.java src/java.base/share/classes/jdk/internal/module/Builder.java src/java.base/share/classes/jdk/internal/module/Checks.java src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java src/java.base/share/classes/jdk/internal/module/ConfigurableModuleFinder.java src/java.base/share/classes/jdk/internal/module/Hasher.java src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java src/java.base/share/classes/jdk/internal/module/ModulePatcher.java src/java.base/share/classes/jdk/internal/module/Modules.java src/java.base/share/classes/jdk/internal/module/ServicesCatalog.java src/java.base/share/classes/jdk/internal/module/SystemModules.java src/java.base/share/classes/jdk/internal/perf/PerfCounter.java src/java.base/share/classes/jdk/internal/vm/cds/resources/ModuleLoaderMap.dat src/java.base/share/classes/module-info.java src/java.base/share/classes/sun/invoke/util/VerifyAccess.java src/java.base/share/classes/sun/launcher/LauncherHelper.java src/java.base/share/classes/sun/launcher/resources/launcher.properties src/java.base/share/classes/sun/misc/Launcher.java src/java.base/share/classes/sun/misc/URLClassPath.java src/java.base/share/classes/sun/net/www/protocol/jmod/Handler.java src/java.base/share/classes/sun/net/www/protocol/jrt/JavaRuntimeURLConnection.java src/java.base/share/classes/sun/reflect/Reflection.java src/java.base/share/classes/sun/reflect/misc/MethodUtil.java src/java.base/share/classes/sun/reflect/misc/ReflectUtil.java src/java.base/share/classes/sun/security/jca/ProviderList.java src/java.base/share/classes/sun/security/jca/Providers.java src/java.base/share/classes/sun/security/provider/PolicyFile.java src/java.base/share/classes/sun/security/util/SecurityConstants.java src/java.base/share/classes/sun/text/resources/BreakIteratorInfoProvider.java src/java.base/share/classes/sun/text/resources/BreakIteratorRulesProvider.java src/java.base/share/classes/sun/text/resources/CollationDataProvider.java src/java.base/share/classes/sun/text/resources/FormatDataProvider.java src/java.base/share/classes/sun/text/resources/JavaTimeSupplementaryProvider.java src/java.base/share/classes/sun/text/resources/cldr/FormatDataProvider.java src/java.base/share/classes/sun/util/CoreResourceBundleControl-XLocales.java.template src/java.base/share/classes/sun/util/locale/provider/BreakDictionary.java src/java.base/share/classes/sun/util/locale/provider/BreakIteratorProviderImpl.java src/java.base/share/classes/sun/util/locale/provider/DictionaryBasedBreakIterator.java src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java src/java.base/share/classes/sun/util/locale/provider/ResourceBundleProviderSupport.java src/java.base/share/classes/sun/util/locale/provider/RuleBasedBreakIterator.java src/java.base/share/classes/sun/util/resources/Bundles.java src/java.base/share/classes/sun/util/resources/CalendarDataProvider.java src/java.base/share/classes/sun/util/resources/CurrencyNamesProvider.java src/java.base/share/classes/sun/util/resources/LocaleData.java src/java.base/share/classes/sun/util/resources/LocaleDataProvider.java src/java.base/share/classes/sun/util/resources/LocaleNamesProvider.java src/java.base/share/classes/sun/util/resources/TimeZoneNamesProvider.java src/java.base/share/classes/sun/util/resources/cldr/CalendarDataProvider.java src/java.base/share/classes/sun/util/resources/cldr/CurrencyNamesProvider.java src/java.base/share/classes/sun/util/resources/cldr/LocaleNamesProvider.java src/java.base/share/classes/sun/util/resources/cldr/TimeZoneNamesProvider.java src/java.base/share/conf/security/java.policy src/java.base/share/conf/security/java.security src/java.base/share/native/include/jni.h src/java.base/share/native/include/jvm.h src/java.base/share/native/include/jvmti.h src/java.base/share/native/launcher/defines.h src/java.base/share/native/launcher/main.c src/java.base/share/native/libjava/BootLoader.c src/java.base/share/native/libjava/Module.c src/java.base/share/native/libjava/Package.c src/java.base/share/native/libjava/Proxy.c src/java.base/share/native/libjava/Reflection.c src/java.base/share/native/libjimage/ImageNativeSubstrate.cpp src/java.base/share/native/libjimage/NativeImageBuffer.cpp src/java.base/share/native/libjimage/imageDecompressor.cpp src/java.base/share/native/libjimage/imageDecompressor.hpp src/java.base/share/native/libjimage/imageFile.cpp src/java.base/share/native/libjimage/imageFile.hpp src/java.base/share/native/libjimage/jimage.cpp src/java.base/share/native/libjimage/jimage.hpp src/java.base/share/native/libjli/args.c src/java.base/share/native/libjli/emessages.h src/java.base/share/native/libjli/java.c src/java.base/share/native/libjli/java.h src/java.base/solaris/classes/module-info.java.extra src/java.base/windows/classes/module-info.java.extra src/java.compact1/share/classes/module-info.java src/java.compact2/share/classes/module-info.java src/java.compact3/share/classes/module-info.java src/java.datatransfer/share/classes/module-info.java src/java.desktop/macosx/classes/com/apple/laf/AquaUtils.java src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java src/java.desktop/share/classes/META-INF/services/java.net.ContentHandlerFactory src/java.desktop/share/classes/META-INF/services/javax.print.PrintServiceLookup src/java.desktop/share/classes/META-INF/services/javax.print.StreamPrintServiceFactory src/java.desktop/share/classes/META-INF/services/javax.sound.midi.spi.MidiDeviceProvider src/java.desktop/share/classes/META-INF/services/javax.sound.midi.spi.MidiFileReader src/java.desktop/share/classes/META-INF/services/javax.sound.midi.spi.MidiFileWriter src/java.desktop/share/classes/META-INF/services/javax.sound.midi.spi.SoundbankReader src/java.desktop/share/classes/META-INF/services/javax.sound.sampled.spi.AudioFileReader src/java.desktop/share/classes/META-INF/services/javax.sound.sampled.spi.AudioFileWriter src/java.desktop/share/classes/META-INF/services/javax.sound.sampled.spi.FormatConversionProvider src/java.desktop/share/classes/META-INF/services/javax.sound.sampled.spi.MixerProvider src/java.desktop/share/classes/META-INF/services/sun.datatransfer.DesktopDatatransferService src/java.desktop/share/classes/com/sun/beans/finder/ConstructorFinder.java src/java.desktop/share/classes/com/sun/beans/finder/FieldFinder.java src/java.desktop/share/classes/com/sun/beans/finder/FinderUtils.java src/java.desktop/share/classes/com/sun/beans/finder/MethodFinder.java src/java.desktop/share/classes/com/sun/media/sound/JARSoundbankReader.java src/java.desktop/share/classes/java/awt/Component.java src/java.desktop/share/classes/java/awt/Toolkit.java src/java.desktop/share/classes/java/awt/Window.java src/java.desktop/share/classes/javax/imageio/ImageReader.java src/java.desktop/share/classes/javax/imageio/ImageWriter.java src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadata.java src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataFormat.java src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataFormatImpl.java src/java.desktop/share/classes/javax/imageio/spi/ImageReaderWriterSpi.java src/java.desktop/share/classes/javax/swing/UIDefaults.java src/java.desktop/share/classes/javax/swing/text/DefaultFormatter.java src/java.desktop/share/classes/javax/swing/text/html/ObjectView.java src/java.desktop/share/classes/module-info.java src/java.desktop/share/classes/sun/applet/AppletSecurity.java src/java.desktop/share/classes/sun/awt/datatransfer/TransferableProxy.java src/java.httpclient/share/classes/module-info.java src/java.instrument/share/classes/java/lang/instrument/ClassFileTransformer.java src/java.instrument/share/classes/java/lang/instrument/Instrumentation.java src/java.instrument/share/classes/java/lang/instrument/package.html src/java.instrument/share/classes/module-info.java src/java.instrument/share/classes/sun/instrument/InstrumentationImpl.java src/java.instrument/share/classes/sun/instrument/TransformerManager.java src/java.instrument/share/native/libinstrument/JPLISAgent.c src/java.instrument/share/native/libinstrument/JPLISAgent.h src/java.logging/share/classes/META-INF/services/jdk.internal.logger.DefaultLoggerFinder src/java.logging/share/classes/java/util/logging/Level.java src/java.logging/share/classes/java/util/logging/Logger.java src/java.logging/share/classes/module-info.java src/java.management/share/classes/javax/management/remote/rmi/RMIConnector.java src/java.management/share/classes/module-info.java src/java.management/share/classes/sun/management/RuntimeImpl.java src/java.management/share/classes/sun/management/StackTraceElementCompositeData.java src/java.management/share/classes/sun/management/ThreadInfoCompositeData.java src/java.management/share/classes/sun/management/TypeVersionMapper.java src/java.management/share/classes/sun/management/VMManagementImpl.java src/java.management/share/native/include/jmm.h src/java.management/share/native/libmanagement/VMManagementImpl.c src/java.naming/share/classes/com/sun/jndi/ldap/Obj.java src/java.naming/share/classes/com/sun/naming/internal/VersionHelper.java src/java.naming/share/classes/javax/naming/ldap/ControlFactory.java src/java.naming/share/classes/javax/naming/spi/NamingManager.java src/java.naming/share/classes/javax/naming/spi/ObjectFactory.java src/java.naming/share/classes/javax/naming/spi/StateFactory.java src/java.naming/share/classes/module-info.java src/java.naming/share/classes/sun/security/provider/certpath/ldap/LDAPCertStoreImpl.java src/java.prefs/share/classes/module-info.java src/java.rmi/share/classes/java/rmi/activation/ActivationID.java src/java.rmi/share/classes/module-info.java src/java.scripting/share/classes/com/sun/tools/script/shell/Main.java src/java.scripting/share/classes/module-info.java src/java.se.ee/share/classes/module-info.java src/java.se/share/classes/module-info.java src/java.security.jgss/share/classes/META-INF/services/sun.security.ssl.ClientKeyExchangeService src/java.security.jgss/share/classes/module-info.java src/java.security.sasl/share/classes/module-info.java src/java.smartcardio/share/classes/module-info.java src/java.sql.rowset/share/classes/com/sun/rowset/CachedRowSetImpl.java src/java.sql.rowset/share/classes/com/sun/rowset/JdbcRowSetResourceBundle.java src/java.sql.rowset/share/classes/com/sun/rowset/internal/CachedRowSetWriter.java src/java.sql.rowset/share/classes/javax/sql/rowset/RowSetProvider.java src/java.sql.rowset/share/classes/javax/sql/rowset/serial/SQLInputImpl.java src/java.sql.rowset/share/classes/javax/sql/rowset/spi/SyncFactory.java src/java.sql.rowset/share/classes/module-info.java src/java.sql/share/classes/module-info.java src/java.transaction/share/classes/module-info.java src/java.xml.crypto/share/classes/module-info.java src/jdk.accessibility/share/classes/module-info.java src/jdk.accessibility/windows/classes/META-INF/services/javax.accessibility.AccessibilityProvider src/jdk.accessibility/windows/classes/module-info.java.extra src/jdk.attach/share/classes/META-INF/services/com.sun.tools.attach.spi.AttachProvider src/jdk.attach/share/classes/module-info.java src/jdk.charsets/share/classes/META-INF/services/java.nio.charset.spi.CharsetProvider src/jdk.charsets/share/classes/module-info.java src/jdk.compiler/share/classes/sun/tools/serialver/SerialVer.java src/jdk.crypto.ec/share/classes/module-info.java src/jdk.crypto.mscapi/windows/classes/module-info.java src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/RSAKeyPairGenerator.java src/jdk.crypto.pkcs11/share/classes/module-info.java src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/SunPKCS11.java src/jdk.crypto.ucrypto/solaris/classes/module-info.java src/jdk.deploy.osx/macosx/classes/module-info.java src/jdk.dev/share/classes/jdk/tools/jimage/ExtractedImage.java src/jdk.dev/share/classes/jdk/tools/jimage/JImageTask.java src/jdk.dev/share/classes/jdk/tools/jimage/Main.java src/jdk.dev/share/classes/jdk/tools/jimage/TaskHelper.java src/jdk.dev/share/classes/jdk/tools/jimage/resources/jimage.properties src/jdk.httpserver/share/classes/module-info.java src/jdk.internal.le/share/classes/module-info.java src/jdk.internal.opt/share/classes/module-info.java src/jdk.jartool/share/classes/module-info.java src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java src/jdk.jartool/share/classes/sun/tools/jar/Main.java src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties src/jdk.jcmd/share/classes/jdk/internal/vm/agent/spi/ToolProvider.java src/jdk.jcmd/share/classes/jdk/internal/vm/agent/spi/ToolProviderFinder.java src/jdk.jcmd/share/classes/module-info.java src/jdk.jcmd/share/classes/sun/tools/jinfo/JInfo.java src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java src/jdk.jcmd/share/classes/sun/tools/jstack/JStack.java src/jdk.jconsole/share/classes/module-info.java src/jdk.jdi/share/classes/META-INF/services/com.sun.jdi.connect.Connector src/jdk.jdi/share/classes/META-INF/services/com.sun.jdi.connect.spi.TransportService src/jdk.jdi/share/classes/com/sun/jdi/InvalidModuleException.java src/jdk.jdi/share/classes/com/sun/jdi/ModuleReference.java src/jdk.jdi/share/classes/com/sun/jdi/ReferenceType.java src/jdk.jdi/share/classes/com/sun/jdi/VirtualMachine.java src/jdk.jdi/share/classes/com/sun/tools/jdi/JDWPException.java src/jdk.jdi/share/classes/com/sun/tools/jdi/ModuleReferenceImpl.java src/jdk.jdi/share/classes/com/sun/tools/jdi/PacketStream.java src/jdk.jdi/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java src/jdk.jdi/share/classes/com/sun/tools/jdi/VirtualMachineImpl.java src/jdk.jdi/share/classes/com/sun/tools/jdi/VirtualMachineManagerImpl.java src/jdk.jdi/share/classes/module-info.java src/jdk.jdi/windows/classes/module-info.java.extra src/jdk.jdwp.agent/share/classes/module-info.java src/jdk.jdwp.agent/share/native/libjdwp/JDWP.h src/jdk.jdwp.agent/share/native/libjdwp/ModuleReferenceImpl.c src/jdk.jdwp.agent/share/native/libjdwp/ModuleReferenceImpl.h src/jdk.jdwp.agent/share/native/libjdwp/ReferenceTypeImpl.c src/jdk.jdwp.agent/share/native/libjdwp/VirtualMachineImpl.c src/jdk.jdwp.agent/share/native/libjdwp/debugDispatch.c src/jdk.jdwp.agent/share/native/libjdwp/inStream.c src/jdk.jdwp.agent/share/native/libjdwp/inStream.h src/jdk.jdwp.agent/share/native/libjdwp/outStream.c src/jdk.jdwp.agent/share/native/libjdwp/outStream.h src/jdk.jdwp.agent/share/native/libjdwp/util.c src/jdk.jdwp.agent/share/native/libjdwp/util.h src/jdk.jlink/share/classes/jdk/tools/jimage/ExtractedImage.java src/jdk.jlink/share/classes/jdk/tools/jimage/JImageTask.java src/jdk.jlink/share/classes/jdk/tools/jimage/Main.java src/jdk.jlink/share/classes/jdk/tools/jimage/resources/jimage.properties src/jdk.jlink/share/classes/jdk/tools/jlink/Jlink.java src/jdk.jlink/share/classes/jdk/tools/jlink/JlinkPermission.java src/jdk.jlink/share/classes/jdk/tools/jlink/builder/DefaultImageBuilder.java src/jdk.jlink/share/classes/jdk/tools/jlink/builder/ImageBuilder.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Archive.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/BasicImageWriter.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/DirArchive.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageFileCreator.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageLocationWriter.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginConfiguration.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginStack.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageResourcesTree.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageStringsWriter.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JarArchive.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JmodArchive.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Main.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ModularJarArchive.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/PerfectHashBuilder.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/PluginContextImpl.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/PluginOrderingGraph.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/PluginRepository.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/PoolImpl.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePrevisitor.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/StringTable.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Utils.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/DefaultCompressPlugin.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ExcludeFilesPlugin.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ExcludePlugin.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ExcludeVMPlugin.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/FileCopierPlugin.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/OptimizationPlugin.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/PluginsResourceBundle.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ReleaseInfoPlugin.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ResourceFilter.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SortResourcesPlugin.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StringSharingPlugin.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StripDebugPlugin.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StripNativeCommandsPlugin.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModuleDescriptorPlugin.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ZipPlugin.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/asm/AsmGlobalPool.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/asm/AsmModulePool.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/asm/AsmPlugin.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/asm/AsmPool.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/asm/AsmPoolImpl.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/asm/AsmPools.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/optim/ControlFlow.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/optim/ForNameFolding.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/optim/ReflectionOptimizer.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/optim/Utils.java src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/ExecutableImage.java src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/Plugin.java src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/PluginContext.java src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/PluginException.java src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/Pool.java src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/PostProcessorPlugin.java src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/TransformerPlugin.java src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java src/jdk.jlink/share/classes/jdk/tools/jmod/Main.java src/jdk.jlink/share/classes/jdk/tools/jmod/resources/jmod.properties src/jdk.jlink/share/classes/module-info.java src/jdk.jsobject/share/classes/module-info.java src/jdk.jvmstat.rmi/share/classes/META-INF/services/sun.jvmstat.monitor.MonitoredHostService src/jdk.jvmstat.rmi/share/classes/module-info.java src/jdk.jvmstat/share/classes/META-INF/services/sun.jvmstat.monitor.MonitoredHostService src/jdk.jvmstat/share/classes/module-info.java src/jdk.localedata/share/classes/META-INF/services/sun.util.locale.provider.LocaleDataMetaInfo src/jdk.localedata/share/classes/module-info.java src/jdk.localedata/share/classes/sun/util/resources/provider/LocaleDataProvider.java src/jdk.localedata/share/classes/sun/util/resources/provider/SupplementaryLocaleDataProvider.java src/jdk.management/share/classes/META-INF/services/sun.management.spi.PlatformMBeanProvider src/jdk.management/share/classes/module-info.java src/jdk.naming.dns/share/classes/META-INF/services/sun.net.spi.nameservice.NameServiceDescriptor src/jdk.naming.dns/share/classes/module-info.java src/jdk.naming.rmi/share/classes/module-info.java src/jdk.pack200/share/classes/module-info.java src/jdk.policytool/share/classes/module-info.java src/jdk.rmic/share/classes/jdk/rmi/rmic/Main.java src/jdk.rmic/share/classes/module-info.java src/jdk.rmic/share/classes/sun/rmi/rmic/BatchEnvironment.java src/jdk.rmic/share/classes/sun/tools/java/ClassPath.java src/jdk.sctp/share/classes/module-info.java src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisNumericGroupPrincipal.java src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisNumericUserPrincipal.java src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisPrincipal.java src/jdk.security.auth/share/classes/com/sun/security/auth/X500Principal.java src/jdk.security.auth/share/classes/com/sun/security/auth/module/JndiLoginModule.java src/jdk.security.auth/share/classes/com/sun/security/auth/module/KeyStoreLoginModule.java src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java src/jdk.security.auth/share/classes/com/sun/security/auth/module/LdapLoginModule.java src/jdk.security.auth/share/classes/module-info.java src/jdk.security.jgss/share/classes/module-info.java src/jdk.zipfs/share/classes/META-INF/services/java.nio.file.spi.FileSystemProvider src/jdk.zipfs/share/classes/module-info.java test/Makefile test/ProblemList.txt test/TEST.ROOT test/TEST.groups test/com/sun/jdi/EarlyReturnNegativeTest.java test/com/sun/jdi/EarlyReturnTest.java test/com/sun/jdi/ImmutableResourceTest.sh test/com/sun/jdi/MethodExitReturnValuesTest.java test/com/sun/jdi/ModulesTest.java test/com/sun/management/HotSpotDiagnosticMXBean/CheckOrigin.java test/java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusToFrontTest.java test/java/awt/Focus/FocusEmbeddedFrameTest/FocusEmbeddedFrameTest.java test/java/awt/Mixing/AWT_Mixing/JButtonInGlassPaneOverlapping.java test/java/awt/Mixing/AWT_Mixing/JButtonOverlapping.java test/java/awt/Mixing/AWT_Mixing/JColorChooserOverlapping.java test/java/awt/Mixing/AWT_Mixing/JComboBoxOverlapping.java test/java/awt/Mixing/AWT_Mixing/JEditorPaneInGlassPaneOverlapping.java test/java/awt/Mixing/AWT_Mixing/JEditorPaneOverlapping.java test/java/awt/Mixing/AWT_Mixing/JLabelInGlassPaneOverlapping.java test/java/awt/Mixing/AWT_Mixing/JLabelOverlapping.java test/java/awt/Mixing/AWT_Mixing/JListInGlassPaneOverlapping.java test/java/awt/Mixing/AWT_Mixing/JListOverlapping.java test/java/awt/Mixing/AWT_Mixing/JMenuBarOverlapping.java test/java/awt/Mixing/AWT_Mixing/JPanelInGlassPaneOverlapping.java test/java/awt/Mixing/AWT_Mixing/JPanelOverlapping.java test/java/awt/Mixing/AWT_Mixing/JPopupMenuOverlapping.java test/java/awt/Mixing/AWT_Mixing/JProgressBarInGlassPaneOverlapping.java test/java/awt/Mixing/AWT_Mixing/JProgressBarOverlapping.java test/java/awt/Mixing/AWT_Mixing/JScrollBarInGlassPaneOverlapping.java test/java/awt/Mixing/AWT_Mixing/JScrollBarOverlapping.java test/java/awt/Mixing/AWT_Mixing/JSliderInGlassPaneOverlapping.java test/java/awt/Mixing/AWT_Mixing/JSliderOverlapping.java test/java/awt/Mixing/AWT_Mixing/JSpinnerInGlassPaneOverlapping.java test/java/awt/Mixing/AWT_Mixing/JSpinnerOverlapping.java test/java/awt/Mixing/AWT_Mixing/JTableInGlassPaneOverlapping.java test/java/awt/Mixing/AWT_Mixing/JTableOverlapping.java test/java/awt/Mixing/AWT_Mixing/JTextAreaInGlassPaneOverlapping.java test/java/awt/Mixing/AWT_Mixing/JTextAreaOverlapping.java test/java/awt/Mixing/AWT_Mixing/JTextFieldInGlassPaneOverlapping.java test/java/awt/Mixing/AWT_Mixing/JTextFieldOverlapping.java test/java/awt/Mixing/AWT_Mixing/JToggleButtonInGlassPaneOverlapping.java test/java/awt/Mixing/AWT_Mixing/JToggleButtonOverlapping.java test/java/awt/Mixing/AWT_Mixing/MixingFrameResizing.java test/java/awt/Mixing/AWT_Mixing/OverlappingTestBase.java test/java/awt/Toolkit/Headless/WrappedToolkitTest/WrappedToolkitTest.sh test/java/awt/TrayIcon/ActionCommand/ActionCommand.java test/java/awt/TrayIcon/ActionEventMask/ActionEventMask.java test/java/awt/TrayIcon/ModalityTest/ModalityTest.java test/java/awt/TrayIcon/MouseEventMask/MouseEventMaskTest.java test/java/awt/TrayIcon/SecurityCheck/FunctionalityCheck/FunctionalityCheck.java test/java/awt/TrayIcon/SystemTrayIconHelper.java test/java/awt/TrayIcon/TrayIconEventModifiers/TrayIconEventModifiersTest.java test/java/awt/TrayIcon/TrayIconEvents/TrayIconEventsTest.java test/java/awt/TrayIcon/TrayIconMouseTest/TrayIconMouseTest.java test/java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java test/java/awt/datatransfer/ConstructFlavoredObjectTest/ConstructFlavoredObjectTest.java test/java/awt/datatransfer/DataFlavor/DataFlavorRemoteTest.java test/java/awt/grab/EmbeddedFrameTest1/EmbeddedFrameTest1.java test/java/awt/patchlib/java.desktop/java/awt/Helper.java test/java/awt/regtesthelpers/Util.java test/java/awt/regtesthelpers/UtilInternal.java test/java/awt/xembed/server/TesterClient.java test/java/beans/XMLEncoder/sun_swing_PrintColorUIResource.java test/java/lang/Class/Foo.java test/java/lang/Class/GetModuleTest.java test/java/lang/Class/GetPackageTest.java test/java/lang/Class/forName/modules/TestDriver.java test/java/lang/Class/forName/modules/TestLayer.java test/java/lang/Class/forName/modules/TestMain.java test/java/lang/Class/forName/modules/policy test/java/lang/Class/forName/modules/policy.denied test/java/lang/Class/forName/modules/src/m1/module-info.java test/java/lang/Class/forName/modules/src/m1/p1/A.java test/java/lang/Class/forName/modules/src/m1/p1/Initializer.java test/java/lang/Class/forName/modules/src/m1/p1/internal/B.java test/java/lang/Class/forName/modules/src/m2/module-info.java test/java/lang/Class/forName/modules/src/m2/p2/C.java test/java/lang/Class/forName/modules/src/m2/p2/test/Main.java test/java/lang/Class/forName/modules/src/m3/module-info.java test/java/lang/Class/forName/modules/src/m3/p3/NoAccess.java test/java/lang/Class/forName/modules/src/m3/p3/NoGetClassLoaderAccess.java test/java/lang/Class/forName/modules/src/m3/p3/internal/Foo.java test/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java test/java/lang/Class/getPackageName/Basic.java test/java/lang/Class/getResource/Main.java test/java/lang/Class/getResource/ResourcesTest.java test/java/lang/Class/getResource/src/m1/module-info.java test/java/lang/Class/getResource/src/m1/p1/Main.java test/java/lang/Class/getResource/src/m2/module-info.java test/java/lang/Class/getResource/src/m2/p2/Main.java test/java/lang/Class/getResource/src/m3/module-info.java test/java/lang/Class/getResource/src/m3/p3/Main.java test/java/lang/ClassLoader/GetSystemPackage.java test/java/lang/ClassLoader/findSystemClass/Loader.java test/java/lang/ClassLoader/getResource/GetResource.sh test/java/lang/ClassLoader/getResource/modules/Main.java test/java/lang/ClassLoader/getResource/modules/ResourcesTest.java test/java/lang/ClassLoader/getResource/modules/src/m1/module-info.java test/java/lang/ClassLoader/getResource/modules/src/m1/p1/Main.java test/java/lang/ClassLoader/getResource/modules/src/m2/module-info.java test/java/lang/ClassLoader/getResource/modules/src/m2/p2/Main.java test/java/lang/ClassLoader/getResource/modules/src/m3/module-info.java test/java/lang/ClassLoader/getResource/modules/src/m3/p3/Main.java test/java/lang/ClassLoader/platformClassLoader/DefinePlatformClass.java test/java/lang/ClassLoader/platformClassLoader/jdk.zipfs/java/fake/Fake.java test/java/lang/Package/Foo.java test/java/lang/Package/GetPackages.java test/java/lang/Package/annotation/PackageInfoTest.java test/java/lang/Package/annotation/jdk.xml.dom/org/w3c/dom/css/Fake.java test/java/lang/Package/annotation/jdk.xml.dom/org/w3c/dom/css/FakePackage.java test/java/lang/Package/annotation/jdk.xml.dom/org/w3c/dom/css/package-info.java test/java/lang/Package/annotation/package-info.java test/java/lang/Package/annotation/src/p/Bar.java test/java/lang/Package/annotation/src/p/Duplicate.java test/java/lang/Package/annotation/src/p/package-info.java test/java/lang/SecurityManager/RestrictedPackages.java test/java/lang/SecurityManager/modules/CustomSecurityManager.sh test/java/lang/SecurityManager/modules/Test.java test/java/lang/SecurityManager/modules/m/module-info.java test/java/lang/SecurityManager/modules/m/p/CustomSecurityManager.java test/java/lang/SecurityManager/modules/test.policy test/java/lang/StackTraceElement/ModuleFrames.java test/java/lang/StackTraceElement/PublicConstructor.java test/java/lang/StackWalker/VerifyStackTrace.java test/java/lang/instrument/ATransformerManagementTestCase.java test/java/lang/instrument/BootClassPath/Agent.java test/java/lang/instrument/MakeJAR2.sh test/java/lang/instrument/RedefineClassWithNativeMethodAgent.java test/java/lang/instrument/RetransformAgent.java test/java/lang/instrument/SimpleIdentityTransformer.java test/java/lang/invoke/AccessControlTest.java test/java/lang/invoke/CustomizedLambdaFormTest.java test/java/lang/invoke/MethodHandlesTest.java test/java/lang/invoke/VarargsArrayTest.java test/java/lang/invoke/java.base/java/lang/invoke/MethodHandleHelper.java test/java/lang/invoke/lambda/LambdaAccessControlDoPrivilegedTest.java test/java/lang/invoke/modules/ModuleAccessControlTest.java test/java/lang/invoke/modules/src/m1/module-info.java test/java/lang/invoke/modules/src/m1/p1/Main.java test/java/lang/invoke/modules/src/m1/p1/Type1.java test/java/lang/invoke/modules/src/m1/p2/Type2.java test/java/lang/invoke/modules/src/m2/module-info.java test/java/lang/invoke/modules/src/m2/q1/Type1.java test/java/lang/invoke/modules/src/m2/q2/Type2.java test/java/lang/management/CompositeData/ThreadInfoCompositeData.java test/java/lang/management/MemoryMXBean/PendingAllGC.sh test/java/lang/module/AutomaticModulesTest.java test/java/lang/module/ConfigurationTest.java test/java/lang/module/ModuleDescriptorTest.java test/java/lang/module/ModuleFinderTest.java test/java/lang/module/ModuleReader/ModuleReaderTest.java test/java/lang/module/ModuleReader/src/m/module-info.java test/java/lang/module/ModuleReader/src/m/p/Main.java test/java/lang/module/ModuleReferenceTest.java test/java/lang/module/VersionTest.java test/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java test/java/lang/reflect/Layer/BasicLayerTest.java test/java/lang/reflect/Layer/LayerAndLoadersTest.java test/java/lang/reflect/Layer/layertest/Test.java test/java/lang/reflect/Layer/src/m1/module-info.java test/java/lang/reflect/Layer/src/m1/p/Main.java test/java/lang/reflect/Layer/src/m1/p/Service.java test/java/lang/reflect/Layer/src/m2/module-info.java test/java/lang/reflect/Layer/src/m2/q/Hello.java test/java/lang/reflect/Layer/src/m3/module-info.java test/java/lang/reflect/Layer/src/m3/w/Hello.java test/java/lang/reflect/Layer/src/m4/impl/ServiceImpl.java test/java/lang/reflect/Layer/src/m4/module-info.java test/java/lang/reflect/Module/AddExportsTest.java test/java/lang/reflect/Module/BasicModuleTest.java test/java/lang/reflect/Module/access/AccessTest.java test/java/lang/reflect/Module/access/src/target/module-info.java test/java/lang/reflect/Module/access/src/target/p/Exported.java test/java/lang/reflect/Module/access/src/target/p/Helper.java test/java/lang/reflect/Module/access/src/target/q/Internal.java test/java/lang/reflect/Module/access/src/test/module-info.java test/java/lang/reflect/Module/access/src/test/test/Main.java test/java/lang/reflect/Proxy/Basic1.java test/java/lang/reflect/Proxy/NullClassLoader.java test/java/lang/reflect/Proxy/ProxyClassAccessTest.java test/java/lang/reflect/Proxy/ProxyForMethodHandle.java test/java/lang/reflect/Proxy/ProxyLayerTest.java test/java/lang/reflect/Proxy/ProxyModuleMapping.java test/java/lang/reflect/Proxy/ProxyTest.java test/java/lang/reflect/Proxy/q/NP.java test/java/lang/reflect/Proxy/q/U.java test/java/lang/reflect/Proxy/src/m1/module-info.java test/java/lang/reflect/Proxy/src/m1/p/one/I.java test/java/lang/reflect/Proxy/src/m1/p/one/internal/J.java test/java/lang/reflect/Proxy/src/m2/module-info.java test/java/lang/reflect/Proxy/src/m2/p/two/A.java test/java/lang/reflect/Proxy/src/m2/p/two/B.java test/java/lang/reflect/Proxy/src/m2/p/two/Bar.java test/java/lang/reflect/Proxy/src/m2/p/two/internal/C.java test/java/lang/reflect/Proxy/src/m3/module-info.java test/java/lang/reflect/Proxy/src/m3/p/three/P.java test/java/lang/reflect/Proxy/src/m3/p/three/internal/Q.java test/java/lang/reflect/Proxy/src/test/jdk/test/Main.java test/java/lang/reflect/Proxy/src/test/jdk/test/NP.java test/java/lang/reflect/Proxy/src/test/jdk/test/ProxyClassAccess.java test/java/lang/reflect/Proxy/src/test/jdk/test/ProxyTest.java test/java/lang/reflect/Proxy/src/test/jdk/test/internal/R.java test/java/lang/reflect/Proxy/src/test/jdk/test/internal/RImpl.java test/java/lang/reflect/Proxy/src/test/jdk/test/internal/foo/Foo.java test/java/lang/reflect/Proxy/src/test/jdk/test/internal/foo/FooException.java test/java/lang/reflect/Proxy/src/test/module-info.java test/java/net/Authenticator/B4933582.sh test/java/net/DatagramSocket/SetDatagramSocketImplFactory/ADatagramSocket.java test/java/net/DatagramSocket/SetDatagramSocketImplFactory/ADatagramSocket.sh test/java/net/DatagramSocket/SetDatagramSocketImplFactory/java.base/java/net/MyDatagramSocketImplFactory.java test/java/net/DatagramSocket/SetDatagramSocketImplFactory/java/net/MyDatagramSocketImplFactory.java test/java/net/NetworkInterface/NetworkInterfaceStreamTest.java test/java/net/URI/URItoURLTest.java test/java/net/URLPermission/nstest/lookup.sh test/java/net/httpclient/whitebox/Driver.java test/java/net/httpclient/whitebox/TEST.properties test/java/net/httpclient/whitebox/java.httpclient/java/net/http/SelectorTest.java test/java/net/httpclient/whitebox/java/net/http/SelectorTest.java test/java/nio/Buffer/LimitDirectMemory.sh test/java/nio/channels/spi/SelectorProvider/inheritedChannel/run_tests.sh test/java/nio/file/Files/StreamLinesTest.java test/java/nio/file/spi/SetDefaultProvider.java test/java/nio/file/spi/TestProvider.java test/java/rmi/activation/Activatable/extLoadedImpl/ext.sh test/java/rmi/activation/ActivationGroup/downloadActivationGroup/DownloadActivationGroup.java test/java/rmi/activation/ActivationSystem/stubClassesPermitted/StubClassesPermitted.java test/java/rmi/activation/ActivationSystem/stubClassesPermitted/rmid.security.policy test/java/rmi/activation/rmidViaInheritedChannel/InheritedChannelNotServerSocket.java test/java/rmi/activation/rmidViaInheritedChannel/RmidViaInheritedChannel.java test/java/rmi/dgc/dgcAckFailure/DGCAckFailure.java test/java/rmi/registry/readTest/readTest.sh test/java/rmi/reliability/benchmark/bench/HtmlReporter.java test/java/rmi/reliability/benchmark/bench/TextReporter.java test/java/rmi/testlibrary/JavaVM.java test/java/rmi/transport/checkFQDN/CheckFQDN.java test/java/rmi/transport/dgcDeadLock/DGCDeadLock.java test/java/security/PermissionCollection/PermissionCollectionStreamTest.java test/java/security/Provider/DefaultProviderList.java test/java/security/Provider/SecurityProviderModularTest.java test/java/security/Provider/TestSecurityProvider.java test/java/security/Provider/TestSecurityProviderClient.java test/java/security/cert/X509Certificate/EmptySubject.java test/java/security/modules/ModularTest.java test/java/security/testlibrary/Proc.java test/java/util/Calendar/GenericTimeZoneNamesTest.sh test/java/util/Currency/CheckDataVersion.java test/java/util/Currency/CurrencyTest.java test/java/util/Formatter/Basic.sh test/java/util/Locale/LocaleProviders.sh test/java/util/PluggableLocale/ExecTest.sh test/java/util/PluggableLocale/ProviderTest.java test/java/util/ResourceBundle/Bug4168625Test.java test/java/util/ResourceBundle/Bug6299235Test.java test/java/util/ResourceBundle/Bug6299235Test.sh test/java/util/ResourceBundle/modules/appbasic/src/asiabundles/jdk/test/resources/asia/MyResourcesAsia.java test/java/util/ResourceBundle/modules/appbasic/src/asiabundles/jdk/test/resources/asia/MyResources_ja.properties test/java/util/ResourceBundle/modules/appbasic/src/asiabundles/jdk/test/resources/asia/MyResources_zh.properties test/java/util/ResourceBundle/modules/appbasic/src/asiabundles/jdk/test/resources/asia/MyResources_zh_TW.properties test/java/util/ResourceBundle/modules/appbasic/src/asiabundles/module-info.java test/java/util/ResourceBundle/modules/appbasic/src/eubundles/jdk/test/resources/eu/MyResourcesEU.java test/java/util/ResourceBundle/modules/appbasic/src/eubundles/jdk/test/resources/eu/MyResources_de.java test/java/util/ResourceBundle/modules/appbasic/src/eubundles/jdk/test/resources/eu/MyResources_fr.java test/java/util/ResourceBundle/modules/appbasic/src/eubundles/module-info.java test/java/util/ResourceBundle/modules/appbasic/src/test/jdk/test/Main.java test/java/util/ResourceBundle/modules/appbasic/src/test/jdk/test/resources/MyControl.java test/java/util/ResourceBundle/modules/appbasic/src/test/jdk/test/resources/MyResources.java test/java/util/ResourceBundle/modules/appbasic/src/test/jdk/test/resources/MyResourcesProvider.java test/java/util/ResourceBundle/modules/appbasic/src/test/jdk/test/resources/MyResourcesProviderImpl.java test/java/util/ResourceBundle/modules/appbasic/src/test/jdk/test/resources/MyResources_en.java test/java/util/ResourceBundle/modules/appbasic/src/test/module-info.java test/java/util/ResourceBundle/modules/appbasic2/appbasic2.sh test/java/util/ResourceBundle/modules/appbasic2/src/asiabundles/jdk/test/resources/asia/MyResourcesAsia.java test/java/util/ResourceBundle/modules/appbasic2/src/asiabundles/jdk/test/resources/asia/MyResources_ja.properties test/java/util/ResourceBundle/modules/appbasic2/src/asiabundles/jdk/test/resources/asia/MyResources_zh.properties test/java/util/ResourceBundle/modules/appbasic2/src/asiabundles/jdk/test/resources/asia/MyResources_zh_TW.properties test/java/util/ResourceBundle/modules/appbasic2/src/asiabundles/module-info.java test/java/util/ResourceBundle/modules/appbasic2/src/eubundles/jdk/test/resources/eu/MyResourcesEU.java test/java/util/ResourceBundle/modules/appbasic2/src/eubundles/jdk/test/resources/eu/MyResources_de.java test/java/util/ResourceBundle/modules/appbasic2/src/eubundles/jdk/test/resources/eu/MyResources_fr.java test/java/util/ResourceBundle/modules/appbasic2/src/eubundles/module-info.java test/java/util/ResourceBundle/modules/appbasic2/src/test/jdk/test/Main.java test/java/util/ResourceBundle/modules/appbasic2/src/test/jdk/test/resources/MyResources.java test/java/util/ResourceBundle/modules/appbasic2/src/test/jdk/test/resources/MyResourcesProvider.java test/java/util/ResourceBundle/modules/appbasic2/src/test/jdk/test/resources/MyResourcesProviderImpl.java test/java/util/ResourceBundle/modules/appbasic2/src/test/jdk/test/resources/MyResources_en.java test/java/util/ResourceBundle/modules/appbasic2/src/test/module-info.java test/java/util/ResourceBundle/modules/basic/basic.sh test/java/util/ResourceBundle/modules/basic/src/asiabundles/jdk/test/resources/MyResources_ja_JP.properties test/java/util/ResourceBundle/modules/basic/src/asiabundles/jdk/test/resources/asia/MyResourcesAsia.java test/java/util/ResourceBundle/modules/basic/src/asiabundles/jdk/test/resources/asia/MyResources_ja.properties test/java/util/ResourceBundle/modules/basic/src/asiabundles/jdk/test/resources/asia/MyResources_zh.properties test/java/util/ResourceBundle/modules/basic/src/asiabundles/jdk/test/resources/asia/MyResources_zh_TW.properties test/java/util/ResourceBundle/modules/basic/src/asiabundles/module-info.java test/java/util/ResourceBundle/modules/basic/src/eubundles/jdk/test/resources/eu/MyResourcesEU.java test/java/util/ResourceBundle/modules/basic/src/eubundles/jdk/test/resources/eu/MyResources_de.java test/java/util/ResourceBundle/modules/basic/src/eubundles/jdk/test/resources/eu/MyResources_fr.java test/java/util/ResourceBundle/modules/basic/src/eubundles/module-info.java test/java/util/ResourceBundle/modules/basic/src/extra/jdk/test/resources/asia/MyResources_vi.properties test/java/util/ResourceBundle/modules/basic/src/extra/jdk/test/resources/eu/MyResources_es.java test/java/util/ResourceBundle/modules/basic/src/mainbundles/jdk/test/resources/MyResources.java test/java/util/ResourceBundle/modules/basic/src/mainbundles/jdk/test/resources/MyResourcesMain.java test/java/util/ResourceBundle/modules/basic/src/mainbundles/jdk/test/resources/MyResourcesProvider.java test/java/util/ResourceBundle/modules/basic/src/mainbundles/jdk/test/resources/MyResources_en.java test/java/util/ResourceBundle/modules/basic/src/mainbundles/module-info.java test/java/util/ResourceBundle/modules/basic/src/test/jdk/test/Main.java test/java/util/ResourceBundle/modules/basic/src/test/module-info.java test/java/util/ResourceBundle/modules/modlocal/modlocal.sh test/java/util/ResourceBundle/modules/modlocal/src/extra/jdk/test/resources/MyResources_vi.properties test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/Main.java test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/resources/MyResources.java test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/resources/MyResources_de.java test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/resources/MyResources_en.java test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/resources/MyResources_fr.java test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/resources/MyResources_ja.properties test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/resources/MyResources_zh.properties test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/resources/MyResources_zh_TW.properties test/java/util/ResourceBundle/modules/modlocal/src/test/module-info.java test/java/util/ResourceBundle/modules/security/TestPermission.java test/java/util/ResourceBundle/modules/security/src/m1/module-info.java test/java/util/ResourceBundle/modules/security/src/m1/p1/Bundle.java test/java/util/ResourceBundle/modules/security/src/m1/p1/resources/MyResources.java test/java/util/ResourceBundle/modules/security/src/test/jdk/test/Main.java test/java/util/ResourceBundle/modules/security/src/test/jdk/test/resources/TestResources.java test/java/util/ResourceBundle/modules/security/src/test/module-info.java test/java/util/ResourceBundle/modules/simple/simple.sh test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResources.java test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResourcesProvider.java test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResources_de.java test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResources_en.java test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResources_fr.java test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResources_ja.properties test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResources_zh.properties test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResources_zh_TW.properties test/java/util/ResourceBundle/modules/simple/src/bundles/module-info.java test/java/util/ResourceBundle/modules/simple/src/test/jdk/test/Main.java test/java/util/ResourceBundle/modules/simple/src/test/module-info.java test/java/util/ResourceBundle/modules/visibility/src/embargo/jdk/embargo/TestWithNoModuleArg.java test/java/util/ResourceBundle/modules/visibility/src/embargo/jdk/embargo/TestWithUnnamedModuleArg.java test/java/util/ResourceBundle/modules/visibility/src/embargo/module-info.java test/java/util/ResourceBundle/modules/visibility/src/exported.named.bundles/jdk/test/resources/exported/classes/MyResources.java test/java/util/ResourceBundle/modules/visibility/src/exported.named.bundles/jdk/test/resources/exported/classes/MyResourcesProvider.java test/java/util/ResourceBundle/modules/visibility/src/exported.named.bundles/jdk/test/resources/exported/props/MyResources.properties test/java/util/ResourceBundle/modules/visibility/src/exported.named.bundles/module-info.java test/java/util/ResourceBundle/modules/visibility/src/named.bundles/jdk/test/resources/classes/MyResources.java test/java/util/ResourceBundle/modules/visibility/src/named.bundles/jdk/test/resources/classes/MyResourcesProvider.java test/java/util/ResourceBundle/modules/visibility/src/named.bundles/jdk/test/resources/props/MyResources.properties test/java/util/ResourceBundle/modules/visibility/src/named.bundles/jdk/test/resources/props/MyResourcesProvider.java test/java/util/ResourceBundle/modules/visibility/src/named.bundles/module-info.java test/java/util/ResourceBundle/modules/visibility/src/pkg/jdk/pkg/resources/classes/MyResources.java test/java/util/ResourceBundle/modules/visibility/src/pkg/jdk/pkg/resources/props/MyResources.properties test/java/util/ResourceBundle/modules/visibility/src/pkg/jdk/pkg/test/Main.java test/java/util/ResourceBundle/modules/visibility/src/test/jdk/test/TestWithNoModuleArg.java test/java/util/ResourceBundle/modules/visibility/src/test/jdk/test/TestWithUnnamedModuleArg.java test/java/util/ResourceBundle/modules/visibility/src/test/module-info.java test/java/util/ResourceBundle/modules/visibility/visibility.sh test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResources.xml test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResourcesProvider.java test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResources_de.xml test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResources_en.xml test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResources_fr.xml test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResources_ja.xml test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResources_zh.xml test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResources_zh_TW.xml test/java/util/ResourceBundle/modules/xmlformat/src/bundles/module-info.java test/java/util/ResourceBundle/modules/xmlformat/src/test/jdk/test/Main.java test/java/util/ResourceBundle/modules/xmlformat/src/test/module-info.java test/java/util/ResourceBundle/modules/xmlformat/xmlformat.sh test/java/util/Scanner/ScannerStreamTest.java test/java/util/ServiceLoader/TwoIterators.java test/java/util/ServiceLoader/modules/BasicTest.java test/java/util/ServiceLoader/modules/ServicesTest.java test/java/util/ServiceLoader/modules/src/bananascript/module-info.java test/java/util/ServiceLoader/modules/src/bananascript/org/banana/BananaScript.java test/java/util/ServiceLoader/modules/src/bananascript/org/banana/BananaScriptEngineFactory.java test/java/util/ServiceLoader/modules/src/pearscript/META-INF/services/javax.script.ScriptEngineFactory test/java/util/ServiceLoader/modules/src/pearscript/org/pear/PearScript.java test/java/util/ServiceLoader/modules/src/pearscript/org/pear/PearScriptEngineFactory.java test/java/util/ServiceLoader/modules/src/test/module-info.java test/java/util/ServiceLoader/modules/src/test/test/Main.java test/java/util/logging/LocalizedLevelName.java test/java/util/logging/modules/GetResourceBundleTest.java test/java/util/logging/modules/pkgs/p3/resource/ClassResource.java test/java/util/logging/modules/pkgs/p3/resource/p.properties test/java/util/logging/modules/pkgs/p3/test/ResourceBundleTest.java test/java/util/logging/modules/src/m1/module-info.java test/java/util/logging/modules/src/m1/p1/resource/ClassResource.java test/java/util/logging/modules/src/m1/p1/resource/p.properties test/java/util/logging/modules/src/m2/module-info.java test/java/util/logging/modules/src/m2/p2/resource/ClassResource.java test/java/util/logging/modules/src/m2/p2/resource/p.properties test/java/util/logging/modules/src/m2/p2/test/ModuleLoggerAccess.java test/java/util/regex/PatternStreamTest.java test/java/util/stream/bootlib/TEST.properties test/java/util/stream/boottest/TEST.properties test/java/util/stream/test/TEST.properties test/javax/crypto/NullCipher/TestWithoutInit.java test/javax/imageio/plugins/external_plugin_tests/TestClassPathPlugin.sh test/javax/imageio/plugins/external_plugin_tests/src/simp/META-INF/services/javax.imageio.spi.ImageReaderSpi test/javax/imageio/plugins/external_plugin_tests/src/simp/SIMPImageReader.java test/javax/imageio/plugins/external_plugin_tests/src/simp/SIMPImageReaderSpi.java test/javax/imageio/plugins/external_plugin_tests/src/simp/SIMPMetadata.java test/javax/imageio/plugins/external_plugin_tests/src/simp/SIMPMetadataFormat.java test/javax/imageio/plugins/external_plugin_tests/src/simp/module-info.java test/javax/imageio/plugins/external_plugin_tests/src/simptest/TestSIMPPlugin.java test/javax/imageio/stream/StreamCloserLeak/run_test.sh test/javax/management/MBeanInfo/NotificationInfoTest.java test/javax/naming/module/basic.sh test/javax/naming/module/src/authz/module-info.java test/javax/naming/module/src/authz/org/example/authz/AuthzIdRequestControl.java test/javax/naming/module/src/authz/org/example/authz/AuthzIdResponseControl.java test/javax/naming/module/src/authz/org/example/authz/AuthzIdResponseControlFactory.java test/javax/naming/module/src/foo/module-info.java test/javax/naming/module/src/foo/org/example/foo/FooControl.java test/javax/naming/module/src/fruit/module-info.java test/javax/naming/module/src/fruit/org/example/fruit/Fruit.java test/javax/naming/module/src/fruit/org/example/fruit/FruitFactory.java test/javax/naming/module/src/hello/module-info.java test/javax/naming/module/src/hello/org/example/hello/Hello.java test/javax/naming/module/src/hello/org/example/hello/HelloImpl.java test/javax/naming/module/src/ldapv4/module-info.java test/javax/naming/module/src/ldapv4/org/example/ldapv4/ldapv4URLContext.java test/javax/naming/module/src/ldapv4/org/example/ldapv4/ldapv4URLContextFactory.java test/javax/naming/module/src/person/module-info.java test/javax/naming/module/src/person/org/example/person/Person.java test/javax/naming/module/src/person/org/example/person/PersonFactory.java test/javax/naming/module/src/test/module-info.java test/javax/naming/module/src/test/test/ConnectWithAuthzId.java test/javax/naming/module/src/test/test/ConnectWithAuthzId.ldap test/javax/naming/module/src/test/test/ConnectWithFoo.java test/javax/naming/module/src/test/test/ConnectWithFoo.ldap test/javax/naming/module/src/test/test/LDAPServer.java test/javax/naming/module/src/test/test/ReadByUrl.java test/javax/naming/module/src/test/test/ReadByUrl.ldap test/javax/naming/module/src/test/test/StoreFruit.java test/javax/naming/module/src/test/test/StoreFruit.ldap test/javax/naming/module/src/test/test/StoreObject.java test/javax/naming/module/src/test/test/StoreObject.ldap test/javax/naming/module/src/test/test/StorePerson.java test/javax/naming/module/src/test/test/StorePerson.ldap test/javax/naming/module/src/test/test/StoreRemote.java test/javax/naming/module/src/test/test/StoreRemote.ldap test/javax/net/ssl/Stapling/TEST.properties test/javax/security/auth/login/modules/JaasClient.java test/javax/security/auth/login/modules/JaasModularClientTest.java test/javax/security/auth/login/modules/TEST.properties test/javax/security/auth/login/modules/TestLoginModule.java test/javax/security/auth/login/modules/jaas.conf test/javax/swing/JComboBox/8080972/TestBasicComboBoxEditor.java test/javax/swing/JEditorPane/8080972/TestJEditor.java test/javax/swing/JFormattedTextField/8080972/TestDefaultFormatter.java test/javax/swing/JTable/8080972/TestJTableCellEditor.java test/javax/swing/UIDefaults/8080972/TestProxyLazyValue.java test/javax/swing/dnd/8080972/TestTransferHandler.java test/javax/swing/plaf/nimbus/8080972/TestAbstractRegionPainter.java test/javax/swing/text/View/8080972/TestObjectView.java test/javax/xml/jaxp/Encodings/CheckEncodingPropertiesFile.java test/javax/xml/jaxp/common/8035437/run.sh test/javax/xml/soap/XmlTest.java test/jdk/asm/AsmSanity.java test/jdk/internal/jimage/ExecutableTest.java test/jdk/internal/jimage/JImageReadTest.java test/jdk/internal/jimage/JImageTest.java test/jdk/internal/jimage/TEST.properties test/jdk/internal/jimage/VerifyJimage.java test/jdk/internal/jrtfs/Basic.java test/jdk/internal/ref/Cleaner/ExitOnThrow.java test/jdk/modules/etc/VerifyModuleDelegation.java test/jdk/modules/scenarios/automaticmodules/RunWithAutomaticModules.java test/jdk/modules/scenarios/automaticmodules/src/bananascript/META-INF/services/javax.script.ScriptEngineFactory test/jdk/modules/scenarios/automaticmodules/src/bananascript/org/banana/BananaScript.java test/jdk/modules/scenarios/automaticmodules/src/bananascript/org/banana/BananaScriptEngineFactory.java test/jdk/modules/scenarios/automaticmodules/src/basictest/module-info.java test/jdk/modules/scenarios/automaticmodules/src/basictest/test/Main.java test/jdk/modules/scenarios/automaticmodules/src/httpserver/http/HttpServer.java test/jdk/modules/scenarios/automaticmodules/src/httpserver/http/spi/HttpServerProvider.java test/jdk/modules/scenarios/automaticmodules/src/logging/logging/Logger.java test/jdk/modules/scenarios/automaticmodules/src/sptest/module-info.java test/jdk/modules/scenarios/automaticmodules/src/sptest/test/Main.java test/jdk/modules/scenarios/container/ContainerTest.java test/jdk/modules/scenarios/container/src/app1/app1/Main.java test/jdk/modules/scenarios/container/src/app1/module-info.java test/jdk/modules/scenarios/container/src/app2/app2/Main.java test/jdk/modules/scenarios/container/src/app2/module-info.java test/jdk/modules/scenarios/container/src/container/container/Main.java test/jdk/modules/scenarios/container/src/container/module-info.java test/jdk/modules/scenarios/container/src/java.ws.rs/javax/ws/rs/Client.java test/jdk/modules/scenarios/container/src/java.ws.rs/module-info.java test/jdk/modules/scenarios/container/src/java.xml.ws/javax/xml/ws/WebService.java test/jdk/modules/scenarios/container/src/java.xml.ws/module-info.java test/jdk/modules/scenarios/overlappingpackages/OverlappingPackagesTest.java test/jdk/modules/scenarios/overlappingpackages/src/m1/module-info.java test/jdk/modules/scenarios/overlappingpackages/src/m1/p/C1.java test/jdk/modules/scenarios/overlappingpackages/src/m2/module-info.java test/jdk/modules/scenarios/overlappingpackages/src/m2/p/C2.java test/jdk/modules/scenarios/overlappingpackages/src/misc/module-info.java test/jdk/modules/scenarios/overlappingpackages/src/misc/sun/misc/Unsafe.java test/jdk/modules/scenarios/overlappingpackages/src/test/module-info.java test/jdk/modules/scenarios/overlappingpackages/src/test/test/Main.java test/lib/testlibrary/CompilerUtils.java test/lib/testlibrary/JarUtils.java test/lib/testlibrary/ModuleUtils.java test/lib/testlibrary/jdk/testlibrary/OutputAnalyzer.java test/lib/testlibrary/jdk/testlibrary/ProcessTools.java test/sun/awt/shell/ShellFolderMemoryLeak.java test/sun/management/StackTraceElementCompositeData/CompatibilityTest.java test/sun/management/jmxremote/bootstrap/CustomLauncherTest.java test/sun/management/jmxremote/bootstrap/LocalManagementTest.java test/sun/management/jmxremote/bootstrap/RmiBootstrapTest.sh test/sun/management/jmxremote/bootstrap/RmiSslBootstrapTest.sh test/sun/management/jmxremote/bootstrap/RmiSslNoKeyStoreTest.sh test/sun/management/jmxremote/startstop/JMXStatusPerfCountersTest.java test/sun/net/idn/TestStringPrep.java test/sun/net/util/IPAddressUtilTest.java test/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxy.sh test/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxyWithAuth.sh test/sun/net/www/protocol/jrt/Basic.java test/sun/net/www/protocol/jrt/OtherResources.java test/sun/net/www/protocol/jrt/WithSecurityManager.java test/sun/net/www/protocol/jrt/other_resources.sh test/sun/reflect/Reflection/GetCallerClassTest.sh test/sun/reflect/constantPool/ConstantPoolTest.java test/sun/rmi/runtime/Log/6409194/NoConsoleOutput.java test/sun/security/krb5/auto/HttpNegotiateServer.java test/sun/security/krb5/config/ConfPlusProp.java test/sun/security/krb5/config/DNS.java test/sun/security/krb5/config/NamingManager.java test/sun/security/krb5/config/dns.sh test/sun/security/krb5/config/java.naming/javax/naming/spi/NamingManager.java test/sun/security/krb5/tools/ktcheck.sh test/sun/security/mscapi/IsSunMSCAPIAvailable.java test/sun/security/mscapi/IsSunMSCAPIAvailable.sh test/sun/security/mscapi/PublicKeyInterop.sh test/sun/security/mscapi/ShortRSAKey1024.sh test/sun/security/pkcs11/KeyStore/ClientAuth.sh test/sun/security/pkcs11/Provider/Login.policy test/sun/security/provider/PolicyFile/Modules.java test/sun/security/provider/PolicyFile/modules.policy test/sun/security/provider/certpath/OCSP/OCSPSingleExtensions.java test/sun/security/ssl/StatusStapling/BogusStatusRequest.java test/sun/security/ssl/StatusStapling/CertStatusReqExtensionTests.java test/sun/security/ssl/StatusStapling/CertStatusReqItemV2Tests.java test/sun/security/ssl/StatusStapling/CertStatusReqListV2ExtensionTests.java test/sun/security/ssl/StatusStapling/OCSPStatusRequestTests.java test/sun/security/ssl/StatusStapling/StatusResponseManagerTests.java test/sun/security/ssl/StatusStapling/TEST.properties test/sun/security/ssl/StatusStapling/TestCase.java test/sun/security/ssl/StatusStapling/TestRun.java test/sun/security/ssl/StatusStapling/TestUtils.java test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/BogusStatusRequest.java test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/CertStatusReqExtensionTests.java test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/CertStatusReqItemV2Tests.java test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/CertStatusReqListV2ExtensionTests.java test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/OCSPStatusRequestTests.java test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/StatusResponseManagerTests.java test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/TestCase.java test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/TestUtils.java test/sun/security/tools/jarsigner/ts.sh test/sun/security/tools/keytool/autotest.sh test/sun/security/tools/keytool/standard.sh test/sun/security/util/Oid/OidEquals.java test/sun/security/validator/certreplace.sh test/sun/security/validator/samedn.sh test/sun/security/x509/URICertStore/ExtensionsWithLDAP.java test/sun/tools/jconsole/ResourceCheckTest.java test/sun/tools/jhsdb/SAGetoptTest.java test/sun/util/resources/TimeZone/Bug4640234.java test/tools/jar/compat/CLICompatibility.java test/tools/jar/modularJar/Basic.java test/tools/jar/modularJar/src/bar/jdk/test/bar/Bar.java test/tools/jar/modularJar/src/bar/jdk/test/bar/internal/Message.java test/tools/jar/modularJar/src/bar/module-info.java test/tools/jar/modularJar/src/baz/jdk/test/baz/BazService.java test/tools/jar/modularJar/src/baz/jdk/test/baz/internal/BazServiceImpl.java test/tools/jar/modularJar/src/baz/module-info.java test/tools/jar/modularJar/src/foo/jdk/test/foo/Foo.java test/tools/jar/modularJar/src/foo/jdk/test/foo/internal/Message.java test/tools/jar/modularJar/src/foo/module-info.java test/tools/jimage/JImageTest.java test/tools/jimage/JImageToolTest.java test/tools/jimage/VerifyJimage.java test/tools/jlink/CheckExecutable.java test/tools/jlink/CustomPluginTest.java test/tools/jlink/DefaultProviderTest.java test/tools/jlink/ImageFileCreatorTest.java test/tools/jlink/ImageFilePoolTest.java test/tools/jlink/IntegrationTest.java test/tools/jlink/JLink2Test.java test/tools/jlink/JLinkNegativeTest.java test/tools/jlink/JLinkOptimTest.java test/tools/jlink/JLinkOptionsTest.java test/tools/jlink/JLinkPluginsTest.java test/tools/jlink/JLinkPostProcessingTest.java test/tools/jlink/JLinkTest.java test/tools/jlink/NativeTest.java test/tools/jlink/ResourcePoolTest.java test/tools/jlink/SecurityTest.java test/tools/jlink/asmplugin/AddForgetResourcesTest.java test/tools/jlink/asmplugin/AsmPluginTestBase.java test/tools/jlink/asmplugin/BasicTest.java test/tools/jlink/asmplugin/IdentityPluginTest.java test/tools/jlink/asmplugin/NegativeTest.java test/tools/jlink/asmplugin/PackageMappingTest.java test/tools/jlink/asmplugin/SortingTest.java test/tools/jlink/asmplugin/VisitorTest.java test/tools/jlink/basic/BasicTest.java test/tools/jlink/basic/src/test/jdk/test/Test.java test/tools/jlink/basic/src/test/module-info.java test/tools/jlink/customplugin/module-info.java test/tools/jlink/customplugin/plugin/CustomPlugin.java test/tools/jlink/customplugin/plugin/HelloPlugin.java test/tools/jlink/hashes/HashesTest.java test/tools/jlink/hashes/newsrc/m2/module-info.java test/tools/jlink/hashes/newsrc/m2/org/m2/Util.java test/tools/jlink/hashes/newsrc/not_matched/module-info.java test/tools/jlink/hashes/newsrc/not_matched/org/not_matched/Name.java test/tools/jlink/hashes/src/m1/module-info.java test/tools/jlink/hashes/src/m1/org/m1/Main.java test/tools/jlink/hashes/src/m2/module-info.java test/tools/jlink/hashes/src/m2/org/m2/Util.java test/tools/jlink/hashes/src/not_matched/module-info.java test/tools/jlink/hashes/src/not_matched/org/not_matched/Name.java test/tools/jlink/optimplugin/module-info.java test/tools/jlink/optimplugin/optim/AType.java test/tools/jlink/optimplugin/optim/ForNameTestCase.java test/tools/jlink/plugins/CompressIndexesTest.java test/tools/jlink/plugins/CompressorPluginTest.java test/tools/jlink/plugins/ExcludeFilesPluginTest.java test/tools/jlink/plugins/ExcludePluginTest.java test/tools/jlink/plugins/ExcludeVMPluginTest.java test/tools/jlink/plugins/FileCopierPluginTest.java test/tools/jlink/plugins/GetAvailableLocales.java test/tools/jlink/plugins/IncludeLocalesPluginTest.java test/tools/jlink/plugins/InstalledModuleDescriptors/InstalledModulesTest.java test/tools/jlink/plugins/InstalledModuleDescriptors/UserModuleTest.java test/tools/jlink/plugins/InstalledModuleDescriptors/src/m1/module-info.java test/tools/jlink/plugins/InstalledModuleDescriptors/src/m1/p1/Main.java test/tools/jlink/plugins/InstalledModuleDescriptors/src/m1/p2/T.java test/tools/jlink/plugins/InstalledModuleDescriptors/src/m2/module-info.java test/tools/jlink/plugins/InstalledModuleDescriptors/src/m2/q/S1.java test/tools/jlink/plugins/InstalledModuleDescriptors/src/m2/q/S2.java test/tools/jlink/plugins/InstalledModuleDescriptors/src/m3/module-info.java test/tools/jlink/plugins/LastSorterTest.java test/tools/jlink/plugins/PluginOrderTest.java test/tools/jlink/plugins/PluginsNegativeTest.java test/tools/jlink/plugins/PrevisitorTest.java test/tools/jlink/plugins/ResourceFilterTest.java test/tools/jlink/plugins/SignatureParserTest.java test/tools/jlink/plugins/SorterPluginTest.java test/tools/jlink/plugins/StringSharingPluginTest.java test/tools/jlink/plugins/StripDebugPluginTest.java test/tools/jmod/JmodNegativeTest.java test/tools/jmod/JmodTest.java test/tools/jmod/src/foo/jdk/test/foo/Foo.java test/tools/jmod/src/foo/jdk/test/foo/internal/Message.java test/tools/jmod/src/foo/module-info.java test/tools/launcher/MiscTests.java test/tools/launcher/ToolsOpts.java test/tools/launcher/VersionCheck.java test/tools/launcher/modules/addexports/AddExportsTest.java test/tools/launcher/modules/addexports/src/java.transaction/javax/transaction/Transaction.java test/tools/launcher/modules/addexports/src/java.transaction/javax/transaction/internal/Helper.java test/tools/launcher/modules/addexports/src/java.transaction/module-info.java test/tools/launcher/modules/addexports/src/m1/jdk/test1/Main.java test/tools/launcher/modules/addexports/src/m1/module-info.java test/tools/launcher/modules/addexports/src/m2/jdk/test2/Main.java test/tools/launcher/modules/addexports/src/m2/module-info.java test/tools/launcher/modules/addexports/src/m3/jdk/test3/Main.java test/tools/launcher/modules/addexports/src/m3/module-info.java test/tools/launcher/modules/addexports/src/m4/jdk/test4/Type.java test/tools/launcher/modules/addexports/src/m4/module-info.java test/tools/launcher/modules/addmods/AddModsTest.java test/tools/launcher/modules/addmods/src/app/Main.java test/tools/launcher/modules/addmods/src/lib/jdk/lib/Util.java test/tools/launcher/modules/addmods/src/lib/module-info.java test/tools/launcher/modules/addreads/AddReadsTest.java test/tools/launcher/modules/addreads/src/junit/org/junit/Assert.java test/tools/launcher/modules/addreads/src/m1/module-info.java test/tools/launcher/modules/addreads/src/m1/p/Main.java test/tools/launcher/modules/basic/BasicTest.java test/tools/launcher/modules/basic/src/test/jdk/test/Main.java test/tools/launcher/modules/basic/src/test/module-info.java test/tools/launcher/modules/limitmods/LimitModsTest.java test/tools/launcher/modules/limitmods/src/test/jdk/test/UseAWT.java test/tools/launcher/modules/limitmods/src/test/module-info.java test/tools/launcher/modules/listmods/ListModsTest.java test/tools/launcher/modules/listmods/src/java.transaction/javax/transaction/Transaction.java test/tools/launcher/modules/listmods/src/java.transaction/javax/transaction/atomic/Atomic.java test/tools/launcher/modules/listmods/src/java.transaction/module-info.java test/tools/launcher/modules/listmods/src/m1/module-info.java test/tools/launcher/modules/patch/PatchTest.java test/tools/launcher/modules/patch/src/test/jdk/test/Main.java test/tools/launcher/modules/patch/src/test/module-info.java test/tools/launcher/modules/patch/src1/java.base/java/text/Annotation.java test/tools/launcher/modules/patch/src1/java.base/java/text/AnnotationBuddy.java test/tools/launcher/modules/patch/src1/jdk.compiler/com/sun/tools/javac/Main.java test/tools/launcher/modules/patch/src1/jdk.compiler/com/sun/tools/javac/MainBuddy.java test/tools/launcher/modules/patch/src1/jdk.naming.dns/com/sun/jndi/dns/DnsClient.java test/tools/launcher/modules/patch/src1/jdk.naming.dns/com/sun/jndi/dns/DnsClientBuddy.java test/tools/launcher/modules/patch/src2/java.base/java/lang2/Object.java test/tools/launcher/modules/patch/src2/jdk.compiler/com/sun/tools/javac2/Main.java test/tools/launcher/modules/patch/src2/jdk.naming.dns/com/sun/jndi/dns2/Zone.java test/tools/launcher/modules/upgrademodulepath/UpgradeModulePathTest.java test/tools/launcher/modules/upgrademodulepath/src/java.enterprise/javax/enterprise/context/Scope.java test/tools/launcher/modules/upgrademodulepath/src/java.enterprise/module-info.java test/tools/launcher/modules/upgrademodulepath/src/java.transaction/javax/transaction/Transaction.java test/tools/launcher/modules/upgrademodulepath/src/java.transaction/module-info.java test/tools/launcher/modules/upgrademodulepath/src/test/jdk/test/Main.java test/tools/launcher/modules/upgrademodulepath/src/test/module-info.java test/tools/lib/tests/Helper.java test/tools/lib/tests/JImageGenerator.java test/tools/lib/tests/JImageValidator.java test/tools/lib/tests/Result.java test/tools/pack200/ModuleAttributes.java test/tools/pack200/Utils.java test/tools/pack200/pack200-verifier/make/build.xml test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java
diffstat 1221 files changed, 98921 insertions(+), 16782 deletions(-) [+]
line wrap: on
line diff
--- a/make/CompileInterimRmic.gmk	Tue Mar 15 13:48:26 2016 -0700
+++ b/make/CompileInterimRmic.gmk	Thu Mar 17 19:04:16 2016 +0000
@@ -44,8 +44,9 @@
 $(eval $(call SetupJavaCompilation,BUILD_INTERIM_RMIC, \
     SETUP := GENERATE_OLDBYTECODE, \
     SRC := $(JDK_TOPDIR)/src/jdk.rmic/share/classes, \
+    EXCLUDE_FILES := module-info.java, \
     INCLUDES := $(RMIC_PKGS), \
-    BIN := $(BUILDTOOLS_OUTPUTDIR)/interim_rmic_classes, \
+    BIN := $(BUILDTOOLS_OUTPUTDIR)/override_modules/jdk.rmic, \
     COPY := .properties))
 
 ##########################################################################################
--- a/make/CompileTools.gmk	Tue Mar 15 13:48:26 2016 -0700
+++ b/make/CompileTools.gmk	Thu Mar 17 19:04:16 2016 +0000
@@ -32,42 +32,12 @@
 
 ################################################################################
 
-JIMAGE_PKGS := \
-    jdk/internal/jimage \
-    jdk/internal/jrtfs \
-    #
-
-$(eval $(call SetupJavaCompilation,BUILD_INTERIM_JIMAGE, \
-    SETUP := GENERATE_OLDBYTECODE, \
-    SRC := $(JDK_TOPDIR)/src/java.base/share/classes, \
-    INCLUDES := $(JIMAGE_PKGS), \
-    BIN := $(BUILDTOOLS_OUTPUTDIR)/interim_jimage_classes))
-
-TARGETS += $(BUILD_INTERIM_JIMAGE)
-
-# Because of the explicit INCLUDES in the compilation setup above, the service provider
-# file will not be copied unless META-INF/services would also be added to the INCLUDES.
-# Adding META-INF/services would include all files in that directory when only the one
-# is needed, which is why this explicit copy is defined instead.
-$(eval $(call SetupCopyFiles,COPY_JIMAGE_SERVICE_PROVIDER, \
-    SRC := $(JDK_TOPDIR)/src/java.base/share/classes, \
-    DEST := $(BUILDTOOLS_OUTPUTDIR)/interim_jimage_classes, \
-    FILES := META-INF/services/java.nio.file.spi.FileSystemProvider))
-
-TARGETS += $(COPY_JIMAGE_SERVICE_PROVIDER)
-
-################################################################################
-
 $(eval $(call SetupJavaCompilation,BUILD_TOOLS_JDK, \
     SETUP := GENERATE_OLDBYTECODE, \
-    ADD_JAVAC_FLAGS := -Xbootclasspath/p:$(call PathList, \
-        $(BUILDTOOLS_OUTPUTDIR)/interim_jimage_classes \
-        $(BUILDTOOLS_OUTPUTDIR)/interim_cldrconverter_classes), \
     SRC := $(JDK_TOPDIR)/make/src/classes $(BUILDTOOLS_OUTPUTDIR)/interim_cldrconverter_classes, \
-    BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes, \
-    COPY := boot.modules ext.modules))
-
-$(BUILD_TOOLS_JDK): $(BUILD_INTERIM_JIMAGE) $(COPY_JIMAGE_SERVICE_PROVIDER)
+    EXCLUDES := build/tools/deps \
+                build/tools/jigsaw, \
+    BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes))
 
 TARGETS += $(BUILD_TOOLS_JDK)
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/GenerateModuleSummary.gmk	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,47 @@
+#
+# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+# Default target declared first
+default: all
+
+include $(SPEC)
+include MakeBase.gmk
+include ModuleTools.gmk
+
+GENGRAPHS_DIR := $(IMAGES_OUTPUTDIR)/gengraphs
+TOOLS_MODULE_SRCDIR := $(JDK_TOPDIR)/make/src/classes/build/tools/jigsaw
+
+$(GENGRAPHS_DIR)/jdk.dot: $(BUILD_JIGSAW_TOOLS)
+	$(MKDIR) -p $(@D)
+	$(TOOL_GENGRAPHS) $(GENGRAPHS_DIR)
+
+$(GENGRAPHS_DIR)/technology-summary.html: $(TOOLS_MODULE_SRCDIR)/technology-summary.html
+	$(install-file)
+
+$(GENGRAPHS_DIR)/module-summary.html: $(BUILD_JIGSAW_TOOLS) $(GENGRAPHS_DIR)/technology-summary.html
+	$(MKDIR) -p $(@D)
+	$(TOOL_MODULESUMMARY) -o $@ -mp $(IMAGES_OUTPUTDIR)/jmods
+
+all: $(GENGRAPHS_DIR)/jdk.dot $(GENGRAPHS_DIR)/module-summary.html
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/ModuleTools.gmk	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,47 @@
+#
+# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+include $(SPEC)
+include MakeBase.gmk
+include JavaCompilation.gmk
+include SetupJavaCompilers.gmk
+
+TOOLS_CLASSES_DIR := $(BUILDTOOLS_OUTPUTDIR)/tools_jigsaw_classes
+
+$(eval $(call SetupJavaCompilation,BUILD_JIGSAW_TOOLS, \
+    SETUP := GENERATE_USINGJDKBYTECODE, \
+    SRC := $(JDK_TOPDIR)/make/src/classes, \
+    INCLUDES := build/tools/deps \
+                build/tools/jigsaw, \
+    BIN := $(TOOLS_CLASSES_DIR), \
+    ADD_JAVAC_FLAGS := -XaddExports:jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED ))
+
+
+TOOL_GENGRAPHS := $(BUILD_JAVA) -esa -ea -cp $(TOOLS_CLASSES_DIR) \
+    build.tools.jigsaw.GenGraphs
+
+TOOL_MODULESUMMARY := $(BUILD_JAVA) -esa -ea -cp $(TOOLS_CLASSES_DIR) \
+    -XaddExports:jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED \
+    build.tools.jigsaw.ModuleSummary
--- a/make/Tools.gmk	Tue Mar 15 13:48:26 2016 -0700
+++ b/make/Tools.gmk	Thu Mar 17 19:04:16 2016 +0000
@@ -41,7 +41,12 @@
 TOOL_ADDJSUM = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \
     build.tools.addjsum.AddJsum
 
+ifeq ($(BOOT_JDK_MODULAR), true)
+  COMPILEFONTCONFIG_ADD_EXPORTS := -XaddExports:java.desktop/sun.awt=ALL-UNNAMED
+endif
+
 TOOL_COMPILEFONTCONFIG = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \
+    $(COMPILEFONTCONFIG_ADD_EXPORTS) \
     build.tools.compilefontconfig.CompileFontConfig
 
 TOOL_COMPILEPROPERTIES = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \
@@ -106,12 +111,18 @@
 TOOL_CLDRCONVERTER = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \
     build.tools.cldrconverter.CLDRConverter
 
-TOOL_GENMODULESXML = $(JAVA_SMALL) -Xbootclasspath/p:$(INTERIM_LANGTOOLS_JAR) \
-    -cp $(call PathList, $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes $(JDK_OUTPUTDIR)) \
+TOOL_GENMODULESXML = $(JAVA_SMALL) $(INTERIM_LANGTOOLS_BOOTCLASSPATH) \
+    -cp $(call PathList, $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes) \
     build.tools.module.GenJdepsModulesXml
 
-TOOL_IMAGEBUILDER = $(JAVA_SMALL) -Xbootclasspath/p:$(BUILDTOOLS_OUTPUTDIR)/interim_jimage_classes \
-    -cp $(call PathList, $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes $(JDK_OUTPUTDIR)) \
-    build.tools.module.ImageBuilder
+TOOL_GENMODULEINFOSOURCE = $(JAVA_SMALL) $(INTERIM_LANGTOOLS_BOOTCLASSPATH) \
+    -cp $(call PathList, $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes) \
+    build.tools.module.GenModuleInfoSource
+
+TOOL_GENCLASSLOADERMAP = $(JAVA_SMALL) $(INTERIM_LANGTOOLS_BOOTCLASSPATH) \
+    -cp $(call PathList, $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes) \
+    build.tools.module.GenModuleLoaderMap
+
+##########################################################################################
 
 endif # _TOOLS_GMK
--- a/make/copy/Copy-java.base.gmk	Tue Mar 15 13:48:26 2016 -0700
+++ b/make/copy/Copy-java.base.gmk	Thu Mar 17 19:04:16 2016 +0000
@@ -172,6 +172,11 @@
   POLICY_SRC_LIST += $(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS)/conf/security/java.policy
 endif
 
+# Allow imported modules to modify the java.policy
+ifneq ($(IMPORT_MODULES_CONF), )
+  POLICY_SRC_LIST += $(wildcard $(IMPORT_MODULES_CONF)/java.base/security/java.policy.extra)
+endif
+
 POLICY_SRC_LIST += $(POLICY_SRC)
 
 $(POLICY_DST): $(POLICY_SRC_LIST)
--- a/make/data/jdwp/jdwp.spec	Tue Mar 15 13:48:26 2016 -0700
+++ b/make/data/jdwp/jdwp.spec	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -569,6 +569,21 @@
             (Error VM_DEAD)
         )
     )
+    (Command AllModules=22
+        "Returns all modules in the target VM."
+        "<p>Since JDWP version 9."
+        (Out
+        )
+        (Reply
+            (Repeat modules "The number of the modules that follow."
+                (moduleID module "One of the modules.")
+            )
+        )
+        (ErrorSet
+            (Error NOT_IMPLEMENTED)
+            (Error VM_DEAD)
+        )
+    )
 )
 
 (CommandSet ReferenceType=2
@@ -1029,6 +1044,22 @@
             (Error VM_DEAD)
         )
     )
+    (Command Module=19
+        "Returns the module that this reference type belongs to."
+        "<p>Since JDWP version 9."
+        (Out
+            (referenceType refType "The reference type.")
+        )
+        (Reply
+            (moduleID module "The module this reference type belongs to.")
+        )
+        (ErrorSet
+            (Error INVALID_CLASS   "refType is not the ID of a reference type.")
+            (Error INVALID_OBJECT  "refType is not a known ID.")
+            (Error NOT_IMPLEMENTED)
+            (Error VM_DEAD)
+        )
+    )
 )
 (CommandSet ClassType=3
     (Command Superclass=1
@@ -2647,6 +2678,54 @@
         )
     )
 )
+(CommandSet ModuleReference=18
+    (Command Name=1
+        "Returns the name of this module."
+        "<p>Since JDWP version 9."
+        (Out
+            (moduleID module "This module.")
+        )
+        (Reply
+            (string name  "The module's name.")
+        )
+        (ErrorSet
+            (Error INVALID_MODULE)
+            (Error NOT_IMPLEMENTED)
+            (Error VM_DEAD)
+        )
+    )
+    (Command ClassLoader=2
+        "Returns the class loader of this module."
+        "<p>Since JDWP version 9."
+        (Out
+            (moduleID module "This module.")
+        )
+        (Reply
+            (classLoaderObject classLoader  "The module's class loader.")
+        )
+        (ErrorSet
+            (Error INVALID_MODULE)
+            (Error NOT_IMPLEMENTED)
+            (Error VM_DEAD)
+        )
+    )
+    (Command CanRead=3
+        "Returns true if this module can read the source module; false otherwise."
+        "<p>Since JDWP version 9."
+        (Out
+            (moduleID module "This module.")
+            (moduleID sourceModule "The source module.")
+        )
+        (Reply
+            (boolean canRead  "true if this module can read the source module; false otherwise.")
+        )
+        (ErrorSet
+            (Error INVALID_MODULE  "This module or sourceModule is not the ID of a module.")
+            (Error NOT_IMPLEMENTED)
+            (Error VM_DEAD)
+        )
+    )
+)
 (CommandSet Event=64
     (Command Composite=100
         "Several events may occur at a given time in the target VM. "
@@ -3054,6 +3133,7 @@
     (Constant INVALID_SLOT           =35  "Invalid slot.")
     (Constant DUPLICATE              =40  "Item already set.")
     (Constant NOT_FOUND              =41  "Desired element not found.")
+    (Constant INVALID_MODULE         =42  "Invalid module.")
     (Constant INVALID_MONITOR        =50  "Invalid monitor.")
     (Constant NOT_MONITOR_OWNER      =51  "This thread doesn't own the monitor.")
     (Constant INTERRUPT              =52  "The call has been interrupted before completion.")
--- a/make/gendata/Gendata-jdk.jdeps.gmk	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-#
-# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.  Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-include GendataCommon.gmk
-
-$(eval $(call IncludeCustomExtension, jdk, gendata/Gendata-jdk.jdeps.gmk))
-
-JDEPS_MODULES_XML := $(JDK_OUTPUTDIR)/modules/jdk.jdeps/com/sun/tools/jdeps/resources/jdeps-modules.xml
-MODULES_XML += $(TOPDIR)/modules.xml
-
-#
-# Generate modules.xml for jdeps to use
-# It augments $(TOPDIR)/modules.xml to include module membership
-#
-$(JDEPS_MODULES_XML): $(BUILD_TOOLS_JDK) $(MODULES_XML)
-	$(MKDIR) -p $(@D)
-	$(RM) $@
-	$(TOOL_GENMODULESXML) -o $@ -mp $(JDK_OUTPUTDIR)/modules $(MODULES_XML)
-
-TARGETS += $(JDEPS_MODULES_XML)
--- a/make/gendata/GendataBreakIterator.gmk	Tue Mar 15 13:48:26 2016 -0700
+++ b/make/gendata/GendataBreakIterator.gmk	Thu Mar 17 19:04:16 2016 +0000
@@ -33,8 +33,6 @@
 # They are used at JDK build phase in order to create $(BIFILES) which
 # are used on runtime instead.
 #
-TEXT_SRCDIR := $(JDK_TOPDIR)/src/java.base/share/classes \
-    $(JDK_TOPDIR)/src/jdk.localedata/share/classes
 TEXT_PKG := sun/text/resources
 TEXT_PKG_LD := $(TEXT_PKG)/ext
 TEXT_SOURCES := $(TEXT_PKG)/BreakIteratorRules.java \
@@ -46,11 +44,35 @@
 BREAK_ITERATOR_CLASSES := $(BUILDTOOLS_OUTPUTDIR)/break_iterator_classes
 
 # These two files should be moved out to a build tool!
-$(eval $(call SetupJavaCompilation,BUILD_BREAKITERATOR, \
+$(eval $(call SetupJavaCompilation,BUILD_BREAKITERATOR_BASE, \
+    SETUP := GENERATE_OLDBYTECODE, \
+    SRC := $(JDK_TOPDIR)/src/java.base/share/classes, \
+    INCLUDE_FILES := \
+        $(TEXT_PKG)/BreakIteratorRules.java \
+        $(TEXT_PKG)/BreakIteratorInfo.java, \
+    BIN := $(BREAK_ITERATOR_CLASSES)/java.base))
+
+$(eval $(call SetupJavaCompilation,BUILD_BREAKITERATOR_LD, \
     SETUP := GENERATE_OLDBYTECODE, \
-    SRC := $(TEXT_SRCDIR), \
-    INCLUDE_FILES := $(TEXT_SOURCES), \
-    BIN := $(BREAK_ITERATOR_CLASSES)))
+    SRC := $(JDK_TOPDIR)/src/jdk.localedata/share/classes, \
+    INCLUDES := $(TEXT_PKG_LD), \
+    INCLUDE_FILES := \
+        $(TEXT_PKG_LD)/BreakIteratorRules_th.java \
+        $(TEXT_PKG_LD)/BreakIteratorInfo_th.java, \
+    BIN := $(BREAK_ITERATOR_CLASSES)/jdk.localedata))
+
+ifeq ($(BOOT_JDK_MODULAR), true)
+  BREAK_ITERATOR_BOOTCLASSPATH := -Xpatch:$(BREAK_ITERATOR_CLASSES) \
+      -XaddExports:$(subst $(SPACE),$(COMMA),$(strip \
+          java.base/sun.text=ALL-UNNAMED \
+          java.base/sun.text.resources=ALL-UNNAMED \
+          jdk.localedata/sun.text.resources.ext=ALL-UNNAMED \
+      ))
+else
+  BREAK_ITERATOR_BOOTCLASSPATH := -Xbootclasspath/p:$(call PathList, \
+      $(BREAK_ITERATOR_CLASSES)/java.base \
+      $(BREAK_ITERATOR_CLASSES)/jdk.localedata)
+endif
 
 # Generate data resource files.
 # input
@@ -67,8 +89,9 @@
     $(LD_DATA_PKG_DIR)/LineBreakIteratorData_th
 
 $(BIFILES): $(BASE_DATA_PKG_DIR)/_the.bifiles
-$(BASE_DATA_PKG_DIR)/_the.bifiles: JAVA_FLAGS += -Xbootclasspath/p:$(BREAK_ITERATOR_CLASSES)
-$(BASE_DATA_PKG_DIR)/_the.bifiles: $(BUILD_TOOLS) $(UNICODEDATA) $(BUILD_BREAKITERATOR)
+$(BASE_DATA_PKG_DIR)/_the.bifiles: JAVA_FLAGS += $(BREAK_ITERATOR_BOOTCLASSPATH)
+$(BASE_DATA_PKG_DIR)/_the.bifiles: $(BUILD_TOOLS) $(UNICODEDATA) \
+    $(BUILD_BREAKITERATOR_BASE) $(BUILD_BREAKITERATOR_LD)
 	$(call LogInfo, Generating BreakIteratorData)
 	$(call MakeDir, $(@D))
 	$(RM) $(BIFILES)
@@ -78,8 +101,9 @@
 	$(TOUCH) $@
 
 $(BIFILES_TH): $(LD_DATA_PKG_DIR)/_the.bifiles_th
-$(LD_DATA_PKG_DIR)/_the.bifiles_th: JAVA_FLAGS += -Xbootclasspath/p:$(BREAK_ITERATOR_CLASSES)
-$(LD_DATA_PKG_DIR)/_the.bifiles_th: $(BUILD_TOOLS) $(UNICODEDATA) $(BUILD_BREAKITERATOR)
+$(LD_DATA_PKG_DIR)/_the.bifiles_th: JAVA_FLAGS += $(BREAK_ITERATOR_BOOTCLASSPATH)
+$(LD_DATA_PKG_DIR)/_the.bifiles_th: $(BUILD_TOOLS) $(UNICODEDATA) \
+    $(BUILD_BREAKITERATOR_BASE) $(BUILD_BREAKITERATOR_LD)
 	$(call LogInfo, Generating BreakIteratorData_th)
 	$(RM) $(BIFILES_TH)
 	$(TOOL_GENERATEBREAKITERATORDATA) \
--- a/make/gensrc/Gensrc-java.base.gmk	Tue Mar 15 13:48:26 2016 -0700
+++ b/make/gensrc/Gensrc-java.base.gmk	Thu Mar 17 19:04:16 2016 +0000
@@ -33,6 +33,7 @@
 include GensrcCharsetCoder.gmk
 include GensrcBuffer.gmk
 include GensrcExceptions.gmk
+include GensrcModuleLoaderMap.gmk
 
 ################################################################################
 
--- a/make/gensrc/Gensrc-jdk.dev.gmk	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-#
-# Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.  Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-include GensrcCommon.gmk
-
-################################################################################
-
-include GensrcProperties.gmk
-
-$(eval $(call SetupCompileProperties, COMPILE_PROPERTIES, \
-    SRC_DIRS := $(JDK_TOPDIR)/src/jdk.dev/share/classes/jdk/tools/jimage/resources, \
-    CLASS := ListResourceBundle, \
-))
-
-TARGETS += $(COMPILE_PROPERTIES)
-
-################################################################################
-
-all: $(TARGETS)
-
-.PHONY: all
--- a/make/gensrc/Gensrc-jdk.jdi.gmk	Tue Mar 15 13:48:26 2016 -0700
+++ b/make/gensrc/Gensrc-jdk.jdi.gmk	Thu Mar 17 19:04:16 2016 +0000
@@ -61,30 +61,6 @@
 
 ################################################################################
 
-define process-provider
-	$(call MakeDir, $(@D))
-	$(CAT) $^ | $(SED) -e "s/^#\[$(OPENJDK_TARGET_OS)\]//" > $@
-endef
-
-# Filter com.sun.jdi.connect.Connector
-$(SUPPORT_OUTPUTDIR)/gensrc/jdk.jdi/META-INF/services/com.sun.jdi.connect.Connector: \
-    $(JDK_TOPDIR)/src/jdk.jdi/share/classes/META-INF/services/com.sun.jdi.connect.Connector \
-    $(HOTSPOT_TOPDIR)/src/jdk.hotspot.agent/share/classes/META-INF/services/com.sun.jdi.connect.Connector
-	$(process-provider)
-
-# Copy the same service file into jdk.hotspot.agent so that they are kept the same.
-$(SUPPORT_OUTPUTDIR)/gensrc/jdk.hotspot.agent/META-INF/services/com.sun.jdi.connect.Connector: \
-    $(SUPPORT_OUTPUTDIR)/gensrc/jdk.jdi/META-INF/services/com.sun.jdi.connect.Connector
-	$(install-file)
-
-# Some platforms don't have the serviceability agent
-ifeq ($(INCLUDE_SA), true)
-  GENSRC_JDK_JDI += $(SUPPORT_OUTPUTDIR)/gensrc/jdk.jdi/META-INF/services/com.sun.jdi.connect.Connector \
-      $(SUPPORT_OUTPUTDIR)/gensrc/jdk.hotspot.agent/META-INF/services/com.sun.jdi.connect.Connector
-endif
-
-################################################################################
-
 include GensrcProperties.gmk
 
 $(eval $(call SetupCompileProperties, COMPILE_PROPERTIES, \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/gensrc/Gensrc-jdk.jlink.gmk	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,54 @@
+#
+# Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+include GensrcCommon.gmk
+
+################################################################################
+
+include GensrcProperties.gmk
+
+$(eval $(call SetupCompileProperties, JLINK_PROPERTIES, \
+    SRC_DIRS := $(JDK_TOPDIR)/src/jdk.jlink/share/classes/jdk/tools/jlink/resources, \
+    CLASS := ListResourceBundle, \
+))
+
+$(eval $(call SetupCompileProperties, JMOD_PROPERTIES, \
+    SRC_DIRS := $(JDK_TOPDIR)/src/jdk.jlink/share/classes/jdk/tools/jmod/resources, \
+    CLASS := ListResourceBundle, \
+))
+
+$(eval $(call SetupCompileProperties, JIMAGE_PROPERTIES, \
+    SRC_DIRS := $(JDK_TOPDIR)/src/jdk.jlink/share/classes/jdk/tools/jimage/resources, \
+    CLASS := ListResourceBundle, \
+))
+
+
+TARGETS += $(JLINK_PROPERTIES) $(JMOD_PROPERTIES) $(JIMAGE_PROPERTIES)
+
+################################################################################
+
+all: $(TARGETS)
+
+.PHONY: all
--- a/make/gensrc/Gensrc-jdk.jvmstat.gmk	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-#
-# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.  Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-include GensrcCommon.gmk
-
-################################################################################
-
-define merge-providers
-	$(MKDIR) -p $(@D)
-	$(CAT) $^ > $@
-endef
-
-PROVIDER_FILE := META-INF/services/sun.jvmstat.monitor.MonitoredHostService
-
-# Merge the local and remote sevice providers into jdk.jvmstat/META-INF/services
-$(SUPPORT_OUTPUTDIR)/gensrc/jdk.jvmstat/$(PROVIDER_FILE): \
-    $(JDK_TOPDIR)/src/jdk.jvmstat/share/classes/$(PROVIDER_FILE) \
-    $(JDK_TOPDIR)/src/jdk.jvmstat.rmi/share/classes/$(PROVIDER_FILE)
-	$(merge-providers)
-
-# Copy the same service file into jdk.jvmstat.rmi so that they are kept the same.
-$(SUPPORT_OUTPUTDIR)/gensrc/jdk.jvmstat.rmi/$(PROVIDER_FILE): \
-    $(SUPPORT_OUTPUTDIR)/gensrc/jdk.jvmstat/$(PROVIDER_FILE)
-	$(install-file)
-
-################################################################################
-
-jdk.jvmstat: $(SUPPORT_OUTPUTDIR)/gensrc/jdk.jvmstat/$(PROVIDER_FILE) \
-    $(SUPPORT_OUTPUTDIR)/gensrc/jdk.jvmstat.rmi/$(PROVIDER_FILE)
-
-all: jdk.jvmstat
-
-.PHONY: all
\ No newline at end of file
--- a/make/gensrc/GensrcLocaleData.gmk	Tue Mar 15 13:48:26 2016 -0700
+++ b/make/gensrc/GensrcLocaleData.gmk	Thu Mar 17 19:04:16 2016 +0000
@@ -143,19 +143,6 @@
 GENSRC_BASELOCALEDATA := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/util/locale/provider/BaseLocaleDataMetaInfo.java
 GENSRC_LOCALEDATA := $(SUPPORT_OUTPUTDIR)/gensrc/jdk.localedata/sun/util/resources/provider/NonBaseLocaleDataMetaInfo.java
 
-################################################################################
-
-GENSRC_CRBC_DST := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/util/CoreResourceBundleControl.java
-GENSRC_CRBC_CMD := $(JDK_TOPDIR)/make/scripts/localelist.sh
-
-JRE_NONEXIST_LOCALES := en en_US de_DE es_ES fr_FR it_IT ja_JP ko_KR sv_SE zh
-
-$(GENSRC_CRBC_DST): $(JDK_TOPDIR)/src/java.base/share/classes/sun/util/CoreResourceBundleControl-XLocales.java.template \
-    $(GENSRC_CRBC_CMD)
-	$(MKDIR) -p $(@D)
-	NAWK="$(NAWK)" SED="$(SED)" $(SH) $(GENSRC_CRBC_CMD) "$(JRE_NONEXIST_LOCALES)" $< $@
-
-GENSRC_BASELOCALEDATA += $(GENSRC_CRBC_DST)
 GENSRC_JAVA_BASE += $(GENSRC_BASELOCALEDATA)
 GENSRC_JDK_LOCALEDATA += $(GENSRC_LOCALEDATA)
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/gensrc/GensrcModuleLoaderMap.gmk	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,164 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+include Modules.gmk
+
+BOOT_MODULES :=
+UPGRADEABLE_MDOULES :=
+AGGREGATOR_MDOULES :=
+OTHER_PLATFORM_MODULES :=
+
+# Hook to include the corresponding custom file, if present.
+$(eval $(call IncludeCustomExtension, jdk, gensrc/GensrcModuleLoaderMap.gmk))
+
+BOOT_MODULES += \
+    java.base \
+    java.datatransfer \
+    java.desktop \
+    java.httpclient \
+    java.instrument \
+    java.logging \
+    java.management \
+    java.naming \
+    java.prefs \
+    java.rmi \
+    java.security.jgss \
+    java.security.sasl \
+    java.sql \
+    java.xml \
+    java.xml.crypto \
+    jdk.httpserver \
+    jdk.management \
+    jdk.sctp \
+    jdk.security.auth \
+    jdk.security.jgss \
+    #
+
+# to be deprivileged
+BOOT_MODULES += \
+    java.compiler \
+    java.scripting \
+    java.sql.rowset \
+    java.smartcardio \
+    jdk.charsets \
+    jdk.naming.rmi \
+    #
+
+UPGRADEABLE_MODULES += \
+    java.activation \
+    java.annotations.common \
+    java.corba \
+    java.transaction \
+    java.xml.bind \
+    java.xml.ws \
+    #
+
+AGGREGATOR_MODULES += \
+    java.compact1 \
+    java.compact2 \
+    java.compact3 \
+    java.se \
+    java.se.ee \
+    #
+
+OTHER_PLATFORM_MODULES += \
+    jdk.accessibility \
+    jdk.crypto.ec \
+    jdk.crypto.pkcs11 \
+    jdk.dynalink \
+    jdk.jsobject \
+    jdk.xml.dom \
+    jdk.localedata \
+    jdk.naming.dns \
+    jdk.scripting.nashorn \
+    jdk.zipfs \
+    #
+
+ifeq ($(OPENJDK_TARGET_OS), macsox)
+  BOOT_MODULES += jdk.deploy.osx
+endif
+ifeq ($(OPENJDK_TARGET_OS), windows)
+  OTHER_PLATFORM_MODULES += jdk.crypto.mscapi
+endif
+ifeq ($(OPENJDK_TARGET_OS), solaris)
+  OTHER_PLATFORM_MODULES += jdk.crypto.ucrypto
+endif
+
+# Param 1 - Name of module
+define ReadImportMetaData
+  ifneq ($$(wildcard $(IMPORT_MODULES_MAKE)/$$(strip $1)/build.properties), )
+    classloader :=
+    include $(IMPORT_MODULES_MAKE)/$$(strip $1)/build.properties
+    ifeq ($$(classloader), boot)
+      BOOT_MODULES += $1
+    else ifeq ($$(classloader), ext)
+      OTHER_PLATFORM_MODULES += $1
+    endif
+  endif
+endef
+
+IMPORTED_MODULES := $(call FindImportedModules)
+$(foreach m, $(IMPORTED_MODULES), $(eval $(call ReadImportMetaData, $m)))
+
+
+# Replacing double-comma with a single comma is to workaround the issue
+# with some version of make on windows that doesn't substitute spaces
+# with one comma properly as with make 4.0
+define SubstComma
+$(strip \
+  $(subst $(COMMA)$(COMMA),$(COMMA),$(subst $(SPACE),$(COMMA),$(strip $1))) \
+)
+endef
+BOOT_MODULES_LIST := $(call SubstComma, $(BOOT_MODULES))
+PLATFORM_MODULES_LIST := $(call SubstComma, $(UPGRADEABLE_MODULES) $(AGGREGATOR_MODULES) $(OTHER_PLATFORM_MODULES))
+
+VARDEPS_VALUE := $(BOOT_MODULES_LIST) $(PLATFORM_MODULES_LIST)
+VARDEPS_FILE := $(call DependOnVariable, VARDEPS_VALUE)
+
+############################################################################
+
+$(SUPPORT_OUTPUTDIR)/gensrc/java.base/jdk/internal/module/ModuleLoaderMap.java: \
+    $(JDK_TOPDIR)/src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java \
+    $(VARDEPS_FILE) $(BUILD_TOOLS_JDK)
+	$(MKDIR) -p $(@D)
+	$(RM) $@ $@.tmp
+	$(TOOL_GENCLASSLOADERMAP) -boot $(BOOT_MODULES_LIST) \
+	     -platform $(PLATFORM_MODULES_LIST) -o $@.tmp $<
+	$(MV) $@.tmp $@
+
+GENSRC_JAVA_BASE += $(SUPPORT_OUTPUTDIR)/gensrc/java.base/jdk/internal/module/ModuleLoaderMap.java
+
+$(SUPPORT_OUTPUTDIR)/gensrc/java.base/jdk/internal/vm/cds/resources/ModuleLoaderMap.dat: \
+    $(JDK_TOPDIR)/src/java.base/share/classes/jdk/internal/vm/cds/resources/ModuleLoaderMap.dat \
+    $(VARDEPS_FILE) $(BUILD_TOOLS_JDK)
+	$(MKDIR) -p $(@D)
+	$(RM) $@ $@.tmp
+	$(TOOL_GENCLASSLOADERMAP) -boot $(BOOT_MODULES_LIST) \
+	    -platform $(PLATFORM_MODULES_LIST) -o $@.tmp $<
+	$(MV) $@.tmp $@
+
+GENSRC_JAVA_BASE += $(SUPPORT_OUTPUTDIR)/gensrc/java.base/jdk/internal/vm/cds/resources/ModuleLoaderMap.dat
+
+################################################################################
--- a/make/launcher/Launcher-java.desktop.gmk	Tue Mar 15 13:48:26 2016 -0700
+++ b/make/launcher/Launcher-java.desktop.gmk	Thu Mar 17 19:04:16 2016 +0000
@@ -31,6 +31,7 @@
 ifndef BUILD_HEADLESS_ONLY
   $(eval $(call SetupBuildLauncher, appletviewer, \
       MAIN_CLASS := sun.applet.Main, \
+      JAVA_ARGS := -addmods ALL-SYSTEM, \
       LIBS_unix := $(X_LIBS), \
   ))
 endif
--- a/make/launcher/Launcher-jdk.dev.gmk	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-#
-# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.  Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-include LauncherCommon.gmk
-
-$(eval $(call SetupBuildLauncher, jimage,\
-    MAIN_CLASS := jdk.tools.jimage.Main, \
-))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/launcher/Launcher-jdk.jlink.gmk	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,45 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+include LauncherCommon.gmk
+
+$(eval $(call SetupBuildLauncher, jimage,\
+    MAIN_CLASS := jdk.tools.jimage.Main, \
+    CFLAGS := -DENABLE_ARG_FILES, \
+))
+
+$(eval $(call SetupBuildLauncher, jlink,\
+    MAIN_CLASS := jdk.tools.jlink.internal.Main, \
+    CFLAGS := -DENABLE_ARG_FILES \
+        -DEXPAND_CLASSPATH_WILDCARDS \
+        -DNEVER_ACT_AS_SERVER_CLASS_MACHINE, \
+))
+
+$(eval $(call SetupBuildLauncher, jmod,\
+    MAIN_CLASS := jdk.tools.jmod.Main, \
+    CFLAGS := -DENABLE_ARG_FILES \
+        -DEXPAND_CLASSPATH_WILDCARDS \
+        -DNEVER_ACT_AS_SERVER_CLASS_MACHINE, \
+))
--- a/make/launcher/Launcher-jdk.pack200.gmk	Tue Mar 15 13:48:26 2016 -0700
+++ b/make/launcher/Launcher-jdk.pack200.gmk	Thu Mar 17 19:04:16 2016 +0000
@@ -26,6 +26,7 @@
 include LauncherCommon.gmk
 
 $(eval $(call SetupBuildLauncher, pack200, \
+    MAIN_MODULE := java.base, \
     MAIN_CLASS := com.sun.java.util.jar.pack.Driver, \
 ))
 
--- a/make/launcher/Launcher-jdk.rmic.gmk	Tue Mar 15 13:48:26 2016 -0700
+++ b/make/launcher/Launcher-jdk.rmic.gmk	Thu Mar 17 19:04:16 2016 +0000
@@ -26,6 +26,6 @@
 include LauncherCommon.gmk
 
 $(eval $(call SetupBuildLauncher, rmic, \
-    MAIN_CLASS := sun.rmi.rmic.Main, \
+    MAIN_CLASS := jdk.rmi.rmic.Main, \
     CFLAGS := -DEXPAND_CLASSPATH_WILDCARDS, \
 ))
--- a/make/launcher/LauncherCommon.gmk	Tue Mar 15 13:48:26 2016 -0700
+++ b/make/launcher/LauncherCommon.gmk	Thu Mar 17 19:04:16 2016 +0000
@@ -63,6 +63,8 @@
 # used as the name of the executable.
 #
 # Remaining parameters are named arguments. These include:
+# MAIN_MODULE  The module of the main class to launch if different from the
+#     current module
 # MAIN_CLASS   The Java main class to launch
 # JAVA_ARGS   Processed into a -DJAVA_ARGS C flag
 # CFLAGS   Additional CFLAGS
@@ -97,9 +99,13 @@
     $1_JAVA_ARGS += -ms8m
   endif
 
+  ifeq ($$($1_MAIN_MODULE), )
+    $1_MAIN_MODULE := $(MODULE)
+  endif
+
   ifneq ($$($1_JAVA_ARGS), )
     $1_JAVA_ARGS_STR := '{ $$(strip $$(foreach a, \
-        $$(addprefix -J, $$($1_JAVA_ARGS)) $$($1_MAIN_CLASS), "$$a"$(COMMA) )) }'
+        $$(addprefix -J, $$($1_JAVA_ARGS)) -m $$($1_MAIN_MODULE)/$$($1_MAIN_CLASS), "$$a"$(COMMA) )) }'
     $1_CFLAGS += -DJAVA_ARGS=$$($1_JAVA_ARGS_STR)
   endif
 
--- a/make/lib/CoreLibraries.gmk	Tue Mar 15 13:48:26 2016 -0700
+++ b/make/lib/CoreLibraries.gmk	Thu Mar 17 19:04:16 2016 +0000
@@ -146,6 +146,7 @@
         $(LIBJAVA_CFLAGS), \
     System.c_CFLAGS := $(VERSION_CFLAGS), \
     jdk_util.c_CFLAGS := $(VERSION_CFLAGS), \
+    DISABLED_WARNINGS_gcc := unused-result, \
     DISABLED_WARNINGS_solstudio := E_STATEMENT_NOT_REACHED, \
     MAPFILE := $(LIBJAVA_MAPFILE), \
     LDFLAGS := $(LDFLAGS_JDKLIB) \
--- a/make/lib/Lib-java.instrument.gmk	Tue Mar 15 13:48:26 2016 -0700
+++ b/make/lib/Lib-java.instrument.gmk	Thu Mar 17 19:04:16 2016 +0000
@@ -68,14 +68,14 @@
     LDFLAGS_macosx := -Wl$(COMMA)-all_load, \
     LDFLAGS_aix := -L$(SUPPORT_OUTPUTDIR)/native/java.base, \
     LIBS := $(JDKLIB_LIBS), \
-    LIBS_unix := -ljava $(LIBZ), \
+    LIBS_unix := -ljava -ljvm $(LIBZ), \
     LIBS_linux := -ljli $(LIBDL), \
     LIBS_solaris := -ljli $(LIBDL), \
     LIBS_aix := -liconv -ljli_static $(LIBDL), \
     LIBS_macosx := -liconv -framework Cocoa -framework Security \
         -framework ApplicationServices \
         $(SUPPORT_OUTPUTDIR)/native/java.base/libjli_static.a, \
-    LIBS_windows := $(WIN_JAVA_LIB) advapi32.lib \
+    LIBS_windows := jvm.lib $(WIN_JAVA_LIB) advapi32.lib \
         $(SUPPORT_OUTPUTDIR)/native/java.base/jli_static.lib, \
     VERSIONINFO_RESOURCE := $(GLOBAL_VERSION_INFO_RESOURCE), \
     RC_FLAGS := $(RC_FLAGS) \
--- a/make/mapfiles/libjava/mapfile-vers	Tue Mar 15 13:48:26 2016 -0700
+++ b/make/mapfiles/libjava/mapfile-vers	Thu Mar 17 19:04:16 2016 +0000
@@ -137,7 +137,6 @@
 		Java_java_lang_ClassLoader_registerNatives;
 		Java_java_lang_Double_longBitsToDouble;
 		Java_java_lang_Double_doubleToRawLongBits;
-		Java_java_lang_reflect_Proxy_defineClass0;
 		Java_java_lang_Float_intBitsToFloat;
 		Java_java_lang_Float_floatToRawIntBits;
                 Java_java_lang_StackFrameInfo_fillInStackFrames;
@@ -165,8 +164,6 @@
 		Java_java_lang_StrictMath_expm1;
 		Java_java_lang_Object_getClass;
 		Java_java_lang_Object_registerNatives;
-		Java_java_lang_Package_getSystemPackage0;
-		Java_java_lang_Package_getSystemPackages0;
 		Java_java_lang_ProcessEnvironment_environ;
 		Java_java_lang_ProcessHandleImpl_destroy0;
 		Java_java_lang_ProcessHandleImpl_getCurrentPid0;
@@ -204,11 +201,11 @@
 		Java_java_lang_reflect_Executable_getTypeAnnotationBytes0;
 		Java_java_lang_reflect_Field_getTypeAnnotationBytes0;
 		Java_java_lang_Runtime_freeMemory;
-                Java_java_lang_Runtime_maxMemory;
+		Java_java_lang_Runtime_maxMemory;
 		Java_java_lang_Runtime_gc;
 		Java_java_lang_Runtime_runFinalization0;
 		Java_java_lang_Runtime_totalMemory;
-                Java_java_lang_Runtime_availableProcessors;
+		Java_java_lang_Runtime_availableProcessors;
 		Java_java_lang_SecurityManager_classDepth;
 		Java_java_lang_SecurityManager_classLoaderDepth0;
 		Java_java_lang_SecurityManager_currentClassLoader0;
@@ -274,6 +271,18 @@
                 Java_jdk_internal_misc_VM_getgid;
                 Java_jdk_internal_misc_VM_getegid;
                 Java_jdk_internal_misc_VM_initialize;
+
+                Java_java_lang_reflect_Module_defineModule0;
+                Java_java_lang_reflect_Module_addReads0;
+                Java_java_lang_reflect_Module_addExports0;
+                Java_java_lang_reflect_Module_addExportsToAll0;
+                Java_java_lang_reflect_Module_addExportsToAllUnnamed0;
+                Java_java_lang_reflect_Module_addPackage0;
+
+		Java_jdk_internal_loader_BootLoader_getSystemPackageLocation;
+		Java_jdk_internal_loader_BootLoader_getSystemPackageNames;
+                Java_jdk_internal_loader_BootLoader_setBootLoaderUnnamedModule0;
+
 		Java_sun_misc_VMSupport_initAgentProperties;
 		Java_sun_misc_VMSupport_getVMTemporaryDirectory;
 
--- a/make/mapfiles/libjimage/mapfile-vers	Tue Mar 15 13:48:26 2016 -0700
+++ b/make/mapfiles/libjimage/mapfile-vers	Thu Mar 17 19:04:16 2016 +0000
@@ -27,23 +27,7 @@
 
 SUNWprivate_1.1 {
     global:
-        JNI_OnLoad;
-        Java_jdk_internal_jimage_ImageNativeSubstrate_openImage;
-        Java_jdk_internal_jimage_ImageNativeSubstrate_closeImage;
-        Java_jdk_internal_jimage_ImageNativeSubstrate_getIndexAddress;
-        Java_jdk_internal_jimage_ImageNativeSubstrate_getDataAddress;
-        Java_jdk_internal_jimage_ImageNativeSubstrate_read;
-        Java_jdk_internal_jimage_ImageNativeSubstrate_readCompressed;
-        Java_jdk_internal_jimage_ImageNativeSubstrate_getStringBytes;
-        Java_jdk_internal_jimage_ImageNativeSubstrate_getAttributes;
-        Java_jdk_internal_jimage_ImageNativeSubstrate_findAttributes;
-        Java_jdk_internal_jimage_ImageNativeSubstrate_attributeOffsets;
-        Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1Open;
-        Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1Close;
-        Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1FindResource;
-        Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1GetResource;
-        Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1PackageToModule;
-        Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1Resources;
+        Java_jdk_internal_jimage_NativeImageBuffer_getNativeMap;
         JIMAGE_Open;
         JIMAGE_Close;
         JIMAGE_PackageToModule;
--- a/make/rmic/Rmic-java.management.gmk	Tue Mar 15 13:48:26 2016 -0700
+++ b/make/rmic/Rmic-java.management.gmk	Thu Mar 17 19:04:16 2016 +0000
@@ -40,7 +40,7 @@
 $(eval $(call SetupRMICompilation,RMI_GEN, \
     CLASSES := $(JMX_RMI_CLASSES), \
     CLASSES_DIR := $(CLASSES_DIR)/java.management, \
-    STUB_CLASSES_DIR := $(RMIC_GENSRC_DIR), \
+    STUB_CLASSES_DIR := $(RMIC_GENSRC_DIR)/java.management, \
     RUN_V12 := true, \
     KEEP_GENERATED := true, \
 ))
@@ -50,7 +50,7 @@
 	$(eval classfiles := $(shell $(FIND) $(RMIC_GENSRC_DIR) -name "*.class"))
 	$(foreach src, $(classfiles), \
 	    $(eval target := $(patsubst $(RMIC_GENSRC_DIR)/%, \
-	        $(STUB_CLASSES_DIR)/java.management/%, $(src))) \
+	        $(STUB_CLASSES_DIR)/%, $(src))) \
 	    $(MKDIR) -p $(dir $(target)) ; \
 	    $(MV) $(src) $(target) $(NEWLINE))
 	$(TOUCH) $@
--- a/make/rmic/RmicCommon.gmk	Tue Mar 15 13:48:26 2016 -0700
+++ b/make/rmic/RmicCommon.gmk	Thu Mar 17 19:04:16 2016 +0000
@@ -31,10 +31,7 @@
 
 ##########################################################################################
 
-BTRMIC_CP := $(call PathList, \
-    $(BUILDTOOLS_OUTPUTDIR)/interim_rmic_classes $(INTERIM_LANGTOOLS_JAR))
-BTRMIC_ARGS := -cp $(BTRMIC_CP)
-RMIC := $(JAVA) $(BTRMIC_ARGS) sun.rmi.rmic.Main
+RMIC := $(JAVA) $(INTERIM_OVERRIDE_MODULES_ARGS) sun.rmi.rmic.Main
 
 CLASSES_DIR := $(JDK_OUTPUTDIR)/modules
 # NOTE: If the smart javac dependency management is reintroduced, these classes risk
--- a/make/scripts/localelist.sh	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,106 +0,0 @@
-#!/bin/sh
-
-#
-# Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.  Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-#
-# This script is to generate the supported locale list string and replace the
-# #LOCALE_LIST# in <ws>/src/share/classes/sun/util/CoreResourceBundleControl.java.
-#
-# NAWK & SED is passed in as environment variables.
-#
-LOCALE_LIST=$1
-INUT_FILE=$2
-OUTPUT_FILE=$3
-
-LOCALES=`(for I in $LOCALE_LIST; do echo $I;done) | sort | uniq`
-JAVA_LOCALES=
-
-toJavaLocale()
-{
-  NewLocale=`echo $1 | $NAWK '
-      BEGIN {
-        # The following values have to be consistent with java.util.Locale.
-        javalocales["en"] = "ENGLISH";
-        javalocales["fr"] = "FRENCH";
-        javalocales["de"] = "GERMAN";
-        javalocales["it"] = "ITALIAN";
-        javalocales["ja"] = "JAPANESE";
-        javalocales["ko"] = "KOREAN";
-        javalocales["zh"] = "CHINESE";
-        javalocales["zh_CN"] = "SIMPLIFIED_CHINESE";
-        javalocales["zh_TW"] = "TRADITIONAL_CHINESE";
-        javalocales["fr_FR"] = "FRANCE";
-        javalocales["de_DE"] = "GERMANY";
-        javalocales["it_IT"] = "ITALY";
-        javalocales["ja_JP"] = "JAPAN";
-        javalocales["ko_KR"] = "KOREA";
-        javalocales["en_GB"] = "UK";
-        javalocales["en_US"] = "US";
-        javalocales["en_CA"] = "CANADA";
-        javalocales["fr_CA"] = "CANADA_FRENCH";
-      }
-      {
-        if ($0 in javalocales) {
-          print "        Locale." javalocales[$0];
-        } else {
-          split($0, a, "_");
-          if (a[3] != "") {
-            print " new Locale(\"" a[1] "\", \"" a[2] "\", \"" a[3] "\")";
-          } else if (a[2] != "") {
-            print " new Locale(\"" a[1] "\", \"" a[2] "\")";
-          } else {
-            print " new Locale(\"" a[1] "\")";
-          }
-        }
-      }'`
-
-  JAVA_LOCALES=$JAVA_LOCALES$NewLocale
-}
-
-# count the number of locales
-counter=0
-for i in $LOCALES
-do
-  counter=`expr $counter + 1`
-done
-
-index=0
-for locale in $LOCALES
-do
-  index=`expr $index + 1`;
-  if [ $index != $counter ]
-  then
-    toJavaLocale $locale
-    JAVA_LOCALES=$JAVA_LOCALES","
-  else
-    toJavaLocale $locale
-  fi
-done
-
-# replace the #LOCALE_LIST# in the precompiled CoreResourceBundleControl.java file.
-
-$SED -e "s@^#warn .*@// -- This file was mechanically generated: Do not edit! -- //@" \
-    -e "s/#LOCALE_LIST#/$JAVA_LOCALES/g" $2 > $3
--- a/make/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/make/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java	Thu Mar 17 19:04:16 2016 +0000
@@ -343,9 +343,7 @@
                 if (!all && CLDRConverter.isBaseModule ^ isBaseLocale(id)) {
                     continue;
                 }
-                if (sb.length() > 0) {
-                    sb.append(' ');
-                }
+                sb.append(' ');
                 sb.append(id);
             }
         }
--- a/make/src/classes/build/tools/generatebreakiteratordata/GenerateBreakIteratorData.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/make/src/classes/build/tools/generatebreakiteratordata/GenerateBreakIteratorData.java	Thu Mar 17 19:04:16 2016 +0000
@@ -62,25 +62,37 @@
         CharacterCategory.makeCategoryMap(unicodeData);
 
         /* Generate files */
-        generateFiles();
+        try {
+            generateFiles();
+        } catch (Exception e) {
+            e.printStackTrace();
+            System.exit(1);
+        }
+    }
+
+    private static String localizedBundleName(String pkg, String clazz) {
+        if (language.length() > 0) {
+            return pkg + ".ext." + clazz + '_' + language;
+        } else {
+            return pkg + '.' + clazz;
+        }
     }
 
     /**
      * Generate data files whose names are included in
      * sun.text.resources.BreakIteratorInfo+<localeName>
      */
-    private static void generateFiles() {
+    private static void generateFiles() throws Exception {
         String[] classNames;
         ResourceBundle rules, info;
 
-        String pkgName = "sun.text.resources" + (language.length() > 0 ? ".ext" : "");
+        info = (ResourceBundle) Class.forName(
+            localizedBundleName("sun.text.resources", "BreakIteratorInfo")).newInstance();
 
-        info =  ResourceBundle.getBundle(pkgName + ".BreakIteratorInfo",
-                                         new Locale(language, country, valiant));
         classNames = info.getStringArray("BreakIteratorClasses");
 
-        rules = ResourceBundle.getBundle(pkgName + ".BreakIteratorRules",
-                                         new Locale(language, country, valiant));
+        rules = (ResourceBundle) Class.forName(
+            localizedBundleName("sun.text.resources", "BreakIteratorRules")).newInstance();
 
         if (info.containsKey("CharacterData")) {
             generateDataFile(info.getString("CharacterData"),
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/src/classes/build/tools/jdwpgen/ModuleTypeNode.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package build.tools.jdwpgen;
+
+import java.util.*;
+import java.io.*;
+
+class ModuleTypeNode extends AbstractSimpleTypeNode {
+
+    String docType() {
+        return "moduleID";
+    }
+
+    String javaType() {
+        return "ModuleReferenceImpl";
+    }
+
+    String debugValue(String label) {
+        return "(" + label + "==null?\"NULL\":\"ref=\"+" + label + ".ref())";
+    }
+
+    public void genJavaWrite(PrintWriter writer, int depth,
+                             String writeLabel) {
+        genJavaDebugWrite(writer, depth, writeLabel,
+                          debugValue(writeLabel));
+        indent(writer, depth);
+        writer.println("ps.writeModuleRef(" + writeLabel + ".ref());");
+    }
+
+    String javaRead() {
+        return "ps.readModule()";
+    }
+}
--- a/make/src/classes/build/tools/jdwpgen/Parse.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/make/src/classes/build/tools/jdwpgen/Parse.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -80,6 +80,7 @@
         kindMap.put("field", new FieldTypeNode());
         kindMap.put("frame", new FrameTypeNode());
         kindMap.put("string", new StringTypeNode());
+        kindMap.put("moduleID", new ModuleTypeNode());
         kindMap.put("value", new ValueTypeNode());
         kindMap.put("byte", new ByteTypeNode());
         kindMap.put("location", new LocationTypeNode());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/src/classes/build/tools/jigsaw/GenGraphs.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package build.tools.jigsaw;
+
+import java.io.IOException;
+import java.io.PrintStream;
+import java.lang.module.Configuration;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReference;
+import java.lang.module.ResolvedModule;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import static java.lang.module.ModuleDescriptor.Requires.Modifier.PUBLIC;
+
+/**
+ * Generate the DOT file for a module graph for each module in the JDK
+ * after transitive reduction.
+ */
+public class GenGraphs {
+
+    public static void main(String[] args) throws Exception {
+
+        if (args.length != 1) {
+            System.err.println("ERROR: specify the output directory");
+            System.exit(1);
+        }
+        Path dir = Paths.get(args[0]);
+        Files.createDirectories(dir);
+
+        ModuleFinder finder = ModuleFinder.ofSystem();
+
+        Set<ModuleDescriptor> javaSEModules
+            = new TreeSet<>(finder.findAll().stream()
+                                  .map(ModuleReference::descriptor)
+                                  .filter(m -> (m.name().startsWith("java.") &&
+                                               !m.name().equals("java.smartcardio")))
+                                  .collect(Collectors.toSet()));
+        Set<ModuleDescriptor> jdkModules
+            = new TreeSet<>(finder.findAll().stream()
+                                  .map(ModuleReference::descriptor)
+                                  .filter(m -> !javaSEModules.contains(m))
+                                  .collect(Collectors.toSet()));
+
+        GenGraphs genGraphs = new GenGraphs(javaSEModules, jdkModules);
+        Set<String> mods = new HashSet<>();
+        for (ModuleReference mref: finder.findAll()) {
+            ModuleDescriptor descriptor = mref.descriptor();
+            String name = descriptor.name();
+            mods.add(name);
+            Configuration cf = Configuration.empty()
+                    .resolveRequires(finder,
+                                     ModuleFinder.empty(),
+                                     Set.of(name));
+            genGraphs.genDotFile(dir, name, cf);
+        }
+
+        Configuration cf = Configuration.empty()
+                .resolveRequires(finder,
+                                 ModuleFinder.empty(),
+                                 mods);
+        genGraphs.genDotFile(dir, "jdk", cf);
+
+    }
+
+    private final Set<ModuleDescriptor> javaGroup;
+    private final Set<ModuleDescriptor> jdkGroup;
+
+    GenGraphs(Set<ModuleDescriptor> javaGroup, Set<ModuleDescriptor> jdkGroup) {
+        this.javaGroup = Collections.unmodifiableSet(javaGroup);
+        this.jdkGroup = Collections.unmodifiableSet(jdkGroup);
+    }
+
+    private static final String ORANGE = "#e76f00";
+    private static final String BLUE = "#437291";
+    private static final String GRAY = "#dddddd";
+
+    private static final String REEXPORTS = "";
+    private static final String REQUIRES = "style=\"dashed\"";
+    private static final String REQUIRES_BASE = "color=\"" + GRAY + "\"";
+
+    private static final Map<String,Integer> weights = new HashMap<>();
+
+    private static void weight(String s, String t, int w) {
+        weights.put(s + ":" + t, w);
+    }
+
+    private static int weightOf(String s, String t) {
+        int w = weights.getOrDefault(s + ":" + t, 1);
+        if (w != 1)
+            return w;
+        if (s.startsWith("java.") && t.startsWith("java."))
+            return 10;
+        return 1;
+    }
+
+    static {
+        int h = 1000;
+        weight("java.se", "java.compact3", h * 10);
+        weight("jdk.compact3", "java.compact3", h * 10);
+        weight("java.compact3", "java.compact2", h * 10);
+        weight("java.compact2", "java.compact1", h * 10);
+        weight("java.compact1", "java.logging", h * 10);
+        weight("java.logging", "java.base", h * 10);
+    }
+
+    private void genDotFile(Path dir, String name, Configuration cf) throws IOException {
+        try (PrintStream out
+                 = new PrintStream(Files.newOutputStream(dir.resolve(name + ".dot")))) {
+
+            Map<String, ModuleDescriptor> nameToModule = cf.modules().stream()
+                    .map(ResolvedModule::reference)
+                    .map(ModuleReference::descriptor)
+                    .collect(Collectors.toMap(ModuleDescriptor::name, Function.identity()));
+
+            Set<ModuleDescriptor> descriptors = new TreeSet<>(nameToModule.values());
+
+            out.format("digraph \"%s\" {%n", name);
+            out.format("size=\"25,25\";");
+            out.format("nodesep=.5;%n");
+            out.format("ranksep=1.5;%n");
+            out.format("pencolor=transparent;%n");
+            out.format("node [shape=plaintext, fontname=\"DejaVuSans\", fontsize=36, margin=\".2,.2\"];%n");
+            out.format("edge [penwidth=4, color=\"#999999\", arrowhead=open, arrowsize=2];%n");
+
+            out.format("subgraph %sse {%n", name.equals("jdk") ? "cluster_" : "");
+            descriptors.stream()
+                .filter(javaGroup::contains)
+                .map(ModuleDescriptor::name)
+                .forEach(mn -> out.format("  \"%s\" [fontcolor=\"%s\", group=%s];%n",
+                                          mn, ORANGE, "java"));
+            out.format("}%n");
+            descriptors.stream()
+                .filter(jdkGroup::contains)
+                .map(ModuleDescriptor::name)
+                .forEach(mn -> out.format("  \"%s\" [fontcolor=\"%s\", group=%s];%n",
+                                          mn, BLUE, "jdk"));
+
+            // transitive reduction
+            Graph<String> graph = gengraph(cf);
+            descriptors.forEach(md -> {
+                String mn = md.name();
+                Set<String> requiresPublic = md.requires().stream()
+                        .filter(d -> d.modifiers().contains(PUBLIC))
+                        .map(d -> d.name())
+                        .collect(Collectors.toSet());
+
+                graph.adjacentNodes(mn).forEach(dn -> {
+                    String attr = dn.equals("java.base") ? REQUIRES_BASE
+                            : (requiresPublic.contains(dn) ? REEXPORTS : REQUIRES);
+                    int w = weightOf(mn, dn);
+                    if (w > 1)
+                        attr += "weight=" + w;
+                    out.format("  \"%s\" -> \"%s\" [%s];%n", mn, dn, attr);
+                });
+            });
+
+            out.println("}");
+        }
+    }
+
+    /**
+     * Returns a Graph of the given Configuration after transitive reduction.
+     *
+     * Transitive reduction of requires public edge and requires edge have
+     * to be applied separately to prevent the requires public edges
+     * (e.g. U -> V) from being reduced by a path (U -> X -> Y -> V)
+     * in which  V would not be re-exported from U.
+     */
+    private Graph<String> gengraph(Configuration cf) {
+        Graph.Builder<String> builder = new Graph.Builder<>();
+        for (ResolvedModule resolvedModule : cf.modules()) {
+            String mn = resolvedModule.reference().descriptor().name();
+            builder.addNode(mn);
+            resolvedModule.reads().stream()
+                    .map(ResolvedModule::name)
+                    .forEach(target -> builder.addEdge(mn, target));
+        }
+        Graph<String> rpg = requiresPublicGraph(cf);
+        return builder.build().reduce(rpg);
+    }
+
+    /**
+     * Returns a Graph containing only requires public edges
+     * with transitive reduction.
+     */
+    private Graph<String> requiresPublicGraph(Configuration cf) {
+        Graph.Builder<String> builder = new Graph.Builder<>();
+        for (ResolvedModule resolvedModule : cf.modules()) {
+            ModuleDescriptor descriptor = resolvedModule.reference().descriptor();
+            String mn = descriptor.name();
+            descriptor.requires().stream()
+                    .filter(d -> d.modifiers().contains(PUBLIC))
+                    .map(d -> d.name())
+                    .forEach(d -> builder.addEdge(mn, d));
+        }
+        return builder.build().reduce();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/src/classes/build/tools/jigsaw/Graph.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package build.tools.jigsaw;
+
+import java.io.PrintStream;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Set;
+
+public class Graph<T> {
+    private static boolean traceOn = Boolean.getBoolean("build.tools.module.trace");
+    private final Set<T> nodes;
+    private final Map<T, Set<T>> edges;
+    private Graph(Set<T> nodes, Map<T, Set<T>> edges) {
+        this.nodes = nodes;
+        this.edges = edges;
+    }
+
+    public Set<T> nodes() {
+        return nodes;
+    }
+
+    public Map<T, Set<T>> edges() {
+        return edges;
+    }
+
+    public Set<T> adjacentNodes(T u) {
+        return edges.get(u);
+    }
+
+    /**
+     * Returns a new Graph after transitive reduction
+     */
+    public Graph<T> reduce() {
+        Graph.Builder<T> builder = new Builder<>();
+        nodes.stream()
+             .forEach(u -> {
+                 builder.addNode(u);
+                 edges.get(u).stream()
+                         .filter(v -> !pathExists(u, v, false))
+                         .forEach(v -> builder.addEdge(u, v));
+             });
+        return builder.build();
+    }
+
+    /**
+     * Returns a new Graph after transitive reduction.  All edges in
+     * the given g takes precedence over this graph.
+     *
+     * @throw IllegalArgumentException g must be a subgraph this graph
+     */
+    public Graph<T> reduce(Graph<T> g) {
+        boolean subgraph = nodes.containsAll(g.nodes) && g.edges.keySet().stream()
+               .allMatch(u -> adjacentNodes(u).containsAll(g.adjacentNodes(u)));
+        if (!subgraph) {
+            throw new IllegalArgumentException("the given argument is not a subgraph of this graph");
+        }
+
+        Graph.Builder<T> builder = new Builder<>();
+        nodes.stream()
+             .forEach(u -> {
+                 builder.addNode(u);
+                 // filter the edge if there exists a path from u to v in the given g
+                 // or there exists another path from u to v in this graph
+                 edges.get(u).stream()
+                      .filter(v -> !g.pathExists(u, v) && !pathExists(u, v, false))
+                      .forEach(v -> builder.addEdge(u, v));
+             });
+
+        // add the overlapped edges from this graph and the given g
+        g.edges().keySet().stream()
+                 .forEach(u -> g.adjacentNodes(u).stream()
+                         .filter(v -> isAdjacent(u, v))
+                         .forEach(v -> builder.addEdge(u, v)));
+        return builder.build();
+    }
+
+    private boolean isAdjacent(T u, T v) {
+        return edges.containsKey(u) && edges.get(u).contains(v);
+    }
+
+    private boolean pathExists(T u, T v) {
+        return pathExists(u, v, true);
+    }
+
+    /**
+     * Returns true if there exists a path from u to v in this graph.
+     * If includeAdjacent is false, it returns true if there exists
+     * another path from u to v of distance > 1
+     */
+    private boolean pathExists(T u, T v, boolean includeAdjacent) {
+        if (!nodes.contains(u) || !nodes.contains(v)) {
+            return false;
+        }
+        if (includeAdjacent && isAdjacent(u, v)) {
+            return true;
+        }
+        Deque<T> stack = new LinkedList<>();
+        Set<T> visited = new HashSet<>();
+        stack.push(u);
+        while (!stack.isEmpty()) {
+            T node = stack.pop();
+            if (node.equals(v)) {
+                if (traceOn) {
+                    System.out.format("Edge %s -> %s removed%n", u, v);
+                }
+                return true;
+            }
+            if (!visited.contains(node)) {
+                visited.add(node);
+                edges.get(node).stream()
+                     .filter(e -> includeAdjacent || !node.equals(u) || !e.equals(v))
+                     .forEach(e -> stack.push(e));
+            }
+        }
+        assert !visited.contains(v);
+        return false;
+    }
+
+    void printGraph(PrintStream out) {
+        nodes.stream()
+             .forEach(u -> adjacentNodes(u).stream()
+                     .forEach(v -> out.format("%s -> %s%n", u, v)));
+    }
+
+    public static class Builder<T> {
+        final Set<T> nodes = new HashSet<>();
+        final Map<T, Set<T>> edges = new HashMap<>();
+        public void addNode(T node) {
+            if (nodes.contains(node)) {
+                return;
+            }
+            nodes.add(node);
+            edges.computeIfAbsent(node, _e -> new HashSet<>());
+        }
+        public void addEdge(T u, T v) {
+            addNode(u);
+            addNode(v);
+            edges.get(u).add(v);
+        }
+        public Graph<T> build() {
+            return new Graph<>(nodes, edges);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/src/classes/build/tools/jigsaw/ModuleSummary.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,766 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package build.tools.jigsaw;
+
+import java.io.IOException;
+import java.io.PrintStream;
+import java.lang.module.Configuration;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReference;
+import java.lang.module.ResolvedModule;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import static java.lang.module.ModuleDescriptor.*;
+import static build.tools.jigsaw.ModuleSummary.HtmlDocument.Selector.*;
+import static build.tools.jigsaw.ModuleSummary.HtmlDocument.Division.*;
+
+public class ModuleSummary {
+    private static final String USAGE = "Usage: ModuleSummary -mp <dir> -o <outfile> [-root mn]*";
+
+    public static void main(String[] args) throws Exception {
+        int i=0;
+        Path modpath = null;
+        Path outfile = null;
+        Set<String> roots = new HashSet<>();
+        while (i < args.length && args[i].startsWith("-")) {
+            String arg = args[i++];
+            switch (arg) {
+                case "-mp":
+                    modpath = Paths.get(args[i++]);
+                    break;
+                case "-o":
+                    outfile = Paths.get(args[i++]);
+                    break;
+                case "-root":
+                    roots.add(args[i++]);
+                default:
+                    System.err.println(USAGE);
+                    System.exit(-1);
+            }
+        }
+        if (outfile == null || modpath == null) {
+            System.err.println(USAGE);
+            System.exit(1);
+        }
+        Path dir = outfile.getParent() != null ? outfile.getParent() : Paths.get(".");
+        Files.createDirectories(dir);
+
+        Map<String, ModuleSummary> modules = new HashMap<>();
+        Set<ModuleReference> mrefs = ModuleFinder.ofSystem().findAll();
+        for (ModuleReference mref : mrefs) {
+            String mn = mref.descriptor().name();
+            Path jmod = modpath.resolve(mn + ".jmod");
+            modules.put(mn, new ModuleSummary(mref, jmod));
+        }
+
+        if (roots.isEmpty()) {
+            roots.addAll(modules.keySet());
+        }
+        genReport(outfile, modules, roots, "JDK Module Summary");
+    }
+
+    static void genReport(Path outfile, Map<String, ModuleSummary> modules, Set<String> roots, String title)
+        throws IOException
+    {
+        Configuration cf = resolve(roots);
+        try (PrintStream out = new PrintStream(Files.newOutputStream(outfile))) {
+            HtmlDocument doc = new HtmlDocument(title, modules);
+            Set<ModuleDescriptor> descriptors = cf.modules().stream()
+                    .map(ResolvedModule::reference)
+                    .map(ModuleReference::descriptor)
+                    .collect(Collectors.toSet());
+            doc.writeTo(out, descriptors);
+        }
+    }
+
+    private final String name;
+    private final ModuleDescriptor descriptor;
+    private final JmodInfo jmodInfo;
+    ModuleSummary(ModuleReference mref, Path jmod) throws IOException {
+        this.name = mref.descriptor().name();
+        this.descriptor = mref.descriptor();
+        this.jmodInfo = new JmodInfo(jmod);
+    }
+
+    String name() {
+        return name;
+    }
+
+    long uncompressedSize() {
+        return jmodInfo.size;
+    }
+
+    long jmodFileSize() {
+        return jmodInfo.filesize; // estimated compressed size
+    }
+
+    ModuleDescriptor descriptor() {
+        return descriptor;
+    }
+
+    int numClasses() {
+        return jmodInfo.classCount;
+    }
+
+    long classBytes() {
+        return jmodInfo.classBytes;
+    }
+
+    int numResources() {
+        return jmodInfo.resourceCount;
+    }
+
+    long resourceBytes() {
+        return jmodInfo.resourceBytes;
+    }
+
+    int numConfigs() {
+        return jmodInfo.configCount;
+    }
+    long configBytes() {
+        return jmodInfo.configBytes;
+    }
+    int numCommands() {
+        return jmodInfo.nativeCmds.size();
+    }
+
+    long commandBytes() {
+        return jmodInfo.nativeCmds.values().stream()
+                .mapToLong(l -> l.longValue()).sum() - jmodInfo.debugInfoCmdBytes;
+    }
+    int numCommandsDebug() {
+        return jmodInfo.debugInfoCmdCount;
+    }
+    long commandDebugBytes() {
+        return jmodInfo.debugInfoCmdBytes;
+    }
+    int numNativeLibraries() {
+        return jmodInfo.nativeLibs.size();
+    }
+
+    long nativeLibrariesBytes() {
+        return jmodInfo.nativeLibs.values().stream()
+                .mapToLong(l -> l.longValue()).sum() - jmodInfo.debugInfoLibBytes;
+    }
+    int numNativeLibrariesDebug() {
+        return jmodInfo.debugInfoLibCount;
+    }
+
+    long nativeLibrariesDebugBytes() {
+        return jmodInfo.debugInfoLibBytes;
+    }
+
+    Map<String,Long> commands() {
+        return jmodInfo.nativeCmds;
+    }
+
+    Map<String,Long> nativeLibs() {
+        return jmodInfo.nativeLibs;
+    }
+
+    Map<String,Long> configFiles() {
+        return jmodInfo.configFiles;
+    }
+
+
+    static class JmodInfo {
+        final long size;
+        final long filesize;
+        final int  classCount;
+        final long classBytes;
+        final int  resourceCount;
+        final long resourceBytes;
+        final int  configCount;
+        final long configBytes;
+        final int  debugInfoLibCount;
+        final long debugInfoLibBytes;
+        final int  debugInfoCmdCount;
+        final long debugInfoCmdBytes;
+        final Map<String,Long> configFiles = new HashMap<>();
+        final Map<String,Long> nativeCmds = new HashMap<>();
+        final Map<String,Long> nativeLibs = new HashMap<>();
+
+        JmodInfo(Path jmod) throws IOException {
+            long total = 0;
+            long cBytes = 0, rBytes = 0, cfBytes = 0, dizLibBytes = 0, dizCmdBytes = 0;
+            int  cCount = 0, rCount = 0, cfCount = 0, dizLibCount = 0, dizCmdCount = 0;
+            try (ZipFile zf = new ZipFile(jmod.toFile())) {
+                for (Enumeration<? extends ZipEntry> e = zf.entries(); e.hasMoreElements(); ) {
+                    ZipEntry ze = e.nextElement();
+                    String fn = ze.getName();
+                    int pos = fn.indexOf('/');
+                    String dir = fn.substring(0, pos);
+                    String filename = fn.substring(fn.lastIndexOf('/') + 1);
+                    // name shown in the column
+                    String name = filename;
+
+                    long len = ze.getSize();
+                    total += len;
+                    switch (dir) {
+                        case NATIVE_LIBS:
+                            nativeLibs.put(name, len);
+                            if (filename.endsWith(".diz")) {
+                                dizLibCount++;
+                                dizLibBytes += len;
+                            }
+                            break;
+                        case NATIVE_CMDS:
+                            nativeCmds.put(name, len);
+                            if (filename.endsWith(".diz")) {
+                                dizCmdCount++;
+                                dizCmdBytes += len;
+                            }
+                            break;
+                        case CLASSES:
+                            if (filename.endsWith(".class")) {
+                                cCount++;
+                                cBytes += len;
+                            } else {
+                                rCount++;
+                                rBytes += len;
+                            }
+                            break;
+                        case CONFIG:
+                            configFiles.put(name, len);
+                            cfCount++;
+                            cfBytes += len;
+                            break;
+                        default:
+                            break;
+                    }
+                }
+                this.filesize = jmod.toFile().length();
+                this.classCount = cCount;
+                this.classBytes = cBytes;
+                this.resourceCount = rCount;
+                this.resourceBytes = rBytes;
+                this.configCount = cfCount;
+                this.configBytes = cfBytes;
+                this.size = total;
+                this.debugInfoLibCount = dizLibCount;
+                this.debugInfoLibBytes = dizLibBytes;
+                this.debugInfoCmdCount = dizCmdCount;
+                this.debugInfoCmdBytes = dizCmdBytes;
+            }
+        }
+
+        static final String NATIVE_LIBS = "native";
+        static final String NATIVE_CMDS = "bin";
+        static final String CLASSES     = "classes";
+        static final String CONFIG      = "conf";
+
+        static final String MODULE_ID = "module/id";
+        static final String MODULE_MAIN_CLASS = "module/main-class";
+    }
+
+    static Configuration resolve(Set<String> roots) {
+        return Configuration.empty()
+            .resolveRequires(ModuleFinder.ofSystem(),
+                             ModuleFinder.empty(),
+                             roots);
+    }
+
+    static class HtmlDocument {
+        final String title;
+        final Map<String, ModuleSummary> modules;
+        boolean requiresPublicNote = false;
+        boolean aggregatorNote = false;
+        boolean totalBytesNote = false;
+        HtmlDocument(String title, Map<String, ModuleSummary> modules) {
+            this.title = title;
+            this.modules = modules;
+        }
+
+        void writeTo(PrintStream out, Set<ModuleDescriptor> selectedModules) {
+            out.format("<html><head>%n");
+            out.format("<title>%s</title>%n", title);
+            // stylesheet
+            Arrays.stream(HtmlDocument.STYLES).forEach(out::println);
+            out.format("</head>%n");
+
+            // body begins
+            out.format("<body>%n");
+
+            // title and date
+            out.println(DOCTITLE.toString(title));
+            out.println(VERSION.toString(String.format("%tc", new Date())));
+
+            // total modules and sizes
+            long totalBytes = selectedModules.stream()
+                    .map(ModuleDescriptor::name)
+                    .map(modules::get)
+                    .mapToLong(ModuleSummary::uncompressedSize)
+                    .sum();
+            String[] sections = new String[] {
+                    String.format("%s: %d", "Total modules", selectedModules.size()),
+                    String.format("%s: %,d bytes (%s %s)", "Total size",
+                                  totalBytes,
+                                  System.getProperty("os.name"),
+                                  System.getProperty("os.arch"))
+            };
+            out.println(SECTION.toString(sections));
+
+            // write table and header
+            out.println(String.format("<table class=\"%s\">", MODULES));
+            out.println(header("Module", "Requires", "Exports",
+                    "Services", "Commands/Native Libraries/Configs"));
+
+            // write contents - one row per module
+            selectedModules.stream()
+                    .sorted(Comparator.comparing(ModuleDescriptor::name))
+                    .map(m -> modules.get(m.name()))
+                    .map(ModuleTableRow::new)
+                    .forEach(table -> table.writeTo(out));
+
+            out.format("</table>");  // end table
+            out.format("</body>");
+            out.println("</html>");
+        }
+
+        String header(String... columns) {
+            StringBuilder sb = new StringBuilder();
+            sb.append("<tr>");
+            Arrays.stream(columns)
+                    .forEach(cn -> sb.append("  <th>").append(cn).append("</th>").append("\n"));
+            sb.append("</tr>");
+            return sb.toString();
+        }
+
+        static enum Selector {
+            MODULES("modules"),
+            MODULE("module"),
+            MODULE_DEF("code name def"),
+            AGGREGATOR("code name def agg"),
+            REQUIRES("code"),
+            REQUIRES_PUBLIC("code reexp"),
+            BR("br"),
+            CODE("code"),
+            NUMBER("number"),;
+            final String name;
+            Selector(String name) {
+                this.name = name;
+            }
+            @Override
+            public String toString() {
+                return name;
+            }
+        }
+
+        static enum Division {
+            DOCTITLE("doctitle"),
+            VERSION("versions"),
+            SECTION("section");
+            final String name;
+
+            Division(String name) {
+                this.name = name;
+            }
+
+            public String toString(String... lines) {
+                String value = Arrays.stream(lines).collect(Collectors.joining("<br>\n"));
+                return "<div class=\"" + name + "\">" + value + "</div>";
+            }
+        }
+
+        class ModuleTableRow {
+            private final ModuleSummary ms;
+            private final Set<ModuleDescriptor> deps;
+            private final int maxRows;
+            private final boolean aggregator;
+            ModuleTableRow(ModuleSummary ms) {
+                this.ms = ms;
+                Configuration cf = resolve(Set.of(ms.name()));
+                this.deps = cf.modules().stream()
+                        .map(ResolvedModule::reference)
+                        .map(ModuleReference::descriptor)
+                        .collect(Collectors.toSet());
+                int count = (ms.numClasses() > 0 ? 1 : 0) +
+                            (ms.numResources() > 0 ? 1 : 0) +
+                            (ms.numConfigs() > 0 ? 1 : 0) +
+                            (ms.numNativeLibraries() > 0 ? 1 : 0) +
+                            (ms.numNativeLibrariesDebug() > 0 ? 1 : 0) +
+                            (ms.numCommands() > 0 ? 1 : 0) +
+                            (ms.numCommandsDebug() > 0 ? 1 : 0);
+                this.aggregator = ms.numClasses() == 1 && count == 1; // only module-info.class
+
+                // 5 fixed rows (name + 2 transitive count/size + 2 blank rows)
+                this.maxRows = 5 + count + (aggregator && !aggregatorNote ? 2 : 0);
+            }
+
+            public void writeTo(PrintStream out) {
+                out.println(String.format("<tr id=\"%s\" class=\"%s\">", ms.name(), MODULE));
+                out.println(moduleColumn());
+                out.println(requiresColumn());
+                out.println(exportsColumn());
+                out.println(servicesColumn());
+                out.println(otherSectionColumn());
+                out.println("</td>");
+                out.println("</tr>");
+            }
+
+            public String moduleColumn() {
+                // module name
+                StringBuilder sb = new StringBuilder("  ");
+                sb.append("<td>");
+                sb.append(String.format("<table class=\"%s\">", MODULE)).append("\n");
+                sb.append(moduleName(ms.name()));
+                sb.append(blankRow());
+                // metadata
+                sb.append(toTableRow("class", "classes", ms.numClasses(), ms.classBytes()));
+                sb.append(toTableRow("resource", "resources", ms.numResources(), ms.resourceBytes()));
+                sb.append(toTableRow("config", "configs", ms.numConfigs(), ms.configBytes()));
+                sb.append(toTableRow("native library", "native libraries",
+                                     ms.numNativeLibraries(), ms.nativeLibrariesBytes()));
+                sb.append(toTableRow("native library debug", "native libraries debug",
+                                     ms.numNativeLibrariesDebug(), ms.nativeLibrariesDebugBytes()));
+                sb.append(toTableRow("command", "commands", ms.numCommands(), ms.commandBytes()));
+                sb.append(toTableRow("command debug", "commands debug",
+                                     ms.numCommandsDebug(), ms.commandDebugBytes()));
+                sb.append(blankRow());
+
+                // transitive dependencies
+                long reqBytes = deps.stream()
+                                    .filter(d -> !d.name().equals(ms.name()))
+                                    .mapToLong(d -> modules.get(d.name()).uncompressedSize())
+                                    .sum();
+                long reqJmodFileSize = deps.stream()
+                                            .mapToLong(d -> modules.get(d.name()).jmodFileSize())
+                                            .sum();
+                // size
+                if (totalBytesNote) {
+                    sb.append(toTableRow("Total bytes", ms.uncompressedSize()));
+                    sb.append(toTableRow("Total bytes of dependencies", reqBytes));
+                } else {
+                    // print footnote
+                    sb.append(toTableRow("Total bytes<sup>1</sup>", ms.uncompressedSize()));
+                    sb.append(toTableRow("Total bytes of dependencies<sup>2</sup>", reqBytes));
+                }
+                String files = deps.size() == 1 ? "file" : "files";
+                sb.append(toTableRow(String.format("Total jmod bytes (%d %s)", deps.size(), files), reqJmodFileSize));
+
+                if (aggregator && !aggregatorNote) {
+                    aggregatorNote = true;
+                    sb.append(blankRow());
+                    sb.append(toTableRow("<i>* aggregator is a module with module-info.class only</i>", BR));
+                }
+                if (!totalBytesNote) {
+                    totalBytesNote = true;
+                    sb.append(blankRow());
+                    sb.append(toTableRow("<i><sup>1</sup>sum of all files including debug files</i>", BR));
+                    sb.append(toTableRow("<i><sup>2</sup>sum of direct and indirect dependencies</i>", BR));
+                }
+                sb.append("</table>").append("</td>");
+                return sb.toString();
+            }
+
+            private String moduleName(String mn) {
+                if (aggregator) {
+                    StringBuilder sb = new StringBuilder();
+                    sb.append(String.format("<tr><td colspan=\"2\"><span class=\"%s\">", AGGREGATOR))
+                      .append(mn)
+                      .append("</span>").append("&nbsp;&nbsp;");
+                    if (!aggregatorNote) {
+                        sb.append("(aggregator<sup>*</sup>)");
+                    } else {
+                        sb.append("(aggregator)");
+                    }
+                    sb.append("</td></tr>");
+                    return sb.toString();
+                } else {
+                    return toTableRow(mn, MODULE_DEF);
+                }
+            }
+
+            public String requiresColumn() {
+                StringBuilder sb = new StringBuilder();
+                sb.append(String.format("<td>"));
+                boolean footnote = requiresPublicNote;
+                ms.descriptor().requires().stream()
+                        .sorted(Comparator.comparing(Requires::name))
+                        .forEach(r -> {
+                            boolean requiresPublic = r.modifiers().contains(Requires.Modifier.PUBLIC);
+                            Selector sel = requiresPublic ? REQUIRES_PUBLIC : REQUIRES;
+                            String req = String.format("<a class=\"%s\" href=\"#%s\">%s</a>",
+                                                       sel, r.name(), r.name());
+                            if (!requiresPublicNote && requiresPublic) {
+                                requiresPublicNote = true;
+                                req += "<sup>*</sup>";
+                            }
+                            sb.append(req).append("\n").append("<br>");
+                        });
+
+                if (!ms.name().equals("java.base")) {
+                    int directDeps = ms.descriptor().requires().size();
+                    int indirectDeps = deps.size()-directDeps-1;
+                    for (int i=directDeps; i< (maxRows-1); i++) {
+                        sb.append("<br>");
+                    }
+                    sb.append("<br>");
+                    sb.append("<i>+").append(indirectDeps).append(" transitive dependencies</i>");
+                }
+                if (footnote != requiresPublicNote) {
+                    sb.append("<br><br>").append("<i>* bold denotes requires public</i>");
+                }
+                sb.append("</td>");
+                return sb.toString();
+            }
+
+            public String exportsColumn() {
+                StringBuilder sb = new StringBuilder();
+                sb.append(String.format("  <td class=\"%s\">", CODE));
+                ms.descriptor().exports().stream()
+                        .sorted(Comparator.comparing(Exports::source))
+                        .filter(e -> !e.isQualified())
+                        .forEach(e -> sb.append(e.source()).append("<br>").append("\n"));
+                sb.append("</td>");
+                return sb.toString();
+            }
+
+            public String servicesColumn() {
+                StringBuilder sb = new StringBuilder();
+                sb.append(String.format("  <td class=\"%s\">", CODE));
+                ms.descriptor().uses().stream()
+                        .sorted()
+                        .forEach(s -> sb.append("uses ").append(s).append("<br>").append("\n"));
+                ms.descriptor().provides().entrySet().stream()
+                        .sorted(Map.Entry.comparingByKey())
+                        .flatMap(e -> e.getValue().providers().stream()
+                                .map(p -> String.format("provides %s<br>&nbsp;&nbsp;&nbsp;&nbsp;with %s",
+                                                        e.getKey(), p)))
+                        .forEach(p -> sb.append(p).append("<br>").append("\n"));
+                sb.append("</td>");
+                return sb.toString();
+            }
+
+            public String otherSectionColumn() {
+                StringBuilder sb = new StringBuilder();
+                sb.append("<td>");
+                sb.append(String.format("<table class=\"%s\">", MODULE)).append("\n");
+                // commands
+                if (ms.numCommands() > 0) {
+                    sb.append(toTableRow("bin/", CODE));
+                    ms.commands().entrySet().stream()
+                            .sorted(Map.Entry.comparingByKey())
+                            .forEach(e -> sb.append(toTableRow(e.getKey(), e.getValue(), CODE)));
+                    sb.append(blankRow());
+                }
+
+                // native libraries
+                if (ms.numNativeLibraries() > 0) {
+                    sb.append(toTableRow("lib/", CODE));
+                    ms.nativeLibs().entrySet().stream()
+                            .sorted(Map.Entry.comparingByKey())
+                            .forEach(e -> sb.append(toTableRow(e.getKey(), e.getValue(), CODE)));
+                    sb.append(blankRow());
+                }
+
+                // config files
+                if (ms.numConfigs() > 0) {
+                    sb.append(toTableRow("conf/", CODE));
+                    ms.configFiles().entrySet().stream()
+                            .sorted(Map.Entry.comparingByKey())
+                            .forEach(e -> sb.append(toTableRow(e.getKey(), e.getValue(), CODE)));
+                }
+                // totals
+                sb.append("</table>").append("</td>");
+                return sb.toString();
+            }
+
+            private String blankRow() {
+                return toTableRow("&nbsp;", BR);
+            }
+
+            private String toTableRow(String col, Selector selector) {
+                TableDataBuilder builder = new TableDataBuilder();
+                builder.colspan(selector, 2, col);
+                return builder.build();
+            }
+
+            private String toTableRow(String col1, long col2) {
+                return toTableRow(col1, col2, BR);
+            }
+
+            private String toTableRow(String col1, long col2, Selector selector) {
+                TableDataBuilder builder = new TableDataBuilder();
+                builder.data(selector, col1);
+                builder.data(col2);
+                return builder.build();
+
+            }
+
+            private String toTableRow(String singular, String plural, int count, long bytes) {
+                if (count == 0) {
+                    return "";
+                }
+                TableDataBuilder builder = new TableDataBuilder();
+                if (count == 1) {
+                    builder.data(count + " " + singular);
+                } else {
+                    builder.data(count + " " + plural);
+                }
+                builder.data(bytes);
+                return builder.build();
+            }
+
+            class TableDataBuilder {
+                private final StringBuilder sb;
+                TableDataBuilder() {
+                    this.sb = new StringBuilder("<tr>");
+                }
+                TableDataBuilder data(String s) {
+                    data(BR, s);
+                    return this;
+                }
+                TableDataBuilder data(long num) {
+                    data(NUMBER, String.format("%,d", num));
+                    return this;
+                }
+                TableDataBuilder colspan(Selector selector, int columns, String data) {
+                    sb.append("<td colspan=\"").append(columns).append("\">");
+                    sb.append("<span class=\"").append(selector).append("\">");
+                    sb.append(data).append("</span></td>");
+                    return this;
+                }
+
+                TableDataBuilder data(Selector selector, String data) {
+                    sb.append("<td class=\"").append(selector).append("\">");
+                    sb.append(data).append("</td>");
+                    return this;
+                }
+                String build() {
+                    sb.append("</tr>");
+                    return sb.toString();
+                }
+            }
+        }
+
+        private static final String[] STYLES = new String[]{
+                "<link rel=\"stylesheet\" type=\"text/css\" href=\"/.fonts/dejavu.css\"/>",
+                "<style type=\"text/css\">",
+                "        HTML, BODY, DIV, SPAN, APPLET, OBJECT, IFRAME, H1, H2, H3, H4, H5, H6, P,",
+                "        BLOCKQUOTE, PRE, A, ABBR, ACRONYM, ADDRESS, BIG, CITE, CODE, DEL, DFN, EM,",
+                "        IMG, INS, KBD, Q, S, SAMP, SMALL, STRIKE, STRONG, SUB, SUP, TT, VAR, B, U,",
+                "        I, CENTER, DL, DT, DD, OL, UL, LI, FIELDSET, FORM, LABEL, LEGEND, TABLE,",
+                "        CAPTION, TBODY, TFOOT, THEAD, TR, TH, TD, ARTICLE, ASIDE, CANVAS, DETAILS,",
+                "        EMBED, FIGURE, FIGCAPTION, FOOTER, HEADER, HGROUP, MENU, NAV, OUTPUT, RUBY,",
+                "        SECTION, SUMMARY, TIME, MARK, AUDIO, VIDEO {",
+                "          margin: 0; padding: 0; border: 0; font-size: 100%; font: inherit;",
+                "          vertical-align: baseline; }",
+                "        ARTICLE, ASIDE, DETAILS, FIGCAPTION, FIGURE, ",
+                "        FOOTER, HEADER, HGROUP, MENU, NAV, SECTION { display: block; }",
+                "        BLOCKQUOTE, Q { quotes: none; }",
+                "        BLOCKQUOTE:before, BLOCKQUOTE:after, Q:before, Q:after {",
+                "                content: ''; content: none; }",
+                "        TABLE { border-collapse: collapse; border-spacing: 0; }",
+                "        A { text-decoration: none; }",
+                "        A:link { color: #437291; }",
+                "        A:visited { color: #666666; }",
+                "        A.anchor:link, A.anchor:visited { color: black; }",
+                "        A[href]:hover { color: #e76f00; }",
+                "        A IMG { border-width: 0px; }",
+                "        HTML { font-size: 20px; } /* baseline grid */",
+                "        HTML > BODY { font-size: 14px; }",
+                "        BODY {",
+                "          background: white;",
+                "          margin: 40px;",
+                "          margin-bottom: 150%;",
+                "          line-height: 20px;",
+                "          -webkit-text-size-adjust: 100%; /* iOS */",
+                "          color: #222;",
+                "        }",
+                "        BODY { font-family: \"DejaVu Serif\", \"Lucida Bright\", \"Bookman Old Style\",",
+                "                            Georgia, serif; }",
+                "        CODE, TT, .jref, DIV.spec .open, TABLE.profiles {",
+                "          font-family: \"DejaVu Sans\", \"Lucida Sans\", Helvetica, sans-serif; }",
+                "        PRE, .code { font-family: \"DejaVu Sans Mono\", \"Bitstream Vera Sans Mono\",",
+                "                            Monaco, \"Courier New\", monospace; }",
+                "        H1, H2, H3, H4 { color: green; font-weight: bold; }",
+                "        I { font-style: italic; }",
+                "        TH { font-weight: bold; }",
+                "        P { text-indent: 40px; }",
+                "        P:first-child, UL + P, OL + P, BLOCKQUOTE + P, TABLE + P, P.subsection,",
+                "          P.break, DIV.profiles-table + P { text-indent: 0; }",
+                "        P.break { margin-top: 10px; }",
+                "        P.subsection { margin-top: 20px; }",
+                "        P.subsection SPAN.title { font-weight: bold; padding-right: 20px; }",
+                "        UL, OL { margin: 10px 0; padding-left: 40px; }",
+                "        LI { margin-bottom: 10px; }",
+                "        UL.compact LI { margin-bottom: 0; }",
+                "        PRE { padding: 0; margin: 10px 0 10px 20px; background: #eee; width: 45em; }",
+                "        BLOCKQUOTE { margin: 10px 0; margin-left: 20px; }",
+                "        LI BLOCKQUOTE { margin-left: 0; }",
+                "        UL LI { list-style-type: square; }",
+                "        .todo { color: darkred; text-align: right; }",
+                "        .error { color: red; font-weight: bold; }",
+                "        .warn { color: #ee0000; font-weight: bold; }",
+                "        DIV.doctitle { margin-top: -13px;",
+                "          font-size: 22px; line-height: 40px; font-weight: bold; }",
+                "        DIV.twarn { color: #cc0000; font-weight: bold; margin-bottom: 9px; }",
+                "        DIV.subtitle { margin-top: 2px; font-size: 18px; font-weight: bold; }",
+                "        DIV.authors { margin-top: 10px; margin-bottom: 10px; font-size: 16px; }",
+                "        DIV.author A { font-style: italic; }",
+                "        DIV.version { margin-top: 10px; font-size: 12px; }",
+                "        DIV.version, DIV.legal-notice { font-size: 12px; line-height: 15px; }",
+                "        SPAN.hash { font-size: 9px; }",
+                "        DIV.version SPAN.modified { color: green; font-weight: bold; }",
+                "        DIV.head { margin-bottom: 20px; }",
+                "        DIV.section > DIV.title, DIV.section DIV.number SPAN {",
+                "          font-size: 15px; font-weight: bold; }",
+                "        TABLE { border-collapse: collapse; border: none; }",
+                "        TD.number { text-align: right; }",
+                "        TD, TH { text-align: left; white-space: nowrap; }",
+                "        TD.name, SPAN.name { font-weight: bold; }",
+                "        ",
+                "        TABLE.module { width: 100%; }",
+                "        TABLE.module TD:first-child { padding-right: 10px; }",
+                "        TR.module > TD { padding: 10px 0; border-top: 1px solid black; }",
+                "        TR > TH { padding-bottom: 10px; }",
+                "        TR.br TD { padding-top: 20px; }",
+                "        TABLE.modules { margin-top: 20px; }",
+                "        TABLE.modules > TBODY > TR > TD:nth-child(even) { background: #eee; }",
+                "        TABLE.modules > TBODY > TR > TD, TABLE.modules > TBODY > TR > TH {",
+                "          padding-left: 10px; padding-right: 10px; }",
+                "        .reexp, .def { font-weight: bold; }",
+                "        .agg { font-style: italic; }",
+                "        SUP { height: 0; line-height: 1; position: relative;",
+                "              vertical-align: baseline; bottom: 1ex; font-size: 11px; }",
+                "</style>",
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/src/classes/build/tools/jigsaw/technology-summary.html	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,627 @@
+<html>
+<head>
+<title>JDK Technology Summary</title>
+<style type="text/css">
+table { border: 1px solid black; border-collapse: collapse; }
+tr.se-base { background-color: bisque; }
+tr.se-misc { background-color: lavender; }
+tr.se-ee   { background-color: lightgreen; }
+tr.se-ext  { background-color: pink; }
+td { font-family: monospace; padding: 4px; border: 1px solid; }
+</style>
+</head>
+
+<h1>JCP Technologies in the Modular JDK</h1>
+
+<p><em>Last updated 2015-03-06 (Added java.datatransfer. Assumes JNLP is modularized, and StAX joins the Java SE Platform.)</em></p>
+
+<p><a href="module-summary.html">JDK Module Summary</a> | Technologies in the <a href="https://docs.oracle.com/javase/8/docs/">Java SE Documentation</a></p>
+
+<table>
+<tr><th>Legend</th></tr>
+<tr class="se-base"><td><a href="https://jcp.org/en/jsr/platform?listBy=2&listByType=platform">JCP technology in the Java SE Platform only -- in java.base</a></td></tr>
+<tr class="se-misc"><td><a href="https://jcp.org/en/jsr/platform?listBy=2&listByType=platform">JCP technology in the Java SE Platform only -- not in java.base</a></td></tr>
+<tr class="se-ee"><td><a href="https://jcp.org/en/jsr/platform?listBy=3&listByType=platform">JCP technology in the Java SE Platform and the Java EE Platform</a></a></td></tr>
+<tr class="se-ext"><td><a href="http://docs.oracle.com/javase/8/docs/technotes/guides/standards/#endorsed-standards-apis">JCP technology in the Java SE Platform based on non-JCP standards</a></a></td></tr>
+<tr><td>JCP technology in neither the Java SE or EE Platforms</td></tr>
+</table>
+
+<p><em>An <strong>upgradeable</strong> module contains JCP technology that is in the Java SE Platform but is not exclusive to the Java SE Platform, i.e., the green and pink technologies. Most upgradeable modules are defined by loaders other than the bootstrap.</em></p>
+
+<br/>
+
+<table>
+<tr>
+<th>Technology</th>
+<th>Original JSR</th>
+<th><a href="https://jcp.org/en/procedures/jcp2#DEF">Original Target</a></th>
+<th>Module</th>
+<th><a href="https://jcp.org/en/procedures/jcp2#2.1.2">Evolved By</a></th>
+<th>History</th>
+<th>Profile/SE</th>
+<th>Loader</th>
+<th>Upg?</th>
+</tr>
+
+<tr class="se-misc">
+<td>JMX</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=3">3</a></td>
+<td>Java SE</td>
+<td><a href="module-summary.html#java.management">java.management</a></td>
+<td>UJSR for Java SE</td>
+<td></td>
+<td>3</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-misc">
+<td>Print Service</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=6">6</a></td>
+<td>Java SE</td>
+<td><a href="module-summary.html#java.desktop">java.desktop</a></td>
+<td>UJSR for Java SE</td>
+<td></td>
+<td>SE</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-misc">
+<td>Preferences</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=10">10</a></td>
+<td>Java SE</td>
+<td><a href="module-summary.html#java.prefs">java.prefs</a></td>
+<td>UJSR for Java SE</td>
+<td></td>
+<td>3</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-misc">
+<td>Image I/O</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=15">15</a></td>
+<td>Java SE</td>
+<td><a href="module-summary.html#java.desktop">java.desktop</a></td>
+<td>UJSR for Java SE</td>
+<td></td>
+<td>SE</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-misc">
+<td>SASL</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=28">28</a></td>
+<td>Java SE</td>
+<td><a href="module-summary.html#java.security.sasl"/>java.security.sasl</a></td>
+<td>UJSR for Java SE</td>
+<td></td>
+<td>3</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-misc">
+<td>Logging</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=47">47</a></td>
+<td>Java SE</td>
+<td><a href="module-summary.html#java.logging">java.logging</a></td>
+<td>UJSR for Java SE</td>
+<td></td>
+<td>1</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-base">
+<td>NIO</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=51">51</a></td>
+<td>Java SE</td>
+<td><a href="module-summary.html#java.base"/>java.base</a></td>
+<td>UJSR for Java SE</td>
+<td></td>
+<td>1</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr>
+<td>JNLP</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=56">56</a></td>
+<td>Java SE</td>
+<td><a href="module-summary.html#java.desktop">java.jnlp</a></td>
+<td>Original JSR</td>
+<td></td>
+<td>N/A</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-misc">
+<td>Beans Persistence</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=57">57</a></td>
+<td>Java SE</td>
+<td><a href="module-summary.html#java.desktop">java.desktop</a></td>
+<td>UJSR for Java SE</td>
+<td></td>
+<td>SE</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-misc">
+<td>GSS</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=72">72</a></td>
+<td>Java SE</td>
+<td><a href="module-summary.html#java.security.jgss">java.security.jgss</a></td>
+<td>UJSR for Java SE</td>
+<td></td>
+<td>3</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-misc">
+<td>XML Digital Signature</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=105">105</a></td>
+<td>Java SE</td>
+<td><a href="module-summary.html#java.xml.crypto">java.xml.crypto</a></td>
+<td>UJSR for Java SE</td>
+<td></td>
+<td>3</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-misc">
+<td>JDBC Rowset</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=114">114</a></td>
+<td>Java SE</td>
+<td><a href="module-summary.html#java.sql.rowset">java.sql.rowset</a></td>
+<td>Original JSR</td>
+<td>Co-evolved with JDBC</td>
+<td>3</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-misc">
+<td>JMX Remote</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=160">160</a></td>
+<td>Java SE</td>
+<td><a href="module-summary.html#java.management">java.management</a></td>
+<td>UJSR for Java SE</td>
+<td></td>
+<td>3</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-misc">
+<td>Profiling (Agent)</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=163">163</a></td>
+<td>Java SE</td>
+<td><a href="module-summary.html#java.instrument">java.instrument</a></td>
+<td>UJSR for Java SE</td>
+<td></td>
+<td>3</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-misc">
+<td>Profiling (JMX)</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=163">163</a></td>
+<td>Java SE</td>
+<td><a href="module-summary.html#java.management">java.management</a></td>
+<td>UJSR for Java SE</td>
+<td></td>
+<td>3</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-base">
+<td>Concurrency Utilities</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=166">166</a></td>
+<td>Java SE</td>
+<td><a href="module-summary.html#java.base"/>java.base</a></td>
+<td>UJSR for Java SE</td>
+<td></td>
+<td>1</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-base">
+<td>Annotations</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=175">175</a></td>
+<td>Java SE</td>
+<td><a href="module-summary.html#java.base"/>java.base</a></td>
+<td>UJSR for Java SE</td>
+<td></td>
+<td>1</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-misc">
+<td>StAX</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=173">173</a></td>
+<td>Java SE</td>
+<td><a href="module-summary.html#java.xml">java.xml</a></td>
+<td>Original JSR</td>
+<td>Formerly a <a href="http://docs.oracle.com/javase/8/docs/technotes/guides/standards/#standalone-technologies">Standalone Technology</a></td>
+<td>2</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-misc">
+<td>Annotations (Language Model)</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=175">175</a></td>
+<td>Java SE</td>
+<td><a href="module-summary.html#java.compiler"/>java.compiler</a></td>
+<td>UJSR for Java SE</td>
+<td></td>
+<td>3</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-misc">
+<td>Compiler</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=199">199</a></td>
+<td>Java SE</td>
+<td><a href="module-summary.html#java.compiler">java.compiler</a></td>
+<td>Original JSR</td>
+<td>Formerly a <a href="http://docs.oracle.com/javase/8/docs/technotes/guides/standards/#standalone-technologies">Standalone Technology</a></td>
+<td>3</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-base">
+<td>Pack200</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=200">200</a></td>
+<td>Java SE</td>
+<td><a href="module-summary.html#java.base"/>java.base</a></td>
+<td>UJSR for Java SE</td>
+<td></td>
+<td>1</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-base">
+<td>NIO.2</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=203">203</a></td>
+<td>Java SE</td>
+<td><a href="module-summary.html#java.base"/>java.base</a></td>
+<td>UJSR for Java SE</td>
+<td></td>
+<td>1</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-misc">
+<td>JAXP</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=206">206</a></td>
+<td>Java SE</td>
+<td><a href="module-summary.html#java.xml">java.xml</a></td>
+<td>UJSR for Java SE</td>
+<td>Formerly a <a href="http://docs.oracle.com/javase/8/docs/technotes/guides/standards/#standalone-technologies">Standalone Technology</a></td>
+<td>2</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-misc">
+<td>JDBC</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=221">221</a></td>
+<td>Java SE</td>
+<td><a href="module-summary.html#java.sql">java.sql</a></td>
+<td>Original JSR</td>
+<td>Co-evolved with JDBC Rowset</td>
+<td>2</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-misc">
+<td>Scripting</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=223">223</a></td>
+<td>Java SE</td>
+<td><a href="module-summary.html#java.scripting">java.scripting</a></td>
+<td>Original JSR</td>
+<td>Formerly a <a href="http://docs.oracle.com/javase/8/docs/technotes/guides/standards/#standalone-technologies">Standalone Technology</a></td>
+<td>1</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr>
+<td>Smart Card I/O</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=268">268</a></td>
+<td>Java SE</td>
+<td><a href="module-summary.html#java.smartcardio">java.smartcardio</a></td>
+<td>Original JSR</td>
+<td>Formerly a <a href="http://docs.oracle.com/javase/8/docs/technotes/guides/standards/#standalone-technologies">Standalone Technology</a> (unlisted)</td>
+<td>N/A</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-misc">
+<td>Annotation Processing</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=269">269</a></td>
+<td>Java SE</td>
+<td><a href="module-summary.html#java.compiler">java.compiler</a></td>
+<td>Original JSR</td>
+<td>Formerly a <a href="http://docs.oracle.com/javase/8/docs/technotes/guides/standards/#standalone-technologies">Standalone Technology</a></td>
+<td>3</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-base">
+<td>InvokeDynamic</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=292">292</a></td>
+<td>Java SE</td>
+<td><a href="module-summary.html#java.base"/>java.base</a></td>
+<td>UJSR for Java SE</td>
+<td></td>
+<td>1</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-base">
+<td>Type Annotations</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=308">308</a></td>
+<td>Java SE</td>
+<td><a href="module-summary.html#java.base"/>java.base</a></td>
+<td>UJSR for Java SE</td>
+<td></td>
+<td>1</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-misc">
+<td>Type Annotations (Language Model)</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=308">308</a></td>
+<td>Java SE</td>
+<td><a href="module-summary.html#java.compiler"/>java.compiler</a></td>
+<td>UJSR for Java SE</td>
+<td></td>
+<td>3</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-base">
+<td>Date and Time</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=310">310</a></td>
+<td>Java SE</td>
+<td><a href="module-summary.html#java.base"/>java.base</a></td>
+<td>UJSR for Java SE</td>
+<td></td>
+<td>1</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-base">
+<td>Streams</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=335">335</a></td>
+<td>Java SE</td>
+<td><a href="module-summary.html#java.base"/>java.base</a></td>
+<td>UJSR for Java SE</td>
+<td></td>
+<td>1</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-base">
+<td>Collections, Math, I18N, I/O, Net, Reflection</td>
+<td>---</td>
+<td>---</td>
+<td><a href="module-summary.html#java.base"/>java.base</a></td>
+<td>UJSR for Java SE</td>
+<td></td>
+<td>1</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-base">
+<td>JCA, JAAS, JSSE</td>
+<td>---</td>
+<td>---</td>
+<td><a href="module-summary.html#java.base"/>java.base</a></td>
+<td>UJSR for Java SE</td>
+<td></td>
+<td>1</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-misc">
+<td>Applet, AWT, Swing, Java 2D, Beans, A11Y, Sound</td>
+<td>---</td>
+<td>---</td>
+<td><a href="module-summary.html#java.desktop"/>java.desktop</a></td>
+<td>UJSR for Java SE</td>
+<td></td>
+<td>SE</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-misc">
+<td>Data Transfer</td>
+<td>---</td>
+<td>---</td>
+<td><a href="module-summary.html#java.datatransfer"/>java.datatransfer</a></td>
+<td>UJSR for Java SE</td>
+<td></td>
+<td>SE</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-misc">
+<td>JNDI</td>
+<td>---</td>
+<td>---</td>
+<td><a href="module-summary.html#java.naming"/>java.naming</a></td>
+<td>UJSR for Java SE</td>
+<td></td>
+<td>3</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-misc">
+<td>RMI</td>
+<td>---</td>
+<td>---</td>
+<td><a href="module-summary.html#java.rmi"/>java.rmi</a></td>
+<td>UJSR for Java SE</td>
+<td></td>
+<td>2</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-misc">
+<td>JAF</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=925">925</a></td>
+<td>---</td>
+<td><a href="module-summary.html#java.activation">java.activation</a></a></td>
+<td>Original JSR</td>
+<td>Formerly a <a href="http://docs.oracle.com/javase/8/docs/technotes/guides/standards/#standalone-technologies">Standalone Technology</a> (unlisted)</td>
+<td>SE</td>
+<td>ext</td>
+<td>Yes</td>
+</tr>
+
+<tr class="se-ext">
+<td>RMI-IIOP, IDL</td>
+<td>(OMG)</td>
+<td>---</td>
+<td><a href="module-summary.html#java.corba"/>java.corba</a></td>
+<td>UJSR for Java SE</td>
+<td>Formerly an <a href="http://docs.oracle.com/javase/8/docs/technotes/guides/standards/#endorsed-standards-apis">Endorsed Standard</a></td>
+<td>SE</td>
+<td>ext</td>
+<td>Yes</td>
+</tr>
+
+<tr class="se-ext">
+<td>DOM, SAX</td>
+<td>(W3C)</td>
+<td>---</td>
+<td><a href="module-summary.html#java.xml">java.xml</a></td>
+<td>UJSR for Java SE</td>
+<td>Formerly an <a href="http://docs.oracle.com/javase/8/docs/technotes/guides/standards/#endorsed-standards-apis">Endorsed Standard</a></td>
+<td>2</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+<tr class="se-ee">
+<td>SAAJ</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=67">67</a></td>
+<td>Java SE</td>
+<td><a href="module-summary.html#java.xml.ws">java.xml.ws</a></td>
+<td>Original JSR</td>
+<td>Formerly a <a href="http://docs.oracle.com/javase/8/docs/technotes/guides/standards/#standalone-technologies">Standalone Technology</a> (f.k.a. JAXM)</td>
+<td>SE</td>
+<td>ext</td>
+<td>Yes</td>
+</tr>
+
+<tr class="se-ee">
+<td>Web Services Metadata</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=181">181</a></td>
+<td>Java EE</td>
+<td><a href="module-summary.html#java.xml.ws">java.xml.ws</a></td>
+<td>Original JSR</td>
+<td>Formerly a <a href="http://docs.oracle.com/javase/8/docs/technotes/guides/standards/#standalone-technologies">Standalone Technology</a> (unlisted)</td>
+<td>SE</td>
+<td>ext</td>
+<td>Yes</td>
+</tr>
+
+<tr class="se-ee">
+<td>JAXB</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=222">222</a></td>
+<td>Java SE</td>
+<td><a href="module-summary.html#java.xml.bind">java.xml.bind</a></td>
+<td>Original JSR</td>
+<td>Formerly a <a href="http://docs.oracle.com/javase/8/docs/technotes/guides/standards/#standalone-technologies">Standalone Technology</a></td>
+<td>SE</td>
+<td>ext</td>
+<td>Yes</td>
+</tr>
+
+<tr class="se-ee">
+<td>JAXWS</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=224">224</a></td>
+<td>Java SE</td>
+<td><a href="module-summary.html#java.xml.ws">java.xml.ws</a></td>
+<td>Original JSR</td>
+<td>Formerly a <a href="http://docs.oracle.com/javase/8/docs/technotes/guides/standards/#standalone-technologies">Standalone Technology</a></td>
+<td>SE</td>
+<td>ext</td>
+<td>Yes</td>
+</tr>
+
+<!-- Alex: The Java SE Platform incorporates a cutdown version of the javax.annotation package from the Java EE Platform. -->
+<tr class="se-ee">
+<td>Common Annotations</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=250">250</a></td>
+<td>Java SE,EE</td>
+<td><a href="module-summary.html#java.annotations.common">java.annotations.common</a></td>
+<td>Original JSR</td>
+<td>Formerly a <a href="http://docs.oracle.com/javase/8/docs/technotes/guides/standards/#standalone-technologies">Standalone Technology</a> (unlisted)</td>
+<td>SE</td>
+<td>ext</td>
+<td>Yes</td>
+</tr>
+
+<!-- Alex: The Java SE Platform incorporates a cutdown version of the javax.transaction package from the Java EE Platform. -->
+<tr class="se-ee">
+<td>JTA (non-XA)</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=907">907</a></td>
+<td>---</td>
+<td><a href="module-summary.html#java.transaction">java.transaction</a></td>
+<td>Original JSR</td>
+<td>Formerly a <a href="http://docs.oracle.com/javase/8/docs/technotes/guides/standards/#standalone-technologies">Standalone Technology</a> (unlisted)</td>
+<td>SE</td>
+<td>ext</td>
+<td>Yes</td>
+</tr>
+
+<!-- Alex: The Java SE Platform incorporates the same version of the javax.transaction.xa package as the Java EE Platform. -->
+<tr class="se-ee">
+<td>JTA (XA)</td>
+<td><a href="https://jcp.org/en/jsr/detail?id=907">907</a></td>
+<td>---</td>
+<td><a href="module-summary.html#java.sql"/>java.sql</a></td>
+<td>Original JSR</td>
+<td>Formerly a <a href="http://docs.oracle.com/javase/8/docs/technotes/guides/standards/#standalone-technologies">Standalone Technology</a> (unlisted)</td>
+<td>2</td>
+<td>boot</td>
+<td>No</td>
+</tr>
+
+</table>
+
+</html>
--- a/make/src/classes/build/tools/module/GenJdepsModulesXml.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,130 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package build.tools.module;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.UncheckedIOException;
-import java.nio.file.Files;
-import java.nio.file.NoSuchFileException;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.attribute.BasicFileAttributes;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-/**
- * GenJdepsModulesXml augments the input modules.xml file(s)
- * to include the module membership from the given path to
- * the JDK exploded image.  The output file is used by jdeps
- * to analyze dependencies and enforce module boundaries.
- *
- * The input modules.xml file defines the modular structure of
- * the JDK as described in JEP 200: The Modular JDK
- * (http://openjdk.java.net/jeps/200).
- *
- * $ java build.tools.module.GenJdepsModulesXml \
- *        -o com/sun/tools/jdeps/resources/modules.xml \
- *        -mp $OUTPUTDIR/modules \
- *        top/modules.xml
- */
-public final class GenJdepsModulesXml {
-    private final static String USAGE =
-        "Usage: GenJdepsModulesXml -o <output file> -mp build/modules path-to-modules-xml";
-
-    public static void main(String[] args) throws Exception {
-        Path outfile = null;
-        Path modulepath = null;
-        int i = 0;
-        while (i < args.length) {
-            String arg = args[i];
-            if (arg.equals("-o")) {
-                outfile = Paths.get(args[i+1]);
-                i = i+2;
-            } else if (arg.equals("-mp")) {
-                modulepath = Paths.get(args[i+1]);
-                i = i+2;
-                if (!Files.isDirectory(modulepath)) {
-                    System.err.println(modulepath + " is not a directory");
-                    System.exit(1);
-                }
-            } else {
-                break;
-            }
-        }
-        if (outfile == null || modulepath == null || i >= args.length) {
-            System.err.println(USAGE);
-            System.exit(-1);
-        }
-
-        GenJdepsModulesXml gentool = new GenJdepsModulesXml(modulepath);
-        Set<Module> modules = new HashSet<>();
-        for (; i < args.length; i++) {
-            Path p = Paths.get(args[i]);
-            modules.addAll(ModulesXmlReader.readModules(p)
-                    .stream()
-                    .map(gentool::buildIncludes)
-                    .collect(Collectors.toSet()));
-        }
-
-        Files.createDirectories(outfile.getParent());
-        ModulesXmlWriter.writeModules(modules, outfile);
-    }
-
-    final Path modulepath;
-    public GenJdepsModulesXml(Path modulepath) {
-        this.modulepath = modulepath;
-    }
-
-    private static String packageName(Path p) {
-        return packageName(p.toString().replace(File.separatorChar, '/'));
-    }
-    private static String packageName(String name) {
-        int i = name.lastIndexOf('/');
-        return (i > 0) ? name.substring(0, i).replace('/', '.') : "";
-    }
-
-    private static boolean includes(String name) {
-        return name.endsWith(".class");
-    }
-
-    public Module buildIncludes(Module module) {
-        Module.Builder mb = new Module.Builder(module);
-        Path mclasses = modulepath.resolve(module.name());
-        try {
-            Files.find(mclasses, Integer.MAX_VALUE, (Path p, BasicFileAttributes attr)
-                         -> includes(p.getFileName().toString()))
-                 .map(p -> packageName(mclasses.relativize(p)))
-                 .forEach(mb::include);
-        } catch (NoSuchFileException e) {
-            // aggregate module may not have class
-        } catch (IOException ioe) {
-            throw new UncheckedIOException(ioe);
-        }
-        return mb.build();
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/src/classes/build/tools/module/GenModuleInfoSource.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package build.tools.module;
+
+import java.io.BufferedWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A build tool to extend the module-info.java in the source tree
+ * for platform-specific exports, uses, and provides and write
+ * to the specified output file.
+ *
+ * GenModulesList build tool currently generates the modules.list from
+ * the module-info.java from the source tree that will be used for
+ * the make target and dependences.
+ *
+ * The build currently invokes gensrc-$MODULE.gmk after modules.list
+ * is generated.  Hence, platform-specific requires is not supported.
+ */
+public class GenModuleInfoSource {
+    private final static String USAGE =
+        "Usage: GenModuleInfoSource [option] -o <output file> <module-info-java>\n" +
+        "Options are:\n" +
+        "  -exports  <package-name>\n" +
+        "  -exports  <package-name>/<module-name>\n" +
+        "  -uses     <service>\n" +
+        "  -provides <service>/<provider-impl-classname>\n";
+
+    public static void main(String... args) throws Exception {
+        Path outfile = null;
+        Path moduleInfoJava = null;
+        Map<String, Set<String>> options = new HashMap<>();
+
+        // validate input arguments
+        for (int i = 0; i < args.length; i++){
+            String option = args[i];
+            if (option.startsWith("-")) {
+                String arg = args[++i];
+                if (option.equals("-exports") ||
+                        option.equals("-uses") ||
+                        option.equals("-provides")) {
+                    options.computeIfAbsent(option, _k -> new HashSet<>()).add(arg);
+                } else if (option.equals("-o")) {
+                    outfile = Paths.get(arg);
+                } else {
+                    throw new IllegalArgumentException("invalid option: " + option);
+                }
+            } else if (moduleInfoJava != null) {
+                throw new IllegalArgumentException("more than one module-info.java");
+            } else {
+                moduleInfoJava = Paths.get(option);
+                if (Files.notExists(moduleInfoJava)) {
+                    throw new IllegalArgumentException(option + " not exist");
+                }
+            }
+        }
+
+        if (moduleInfoJava == null || outfile == null) {
+            System.err.println(USAGE);
+            System.exit(-1);
+        }
+        // read module-info.java
+        Module.Builder builder = ModuleInfoReader.builder(moduleInfoJava);
+        augment(builder, options);
+
+        // generate new module-info.java
+        Module module = builder.build();
+        Path parent = outfile.getParent();
+        if (parent != null)
+            Files.createDirectories(parent);
+
+        try (BufferedWriter writer = Files.newBufferedWriter(outfile)) {
+            writer.write(module.toString());
+        }
+    }
+
+    private static void augment(Module.Builder builder, Map<String, Set<String>> options) {
+        for (String opt : options.keySet()) {
+            if (opt.equals("-exports")) {
+                for (String arg : options.get(opt)) {
+                    int index = arg.indexOf('/');
+                    if (index > 0) {
+                        String pn = arg.substring(0, index);
+                        String mn = arg.substring(index + 1, arg.length());
+                        builder.exportTo(pn, mn);
+                    } else {
+                        builder.export(arg);
+                    }
+                }
+            } else if (opt.equals("-uses")) {
+                options.get(opt).stream()
+                        .forEach(builder::use);
+            } else if (opt.equals("-provides")) {
+                for (String arg : options.get(opt)) {
+                    int index = arg.indexOf('/');
+                    if (index <= 0) {
+                        throw new IllegalArgumentException("invalid -provide argument: " + arg);
+                    }
+                    String service = arg.substring(0, index);
+                    String impl = arg.substring(index + 1, arg.length());
+                    builder.provide(service, impl);
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/src/classes/build/tools/module/GenModuleLoaderMap.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package build.tools.module;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class GenModuleLoaderMap {
+    private static final String USAGE =
+        "GenModuleLoaderMap -o <output-file> -boot m1[,m2]* -platform m3[,m4]* <original-source>";
+
+    public static void main(String... args) throws Exception {
+        // default set of boot modules and ext modules
+        Stream<String> bootModules = Stream.empty();
+        Stream<String> platformModules = Stream.empty();
+        Path outfile = null;
+        Path source = null;
+        for (int i=0; i < args.length; i++) {
+            String option = args[i];
+            if (option.startsWith("-")) {
+                String arg = args[++i];
+                if (option.equals("-boot")) {
+                    String[] mns = arg.split(",");
+                    bootModules = Stream.concat(bootModules, Arrays.stream(mns));
+                } else if (option.equals("-platform")) {
+                    String[] mns = arg.split(",");
+                    platformModules = Stream.concat(platformModules, Arrays.stream(mns));
+                } else if (option.equals("-o")) {
+                    outfile = Paths.get(arg);
+                } else {
+                    throw new IllegalArgumentException("invalid option: " + option);
+                }
+            } else {
+                source = Paths.get(option);
+            }
+        }
+
+        if (outfile == null) {
+            throw new IllegalArgumentException("-o must be specified");
+        }
+        if (Files.notExists(source)) {
+            throw new IllegalArgumentException(source + " not exist");
+        }
+
+        boolean needsQuotes = outfile.toString().contains(".java.tmp");
+
+        try (BufferedWriter bw = Files.newBufferedWriter(outfile, StandardCharsets.UTF_8);
+             PrintWriter writer = new PrintWriter(bw)) {
+            for (String line : Files.readAllLines(source)) {
+                if (line.contains("@@BOOT_MODULE_NAMES@@")) {
+                    line = patch(line, "@@BOOT_MODULE_NAMES@@", bootModules, needsQuotes);
+                } else if (line.contains("@@PLATFORM_MODULE_NAMES@@")) {
+                    line = patch(line, "@@PLATFORM_MODULE_NAMES@@", platformModules, needsQuotes);
+                }
+                writer.println(line);
+            }
+        }
+    }
+
+    private static String patch(String s, String tag, Stream<String> stream, boolean needsQuotes) {
+        String mns = null;
+        if (needsQuotes) {
+            mns = stream.sorted()
+                .collect(Collectors.joining("\",\n            \""));
+        } else {
+            mns = stream.sorted()
+                .collect(Collectors.joining("\n"));
+        }
+        return s.replace(tag, mns);
+    }
+
+    /**
+     * Reads the contents of the given modules file.
+     */
+    private static Set<String> readModuleSet(String name) throws IOException {
+        try (InputStream is = GenModuleLoaderMap.class.getResourceAsStream(name);
+             BufferedReader reader = new BufferedReader(new InputStreamReader(is))) {
+            return reader.lines().collect(Collectors.toSet());
+        }
+    }
+}
--- a/make/src/classes/build/tools/module/GenModulesList.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,158 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package build.tools.module;
-
-import java.io.PrintWriter;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.*;
-import java.util.stream.Collectors;
-
-/**
- * $ java build.tools.module.GenModulesList \
- *        -o modules.list \
- *        top/modules.xml ...
- */
-public final class GenModulesList {
-    private final static String USAGE =
-        "Usage: GenModulesList -o <output file> path-to-modules-xml";
-
-    private Set<Module> modules = new HashSet<>();
-    private HashMap<String,Module> nameToModule = new HashMap<>();
-
-    public static void main(String[] args) throws Exception {
-        GenModulesList gen = new GenModulesList();
-        gen.run(args);
-    }
-
-    void run(String[] args) throws Exception {
-        Path outfile = null;
-        int i = 0;
-        while (i < args.length) {
-            String arg = args[i];
-            if (arg.equals("-o")) {
-                outfile = Paths.get(args[i+1]);
-                i = i+2;
-            } else {
-                break;
-            }
-        }
-        if (outfile == null || i >= args.length) {
-            System.err.println(USAGE);
-            System.exit(-1);
-        }
-
-        for (; i < args.length; i++) {
-            Path p = Paths.get(args[i]);
-            modules.addAll(ModulesXmlReader.readModules(p));
-        }
-
-        modules.stream()
-               .forEach(m -> nameToModule.put(m.name(), m));
-
-        Path parent = outfile.getParent();
-        if (parent != null)
-            Files.createDirectories(parent);
-
-        Iterable<Module> sortedModules = (new TopoSorter(modules)).result();
-        try (PrintWriter writer = new PrintWriter(outfile.toFile())) {
-            for (Module m : sortedModules) {
-                if (isNotAggregator(m)) {
-                    String deps = getModuleDependences(m).stream()
-                            .filter(GenModulesList::isNotAggregator)
-                            .map(Module::name)
-                            .collect(Collectors.joining(" "));
-                    writer.format("%s: %s%n", m.name(), deps);
-                }
-            }
-        }
-    }
-
-    private Module nameToModule(String name) {
-        return nameToModule.get(name);
-    }
-
-    private Set<Module> getModuleDependences(Module m) {
-        return m.requires().stream()
-                .map(d -> d.name())
-                .map(this::nameToModule)
-                .collect(Collectors.toSet());
-    }
-
-    static boolean isNotAggregator(Module m) {
-        return isNotAggregator(m.name());
-    }
-
-    static boolean isNotAggregator(String name) {
-        return AGGREGATORS.contains(name) ? false : true;
-    }
-
-    static final List<String> AGGREGATORS = Arrays.asList(new String[] {
-            "java.se", "java.compact1", "java.compact2", "java.compact3"});
-
-    class TopoSorter {
-        final Deque<Module> result = new LinkedList<>();
-        final Deque<Module> nodes = new LinkedList<>();
-
-        TopoSorter(Collection<Module> nodes) {
-            nodes.stream()
-                 .forEach(m -> this.nodes.add(m));
-
-            sort();
-        }
-
-        public Iterable<Module> result() {
-            return result;
-        }
-
-        private void sort() {
-            Deque<Module> visited = new LinkedList<>();
-            Deque<Module> done = new LinkedList<>();
-            Module node;
-            while ((node = nodes.poll()) != null) {
-                if (!visited.contains(node)) {
-                    visit(node, visited, done);
-                }
-            }
-        }
-
-        private void visit(Module m, Deque<Module> visited, Deque<Module> done) {
-            if (visited.contains(m)) {
-                if (!done.contains(m)) {
-                    throw new IllegalArgumentException("Cyclic detected: " +
-                            m + " " + getModuleDependences(m));
-                }
-                return;
-            }
-            visited.add(m);
-            getModuleDependences(m).stream()
-                                   .forEach(x -> visit(x, visited, done));
-            done.add(m);
-            result.addLast(m);
-        }
-    }
-}
--- a/make/src/classes/build/tools/module/ImageBuilder.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,499 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package build.tools.module;
-
-import jdk.internal.jimage.Archive;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.PrintWriter;
-import java.nio.ByteOrder;
-import java.nio.file.Files;
-import java.nio.file.InvalidPathException;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
-import jdk.internal.jimage.ImageFileCreator;
-
-/**
- * A tool for building a runtime image.
- *
- * java build.tools.module.ImageBuilder <options> --output <path> top/modules.xml,...
- *  Possible options are:
- *  --cmds                  Location of native commands
- *  --configs               Location of config files
- *  --help                  Print this usage message
- *  --classes               Location of module classes files
- *  --libs                  Location of native libraries
- *  --mods                  Comma separated list of module names
- *  --output                Location of the output path
- *  --endian                Byte order of the target runtime; {little,big}
- */
-class ImageBuilder {
-    static class BadArgs extends Exception {
-        private static final long serialVersionUID = 0L;
-        BadArgs(String format, Object... args) {
-            super(String.format(format, args));
-            this.format = format;
-            this.args = args;
-        }
-        BadArgs showUsage(boolean b) {
-            showUsage = b;
-            return this;
-        }
-        final String format;
-        final Object[] args;
-        boolean showUsage;
-    }
-
-    static class Option {
-
-        interface Processing {
-
-            void process(ImageBuilder task, String opt, String arg) throws BadArgs;
-        }
-
-        final boolean hasArg;
-        final String[] aliases;
-        final String description;
-        final Processing processing;
-
-        Option(boolean hasArg, String description, Processing processing,
-                String... aliases) {
-            this.hasArg = hasArg;
-            this.description = description;
-            this.processing = processing;
-            this.aliases = aliases;
-        }
-        boolean isHidden() {
-            return false;
-        }
-        boolean matches(String opt) {
-            for (String a : aliases) {
-                if (a.equals(opt)) {
-                    return true;
-                } else if (opt.startsWith("--") && hasArg && opt.startsWith(a + "=")) {
-                    return true;
-                }
-            }
-            return false;
-        }
-        boolean ignoreRest() {
-            return false;
-        }
-        void process(ImageBuilder task, String opt, String arg) throws BadArgs {
-            processing.process(task, opt, arg);
-        }
-        String description() {
-            return description;
-        }
-    }
-
-    private static Path CWD = Paths.get("");
-
-    private static List<Path> splitPath(String arg, String separator)
-        throws BadArgs
-    {
-        List<Path> paths = new ArrayList<>();
-        for (String p: arg.split(separator)) {
-            if (p.length() > 0) {
-                try {
-                    Path path = CWD.resolve(p);
-                    if (Files.notExists(path))
-                        throw new BadArgs("path not found: %s", path);
-                    paths.add(path);
-                } catch (InvalidPathException x) {
-                    throw new BadArgs("path not valid: %s", p);
-                }
-            }
-        }
-        return paths;
-    }
-
-    static Option[] recognizedOptions = {
-        new Option(true, "Location of native commands", (task, opt, arg) -> {
-            task.options.cmds = splitPath(arg, File.pathSeparator);
-        }, "--cmds"),
-        new Option(true, "Location of config files", (task, opt, arg) -> {
-            task.options.configs = splitPath(arg, File.pathSeparator);
-        }, "--configs"),
-        new Option(false, "Print this usage message", (task, opt, arg) -> {
-            task.options.help = true;
-        }, "--help"),
-        new Option(true, "Location of module classes files", (task, opt, arg) -> {
-            task.options.classes = splitPath(arg, File.pathSeparator);
-        }, "--classes"),
-        new Option(true, "Location of native libraries", (task, opt, arg) -> {
-            task.options.libs = splitPath(arg, File.pathSeparator);
-        }, "--libs"),
-        new Option(true, "Comma separated list of module names",
-        (task, opt, arg) -> {
-            for (String mn : arg.split(",")) {
-                if (mn.isEmpty()) {
-                    throw new BadArgs("Module not found", mn);
-                }
-                task.options.mods.add(mn);
-            }
-        }, "--mods"),
-        new Option(true, "Location of the output path", (task, opt, arg) -> {
-            Path path = Paths.get(arg);
-            task.options.output = path;
-        }, "--output"),
-        new Option(true, "Byte order of the target runtime; {little,big}",
-        (task, opt, arg) -> {
-            if (arg.equals("little")) {
-                task.options.endian = ByteOrder.LITTLE_ENDIAN;
-            } else if (arg.equals("big")) {
-                task.options.endian = ByteOrder.BIG_ENDIAN;
-            } else {
-                throw new BadArgs("Unknown byte order " + arg);
-            }
-        }, "--endian")
-    };
-
-    private final Options options = new Options();
-
-    private PrintWriter log;
-    void setLog(PrintWriter out) {
-        log = out;
-    }
-
-    Set<Module> moduleGraph = new java.util.HashSet<>();
-
-    /** Module list files */
-    private static final String BOOT_MODULES = "boot.modules";
-    private static final String EXT_MODULES = "ext.modules";
-
-    /**
-     * Result codes.
-     */
-    static final int EXIT_OK = 0,       // Completed with no errors.
-                     EXIT_ERROR = 1,    // Completed but reported errors.
-                     EXIT_CMDERR = 2,   // Bad command-line arguments
-                     EXIT_SYSERR = 3,   // System error or resource exhaustion.
-                     EXIT_ABNORMAL = 4; // terminated abnormally
-
-
-    static class Options {
-        boolean help;
-        List<Path> classes;
-        List<Path> cmds;
-        List<Path> configs;
-        List<Path> libs;
-        Set<String> mods = new HashSet<>();
-        Path output;
-        ByteOrder endian = ByteOrder.nativeOrder(); // default, if not specified
-    }
-
-    public static void main(String[] args) throws Exception {
-        ImageBuilder builder = new ImageBuilder();
-        int rc = builder.run(args);
-        System.exit(rc);
-    }
-
-    int run(String[] args) {
-        if (log == null)
-            log = new PrintWriter(System.out);
-
-        try {
-            handleOptions(args);
-            if (options.help) {
-                showHelp();
-                return EXIT_OK;
-            }
-
-            if (options.classes == null)
-                throw new BadArgs("--classes must be specified").showUsage(true);
-
-            Path output = options.output;
-            if (output == null)
-                throw new BadArgs("--output must be specified").showUsage(true);
-            Files.createDirectories(output);
-            if (Files.list(output).findFirst().isPresent())
-                throw new BadArgs("dir not empty", output);
-
-            if (options.mods.isEmpty())
-                throw new BadArgs("--mods must be specified").showUsage(true);
-
-            if (moduleGraph.isEmpty())
-                throw new BadArgs("modules.xml must be specified").showUsage(true);
-
-            if (options.cmds == null || options.cmds.isEmpty())
-                warning("--commands is not set");
-            if (options.libs == null || options.libs.isEmpty())
-                warning("--libs is not set");
-            //if (options.configs == null || options.configs.isEmpty())
-            //    warning("--configs is not set");
-
-            // additional option combination validation
-
-            boolean ok = run();
-            return ok ? EXIT_OK : EXIT_ERROR;
-        } catch (BadArgs e) {
-            reportError(e.format, e.args);
-            if (e.showUsage)
-                log.println(USAGE_SUMMARY);
-            return EXIT_CMDERR;
-        } catch (Exception x) {
-            x.printStackTrace();
-            return EXIT_ABNORMAL;
-        } finally {
-            log.flush();
-        }
-    }
-
-    private boolean run() throws IOException {
-        createImage();
-        return true;
-    }
-
-    class SimpleResolver {
-        private final Set<Module> initialMods;
-        private final Map<String,Module> nameToModule = new HashMap<>();
-
-        SimpleResolver(Set<String> mods, Set<Module> graph) {
-            graph.stream()
-                 .forEach(m -> nameToModule.put(m.name(), m));
-            initialMods = mods.stream()
-                         .map(this::nameToModule)
-                         .collect(Collectors.toSet());
-        }
-
-        /** Returns the transitive closure, in topological order */
-        List<String> resolve() {
-            List<Module> result = new LinkedList<>();
-            Set<Module> visited = new HashSet<>();
-            Set<Module> done = new HashSet<>();
-            for (Module m : initialMods) {
-                if (!visited.contains(m))
-                    visit(m, visited, result, done);
-            }
-            return result.stream()
-                         .map(m -> m.name())
-                         .collect(Collectors.toList());
-        }
-
-        private void visit(Module m, Set<Module> visited,
-                           List<Module> result, Set<Module> done) {
-            if (visited.contains(m)) {
-                if (!done.contains(m))
-                    throw new IllegalArgumentException("Cyclic detected: " +
-                            m + " " + getModuleDependences(m));
-                return;
-            }
-            visited.add(m);
-            getModuleDependences(m).stream()
-                                   .forEach(d -> visit(d, visited, result, done));
-            done.add(m);
-            result.add(m);
-        }
-
-        private Module nameToModule(String name) {
-            Module m = nameToModule.get(name);
-            if (m == null)
-                throw new RuntimeException("No module definition for " + name);
-            return m;
-        }
-
-        private Set<Module> getModuleDependences(Module m) {
-            return m.requires().stream()
-                    .map(d -> d.name())
-                    .map(this::nameToModule)
-                    .collect(Collectors.toSet());
-        }
-    }
-
-    private List<String> resolve(Set<String> mods ) {
-        return (new SimpleResolver(mods, moduleGraph)).resolve();
-    }
-
-    private void createImage() throws IOException {
-        Collection<String> modules = resolve(options.mods);
-        log.print(modules.stream().collect(Collectors.joining(" ")));
-        ImageFileHelper imageHelper = new ImageFileHelper(modules);
-        imageHelper.createModularImage(options.output);
-
-        // jspawnhelper, might be in lib or lib/ARCH
-        Path jspawnhelper = Paths.get("jspawnhelper");
-        Path lib = options.output.resolve("lib");
-        Optional<Path> helper = Files.walk(lib, 2)
-                                     .filter(f -> f.getFileName().equals(jspawnhelper))
-                                     .findFirst();
-        if (helper.isPresent())
-            helper.get().toFile().setExecutable(true, false);
-    }
-
-    private class ImageFileHelper {
-        final Collection<String> modules;
-        final Set<String> bootModules;
-        final Set<String> extModules;
-        final Set<String> appModules;
-
-        ImageFileHelper(Collection<String> modules) throws IOException {
-            this.modules = modules;
-            this.bootModules = modulesFor(BOOT_MODULES).stream()
-                    .filter(modules::contains)
-                    .collect(Collectors.toSet());
-            this.extModules = modulesFor(EXT_MODULES).stream()
-                    .filter(modules::contains)
-                    .collect(Collectors.toSet());
-            this.appModules = modules.stream()
-                    .filter(m -> m.length() != 0 &&
-                                 !bootModules.contains(m) &&
-                                 !extModules.contains(m))
-                    .collect(Collectors.toSet());
-        }
-
-        void createModularImage(Path output) throws IOException {
-            Set<Archive> bootArchives = bootModules.stream()
-                    .map(this::toModuleArchive)
-                    .collect(Collectors.toSet());
-            Set<Archive> extArchives = extModules.stream()
-                    .map(this::toModuleArchive)
-                    .collect(Collectors.toSet());
-            Set<Archive> appArchives = appModules.stream()
-                    .map(this::toModuleArchive)
-                    .collect(Collectors.toSet());
-            ImageFileCreator.create(output, "bootmodules", bootArchives, options.endian);
-            ImageFileCreator.create(output, "extmodules", extArchives, options.endian);
-            ImageFileCreator.create(output, "appmodules", appArchives, options.endian);
-        }
-
-        ModuleArchive toModuleArchive(String mn) {
-            return new ModuleArchive(mn,
-                                     moduleToPath(mn, options.classes, false/*true*/),
-                                     moduleToPath(mn, options.cmds, false),
-                                     moduleToPath(mn, options.libs, false),
-                                     moduleToPath(mn, options.configs, false));
-        }
-
-        private Path moduleToPath(String name, List<Path> paths, boolean expect) {
-            Set<Path> foundPaths = new HashSet<>();
-            if (paths != null) {
-                for (Path p : paths) {
-                    Path rp = p.resolve(name);
-                    if (Files.exists(rp))
-                        foundPaths.add(rp);
-                }
-            }
-            if (foundPaths.size() > 1)
-                throw new RuntimeException("Found more that one path for " + name);
-            if (expect && foundPaths.size() != 1)
-                throw new RuntimeException("Expected to find classes path for " + name);
-            return foundPaths.size() == 0 ? null : foundPaths.iterator().next();
-        }
-
-        private List<String> modulesFor(String name) throws IOException {
-            try (InputStream is = ImageBuilder.class.getResourceAsStream(name);
-                 BufferedReader reader = new BufferedReader(new InputStreamReader(is))) {
-                return reader.lines().collect(Collectors.toList());
-            }
-        }
-    }
-
-    public void handleOptions(String[] args) throws BadArgs {
-        // process options
-        for (int i=0; i < args.length; i++) {
-            if (args[i].charAt(0) == '-') {
-                String name = args[i];
-                Option option = getOption(name);
-                String param = null;
-                if (option.hasArg) {
-                    if (name.startsWith("--") && name.indexOf('=') > 0) {
-                        param = name.substring(name.indexOf('=') + 1, name.length());
-                    } else if (i + 1 < args.length) {
-                        param = args[++i];
-                    }
-                    if (param == null || param.isEmpty() || param.charAt(0) == '-') {
-                        throw new BadArgs("Missing arg for %n", name).showUsage(true);
-                    }
-                }
-                option.process(this, name, param);
-                if (option.ignoreRest()) {
-                    i = args.length;
-                }
-            } else {
-                // process rest of the input arguments
-                Path p = Paths.get(args[i]);
-                try {
-                    moduleGraph.addAll(ModulesXmlReader.readModules(p)
-                            .stream()
-                            .collect(Collectors.toSet()));
-                } catch (Exception e) {
-                    throw new RuntimeException(e);
-                }
-            }
-        }
-    }
-
-    private Option getOption(String name) throws BadArgs {
-        for (Option o : recognizedOptions) {
-            if (o.matches(name)) {
-                return o;
-            }
-        }
-        throw new BadArgs("Unknown option %s", name).showUsage(true);
-    }
-
-    private void reportError(String format, Object... args) {
-        log.format("Error: " + format + "%n", args);
-    }
-
-    private void warning(String format, Object... args) {
-        log.format("Warning: " + format + "%n", args);
-    }
-
-    private static final String USAGE =
-            "ImageBuilder <options> --output <path> path-to-modules-xml\n";
-
-    private static final String USAGE_SUMMARY =
-            USAGE + "Use --help for a list of possible options.";
-
-    private void showHelp() {
-        log.format(USAGE);
-        log.format("Possible options are:%n");
-        for (Option o : recognizedOptions) {
-            String name = o.aliases[0].substring(1); // there must always be at least one name
-            name = name.charAt(0) == '-' ? name.substring(1) : name;
-            if (o.isHidden() || name.equals("h"))
-                continue;
-
-            log.format("  --%s\t\t\t%s%n", name, o.description());
-        }
-    }
-}
--- a/make/src/classes/build/tools/module/Module.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/make/src/classes/build/tools/module/Module.java	Thu Mar 17 19:04:16 2016 +0000
@@ -25,10 +25,17 @@
 
 package build.tools.module;
 
-import java.util.*;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 public class Module {
-    static class Dependence {
+    public static class Dependence implements Comparable<Dependence> {
         final String name;
         final boolean reexport;
         Dependence(String name) {
@@ -43,6 +50,10 @@
             return name;
         }
 
+        public boolean reexport(){
+            return reexport;
+        }
+
         @Override
         public int hashCode() {
             int hash = 5;
@@ -55,20 +66,35 @@
             Dependence d = (Dependence)o;
             return this.name.equals(d.name) && this.reexport == d.reexport;
         }
+
+        @Override
+        public int compareTo(Dependence o) {
+            int rc = this.name.compareTo(o.name);
+            return rc != 0 ? rc : Boolean.compare(this.reexport, o.reexport);
+        }
+
+        @Override
+        public String toString() {
+            return String.format("requires %s%s;",
+                                 reexport ? "public " : "", name);
+        }
     }
     private final String moduleName;
     private final Set<Dependence> requires;
     private final Map<String, Set<String>> exports;
-    private final Set<String> packages;
+    private final Set<String> uses;
+    private final Map<String, Set<String>> provides;
 
     private Module(String name,
-            Set<Dependence> requires,
-            Map<String, Set<String>> exports,
-            Set<String> packages) {
+                   Set<Dependence> requires,
+                   Map<String, Set<String>> exports,
+                   Set<String> uses,
+                   Map<String, Set<String>> provides) {
         this.moduleName = name;
         this.requires = Collections.unmodifiableSet(requires);
         this.exports = Collections.unmodifiableMap(exports);
-        this.packages = Collections.unmodifiableSet(packages);
+        this.uses  = Collections.unmodifiableSet(uses);
+        this.provides = Collections.unmodifiableMap(provides);
     }
 
     public String name() {
@@ -83,8 +109,12 @@
         return exports;
     }
 
-    public Set<String> packages() {
-        return packages;
+    public Set<String> uses() {
+        return uses;
+    }
+
+    public Map<String, Set<String>> provides() {
+        return provides;
     }
 
     @Override
@@ -95,8 +125,7 @@
         Module that = (Module) ob;
         return (moduleName.equals(that.moduleName)
                 && requires.equals(that.requires)
-                && exports.equals(that.exports)
-                && packages.equals(that.packages));
+                && exports.equals(that.exports));
     }
 
     @Override
@@ -104,43 +133,55 @@
         int hc = moduleName.hashCode();
         hc = hc * 43 + requires.hashCode();
         hc = hc * 43 + exports.hashCode();
-        hc = hc * 43 + packages.hashCode();
         return hc;
     }
 
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
-        sb.append("module ").append(moduleName).append(" {").append("\n");
-        requires.stream().sorted().forEach(d ->
-                sb.append(String.format("   requires %s%s%n", d.reexport ? "public " : "", d.name)));
-        exports.entrySet().stream().filter(e -> e.getValue().isEmpty())
+        sb.append(String.format("module %s {%n", moduleName));
+        requires.stream()
+                .sorted()
+                .map(d -> String.format("    requires %s%s;%n", d.reexport ? "public " : "", d.name))
+                .forEach(sb::append);
+        exports.entrySet().stream()
+                .filter(e -> e.getValue().isEmpty())
+                .sorted(Map.Entry.comparingByKey())
+                .map(e -> String.format("    exports %s;%n", e.getKey()))
+                .forEach(sb::append);
+        exports.entrySet().stream()
+                .filter(e -> !e.getValue().isEmpty())
                 .sorted(Map.Entry.comparingByKey())
-                .forEach(e -> sb.append(String.format("   exports %s%n", e.getKey())));
-        exports.entrySet().stream().filter(e -> !e.getValue().isEmpty())
+                .map(e -> String.format("    exports %s to%n%s;%n", e.getKey(),
+                        e.getValue().stream().sorted()
+                                .map(mn -> String.format("        %s", mn))
+                                .collect(Collectors.joining(",\n"))))
+                .forEach(sb::append);
+        uses.stream().sorted()
+                .map(s -> String.format("    uses %s;%n", s))
+                .forEach(sb::append);
+        provides.entrySet().stream()
                 .sorted(Map.Entry.comparingByKey())
-                .forEach(e -> sb.append(String.format("   exports %s to %s%n", e.getKey(), e.getValue())));
-        packages.stream().sorted().forEach(pn -> sb.append(String.format("   includes %s%n", pn)));
-        sb.append("}");
+                .flatMap(e -> e.getValue().stream().sorted()
+                        .map(impl -> String.format("    provides %s with %s;%n", e.getKey(), impl)))
+                .forEach(sb::append);
+        sb.append("}").append("\n");
         return sb.toString();
     }
 
+    /**
+     * Module Builder
+     */
     static class Builder {
         private String name;
-        private final Set<Dependence> requires = new HashSet<>();
-        private final Map<String, Set<String>> exports = new HashMap<>();
-        private final Set<String> packages = new HashSet<>();
+        final Set<Dependence> requires = new HashSet<>();
+        final Map<String, Set<String>> exports = new HashMap<>();
+        final Set<String> uses = new HashSet<>();
+        final Map<String, Set<String>> provides = new HashMap<>();
 
         public Builder() {
         }
 
-        public Builder(Module module) {
-            name = module.name();
-            requires.addAll(module.requires());
-            exports.putAll(module.exports());
-            packages.addAll(module.packages());
-        }
-
         public Builder name(String n) {
             name = n;
             return this;
@@ -151,28 +192,89 @@
             return this;
         }
 
-        public Builder include(String p) {
-            packages.add(p);
-            return this;
+        public Builder export(String p) {
+            Objects.requireNonNull(p);
+            if (exports.containsKey(p)) {
+                throw new RuntimeException(name + " already exports " + p +
+                        " " + exports.get(p));
+            }
+            return exportTo(p, Collections.emptySet());
         }
 
-        public Builder export(String p) {
-            return exportTo(p, Collections.emptySet());
+        public Builder exportTo(String p, String mn) {
+            Objects.requireNonNull(p);
+            Objects.requireNonNull(mn);
+            Set<String> ms = exports.get(p);
+            if (ms != null && ms.isEmpty()) {
+                throw new RuntimeException(name + " already has unqualified exports " + p);
+            }
+            exports.computeIfAbsent(p, _k -> new HashSet<>()).add(mn);
+            return this;
         }
 
         public Builder exportTo(String p, Set<String> ms) {
             Objects.requireNonNull(p);
             Objects.requireNonNull(ms);
             if (exports.containsKey(p)) {
-                throw new RuntimeException(name + " already exports " + p);
+                throw new RuntimeException(name + " already exports " + p +
+                        " " + exports.get(p));
             }
             exports.put(p, new HashSet<>(ms));
             return this;
         }
 
+        public Builder use(String cn) {
+            uses.add(cn);
+            return this;
+        }
+
+        public Builder provide(String s, String impl) {
+            provides.computeIfAbsent(s, _k -> new HashSet<>()).add(impl);
+            return this;
+        }
+
+        public Builder merge(Module m1, Module m2) {
+            if (!m1.name().equals(m2.name())) {
+                throw new IllegalArgumentException(m1.name() + " != " + m2.name());
+            }
+            name = m1.name();
+            // ## reexports
+            requires.addAll(m1.requires());
+            requires.addAll(m2.requires());
+            Stream.concat(m1.exports().keySet().stream(), m2.exports().keySet().stream())
+                    .distinct()
+                    .forEach(pn -> {
+                        Set<String> s1 = m2.exports().get(pn);
+                        Set<String> s2 = m2.exports().get(pn);
+                        if (s1 == null || s2 == null) {
+                            exportTo(pn, s1 != null ? s1 : s2);
+                        } else if (s1.isEmpty() || s2.isEmpty()) {
+                            // unqualified exports
+                            export(pn);
+                        } else {
+                            exportTo(pn, Stream.concat(s1.stream(), s2.stream())
+                                               .collect(Collectors.toSet()));
+                        }
+                    });
+            uses.addAll(m1.uses());
+            uses.addAll(m2.uses());
+            m1.provides().keySet().stream()
+                    .forEach(s -> m1.provides().get(s).stream()
+                            .forEach(impl -> provide(s, impl)));
+            m2.provides().keySet().stream()
+                    .forEach(s -> m2.provides().get(s).stream()
+                            .forEach(impl -> provide(s, impl)));
+            return this;
+        }
+
         public Module build() {
-            Module m = new Module(name, requires, exports, packages);
+            Module m = new Module(name, requires, exports, uses, provides);
             return m;
         }
+
+        @Override
+        public String toString() {
+            return name != null ? name : "Unknown";
+        }
     }
 }
--- a/make/src/classes/build/tools/module/ModuleArchive.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,184 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package build.tools.module;
-
-import jdk.internal.jimage.Archive;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UncheckedIOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import jdk.internal.jimage.Archive.Entry.EntryType;
-
-/**
- * An Archive backed by an exploded representation on disk.
- */
-public class ModuleArchive implements Archive {
-    private final Path classes;
-    private final Path cmds;
-    private final Path libs;
-    private final Path configs;
-    private final String moduleName;
-
-    private final List<InputStream> opened = new ArrayList<>();
-
-    public ModuleArchive(String moduleName, Path classes, Path cmds,
-                         Path libs, Path configs) {
-        this.moduleName = moduleName;
-        this.classes = classes;
-        this.cmds = cmds;
-        this.libs = libs;
-        this.configs = configs;
-    }
-
-    @Override
-    public String moduleName() {
-        return moduleName;
-    }
-
-    @Override
-    public void open() throws IOException {
-        // NOOP
-    }
-
-    @Override
-    public void close() throws IOException {
-        IOException e = null;
-        for (InputStream stream : opened) {
-            try {
-                stream.close();
-            } catch (IOException ex) {
-                if (e == null) {
-                    e = ex;
-                } else {
-                    e.addSuppressed(ex);
-                }
-            }
-        }
-        if (e != null) {
-            throw e;
-        }
-    }
-
-    @Override
-    public Stream<Entry> entries() {
-        List<Entry> entries = new ArrayList<>();
-        try {
-            /*
-             * This code should be revisited to avoid buffering of the entries.
-             * 1) Do we really need sorting classes? This force buffering of entries.
-             *    libs, cmds and configs are not sorted.
-             * 2) I/O streams should be concatenated instead of buffering into
-             *    entries list.
-             * 3) Close I/O streams in a close handler.
-             */
-            if (classes != null) {
-                try (Stream<Path> stream = Files.walk(classes)) {
-                    entries.addAll(stream
-                            .filter(p -> !Files.isDirectory(p)
-                                    && !classes.relativize(p).toString().startsWith("_the.")
-                                    && !classes.relativize(p).toString().endsWith(".bc")
-                                    && !classes.relativize(p).toString().equals("javac_state"))
-                            .sorted()
-                            .map(p -> toEntry(p, classes, EntryType.CLASS_OR_RESOURCE))
-                            .collect(Collectors.toList()));
-                }
-            }
-            if (cmds != null) {
-                try (Stream<Path> stream = Files.walk(cmds)) {
-                    entries.addAll(stream
-                            .filter(p -> !Files.isDirectory(p))
-                            .map(p -> toEntry(p, cmds, EntryType.NATIVE_CMD))
-                            .collect(Collectors.toList()));
-                }
-            }
-            if (libs != null) {
-                try (Stream<Path> stream = Files.walk(libs)) {
-                    entries.addAll(stream
-                            .filter(p -> !Files.isDirectory(p))
-                            .map(p -> toEntry(p, libs, EntryType.NATIVE_LIB))
-                            .collect(Collectors.toList()));
-                }
-            }
-            if (configs != null) {
-                try (Stream<Path> stream = Files.walk(configs)) {
-                entries.addAll(stream
-                        .filter(p -> !Files.isDirectory(p))
-                        .map(p -> toEntry(p, configs, EntryType.CONFIG))
-                        .collect(Collectors.toList()));
-                }
-            }
-        } catch (IOException ioe) {
-            throw new UncheckedIOException(ioe);
-        }
-        return entries.stream();
-    }
-
-    private class FileEntry extends Entry {
-        private final boolean isDirectory;
-        private final long size;
-        private final Path entryPath;
-        FileEntry(Path entryPath, String path, EntryType type,
-                  boolean isDirectory, long size) {
-            super(ModuleArchive.this, path, path, type);
-            this.entryPath = entryPath;
-            this.isDirectory = isDirectory;
-            this.size = size;
-        }
-
-        public boolean isDirectory() {
-            return isDirectory;
-        }
-
-        @Override
-        public long size() {
-            return size;
-        }
-
-        @Override
-        public InputStream stream() throws IOException {
-            InputStream stream = Files.newInputStream(entryPath);
-            opened.add(stream);
-            return stream;
-        }
-    }
-
-    private Entry toEntry(Path entryPath, Path basePath, EntryType section) {
-        try {
-            String path = basePath.relativize(entryPath).toString().replace('\\', '/');
-            return new FileEntry(entryPath, path, section,
-                    false, Files.size(entryPath));
-        } catch (IOException e) {
-            throw new UncheckedIOException(e);
-        }
-    }
-}
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/src/classes/build/tools/module/ModuleInfoReader.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,357 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package build.tools.module;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.function.Supplier;
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
+
+import build.tools.module.Module.Builder;
+
+/**
+ * Source reader of module-info.java
+ */
+public class ModuleInfoReader {
+    private final Path sourcefile;
+    private final Builder builder;
+    private ModuleInfoReader(Path file) {
+        this.sourcefile = file;
+        this.builder = new Builder();
+    }
+
+    public static Builder builder(Path file) throws IOException {
+        ModuleInfoReader reader = new ModuleInfoReader(file);
+        reader.readFile();
+        return reader.builder;
+    }
+
+    /**
+     * Reads the source file.
+     */
+    void readFile() throws IOException {
+        List<String> lines = Files.readAllLines(sourcefile);
+        boolean done = false;
+        int lineNumber = 0;
+        boolean inBlockComment = false;
+        boolean inRequires = false;
+        boolean reexports = false;
+        boolean inProvides = false;
+        boolean inWith = false;
+        String serviceIntf = null;
+        String providerClass = null;
+        boolean inUses = false;
+        boolean inExports = false;
+        boolean inExportsTo = false;
+        String qualifiedExports = null;
+        Counter counter = new Counter();
+
+        for (String line : lines) {
+            lineNumber++;
+            if (inBlockComment) {
+                int c = line.indexOf("*/");
+                if (c >= 0) {
+                    line = line.substring(c + 2, line.length());
+                    inBlockComment = false;
+                } else {
+                    // skip lines until end of comment block
+                    continue;
+                }
+            }
+            inBlockComment = beginBlockComment(line);
+
+            line = trimComment(line).trim();
+            // ignore empty lines
+            if (line.length() == 0) {
+                continue;
+            }
+            String values;
+            if (inRequires || inExports | inUses | (inWith && providerClass == null)) {
+                values = line;
+            } else {
+                String[] s = line.split("\\s+");
+                String keyword = s[0].trim();
+                int nextIndex = keyword.length();
+                switch (keyword) {
+                    case "module":
+                        if (s.length != 3 || !s[2].trim().equals("{")) {
+                            throw new RuntimeException(sourcefile + ", line " +
+                                    lineNumber + ", is malformed");
+                        }
+                        builder.name(s[1].trim());
+                        continue;  // next line
+                    case "requires":
+                        inRequires = true;
+                        counter.numRequires++;
+                        if (s.length >= 2) {
+                            String ss = s[1].trim();
+                            if (ss.equals("public")) {
+                                nextIndex = line.indexOf(ss) + ss.length();
+                                reexports = true;
+                            }
+                        }
+                        break;
+                    case "exports":
+                        inExports = true;
+                        inExportsTo = false;
+                        counter.numExports++;
+                        qualifiedExports = null;
+                        if (s.length >= 3) {
+                            qualifiedExports = s[1].trim();
+                            nextIndex = line.indexOf(qualifiedExports, nextIndex)
+                                            + qualifiedExports.length();
+                            if (s[2].trim().equals("to")) {
+                                inExportsTo = true;
+                                nextIndex = line.indexOf("to", nextIndex) + "to".length();
+                            } else {
+                                throw new RuntimeException(sourcefile + ", line " +
+                                        lineNumber + ", is malformed: " + s[2]);
+                            }
+                        }
+                        break;
+                    case "to":
+                        if (!inExports || qualifiedExports == null) {
+                            throw new RuntimeException(sourcefile + ", line " +
+                                    lineNumber + ", is malformed");
+                        }
+                        inExportsTo = true;
+                        break;
+                    case "uses":
+                        inUses = true;
+                        counter.numUses++;
+                        break;
+                    case "provides":
+                        inProvides = true;
+                        inWith = false;
+                        counter.numProvides++;
+                        serviceIntf = null;
+                        providerClass = null;
+                        if (s.length >= 2) {
+                            serviceIntf = s[1].trim();
+                            nextIndex = line.indexOf(serviceIntf) + serviceIntf.length();
+                        }
+                        if (s.length >= 3) {
+                            if (s[2].trim().equals("with")) {
+                                inWith = true;
+                                nextIndex = line.indexOf("with") + "with".length();
+                            } else {
+                                throw new RuntimeException(sourcefile + ", line " +
+                                        lineNumber + ", is malformed: " + s[2]);
+                            }
+                        }
+                        break;
+                    case "with":
+                        if (!inProvides || serviceIntf == null) {
+                            throw new RuntimeException(sourcefile + ", line " +
+                                    lineNumber + ", is malformed");
+                        }
+                        inWith = true;
+                        nextIndex = line.indexOf("with") + "with".length();
+                        break;
+                    case "}":
+                        counter.validate(builder);
+                        done = true;
+                        continue;  // next line
+                    default:
+                        throw new RuntimeException(sourcefile + ", \"" +
+                                keyword + "\" on line " +
+                                lineNumber + ", is not recognized");
+                }
+                values = line.substring(nextIndex, line.length()).trim();
+            }
+
+            int len = values.length();
+            if (len == 0) {
+                continue;  // next line
+            }
+            char lastchar = values.charAt(len - 1);
+            if (lastchar != ',' && lastchar != ';') {
+                throw new RuntimeException(sourcefile + ", line " +
+                        lineNumber + ", is malformed:" +
+                        " ',' or ';' is missing.");
+            }
+
+            values = values.substring(0, len - 1).trim();
+            // parse the values specified for a keyword specified
+            for (String s : values.split(",")) {
+                s = s.trim();
+                if (s.length() > 0) {
+                    if (inRequires) {
+                        if (builder.requires.contains(s)) {
+                            throw new RuntimeException(sourcefile + ", line "
+                                    + lineNumber + " duplicated requires: \"" + s + "\"");
+                        }
+                        builder.require(s, reexports);
+                    } else if (inExports) {
+                        if (!inExportsTo && qualifiedExports == null) {
+                            builder.export(s);
+                        } else {
+                            builder.exportTo(qualifiedExports, s);
+                        }
+                    } else if (inUses) {
+                        builder.use(s);
+                    } else if (inProvides) {
+                        if (!inWith) {
+                            serviceIntf = s;
+                        } else {
+                            providerClass = s;
+                            builder.provide(serviceIntf, providerClass);
+                        }
+                    }
+                }
+            }
+            if (lastchar == ';') {
+                inRequires = false;
+                reexports = false;
+                inExports = false;
+                inExportsTo = false;
+                inProvides = false;
+                inWith = false;
+                inUses = false;
+            }
+        }
+
+        if (inBlockComment) {
+            throw new RuntimeException(sourcefile + ", line " +
+                    lineNumber + ", missing \"*/\" to end a block comment");
+        }
+        if (!done) {
+            throw new RuntimeException(sourcefile + ", line " +
+                    lineNumber + ", missing \"}\" to end module definition" +
+                    " for \"" + builder + "\"");
+        }
+        return;
+    }
+
+    // the naming convention for the module names without dashes
+    private static final Pattern CLASS_NAME_PATTERN = Pattern.compile("[\\w\\.\\*_$/]+");
+    private static boolean beginBlockComment(String line) {
+        int pos = 0;
+        while (pos >= 0 && pos < line.length()) {
+            int c = line.indexOf("/*", pos);
+            if (c < 0) {
+                return false;
+            }
+
+            if (c > 0 && !Character.isWhitespace(line.charAt(c - 1))) {
+                return false;
+            }
+
+            int c1 = line.indexOf("//", pos);
+            if (c1 >= 0 && c1 < c) {
+                return false;
+            }
+
+            int c2 = line.indexOf("*/", c + 2);
+            if (c2 < 0) {
+                return true;
+            }
+            pos = c + 2;
+        }
+        return false;
+    }
+    private static String trimComment(String line) {
+        StringBuilder sb = new StringBuilder();
+
+        int pos = 0;
+        while (pos >= 0 && pos < line.length()) {
+            int c1 = line.indexOf("//", pos);
+            if (c1 > 0 && !Character.isWhitespace(line.charAt(c1 - 1))) {
+                // not a comment
+                c1 = -1;
+            }
+
+            int c2 = line.indexOf("/*", pos);
+            if (c2 > 0 && !Character.isWhitespace(line.charAt(c2 - 1))) {
+                // not a comment
+                c2 = -1;
+            }
+
+            int c = line.length();
+            int n = line.length();
+            if (c1 >= 0 || c2 >= 0) {
+                if (c1 >= 0) {
+                    c = c1;
+                }
+                if (c2 >= 0 && c2 < c) {
+                    c = c2;
+                }
+                int c3 = line.indexOf("*/", c2 + 2);
+                if (c == c2 && c3 > c2) {
+                    n = c3 + 2;
+                }
+            }
+            if (c > 0) {
+                if (sb.length() > 0) {
+                    // add a whitespace if multiple comments on one line
+                    sb.append(" ");
+                }
+                sb.append(line.substring(pos, c));
+            }
+            pos = n;
+        }
+        return sb.toString();
+    }
+
+
+    static class Counter {
+        int numRequires;
+        int numExports;
+        int numUses;
+        int numProvides;
+
+        void validate(Builder builder) {
+            assertEquals("requires", numRequires, builder.requires.size(),
+                         () -> builder.requires.stream()
+                                      .map(Module.Dependence::toString));
+            assertEquals("exports", numExports, builder.exports.size(),
+                         () -> builder.exports.entrySet().stream()
+                                      .map(e -> "exports " + e.getKey() + " to " + e.getValue()));
+            assertEquals("uses", numUses, builder.uses.size(),
+                         () -> builder.uses.stream());
+            assertEquals("provides", numProvides,
+                         (int)builder.provides.values().stream()
+                                     .flatMap(s -> s.stream())
+                                     .count(),
+                         () -> builder.provides.entrySet().stream()
+                                      .map(e -> "provides " + e.getKey() + " with " + e.getValue()));
+        }
+
+        private static void assertEquals(String msg, int expected, int got,
+                                         Supplier<Stream<String>> supplier) {
+            if (expected != got){
+                System.err.println("ERROR: mismatched " + msg +
+                        " expected: " + expected + " got: " + got );
+                supplier.get().sorted()
+                        .forEach(System.err::println);
+                throw new AssertionError("mismatched " + msg +
+                        " expected: " + expected + " got: " + got + " ");
+            }
+        }
+    }
+}
--- a/make/src/classes/build/tools/module/boot.modules	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-java.base
-java.compiler
-java.datatransfer
-java.desktop
-java.httpclient
-java.instrument
-java.logging
-java.management
-java.naming
-java.prefs
-java.rmi
-java.scripting
-java.security.jgss
-java.security.sasl
-java.smartcardio
-java.sql
-java.sql.rowset
-java.xml
-java.xml.crypto
-jdk.charsets
-jdk.deploy
-jdk.httpserver
-jdk.jfr
-jdk.jsobject
-jdk.net
-jdk.vm.cds
-jdk.vm.ci
-jdk.management
-jdk.management.cmm
-jdk.management.jfr
-jdk.management.resource
-jdk.naming.rmi
-jdk.sctp
-jdk.security.auth
-jdk.security.jgss
-jdk.snmp
--- a/make/src/classes/build/tools/module/ext.modules	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-java.activation
-java.annotations.common
-java.corba
-java.transaction
-java.xml.bind
-java.xml.ws
-jdk.accessibility
-jdk.crypto.ec
-jdk.crypto.mscapi
-jdk.crypto.pkcs11
-jdk.crypto.ucrypto
-jdk.dynalink
-jdk.localedata
-jdk.naming.dns
-jdk.scripting.nashorn
-jdk.xml.dom
-jdk.zipfs
--- a/src/demo/share/java2d/J2DBench/src/j2dbench/ResultSet.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/demo/share/java2d/J2DBench/src/j2dbench/ResultSet.java	Thu Mar 17 19:04:16 2016 +0000
@@ -84,7 +84,6 @@
         "java.util.prefs.PreferencesFactory",
         "sun.java2d.fontpath",
         "sun.boot.library.path",
-        "sun.boot.class.path",
     };
 
     /*
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/macosx/classes/module-info.java.extra	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+exports jdk.internal.loader to java.desktop;
+provides java.security.Provider with apple.security.AppleProvider;
--- a/src/java.base/share/classes/com/sun/java/util/jar/pack/intrinsic.properties	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/com/sun/java/util/jar/pack/intrinsic.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -6,7 +6,7 @@
 # but may be overridden here, if necessary.
 
 # The makefile for this directory must copy this file
-# into the target class hierarchy so it will get into rt.jar.
+# into the target class hierarchy so it will get into runtime image.
 
 # JCOV attributes
 pack.code.attribute.CoverageTable = NH[PHHII]
@@ -14,6 +14,15 @@
 pack.class.attribute.SourceID = RUH
 pack.class.attribute.CompilationID = RUH
 
+# Module attributes, supported by the tool and not JSR-200
+pack.class.attribute.Module = NH[RUHFH]NH[RUHNH[RUH]]NH[RCH]NH[RCHRCH]
+pack.class.attribute.ConcealedPackages = NH[RUH]
+pack.class.attribute.Version = RUH
+pack.class.attribute.MainClass = RUH
+pack.class.attribute.TargetPlatform = RUHRUHRUH
+pack.class.attribute.Hashes = RUHNH[RUHRUH]
+
+
 # Note:  Zero-length ("marker") attributes do not need to be specified here.
 # They are automatically defined to have an empty layout.
 #pack.class.attribute.Deprecated =
--- a/src/java.base/share/classes/java/io/ObjectInputStream.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/java/io/ObjectInputStream.java	Thu Mar 17 19:04:16 2016 +0000
@@ -713,9 +713,11 @@
             classObjs[i] = cl;
         }
         try {
-            return Proxy.getProxyClass(
+            @SuppressWarnings("deprecation")
+            Class<?> proxyClass = Proxy.getProxyClass(
                 hasNonPublicInterface ? nonPublicLoader : latestLoader,
                 classObjs);
+            return proxyClass;
         } catch (IllegalArgumentException e) {
             throw new ClassNotFoundException(null, e);
         }
--- a/src/java.base/share/classes/java/lang/Class.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/java/lang/Class.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,8 @@
 
 package java.lang;
 
+import java.lang.annotation.Annotation;
+import java.lang.module.ModuleReader;
 import java.lang.reflect.AnnotatedElement;
 import java.lang.reflect.Array;
 import java.lang.reflect.GenericArrayType;
@@ -33,15 +35,19 @@
 import java.lang.reflect.Field;
 import java.lang.reflect.Executable;
 import java.lang.reflect.Method;
+import java.lang.reflect.Module;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.Type;
 import java.lang.reflect.TypeVariable;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.AnnotatedType;
+import java.lang.reflect.Proxy;
 import java.lang.ref.SoftReference;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.ObjectStreamField;
+import java.net.URL;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.ArrayList;
@@ -55,9 +61,11 @@
 import java.util.HashMap;
 import java.util.Objects;
 import java.util.StringJoiner;
+import jdk.internal.HotSpotIntrinsicCandidate;
+import jdk.internal.loader.BootLoader;
+import jdk.internal.loader.BuiltinClassLoader;
 import jdk.internal.misc.Unsafe;
 import jdk.internal.misc.VM;
-import jdk.internal.HotSpotIntrinsicCandidate;
 import sun.reflect.CallerSensitive;
 import sun.reflect.ConstantPool;
 import sun.reflect.Reflection;
@@ -69,8 +77,6 @@
 import sun.reflect.generics.repository.ConstructorRepository;
 import sun.reflect.generics.scope.ClassScope;
 import sun.security.util.SecurityConstants;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Proxy;
 import sun.reflect.annotation.*;
 import sun.reflect.misc.ReflectUtil;
 
@@ -378,6 +384,86 @@
                                             Class<?> caller)
         throws ClassNotFoundException;
 
+
+    /**
+     * Returns the {@code Class} with the given <a href="ClassLoader.html#name">
+     * binary name</a> in the given module.
+     *
+     * <p> This method attempts to locate, load, and link the class or interface.
+     * It does not run the class initializer.  If the class is not found, this
+     * method returns {@code null}. </p>
+     *
+     * <p> If the class loader of the given module defines other modules and
+     * the given name is a class defined in a different module, this method
+     * returns {@code null} after the class is loaded. </p>
+     *
+     * <p> This method does not check whether the requested class is
+     * accessible to its caller. </p>
+     *
+     * @apiNote
+     * This method returns {@code null} on failure rather than
+     * throwing a {@link ClassNotFoundException}, as is done by
+     * the {@link #forName(String, boolean, ClassLoader)} method.
+     * The security check is a stack-based permission check if the caller
+     * loads a class in another module.
+     *
+     * @param  module   A module
+     * @param  name     The <a href="ClassLoader.html#name">binary name</a>
+     *                  of the class
+     * @return {@code Class} object of the given name defined in the given module;
+     *         {@code null} if not found.
+     *
+     * @throws NullPointerException if the given module or name is {@code null}
+     *
+     * @throws LinkageError if the linkage fails
+     *
+     * @throws SecurityException
+     *         <ul>
+     *         <li> if the caller is not the specified module and
+     *         {@code RuntimePermission("getClassLoader")} permission is denied; or</li>
+     *         <li> access to the module content is denied. For example,
+     *         permission check will be performed when a class loader calls
+     *         {@link ModuleReader#open(String)} to read the bytes of a class file
+     *         in a module.</li>
+     *         </ul>
+     *
+     * @since 9
+     */
+    @CallerSensitive
+    public static Class<?> forName(Module module, String name) {
+        Objects.requireNonNull(module);
+        Objects.requireNonNull(name);
+
+        Class<?> caller = Reflection.getCallerClass();
+        if (caller != null && caller.getModule() != module) {
+            // if caller is null, Class.forName is the last java frame on the stack.
+            // java.base has all permissions
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
+            }
+        }
+
+        PrivilegedAction<ClassLoader> pa = module::getClassLoader;
+        ClassLoader cl = AccessController.doPrivileged(pa);
+        if (module.isNamed() && cl != null) {
+            return cl.loadLocalClass(module, name);
+        }
+
+        final Class<?> c;
+        if (cl != null) {
+            c = cl.loadLocalClass(name);
+        } else {
+            c = BootLoader.loadClassOrNull(name);
+        }
+
+        if (c != null && c.getModule() == module) {
+            return c;
+        } else {
+            return null;
+        }
+    }
+
     /**
      * Creates a new instance of the class represented by this {@code Class}
      * object.  The class is instantiated as if by a {@code new}
@@ -453,13 +539,11 @@
         }
         Constructor<T> tmpConstructor = cachedConstructor;
         // Security check (same as in java.lang.reflect.Constructor)
-        int modifiers = tmpConstructor.getModifiers();
-        if (!Reflection.quickCheckMemberAccess(this, modifiers)) {
-            Class<?> caller = Reflection.getCallerClass();
-            if (newInstanceCallerCache != caller) {
-                Reflection.ensureMemberAccess(caller, this, null, modifiers);
-                newInstanceCallerCache = caller;
-            }
+        Class<?> caller = Reflection.getCallerClass();
+        if (newInstanceCallerCache != caller) {
+            int modifiers = tmpConstructor.getModifiers();
+            Reflection.ensureMemberAccess(caller, this, null, modifiers);
+            newInstanceCallerCache = caller;
         }
         // Run constructor
         try {
@@ -717,6 +801,29 @@
     // Package-private to allow ClassLoader access
     ClassLoader getClassLoader0() { return classLoader; }
 
+    /**
+     * Returns the module that this class or interface is a member of.
+     *
+     * If this class represents an array type then this method returns the
+     * {@code Module} for the element type. If this class represents a
+     * primitive type or void, then the {@code Module} object for the
+     * {@code java.base} module is returned.
+     *
+     * If this class is in an unnamed module then the {@link
+     * ClassLoader#getUnnamedModule() unnamed} {@code Module} of the class
+     * loader for this class is returned.
+     *
+     * @return the module that this class or interface is a member of
+     *
+     * @since 9
+     */
+    public Module getModule() {
+        return module;
+    }
+
+    // set by VM
+    private transient Module module;
+
     // Initialized in JVM not by private constructor
     // This field is filtered from reflection access, i.e. getDeclaredField
     // will throw NoSuchFieldException
@@ -808,24 +915,60 @@
     }
 
     /**
-     * Gets the package for this class.  The class loader of this class is used
-     * to find the package.  If the class was loaded by the bootstrap class
-     * loader the set of packages loaded from CLASSPATH is searched to find the
-     * package of the class. Null is returned if no package object was created
-     * by the class loader of this class.
+     * Gets the package of this class.
      *
-     * <p> Packages have attributes for versions and specifications only if the
-     * information was defined in the manifests that accompany the classes, and
-     * if the class loader created the package instance with the attributes
-     * from the manifest.
+     * <p>If this class represents an array type, a primitive type or void,
+     * this method returns {@code null}.
      *
-     * @return the package of the class, or null if no package
-     *         information is available from the archive or codebase.
+     * @return the package of this class.
      */
     public Package getPackage() {
-        return Package.getPackage(this);
+        if (isPrimitive() || isArray()) {
+            return null;
+        }
+        ClassLoader cl = getClassLoader0();
+        return cl != null ? cl.definePackage(this)
+                          : BootLoader.definePackage(this);
     }
 
+    /**
+     * Returns the fully qualified package name.
+     *
+     * <p> If this class is a top level class, then this method returns the fully
+     * qualified name of the package that the class is a member of, or the
+     * empty string if the class is in an unnamed package.
+     *
+     * <p> If this class is a member class, then this method is equivalent to
+     * invoking {@code getPackageName()} on the {@link #getEnclosingClass
+     * enclosing class}.
+     *
+     * <p> If this class is a {@link #isLocalClass local class} or an {@link
+     * #isAnonymousClass() anonymous class}, then this method is equivalent to
+     * invoking {@code getPackageName()} on the {@link #getDeclaringClass
+     * declaring class} of the {@link #getEnclosingMethod enclosing method} or
+     * {@link #getEnclosingConstructor enclosing constructor}.
+     *
+     * <p> This method returns {@code null} if this class represents an array type,
+     * a primitive type or void.
+     *
+     * @return the fully qualified package name
+     *
+     * @since 9
+     * @jls 6.7  Fully Qualified Names
+     */
+    public String getPackageName() {
+        String pn = this.packageName;
+        if (pn == null && !isArray() && !isPrimitive()) {
+            String cn = getName();
+            int dot = cn.lastIndexOf('.');
+            pn = (dot != -1) ? cn.substring(0, dot).intern() : "";
+            this.packageName = pn;
+        }
+        return pn;
+    }
+
+    // cached package name
+    private String packageName;
 
     /**
      * Returns the interfaces directly implemented by the class or interface
@@ -2213,15 +2356,19 @@
     }
 
     /**
-     * Finds a resource with a given name.  The rules for searching resources
+     * Finds a resource with a given name. If this class is in a named {@link
+     * Module Module}, and the caller of this method is in the same module,
+     * then this method will attempt to find the resource in that module.
+     * Otherwise, the rules for searching resources
      * associated with a given class are implemented by the defining
      * {@linkplain ClassLoader class loader} of the class.  This method
      * delegates to this object's class loader.  If this object was loaded by
      * the bootstrap class loader, the method delegates to {@link
      * ClassLoader#getSystemResourceAsStream}.
      *
-     * <p> Before delegation, an absolute resource name is constructed from the
-     * given resource name using this algorithm:
+     * <p> Before finding a resource in the caller's module or delegation to a
+     * class loader, an absolute resource name is constructed from the given
+     * resource name using this algorithm:
      *
      * <ul>
      *
@@ -2242,26 +2389,60 @@
      * </ul>
      *
      * @param  name name of the desired resource
-     * @return      A {@link java.io.InputStream} object or {@code null} if
-     *              no resource with this name is found
+     * @return  A {@link java.io.InputStream} object or {@code null} if
+     *          no resource with this name is found
      * @throws  NullPointerException If {@code name} is {@code null}
      * @since  1.1
      */
-     public InputStream getResourceAsStream(String name) {
+    @CallerSensitive
+    public InputStream getResourceAsStream(String name) {
         name = resolveName(name);
+
+        // if this Class and the caller are in the same named module
+        // then attempt to get an input stream to the resource in the
+        // module
+        Module module = getModule();
+        if (module.isNamed()) {
+            Class<?> caller = Reflection.getCallerClass();
+            if (caller != null && caller.getModule() == module) {
+                ClassLoader cl = getClassLoader0();
+                String mn = module.getName();
+                try {
+
+                    // special-case built-in class loaders to avoid the
+                    // need for a URL connection
+                    if (cl == null) {
+                        return BootLoader.findResourceAsStream(mn, name);
+                    } else if (cl instanceof BuiltinClassLoader) {
+                        return ((BuiltinClassLoader) cl).findResourceAsStream(mn, name);
+                    } else {
+                        URL url = cl.findResource(mn, name);
+                        return (url != null) ? url.openStream() : null;
+                    }
+
+                } catch (IOException | SecurityException e) {
+                    return null;
+                }
+            }
+        }
+
+        // this Class and caller not in the same named module
         ClassLoader cl = getClassLoader0();
-        if (cl==null) {
-            // A system class.
+        if (cl == null) {
             return ClassLoader.getSystemResourceAsStream(name);
+        } else {
+            return cl.getResourceAsStream(name);
         }
-        return cl.getResourceAsStream(name);
     }
 
     /**
-     * Finds a resource with a given name.  The rules for searching resources
+     * Finds a resource with a given name. If this class is in a named {@link
+     * Module Module}, and the caller of this method is in the same module,
+     * then this method will attempt to find the resource in that module.
+     * Otherwise, the rules for searching resources
      * associated with a given class are implemented by the defining
      * {@linkplain ClassLoader class loader} of the class.  This method
-     * delegates to this object's class loader.  If this object was loaded by
+     * delegates to this object's class loader. If this object was loaded by
      * the bootstrap class loader, the method delegates to {@link
      * ClassLoader#getSystemResource}.
      *
@@ -2287,22 +2468,43 @@
      * </ul>
      *
      * @param  name name of the desired resource
-     * @return      A  {@link java.net.URL} object or {@code null} if no
-     *              resource with this name is found
+     * @return A {@link java.net.URL} object; {@code null} if no
+     *         resource with this name is found or the resource cannot
+     *         be located by a URL.
      * @since  1.1
      */
-    public java.net.URL getResource(String name) {
+    @CallerSensitive
+    public URL getResource(String name) {
         name = resolveName(name);
+
+        // if this Class and the caller are in the same named module
+        // then attempt to get URL to the resource in the module
+        Module module = getModule();
+        if (module.isNamed()) {
+            Class<?> caller = Reflection.getCallerClass();
+            if (caller != null && caller.getModule() == module) {
+                String mn = getModule().getName();
+                ClassLoader cl = getClassLoader0();
+                try {
+                    if (cl == null) {
+                        return BootLoader.findResource(mn, name);
+                    } else {
+                        return cl.findResource(mn, name);
+                    }
+                } catch (IOException ioe) {
+                    return null;
+                }
+            }
+        }
+
         ClassLoader cl = getClassLoader0();
-        if (cl==null) {
-            // A system class.
+        if (cl == null) {
             return ClassLoader.getSystemResource(name);
+        } else {
+            return cl.getResource(name);
         }
-        return cl.getResource(name);
     }
 
-
-
     /** protection domain returned when the internal domain is null */
     private static java.security.ProtectionDomain allPermDomain;
 
@@ -2845,15 +3047,15 @@
         private void remove(int i) {
             if (methods[i] != null && methods[i].isDefault())
                 defaults--;
-            methods[i] = null;
-        }
+                    methods[i] = null;
+                }
 
         private boolean matchesNameAndDescriptor(Method m1, Method m2) {
             return m1.getReturnType() == m2.getReturnType() &&
                    m1.getName() == m2.getName() && // name is guaranteed to be interned
                    arrayContentsEq(m1.getParameterTypes(),
                            m2.getParameterTypes());
-        }
+            }
 
         void compactAndTrim() {
             int newPos = 0;
--- a/src/java.base/share/classes/java/lang/ClassLoader.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/java/lang/ClassLoader.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2015 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,38 +22,44 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.lang;
 
 import java.io.InputStream;
 import java.io.IOException;
 import java.io.File;
 import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Field;
+import java.lang.reflect.Module;
 import java.net.URL;
 import java.security.AccessController;
 import java.security.AccessControlContext;
 import java.security.CodeSource;
 import java.security.PrivilegedAction;
-import java.security.PrivilegedActionException;
-import java.security.PrivilegedExceptionAction;
 import java.security.ProtectionDomain;
 import java.security.cert.Certificate;
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.Stack;
-import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Vector;
-import java.util.Hashtable;
 import java.util.WeakHashMap;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Stream;
 
 import jdk.internal.perf.PerfCounter;
-import sun.misc.Resource;
-import sun.misc.URLClassPath;
+import jdk.internal.module.ServicesCatalog;
+import jdk.internal.loader.BootLoader;
+import jdk.internal.loader.ClassLoaders;
+import jdk.internal.misc.SharedSecrets;
+import jdk.internal.misc.Unsafe;
+import jdk.internal.misc.VM;
 import sun.reflect.CallerSensitive;
 import sun.reflect.Reflection;
 import sun.reflect.misc.ReflectUtil;
@@ -90,9 +96,7 @@
  * associated parent class loader.  When requested to find a class or
  * resource, a <tt>ClassLoader</tt> instance will delegate the search for the
  * class or resource to its parent class loader before attempting to find the
- * class or resource itself.  The virtual machine's built-in class loader,
- * called the "bootstrap class loader", does not itself have a parent but may
- * serve as the parent of a <tt>ClassLoader</tt> instance.
+ * class or resource itself.
  *
  * <p> Class loaders that support concurrent loading of classes are known as
  * <em>parallel capable</em> class loaders and are required to register
@@ -101,19 +105,39 @@
  * #registerAsParallelCapable <tt>ClassLoader.registerAsParallelCapable</tt>}
  * method. Note that the <tt>ClassLoader</tt> class is registered as parallel
  * capable by default. However, its subclasses still need to register themselves
- * if they are parallel capable. <br>
+ * if they are parallel capable.
  * In environments in which the delegation model is not strictly
  * hierarchical, class loaders need to be parallel capable, otherwise class
  * loading can lead to deadlocks because the loader lock is held for the
  * duration of the class loading process (see {@link #loadClass
  * <tt>loadClass</tt>} methods).
  *
+ * <h3> <a name="builtinLoaders">Run-time Built-in Class Loaders</a></h3>
+ *
+ * The Java run-time has the following built-in class loaders:
+ *
+ * <ul>
+ * <li>Bootstrap class loader.
+ *     It is the virtual machine's built-in class loader, typically represented
+ *     as {@code null}, and does not have a parent.</li>
+ * <li>{@linkplain #getPlatformClassLoader() Platform class loader}.
+ *     All <em>platform classes</em> are visible to the platform class loader
+ *     that can be used as the parent of a {@code ClassLoader} instance.
+ *     Platform classes include Java SE platform APIs, their implementation
+ *     classes and JDK-specific run-time classes that are defined by the
+ *     platform class loader or its ancestors.</li>
+ * <li>{@linkplain #getSystemClassLoader() System class loader}.
+ *     It is also known as <em>application class
+ *     loader</em> and is distinct from the platform class loader.
+ *     The system class loader is typically used to define classes on the
+ *     application class path, module path, and JDK-specific tools.
+ *     The platform class loader is a parent or an ancestor of the system class
+ *     loader that all platform classes are visible to it.</li>
+ * </ul>
+ *
  * <p> Normally, the Java virtual machine loads classes from the local file
- * system in a platform-dependent manner.  For example, on UNIX systems, the
- * virtual machine loads classes from the directory defined by the
- * <tt>CLASSPATH</tt> environment variable.
- *
- * <p> However, some classes may not originate from a file; they may originate
+ * system in a platform-dependent manner.
+ * However, some classes may not originate from a file; they may originate
  * from other sources, such as the network, or they could be constructed by an
  * application.  The method {@link #defineClass(String, byte[], int, int)
  * <tt>defineClass</tt>} converts an array of bytes into an instance of class
@@ -159,8 +183,8 @@
  *
  * <h3> <a name="name">Binary names</a> </h3>
  *
- * <p> Any class name provided as a {@link String} parameter to methods in
- * <tt>ClassLoader</tt> must be a binary name as defined by
+ * <p> Any class name provided as a {@code String} parameter to methods in
+ * {@code ClassLoader} must be a binary name as defined by
  * <cite>The Java&trade; Language Specification</cite>.
  *
  * <p> Examples of valid class names include:
@@ -171,9 +195,12 @@
  *   "java.net.URLClassLoader$3$1"
  * </pre></blockquote>
  *
- * {@code Class} objects for array classes are not created by {@code ClassLoader};
- * use the {@link Class#forName} method instead.
+ * <p> Any package name provided as a {@code String} parameter to methods in
+ * {@code ClassLoader} must be either the empty string (denoting an unnamed package)
+ * or a fully qualified name as defined by
+ * <cite>The Java&trade; Language Specification</cite>.
  *
+ * @jls 6.7  Fully Qualified Names
  * @jls 13.1 The Form of a Binary
  * @see      #resolveClass(Class)
  * @since 1.0
@@ -190,6 +217,9 @@
     // must be added *after* it.
     private final ClassLoader parent;
 
+    // the unnamed module for this ClassLoader
+    private final Module unnamedModule;
+
     /**
      * Encapsulates the set of parallel capable loader types.
      */
@@ -241,7 +271,7 @@
     // is parallel capable and the appropriate lock object for class loading.
     private final ConcurrentHashMap<String, Object> parallelLockMap;
 
-    // Hashtable that maps packages to certs
+    // Maps packages to certs
     private final Map <String, Certificate[]> package2certs;
 
     // Shared among all packages with unsigned classes
@@ -265,11 +295,39 @@
         classes.addElement(c);
     }
 
-    // The packages defined in this class loader.  Each package name is mapped
-    // to its corresponding Package object.
-    private final ConcurrentHashMap<String, Package> packages
+    // The packages defined in this class loader.  Each package name is
+    // mapped to its corresponding NamedPackage object.
+    //
+    // The value is a Package object if ClassLoader::definePackage,
+    // Class::getPackage, ClassLoader::getDefinePackage(s) or
+    // Package::getPackage(s) method is called to define it.
+    // Otherwise, the value is a NamedPackage object.
+    private final ConcurrentHashMap<String, NamedPackage> packages
             = new ConcurrentHashMap<>();
 
+    /*
+     * Returns a named package for the given module.
+     */
+    private NamedPackage getNamedPackage(String pn, Module m) {
+        NamedPackage p = packages.get(pn);
+        if (p == null) {
+            p = new NamedPackage(pn, m);
+
+            NamedPackage value = packages.putIfAbsent(pn, p);
+            if (value != null) {
+                // Package object already be defined for the named package
+                p = value;
+                // if definePackage is called by this class loader to define
+                // a package in a named module, this will return Package
+                // object of the same name.  Package object may contain
+                // unexpected information but it does not impact the runtime.
+                // this assertion may be helpful for troubleshooting
+                assert value.module() == m;
+            }
+        }
+        return p;
+    }
+
     private static Void checkCreateClassLoader() {
         SecurityManager security = System.getSecurityManager();
         if (security != null) {
@@ -280,6 +338,9 @@
 
     private ClassLoader(Void unused, ClassLoader parent) {
         this.parent = parent;
+        this.unnamedModule
+            = SharedSecrets.getJavaLangReflectModuleAccess()
+                           .defineUnnamedModule(this);
         if (ParallelLoaders.isRegistered(this.getClass())) {
             parallelLockMap = new ConcurrentHashMap<>();
             package2certs = new ConcurrentHashMap<>();
@@ -438,6 +499,74 @@
     }
 
     /**
+     * Loads the class with the specified <a href="#name">binary name</a>
+     * in a module defined to this class loader.  This method returns {@code null}
+     * if the class could not be found.
+     *
+     * @apiNote This method does not delegate to the parent class loader.
+     *
+     * @implSpec The default implementation of this method searches for classes
+     * in the following order:
+     *
+     * <ol>
+     *   <li>Invoke {@link #findLoadedClass(String)} to check if the class
+     *   has already been loaded.</li>
+     *   <li>Invoke the {@link #findClass(String, String)} method to find the
+     *   class in the given module.</li>
+     * </ol>
+     *
+     * @param  module
+     *         The module
+     * @param  name
+     *         The <a href="#name">binary name</a> of the class
+     *
+     * @return The resulting {@code Class} object in a module defined by
+     *         this class loader, or {@code null} if the class could not be found.
+     */
+    final Class<?> loadLocalClass(Module module, String name) {
+        synchronized (getClassLoadingLock(name)) {
+            // First, check if the class has already been loaded
+            Class<?> c = findLoadedClass(name);
+            if (c == null) {
+                c = findClass(module.getName(), name);
+            }
+            if (c != null && c.getModule() == module) {
+                return c;
+            } else {
+                return null;
+            }
+        }
+    }
+
+    /**
+     * Loads the class with the specified <a href="#name">binary name</a>
+     * defined by this class loader.  This method returns {@code null}
+     * if the class could not be found.
+     *
+     * @apiNote This method does not delegate to the parent class loader.
+     *
+     * @param  name
+     *         The <a href="#name">binary name</a> of the class
+     *
+     * @return The resulting {@code Class} object in a module defined by
+     *         this class loader, or {@code null} if the class could not be found.
+     */
+    final Class<?> loadLocalClass(String name) {
+        synchronized (getClassLoadingLock(name)) {
+            // First, check if the class has already been loaded
+            Class<?> c = findLoadedClass(name);
+            if (c == null) {
+                try {
+                    return findClass(name);
+                } catch (ClassNotFoundException e) {
+                    // ignore
+                }
+            }
+            return c;
+        }
+    }
+
+    /**
      * Returns the lock object for class loading operations.
      * For backward compatibility, the default implementation of this method
      * behaves as follows. If this ClassLoader object is registered as
@@ -532,6 +661,32 @@
     }
 
     /**
+     * Finds the class with the given <a href="#name">binary name</a>
+     * in a module defined to this class loader.
+     * Class loader implementations that support the loading from modules
+     * should override this method.
+     *
+     * @apiNote This method returns {@code null} rather than throwing
+     *          {@code ClassNotFoundException} if the class could not be found
+     *
+     * @implSpec The default implementation returns {@code null}.
+     *
+     * @param  moduleName
+     *         The module name
+     * @param  name
+     *         The <a href="#name">binary name</a> of the class
+     *
+     * @return The resulting {@code Class} object, or {@code null}
+     *         if the class could not be found.
+     *
+     * @since 9
+     */
+    protected Class<?> findClass(String moduleName, String name) {
+        return null;
+    }
+
+
+    /**
      * Converts an array of bytes into an instance of class <tt>Class</tt>.
      * Before the <tt>Class</tt> can be used it must be resolved.  This method
      * is deprecated in favor of the version that takes a <a
@@ -580,55 +735,63 @@
     }
 
     /**
-     * Converts an array of bytes into an instance of class <tt>Class</tt>.
-     * Before the <tt>Class</tt> can be used it must be resolved.
+     * Converts an array of bytes into an instance of class {@code Class}.
+     * Before the {@code Class} can be used it must be resolved.
      *
      * <p> This method assigns a default {@link java.security.ProtectionDomain
-     * <tt>ProtectionDomain</tt>} to the newly defined class.  The
-     * <tt>ProtectionDomain</tt> is effectively granted the same set of
+     * ProtectionDomain} to the newly defined class.  The
+     * {@code ProtectionDomain} is effectively granted the same set of
      * permissions returned when {@link
      * java.security.Policy#getPermissions(java.security.CodeSource)
-     * <tt>Policy.getPolicy().getPermissions(new CodeSource(null, null))</tt>}
-     * is invoked.  The default domain is created on the first invocation of
-     * {@link #defineClass(String, byte[], int, int) <tt>defineClass</tt>},
+     * Policy.getPolicy().getPermissions(new CodeSource(null, null))}
+     * is invoked.  The default protection domain is created on the first invocation
+     * of {@link #defineClass(String, byte[], int, int) defineClass},
      * and re-used on subsequent invocations.
      *
-     * <p> To assign a specific <tt>ProtectionDomain</tt> to the class, use
+     * <p> To assign a specific {@code ProtectionDomain} to the class, use
      * the {@link #defineClass(String, byte[], int, int,
-     * java.security.ProtectionDomain) <tt>defineClass</tt>} method that takes a
-     * <tt>ProtectionDomain</tt> as one of its arguments.  </p>
+     * java.security.ProtectionDomain) defineClass} method that takes a
+     * {@code ProtectionDomain} as one of its arguments.  </p>
+     *
+     * <p>
+     * This method defines a package in this class loader corresponding to the
+     * package of the {@code Class} (if such a package has not already been defined
+     * in this class loader). The name of the defined package is derived from
+     * the <a href="#name">binary name</a> of the class specified by
+     * the byte array {@code b}.
+     * Other properties of the defined package are as specified by {@link Package}.
      *
      * @param  name
      *         The expected <a href="#name">binary name</a> of the class, or
-     *         <tt>null</tt> if not known
+     *         {@code null} if not known
      *
      * @param  b
      *         The bytes that make up the class data.  The bytes in positions
-     *         <tt>off</tt> through <tt>off+len-1</tt> should have the format
+     *         {@code off} through {@code off+len-1} should have the format
      *         of a valid class file as defined by
      *         <cite>The Java&trade; Virtual Machine Specification</cite>.
      *
      * @param  off
-     *         The start offset in <tt>b</tt> of the class data
+     *         The start offset in {@code b} of the class data
      *
      * @param  len
      *         The length of the class data
      *
-     * @return  The <tt>Class</tt> object that was created from the specified
+     * @return  The {@code Class} object that was created from the specified
      *          class data.
      *
      * @throws  ClassFormatError
      *          If the data did not contain a valid class
      *
      * @throws  IndexOutOfBoundsException
-     *          If either <tt>off</tt> or <tt>len</tt> is negative, or if
-     *          <tt>off+len</tt> is greater than <tt>b.length</tt>.
+     *          If either {@code off} or {@code len} is negative, or if
+     *          {@code off+len} is greater than {@code b.length}.
      *
      * @throws  SecurityException
      *          If an attempt is made to add this class to a package that
      *          contains classes that were signed by a different set of
      *          certificates than this class (which is unsigned), or if
-     *          <tt>name</tt> begins with "<tt>java.</tt>".
+     *          {@code name} begins with "{@code java.}".
      *
      * @see  #loadClass(String, boolean)
      * @see  #resolveClass(Class)
@@ -654,7 +817,8 @@
         if (!checkName(name))
             throw new NoClassDefFoundError("IllegalName: " + name);
 
-        if ((name != null) && name.startsWith("java.")) {
+        if ((name != null) && name.startsWith("java.")
+                && this != getBuiltinPlatformClassLoader()) {
             throw new SecurityException
                 ("Prohibited package name: " +
                  name.substring(0, name.lastIndexOf('.')));
@@ -663,13 +827,14 @@
             pd = defaultDomain;
         }
 
-        if (name != null) checkCerts(name, pd.getCodeSource());
+        if (name != null) {
+            checkCerts(name, pd.getCodeSource());
+        }
 
         return pd;
     }
 
-    private String defineClassSourceLocation(ProtectionDomain pd)
-    {
+    private String defineClassSourceLocation(ProtectionDomain pd) {
         CodeSource cs = pd.getCodeSource();
         String source = null;
         if (cs != null && cs.getLocation() != null) {
@@ -678,8 +843,10 @@
         return source;
     }
 
-    private void postDefineClass(Class<?> c, ProtectionDomain pd)
-    {
+    private void postDefineClass(Class<?> c, ProtectionDomain pd) {
+        // define a named package, if not present
+        getNamedPackage(c.getPackageName(), c.getModule());
+
         if (pd.getCodeSource() != null) {
             Certificate certs[] = pd.getCodeSource().getCertificates();
             if (certs != null)
@@ -688,69 +855,80 @@
     }
 
     /**
-     * Converts an array of bytes into an instance of class <tt>Class</tt>,
-     * with an optional <tt>ProtectionDomain</tt>.  If the domain is
-     * <tt>null</tt>, then a default domain will be assigned to the class as
-     * specified in the documentation for {@link #defineClass(String, byte[],
-     * int, int)}.  Before the class can be used it must be resolved.
+     * Converts an array of bytes into an instance of class {@code Class},
+     * with a given {@code ProtectionDomain}.
+     *
+     * <p> If the given {@code ProtectionDomain} is {@code null},
+     * then a default protection domain will be assigned to the class as specified
+     * in the documentation for {@link #defineClass(String, byte[], int, int)}.
+     * Before the class can be used it must be resolved.
      *
      * <p> The first class defined in a package determines the exact set of
      * certificates that all subsequent classes defined in that package must
      * contain.  The set of certificates for a class is obtained from the
-     * {@link java.security.CodeSource <tt>CodeSource</tt>} within the
-     * <tt>ProtectionDomain</tt> of the class.  Any classes added to that
+     * {@link java.security.CodeSource CodeSource} within the
+     * {@code ProtectionDomain} of the class.  Any classes added to that
      * package must contain the same set of certificates or a
-     * <tt>SecurityException</tt> will be thrown.  Note that if
-     * <tt>name</tt> is <tt>null</tt>, this check is not performed.
+     * {@code SecurityException} will be thrown.  Note that if
+     * {@code name} is {@code null}, this check is not performed.
      * You should always pass in the <a href="#name">binary name</a> of the
      * class you are defining as well as the bytes.  This ensures that the
      * class you are defining is indeed the class you think it is.
      *
-     * <p> The specified <tt>name</tt> cannot begin with "<tt>java.</tt>", since
-     * all classes in the "<tt>java.*</tt> packages can only be defined by the
-     * bootstrap class loader.  If <tt>name</tt> is not <tt>null</tt>, it
-     * must be equal to the <a href="#name">binary name</a> of the class
-     * specified by the byte array "<tt>b</tt>", otherwise a {@link
-     * NoClassDefFoundError <tt>NoClassDefFoundError</tt>} will be thrown. </p>
+     * <p> If the specified {@code name} begins with "{@code java.}", it can
+     * only be defined by the {@linkplain #getPlatformClassLoader()
+     * platform class loader} or its ancestors; otherwise {@code SecurityException}
+     * will be thrown.  If {@code name} is not {@code null}, it must be equal to
+     * the <a href="#name">binary name</a> of the class
+     * specified by the byte array {@code b}, otherwise a {@link
+     * NoClassDefFoundError NoClassDefFoundError} will be thrown.
+     *
+     * <p> This method defines a package in this class loader corresponding to the
+     * package of the {@code Class} (if such a package has not already been defined
+     * in this class loader). The name of the defined package is derived from
+     * the <a href="#name">binary name</a> of the class specified by
+     * the byte array {@code b}.
+     * Other properties of the defined package are as specified by {@link Package}.
      *
      * @param  name
      *         The expected <a href="#name">binary name</a> of the class, or
-     *         <tt>null</tt> if not known
+     *         {@code null} if not known
      *
      * @param  b
      *         The bytes that make up the class data. The bytes in positions
-     *         <tt>off</tt> through <tt>off+len-1</tt> should have the format
+     *         {@code off} through {@code off+len-1} should have the format
      *         of a valid class file as defined by
      *         <cite>The Java&trade; Virtual Machine Specification</cite>.
      *
      * @param  off
-     *         The start offset in <tt>b</tt> of the class data
+     *         The start offset in {@code b} of the class data
      *
      * @param  len
      *         The length of the class data
      *
      * @param  protectionDomain
-     *         The ProtectionDomain of the class
+     *         The {@code ProtectionDomain} of the class
      *
-     * @return  The <tt>Class</tt> object created from the data,
-     *          and optional <tt>ProtectionDomain</tt>.
+     * @return  The {@code Class} object created from the data,
+     *          and {@code ProtectionDomain}.
      *
      * @throws  ClassFormatError
      *          If the data did not contain a valid class
      *
      * @throws  NoClassDefFoundError
-     *          If <tt>name</tt> is not equal to the <a href="#name">binary
-     *          name</a> of the class specified by <tt>b</tt>
+     *          If {@code name} is not {@code null} and not equal to the
+     *          <a href="#name">binary name</a> of the class specified by {@code b}
      *
      * @throws  IndexOutOfBoundsException
-     *          If either <tt>off</tt> or <tt>len</tt> is negative, or if
-     *          <tt>off+len</tt> is greater than <tt>b.length</tt>.
+     *          If either {@code off} or {@code len} is negative, or if
+     *          {@code off+len} is greater than {@code b.length}.
      *
      * @throws  SecurityException
      *          If an attempt is made to add this class to a package that
      *          contains classes that were signed by a different set of
-     *          certificates than this class, or if <tt>name</tt> begins with
-     *          "<tt>java.</tt>".
+     *          certificates than this class, or if {@code name} begins with
+     *          "{@code java.}" and this class loader is not the platform
+     *          class loader or its ancestor.
      */
     protected final Class<?> defineClass(String name, byte[] b, int off, int len,
                                          ProtectionDomain protectionDomain)
@@ -764,15 +942,16 @@
     }
 
     /**
-     * Converts a {@link java.nio.ByteBuffer <tt>ByteBuffer</tt>}
-     * into an instance of class <tt>Class</tt>,
-     * with an optional <tt>ProtectionDomain</tt>.  If the domain is
-     * <tt>null</tt>, then a default domain will be assigned to the class as
+     * Converts a {@link java.nio.ByteBuffer ByteBuffer} into an instance
+     * of class {@code Class}, with the given {@code ProtectionDomain}.
+     * If the given {@code ProtectionDomain} is {@code null}, then a default
+     * protection domain will be assigned to the class as
      * specified in the documentation for {@link #defineClass(String, byte[],
      * int, int)}.  Before the class can be used it must be resolved.
      *
      * <p>The rules about the first class defined in a package determining the
-     * set of certificates for the package, and the restrictions on class names
+     * set of certificates for the package, the restrictions on class names,
+     * and the defined package of the class
      * are identical to those specified in the documentation for {@link
      * #defineClass(String, byte[], int, int, ProtectionDomain)}.
      *
@@ -803,23 +982,23 @@
      *         <cite>The Java&trade; Virtual Machine Specification</cite>.
      *
      * @param  protectionDomain
-     *         The ProtectionDomain of the class, or <tt>null</tt>.
+     *         The {@code ProtectionDomain} of the class, or {@code null}.
      *
-     * @return  The <tt>Class</tt> object created from the data,
-     *          and optional <tt>ProtectionDomain</tt>.
+     * @return  The {@code Class} object created from the data,
+     *          and {@code ProtectionDomain}.
      *
      * @throws  ClassFormatError
      *          If the data did not contain a valid class.
      *
      * @throws  NoClassDefFoundError
-     *          If <tt>name</tt> is not equal to the <a href="#name">binary
-     *          name</a> of the class specified by <tt>b</tt>
+     *          If {@code name} is not {@code null} and not equal to the
+     *          <a href="#name">binary name</a> of the class specified by {@code b}
      *
      * @throws  SecurityException
      *          If an attempt is made to add this class to a package that
      *          contains classes that were signed by a different set of
-     *          certificates than this class, or if <tt>name</tt> begins with
-     *          "<tt>java.</tt>".
+     *          certificates than this class, or if {@code name} begins with
+     *          "{@code java.}".
      *
      * @see      #defineClass(String, byte[], int, int, ProtectionDomain)
      *
@@ -1002,8 +1181,7 @@
      * Returns a class loaded by the bootstrap class loader;
      * or return null if not found.
      */
-    private Class<?> findBootstrapClassOrNull(String name)
-    {
+    Class<?> findBootstrapClassOrNull(String name) {
         if (!checkName(name)) return null;
 
         return findBootstrapClass(name);
@@ -1051,13 +1229,44 @@
     }
 
 
-    // -- Resource --
+    // -- Resources --
+
+    /**
+     * Returns a URL to a resource in a module defined to this class loader.
+     * Class loader implementations that support the loading from modules
+     * should override this method.
+     *
+     * @implSpec The default implementation returns {@code null}.
+     *
+     * @param  moduleName
+     *         The module name
+     * @param  name
+     *         The resource name
+     *
+     * @return A URL to the resource; {@code null} if the resource could not be
+     *         found, a URL could not be constructed to locate the resource,
+     *         access to the resource is denied by the security manager, or
+     *         there isn't a module of the given name defined to the class
+     *         loader.
+     *
+     * @throws IOException
+     *         If I/O errors occur
+     *
+     * @see java.lang.module.ModuleReader#find(String)
+     * @since 9
+     */
+    protected URL findResource(String moduleName, String name) throws IOException {
+        return null;
+    }
 
     /**
      * Finds the resource with the given name.  A resource is some data
      * (images, audio, text, etc) that can be accessed by class code in a way
      * that is independent of the location of the code.
      *
+     * Resources in a named module are private to that module. This method does
+     * not find resource in named modules.
+     *
      * <p> The name of a resource is a '<tt>/</tt>'-separated path name that
      * identifies the resource.
      *
@@ -1084,7 +1293,7 @@
         if (parent != null) {
             url = parent.getResource(name);
         } else {
-            url = getBootstrapResource(name);
+            url = BootLoader.findResource(name);
         }
         if (url == null) {
             url = findResource(name);
@@ -1097,6 +1306,9 @@
      * (images, audio, text, etc) that can be accessed by class code in a way
      * that is independent of the location of the code.
      *
+     * Resources in a named module are private to that module. This method does
+     * not find resources in named modules.
+     *
      * <p>The name of a resource is a <tt>/</tt>-separated path name that
      * identifies the resource.
      *
@@ -1131,7 +1343,7 @@
         if (parent != null) {
             tmp[0] = parent.getResources(name);
         } else {
-            tmp[0] = getBootstrapResources(name);
+            tmp[0] = BootLoader.findResources(name);
         }
         tmp[1] = findResources(name);
 
@@ -1142,6 +1354,9 @@
      * Finds the resource with the given name. Class loader implementations
      * should override this method to specify where to find resources.
      *
+     * Resources in a named module are private to that module. This method does
+     * not find resources in named modules defined to this class loader.
+     *
      * @param  name
      *         The resource name
      *
@@ -1160,6 +1375,9 @@
      * implementations should override this method to specify where to load
      * resources from.
      *
+     * Resources in a named module are private to that module. This method does
+     * not find resources in named modules defined to this class loader.
+     *
      * @param  name
      *         The resource name
      *
@@ -1204,6 +1422,9 @@
      * classes.  This method locates the resource through the system class
      * loader (see {@link #getSystemClassLoader()}).
      *
+     * Resources in a named module are private to that module. This method does
+     * not find resources in named modules.
+     *
      * @param  name
      *         The resource name
      *
@@ -1215,7 +1436,7 @@
     public static URL getSystemResource(String name) {
         ClassLoader system = getSystemClassLoader();
         if (system == null) {
-            return getBootstrapResource(name);
+            return BootLoader.findResource(name);
         }
         return system.getResource(name);
     }
@@ -1226,6 +1447,9 @@
      * {@link java.util.Enumeration <tt>Enumeration</tt>} of {@link
      * java.net.URL <tt>URL</tt>} objects.
      *
+     * Resources in a named module are private to that module. This method does
+     * not find resources in named modules.
+     *
      * <p> The search order is described in the documentation for {@link
      * #getSystemResource(String)}.  </p>
      *
@@ -1245,47 +1469,17 @@
     {
         ClassLoader system = getSystemClassLoader();
         if (system == null) {
-            return getBootstrapResources(name);
+            return BootLoader.findResources(name);
         }
         return system.getResources(name);
     }
 
     /**
-     * Find resources from the VM's built-in classloader.
-     */
-    private static URL getBootstrapResource(String name) {
-        URLClassPath ucp = getBootstrapClassPath();
-        Resource res = ucp.getResource(name);
-        return res != null ? res.getURL() : null;
-    }
-
-    /**
-     * Find resources from the VM's built-in classloader.
-     */
-    private static Enumeration<URL> getBootstrapResources(String name)
-        throws IOException
-    {
-        final Enumeration<Resource> e =
-            getBootstrapClassPath().getResources(name);
-        return new Enumeration<> () {
-            public URL nextElement() {
-                return e.nextElement().getURL();
-            }
-            public boolean hasMoreElements() {
-                return e.hasMoreElements();
-            }
-        };
-    }
-
-    // Returns the URLClassPath that is used for finding system resources.
-    static URLClassPath getBootstrapClassPath() {
-        return sun.misc.Launcher.getBootstrapClassPath();
-    }
-
-
-    /**
      * Returns an input stream for reading the specified resource.
      *
+     * Resources in a named module are private to that module. This method does
+     * not find resources in named modules.
+     *
      * <p> The search order is described in the documentation for {@link
      * #getResource(String)}.  </p>
      *
@@ -1311,6 +1505,9 @@
      * used to load classes.  This method locates the resource through the
      * system class loader (see {@link #getSystemClassLoader()}).
      *
+     * Resources in a named module are private to that module. This method does
+     * not find resources in named modules.
+     *
      * @param  name
      *         The resource name
      *
@@ -1371,13 +1568,54 @@
     }
 
     /**
+     * Returns the unnamed {@code Module} for this class loader.
+     *
+     * @return The unnamed Module for this class loader
+     *
+     * @see Module#isNamed()
+     * @since 9
+     */
+    public final Module getUnnamedModule() {
+        return unnamedModule;
+    }
+
+    /**
+     * Returns the platform class loader for delegation.  All
+     * <a href="#builtinLoaders">platform classes</a> are visible to
+     * the platform class loader.
+     *
+     * @return  The platform {@code ClassLoader}.
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and the caller's class loader is
+     *          not {@code null} and the caller's class loader is not the same
+     *          as or an ancestor of the platform class loader,
+     *          and the {@link SecurityManager#checkPermission(java.security.Permission)
+     *          checkPermission} method denies {@code RuntimePermission("getClassLoader")}
+     *          to access the platform class loader.
+     *
+     * @since 9
+     */
+    @CallerSensitive
+    public static ClassLoader getPlatformClassLoader() {
+        SecurityManager sm = System.getSecurityManager();
+        ClassLoader loader = getBuiltinPlatformClassLoader();
+        if (sm != null) {
+            checkClassLoaderPermission(loader, Reflection.getCallerClass());
+        }
+        return loader;
+    }
+
+    /**
      * Returns the system class loader for delegation.  This is the default
      * delegation parent for new <tt>ClassLoader</tt> instances, and is
      * typically the class loader used to start the application.
      *
      * <p> This method is first invoked early in the runtime's startup
-     * sequence, at which point it creates the system class loader and sets it
-     * as the context class loader of the invoking <tt>Thread</tt>.
+     * sequence, at which point it creates the system class loader. This
+     * class loader will be the context class loader for the main application
+     * thread (for example, the thread that invokes the {@code main} method of
+     * the main class).
      *
      * <p> The default system class loader is an implementation-dependent
      * instance of this class.
@@ -1390,7 +1628,10 @@
      * type <tt>ClassLoader</tt> which is used as the delegation parent.  An
      * instance is then created using this constructor with the default system
      * class loader as the parameter.  The resulting class loader is defined
-     * to be the system class loader.
+     * to be the system class loader. During construction, the class loader
+     * should take great care to avoid calling {@code getSystemClassLoader()}.
+     * If circular initialization of the system class loader is detected then
+     * an unspecified error or exception is thrown.
      *
      * <p> If a security manager is present, and the invoker's class loader is
      * not <tt>null</tt> and the invoker's class loader is not the same as or
@@ -1403,6 +1644,11 @@
      * access to the system class loader.  If not, a
      * <tt>SecurityException</tt> will be thrown.  </p>
      *
+     * @implNote The system property to override the system class loader is not
+     * examined until the VM is almost fully initialized. Code that executes
+     * this method during startup should take care not to cache the return
+     * value until the system is fully initialized.
+     *
      * @return  The system <tt>ClassLoader</tt> for delegation, or
      *          <tt>null</tt> if none
      *
@@ -1427,45 +1673,69 @@
      */
     @CallerSensitive
     public static ClassLoader getSystemClassLoader() {
-        initSystemClassLoader();
-        if (scl == null) {
-            return null;
+        switch (VM.initLevel()) {
+            case 0:
+            case 1:
+            case 2:
+                // the system class loader is the built-in app class loader during startup
+                return getBuiltinAppClassLoader();
+            case 3:
+                throw new InternalError("getSystemClassLoader should only be called after VM booted");
+            case 4:
+                // system fully initialized
+                assert VM.isBooted() && scl != null;
+                SecurityManager sm = System.getSecurityManager();
+                if (sm != null) {
+                    checkClassLoaderPermission(scl, Reflection.getCallerClass());
+                }
+                return scl;
+            default:
+                throw new InternalError("should not reach here");
         }
-        SecurityManager sm = System.getSecurityManager();
-        if (sm != null) {
-            checkClassLoaderPermission(scl, Reflection.getCallerClass());
-        }
-        return scl;
+    }
+
+    static ClassLoader getBuiltinPlatformClassLoader() {
+        return ClassLoaders.platformClassLoader();
+    }
+
+    static ClassLoader getBuiltinAppClassLoader() {
+        return ClassLoaders.appClassLoader();
     }
 
-    private static synchronized void initSystemClassLoader() {
-        if (!sclSet) {
-            if (scl != null)
-                throw new IllegalStateException("recursive invocation");
-            sun.misc.Launcher l = sun.misc.Launcher.getLauncher();
-            if (l != null) {
-                Throwable oops = null;
-                scl = l.getClassLoader();
-                try {
-                    scl = AccessController.doPrivileged(
-                        new SystemClassLoaderAction(scl));
-                } catch (PrivilegedActionException pae) {
-                    oops = pae.getCause();
-                    if (oops instanceof InvocationTargetException) {
-                        oops = oops.getCause();
-                    }
-                }
-                if (oops != null) {
-                    if (oops instanceof Error) {
-                        throw (Error) oops;
-                    } else {
-                        // wrap the exception
-                        throw new Error(oops);
-                    }
-                }
+    /*
+     * Initialize the system class loader that may be a custom class on the
+     * application class path or application module path.
+     *
+     * @see java.lang.System#initPhase3
+     */
+    static synchronized ClassLoader initSystemClassLoader() {
+        if (VM.initLevel() != 3) {
+            throw new InternalError("system class loader cannot be set at initLevel " +
+                                    VM.initLevel());
+        }
+
+        // detect recursive initialization
+        if (scl != null) {
+            throw new IllegalStateException("recursive invocation");
+        }
+
+        ClassLoader builtinLoader = getBuiltinAppClassLoader();
+
+        // All are privileged frames.  No need to call doPrivileged.
+        String cn = System.getProperty("java.system.class.loader");
+        if (cn != null) {
+            try {
+                // custom class loader is only supported to be loaded from unnamed module
+                Constructor<?> ctor = Class.forName(cn, false, builtinLoader)
+                                           .getDeclaredConstructor(ClassLoader.class);
+                scl = (ClassLoader) ctor.newInstance(builtinLoader);
+            } catch (Exception e) {
+                throw new Error(e);
             }
-            sclSet = true;
+        } else {
+            scl = builtinLoader;
         }
+        return scl;
     }
 
     // Returns true if the specified class loader can be found in this class
@@ -1524,26 +1794,102 @@
         }
     }
 
-    // The class loader for the system
+    // The system class loader
     // @GuardedBy("ClassLoader.class")
-    private static ClassLoader scl;
-
-    // Set to true once the system class loader has been set
-    // @GuardedBy("ClassLoader.class")
-    private static boolean sclSet;
-
+    private static volatile ClassLoader scl;
 
     // -- Package --
 
     /**
-     * Defines a package by name in this <tt>ClassLoader</tt>.  This allows
-     * class loaders to define the packages for their classes. Packages must
-     * be created before the class is defined, and package names must be
-     * unique within a class loader and cannot be redefined or changed once
-     * created.
+     * Define a Package of the given Class object.
+     *
+     * If the given class represents an array type, a primitive type or void,
+     * this method returns {@code null}.
+     *
+     * This method does not throw IllegalArgumentException.
+     */
+    Package definePackage(Class<?> c) {
+        if (c.isPrimitive() || c.isArray()) {
+            return null;
+        }
+
+        return definePackage(c.getPackageName(), c.getModule());
+    }
+
+    /**
+     * Defines a Package of the given name and module
+     *
+     * This method does not throw IllegalArgumentException.
+     *
+     * @param name package name
+     * @param m    module
+     */
+    Package definePackage(String name, Module m) {
+        if (name.isEmpty() && m.isNamed()) {
+            throw new InternalError("unnamed package in  " + m);
+        }
+
+        // check if Package object is already defined
+        NamedPackage pkg = packages.get(name);
+        if (pkg instanceof Package)
+            return (Package)pkg;
+
+        return (Package)packages.compute(name, (n, p) -> toPackage(n, p, m));
+    }
+
+    /*
+     * Returns a Package object for the named package
+     */
+    private Package toPackage(String name, NamedPackage p, Module m) {
+        // define Package object if the named package is not yet defined
+        if (p == null)
+            return NamedPackage.toPackage(name, m);
+
+        // otherwise, replace the NamedPackage object with Package object
+        if (p instanceof Package)
+            return (Package)p;
+
+        return NamedPackage.toPackage(p.packageName(), p.module());
+    }
+
+    /**
+     * Defines a package by <a href="#name">name</a> in this {@code ClassLoader}.
+     * <p>
+     * <a href="#name">Package names</a> must be unique within a class loader and
+     * cannot be redefined or changed once created.
+     * <p>
+     * If a class loader wishes to define a package with specific properties,
+     * such as version information, then the class loader should call this
+     * {@code definePackage} method before calling {@code defineClass}.
+     * Otherwise, the
+     * {@link #defineClass(String, byte[], int, int, ProtectionDomain) defineClass}
+     * method will define a package in this class loader corresponding to the package
+     * of the newly defined class; the properties of this defined package are
+     * specified by {@link Package}.
+     *
+     * @apiNote
+     * A class loader that wishes to define a package for classes in a JAR
+     * typically uses the specification and implementation titles, versions, and
+     * vendors from the JAR's manifest. If the package is specified as
+     * {@linkplain java.util.jar.Attributes.Name#SEALED sealed} in the JAR's manifest,
+     * the {@code URL} of the JAR file is typically used as the {@code sealBase}.
+     * If classes of package {@code 'p'} defined by this class loader
+     * are loaded from multiple JARs, the {@code Package} object may contain
+     * different information depending on the first class of package {@code 'p'}
+     * defined and which JAR's manifest is read first to explicitly define
+     * package {@code 'p'}.
+     *
+     * <p> It is strongly recommended that a class loader does not call this
+     * method to explicitly define packages in <em>named modules</em>; instead,
+     * the package will be automatically defined when a class is {@linkplain
+     * #defineClass(String, byte[], int, int, ProtectionDomain) being defined}.
+     * If it is desirable to define {@code Package} explicitly, it should ensure
+     * that all packages in a named module are defined with the properties
+     * specified by {@link Package}.  Otherwise, some {@code Package} objects
+     * in a named module may be for example sealed with different seal base.
      *
      * @param  name
-     *         The package name
+     *         The <a href="#name">package name</a>
      *
      * @param  specTitle
      *         The specification title
@@ -1564,89 +1910,155 @@
      *         The implementation vendor
      *
      * @param  sealBase
-     *         If not <tt>null</tt>, then this package is sealed with
-     *         respect to the given code source {@link java.net.URL
-     *         <tt>URL</tt>}  object.  Otherwise, the package is not sealed.
+     *         If not {@code null}, then this package is sealed with
+     *         respect to the given code source {@link java.net.URL URL}
+     *         object.  Otherwise, the package is not sealed.
      *
-     * @return  The newly defined <tt>Package</tt> object
+     * @return  The newly defined {@code Package} object
+     *
+     * @throws  NullPointerException
+     *          if {@code name} is {@code null}.
      *
      * @throws  IllegalArgumentException
-     *          If package name duplicates an existing package either in this
-     *          class loader or one of its ancestors
+     *          if a package of the given {@code name} is already
+     *          defined by this class loader
      *
      * @since  1.2
+     *
+     * @see <a href="../../../technotes/guides/jar/jar.html#versioning">
+     *      The JAR File Specification: Package Versioning</a>
+     * @see <a href="../../../technotes/guides/jar/jar.html#sealing">
+     *      The JAR File Specification: Package Sealing</a>
      */
     protected Package definePackage(String name, String specTitle,
                                     String specVersion, String specVendor,
                                     String implTitle, String implVersion,
                                     String implVendor, URL sealBase)
-        throws IllegalArgumentException
     {
-        Package pkg = getPackage(name);
-        if (pkg != null) {
+        Objects.requireNonNull(name);
+
+        // definePackage is not final and may be overridden by custom class loader
+        Package p = new Package(name, specTitle, specVersion, specVendor,
+                                implTitle, implVersion, implVendor,
+                                sealBase, this);
+
+        if (packages.putIfAbsent(name, p) != null)
             throw new IllegalArgumentException(name);
-        }
-        pkg = new Package(name, specTitle, specVersion, specVendor,
-                          implTitle, implVersion, implVendor,
-                          sealBase, this);
-        if (packages.putIfAbsent(name, pkg) != null) {
-            throw new IllegalArgumentException(name);
-        }
-        return pkg;
+
+        return p;
+    }
+
+    /**
+     * Returns a {@code Package} of the given <a href="#name">name</a> that has been
+     * defined by this class loader.
+     *
+     * @param  name The <a href="#name">package name</a>
+     *
+     * @return The {@code Package} of the given name defined by this class loader,
+     *         or {@code null} if not found
+     *
+     * @since  9
+     */
+    public final Package getDefinedPackage(String name) {
+        NamedPackage p = packages.get(name);
+        if (p == null)
+            return null;
+
+        return definePackage(name, p.module());
     }
 
     /**
-     * Returns a <tt>Package</tt> that has been defined by this class loader
-     * or any of its ancestors.
+     * Returns all of the {@code Package}s defined by this class loader.
+     * The returned array has no duplicated {@code Package}s of the same name.
+     *
+     * @apiNote This method returns an array rather than a {@code Set} or {@code Stream}
+     *          for consistency with the existing {@link #getPackages} method.
+     *
+     * @return The array of {@code Package} objects defined by this class loader;
+     *         or an zero length array if no package has been defined by this class loader.
+     *
+     * @since  9
+     */
+    public final Package[] getDefinedPackages() {
+        return packages().toArray(Package[]::new);
+    }
+
+    /**
+     * Finds a package by <a href="#name">name</a> in this class loader and its ancestors.
+     * <p>
+     * If this class loader defines a {@code Package} of the given name,
+     * the {@code Package} is returned. Otherwise, the ancestors of
+     * this class loader are searched recursively (parent by parent)
+     * for a {@code Package} of the given name.
      *
      * @param  name
-     *         The package name
+     *         The <a href="#name">package name</a>
+     *
+     * @return The {@code Package} corresponding to the given name defined by
+     *         this class loader or its ancestors, or {@code null} if not found.
      *
-     * @return  The <tt>Package</tt> corresponding to the given name, or
-     *          <tt>null</tt> if not found
+     * @deprecated
+     * If multiple class loaders delegate to each other and define classes
+     * with the same package name, and one such loader relies on the lookup
+     * behavior of {@code getPackage} to return a {@code Package} from
+     * a parent loader, then the properties exposed by the {@code Package}
+     * may not be as expected in the rest of the program.
+     * For example, the {@code Package} will only expose annotations from the
+     * {@code package-info.class} file defined by the parent loader, even if
+     * annotations exist in a {@code package-info.class} file defined by
+     * a child loader.  A more robust approach is to use the
+     * {@link ClassLoader#getDefinedPackage} method which returns
+     * a {@code Package} for the specified class loader.
      *
      * @since  1.2
      */
+    @Deprecated
     protected Package getPackage(String name) {
-        Package pkg = packages.get(name);
+        Package pkg = getDefinedPackage(name);
         if (pkg == null) {
             if (parent != null) {
                 pkg = parent.getPackage(name);
             } else {
-                pkg = Package.getSystemPackage(name);
+                pkg = BootLoader.getDefinedPackage(name);
             }
         }
         return pkg;
     }
 
     /**
-     * Returns all of the <tt>Packages</tt> defined by this class loader and
-     * its ancestors.
+     * Returns all of the {@code Package}s defined by this class loader
+     * and its ancestors.  The returned array may contain more than one
+     * {@code Package} object of the same package name, each defined by
+     * a different class loader in the class loader hierarchy.
      *
-     * @return  The array of <tt>Package</tt> objects defined by this
-     *          <tt>ClassLoader</tt>
+     * @return  The array of {@code Package} objects defined by this
+     *          class loader and its ancestors
      *
      * @since  1.2
      */
     protected Package[] getPackages() {
-        Package[] pkgs;
-        if (parent != null) {
-            pkgs = parent.getPackages();
-        } else {
-            pkgs = Package.getSystemPackages();
+        Stream<Package> pkgs = packages();
+        ClassLoader ld = parent;
+        while (ld != null) {
+            pkgs = Stream.concat(ld.packages(), pkgs);
+            ld = ld.parent;
         }
-
-        Map<String, Package> map = packages;
-        if (pkgs != null) {
-            map = new HashMap<>(packages);
-            for (Package pkg : pkgs) {
-                map.putIfAbsent(pkg.getName(), pkg);
-            }
-        }
-        return map.values().toArray(new Package[map.size()]);
+        return Stream.concat(BootLoader.packages(), pkgs)
+                     .toArray(Package[]::new);
     }
 
 
+
+    // package-private
+
+    /**
+     * Returns a stream of Packages defined in this class loader
+     */
+    Stream<Package> packages() {
+        return packages.values().stream()
+                       .map(p -> definePackage(p.packageName(), p.module()));
+    }
+
     // -- Native library access --
 
     /**
@@ -2183,29 +2595,53 @@
 
     // Retrieves the assertion directives from the VM.
     private static native AssertionStatusDirectives retrieveDirectives();
-}
 
 
-class SystemClassLoaderAction
-    implements PrivilegedExceptionAction<ClassLoader> {
-    private ClassLoader parent;
-
-    SystemClassLoaderAction(ClassLoader parent) {
-        this.parent = parent;
+    /**
+     * Returns the ServiceCatalog for modules defined to this class loader
+     * or {@code null} if this class loader does not have a services catalog.
+     */
+    ServicesCatalog getServicesCatalog() {
+        return servicesCatalog;
     }
 
-    public ClassLoader run() throws Exception {
-        String cls = System.getProperty("java.system.class.loader");
-        if (cls == null) {
-            return parent;
+    /**
+     * Returns the ServiceCatalog for modules defined to this class loader,
+     * creating it if it doesn't already exist.
+     */
+    ServicesCatalog createOrGetServicesCatalog() {
+        ServicesCatalog catalog = servicesCatalog;
+        if (catalog == null) {
+            catalog = new ServicesCatalog();
+            boolean set = trySetObjectField("servicesCatalog", catalog);
+            if (!set) {
+                // beaten by someone else
+                catalog = servicesCatalog;
+            }
         }
+        return catalog;
+    }
 
-        Constructor<?> ctor = Class.forName(cls, true, parent)
-            .getDeclaredConstructor(new Class<?>[] { ClassLoader.class });
-        ClassLoader sys = (ClassLoader) ctor.newInstance(
-            new Object[] { parent });
-        Thread.currentThread().setContextClassLoader(sys);
-        return sys;
+    // the ServiceCatalog for modules associated with this class loader.
+    private volatile ServicesCatalog servicesCatalog;
+
+
+    /**
+     * Attempts to atomically set a volatile field in this object. Returns
+     * {@code true} if not beaten by another thread. Avoids the use of
+     * AtomicReferenceFieldUpdater in this class.
+     */
+    private boolean trySetObjectField(String name, Object obj) {
+        Unsafe unsafe = Unsafe.getUnsafe();
+        Class<?> k = ClassLoader.class;
+        long offset;
+        try {
+            Field f = k.getDeclaredField(name);
+            offset = unsafe.objectFieldOffset(f);
+        } catch (NoSuchFieldException e) {
+            throw new InternalError(e);
+        }
+        return unsafe.compareAndSwapObject(this, offset, null, obj);
     }
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/NamedPackage.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang;
+
+import java.lang.module.Configuration;
+import java.lang.module.ModuleReference;
+import java.lang.reflect.Module;
+import java.net.URI;
+
+/**
+ * A NamedPackage represents a package by name in a specific module.
+ *
+ * A class loader will automatically create NamedPackage for each
+ * package when a class is defined.  Package object is lazily
+ * defined until Class::getPackage, Package::getPackage(s), or
+ * ClassLoader::getDefinedPackage(s) method is called.
+ *
+ * NamedPackage allows ClassLoader to keep track of the runtime
+ * packages with minimal footprint and avoid constructing Package
+ * object.
+ */
+class NamedPackage {
+    private final String name;
+    private final Module module;
+
+    NamedPackage(String pn, Module module) {
+        if (pn.isEmpty() && module.isNamed()) {
+            throw new InternalError("unnamed package in  " + module);
+        }
+        this.name = pn.intern();
+        this.module = module;
+    }
+
+    /**
+     * Returns the name of this package.
+     */
+    String packageName() {
+        return name;
+    }
+
+    /**
+     * Returns the module of this named package.
+     */
+    Module module() {
+        return module;
+    }
+
+    /**
+     * Returns the location of the module if this named package is in
+     * a named module; otherwise, returns null.
+     */
+    URI location() {
+        if (module.isNamed() && module.getLayer() != null) {
+            Configuration cf = module.getLayer().configuration();
+            ModuleReference mref
+                = cf.findModule(module.getName()).get().reference();
+            return mref.location().orElse(null);
+        }
+        return null;
+    }
+
+    /**
+     * Creates a Package object of the given name and module.
+     */
+    static Package toPackage(String name, Module module) {
+        return new Package(name, module);
+    }
+}
--- a/src/java.base/share/classes/java/lang/Package.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/java/lang/Package.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,85 +25,94 @@
 
 package java.lang;
 
+import java.lang.annotation.Annotation;
 import java.lang.reflect.AnnotatedElement;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
+import java.lang.reflect.Module;
+import java.net.MalformedURLException;
+import java.net.URI;
 import java.net.URL;
-import java.net.MalformedURLException;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
+import java.util.Objects;
 
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.jar.JarInputStream;
-import java.util.jar.Manifest;
-import java.util.jar.Attributes;
-import java.util.jar.Attributes.Name;
-import java.util.Map;
-
-import sun.net.www.ParseUtil;
+import jdk.internal.loader.BootLoader;
 import sun.reflect.CallerSensitive;
 import sun.reflect.Reflection;
 
-import java.lang.annotation.Annotation;
 
 /**
- * {@code Package} objects contain version information
- * about the implementation and specification of a Java package.
- * This versioning information is retrieved and made available
- * by the {@link ClassLoader} instance that
- * loaded the class(es).  Typically, it is stored in the manifest that is
- * distributed with the classes.
- *
- * <p>The set of classes that make up the package may implement a
- * particular specification and if so the specification title, version number,
- * and vendor strings identify that specification.
- * An application can ask if the package is
- * compatible with a particular version, see the {@link
- * #isCompatibleWith isCompatibleWith}
- * method for details.
+ * Represents metadata about a run-time package associated with a class loader.
+ * Metadata includes annotations, versioning, and sealing.
+ * <p>
+ * Annotations for the run-time package are read from {@code package-info.class}
+ * at the same code source as classes in the run-time package.
+ * <p>
+ * The set of classes that make up the run-time package may implement a
+ * particular specification. The specification title, version, and vendor
+ * (indicating the owner/maintainer of the specification) can be provided
+ * when the {@code Package} is defined. An application can ask if the
+ * {@code Package} is compatible with a particular specification version
+ * by using the {@link #isCompatibleWith Package.isCompatibleWith(String)}
+ * method. In addition, information about the actual classes that make up the
+ * run-time package can be provided when the Package is defined.
+ * This information consists of an implementation title, version, and vendor
+ * (indicating the supplier of the classes).
+ * <p>
+ * A {@code Package} may be explicitly defined with
+ * the {@link ClassLoader#definePackage(String, String, String, String,
+ * String, String, String, URL)} method.
+ * The caller supplies the specification and implementation titles, versions, and
+ * vendors. The caller also indicates whether the package is
+ * {@linkplain java.util.jar.Attributes.Name#SEALED sealed}.
+ * If a {@code Package} is not explicitly defined for a run-time package when
+ * a class in that run-time package is defined, then a {@code Package} is
+ * automatically defined by the class's defining class loader, as follows.
+ * <p>
+ * A {@code Package} automatically defined for classes in a named module has
+ * the following properties:
+ * <ul>
+ * <li>The name of the package is derived from the {@linkplain Class#getName() binary names}
+ *     of the classes. Since classes in a named module must be in a named package,
+ *     the derived name is never empty.</li>
+ * <li>The package is sealed with the {@linkplain java.lang.module.ModuleReference#location()
+ *     module location} as the code source, if known.</li>
+ * <li>The specification and implementation titles, versions, and vendors
+ *     are unspecified.</li>
+ * <li>Any annotations on the package are read from {@code package-info.class}
+ *     as specified above.</li>
+ * </ul>
+ * <p>
+ * A {@code Package} automatically defined for classes in an unnamed module
+ * has the following properties:
+ * <ul>
+ * <li>The name of the package is either {@code ""} (for classes in an unnamed package)
+ *     or derived from the {@linkplain Class#getName() binary names} of the classes
+ *     (for classes in a named package).</li>
+ * <li>The package is not sealed.</li>
+ * <li>The specification and implementation titles, versions, and vendors
+ *     are unspecified.</li>
+ * <li>Any annotations on the package are read from {@code package-info.class}
+ *     as specified above.</li>
+ * </ul>
  *
- * <p>Specification version numbers use a syntax that consists of nonnegative
- * decimal integers separated by periods ".", for example "2.0" or
- * "1.2.3.4.5.6.7".  This allows an extensible number to be used to represent
- * major, minor, micro, etc. versions.  The version specification is described
- * by the following formal grammar:
- * <blockquote>
- * <dl>
- * <dt><i>SpecificationVersion:</i>
- * <dd><i>Digits RefinedVersion<sub>opt</sub></i>
-
- * <dt><i>RefinedVersion:</i>
- * <dd>{@code .} <i>Digits</i>
- * <dd>{@code .} <i>Digits RefinedVersion</i>
- *
- * <dt><i>Digits:</i>
- * <dd><i>Digit</i>
- * <dd><i>Digits</i>
+ * <p>
+ * A {@code Package} can be obtained with the {@link Package#getPackage
+ * Package.getPackage(String)} and {@link ClassLoader#getDefinedPackage
+ * ClassLoader.getDefinedPackage(String)} methods.
+ * Every {@code Package} defined by a class loader can be obtained
+ * with the {@link Package#getPackages Package.getPackages()} and
+ * {@link ClassLoader#getDefinedPackages} methods.
  *
- * <dt><i>Digit:</i>
- * <dd>any character for which {@link Character#isDigit} returns {@code true},
- * e.g. 0, 1, 2, ...
- * </dl>
- * </blockquote>
+ * @jvms 5.3 Run-time package
+ * @see <a href="../../../technotes/guides/jar/jar.html#versioning">
+ * The JAR File Specification: Package Versioning</a>
+ * @see <a href="../../../technotes/guides/jar/jar.html#sealing">
+ * The JAR File Specification: Package Sealing</a>
+ * @see ClassLoader#definePackage(String, String, String, String, String, String, String, URL)
  *
- * <p>The implementation title, version, and vendor strings identify an
- * implementation and are made available conveniently to enable accurate
- * reporting of the packages involved when a problem occurs. The contents
- * all three implementation strings are vendor specific. The
- * implementation version strings have no specified syntax and should
- * only be compared for equality with desired version identifiers.
- *
- * <p>Within each {@code ClassLoader} instance all classes from the same
- * java package have the same Package object.  The static methods allow a package
- * to be found by name or the set of all packages known to the current class
- * loader to be found.
- *
- * @see ClassLoader#definePackage
  * @since 1.2
  */
-public class Package implements java.lang.reflect.AnnotatedElement {
+public class Package extends NamedPackage implements java.lang.reflect.AnnotatedElement {
     /**
      * Return the name of this package.
      *
@@ -112,47 +121,72 @@
      *          for example, {@code java.lang}
      */
     public String getName() {
-        return pkgName;
+        return packageName();
     }
 
-
     /**
      * Return the title of the specification that this package implements.
-     * @return the specification title, null is returned if it is not known.
+     * @return the specification title, {@code null} is returned if it is not known.
      */
     public String getSpecificationTitle() {
-        return specTitle;
+        return versionInfo.specTitle;
     }
 
     /**
      * Returns the version number of the specification
      * that this package implements.
-     * This version string must be a sequence of nonnegative decimal
+     * This version string must be a sequence of non-negative decimal
      * integers separated by "."'s and may have leading zeros.
      * When version strings are compared the most significant
      * numbers are compared.
-     * @return the specification version, null is returned if it is not known.
+     *
+     *
+     * <p>Specification version numbers use a syntax that consists of non-negative
+     * decimal integers separated by periods ".", for example "2.0" or
+     * "1.2.3.4.5.6.7".  This allows an extensible number to be used to represent
+     * major, minor, micro, etc. versions.  The version specification is described
+     * by the following formal grammar:
+     * <blockquote>
+     * <dl>
+     * <dt><i>SpecificationVersion:</i>
+     * <dd><i>Digits RefinedVersion<sub>opt</sub></i>
+
+     * <dt><i>RefinedVersion:</i>
+     * <dd>{@code .} <i>Digits</i>
+     * <dd>{@code .} <i>Digits RefinedVersion</i>
+     *
+     * <dt><i>Digits:</i>
+     * <dd><i>Digit</i>
+     * <dd><i>Digits</i>
+     *
+     * <dt><i>Digit:</i>
+     * <dd>any character for which {@link Character#isDigit} returns {@code true},
+     * e.g. 0, 1, 2, ...
+     * </dl>
+     * </blockquote>
+     *
+     * @return the specification version, {@code null} is returned if it is not known.
      */
     public String getSpecificationVersion() {
-        return specVersion;
+        return versionInfo.specVersion;
     }
 
     /**
      * Return the name of the organization, vendor,
      * or company that owns and maintains the specification
      * of the classes that implement this package.
-     * @return the specification vendor, null is returned if it is not known.
+     * @return the specification vendor, {@code null} is returned if it is not known.
      */
     public String getSpecificationVendor() {
-        return specVendor;
+        return versionInfo.specVendor;
     }
 
     /**
      * Return the title of this package.
-     * @return the title of the implementation, null is returned if it is not known.
+     * @return the title of the implementation, {@code null} is returned if it is not known.
      */
     public String getImplementationTitle() {
-        return implTitle;
+        return versionInfo.implTitle;
     }
 
     /**
@@ -162,19 +196,20 @@
      * runtime. It may be compared for equality with other
      * package version strings used for this implementation
      * by this vendor for this package.
-     * @return the version of the implementation, null is returned if it is not known.
+     * @return the version of the implementation, {@code null} is returned if it is not known.
      */
     public String getImplementationVersion() {
-        return implVersion;
+        return versionInfo.implVersion;
     }
 
     /**
-     * Returns the name of the organization,
-     * vendor or company that provided this implementation.
-     * @return the vendor that implemented this package..
+     * Returns the vendor that implemented this package, {@code null}
+     * is returned if it is not known.
+     * @return the vendor that implemented this package, {@code null}
+     * is returned if it is not known.
      */
     public String getImplementationVendor() {
-        return implVendor;
+        return versionInfo.implVendor;
     }
 
     /**
@@ -183,17 +218,29 @@
      * @return true if the package is sealed, false otherwise
      */
     public boolean isSealed() {
-        return sealBase != null;
+        return module().isNamed() || versionInfo.sealBase != null;
     }
 
     /**
      * Returns true if this package is sealed with respect to the specified
-     * code source url.
+     * code source {@code url}.
      *
-     * @param url the code source url
-     * @return true if this package is sealed with respect to url
+     * @param url the code source URL
+     * @return true if this package is sealed with respect to the given {@code url}
      */
     public boolean isSealed(URL url) {
+        Objects.requireNonNull(url);
+
+        URL sealBase = null;
+        if (versionInfo != VersionInfo.NULL_VERSION_INFO) {
+            sealBase = versionInfo.sealBase;
+        } else {
+            try {
+                URI uri = location();
+                sealBase = uri != null ? uri.toURL() : null;
+            } catch (MalformedURLException e) {
+            }
+        }
         return url.equals(sealBase);
     }
 
@@ -216,17 +263,17 @@
      * @return true if this package's version number is greater
      *          than or equal to the desired version number
      *
-     * @exception NumberFormatException if the desired or current version
-     *          is not of the correct dotted form.
+     * @exception NumberFormatException if the current version is not known or
+     *          the desired or current version is not of the correct dotted form.
      */
     public boolean isCompatibleWith(String desired)
         throws NumberFormatException
     {
-        if (specVersion == null || specVersion.length() < 1) {
+        if (versionInfo.specVersion == null || versionInfo.specVersion.length() < 1) {
             throw new NumberFormatException("Empty version string");
         }
 
-        String [] sa = specVersion.split("\\.", -1);
+        String [] sa = versionInfo.specVersion.split("\\.", -1);
         int [] si = new int[sa.length];
         for (int i = 0; i < sa.length; i++) {
             si[i] = Integer.parseInt(sa[i]);
@@ -255,92 +302,71 @@
     }
 
     /**
-     * Find a package by name in the callers {@code ClassLoader} instance.
-     * The callers {@code ClassLoader} instance is used to find the package
-     * instance corresponding to the named class. If the callers
-     * {@code ClassLoader} instance is null then the set of packages loaded
-     * by the system {@code ClassLoader} instance is searched to find the
-     * named package. <p>
+     * Finds a package by name in the caller's class loader and its
+     * ancestors.
+     * <p>
+     * If the caller's class loader defines a {@code Package} of the given name,
+     * the {@code Package} is returned. Otherwise, the ancestors of the
+     * caller's class loader are searched recursively (parent by parent)
+     * for a {@code Package} of the given name.
+     * <p>
+     * Calling this method is equivalent to calling {@link ClassLoader#getPackage}
+     * on a {@code ClassLoader} instance which is the caller's class loader.
+     *
+     * @param name A package name, such as "{@code java.lang}".
+     * @return The {@code Package} of the given name defined by the caller's
+     *         class loader or its ancestors, or {@code null} if not found.
      *
-     * Packages have attributes for versions and specifications only if the class
-     * loader created the package instance with the appropriate attributes. Typically,
-     * those attributes are defined in the manifests that accompany the classes.
+     * @deprecated
+     * If multiple class loaders delegate to each other and define classes
+     * with the same package name, and one such loader relies on the lookup
+     * behavior of {@code getPackage} to return a {@code Package} from
+     * a parent loader, then the properties exposed by the {@code Package}
+     * may not be as expected in the rest of the program.
+     * For example, the {@code Package} will only expose annotations from the
+     * {@code package-info.class} file defined by the parent loader, even if
+     * annotations exist in a {@code package-info.class} file defined by
+     * a child loader.  A more robust approach is to use the
+     * {@link ClassLoader#getDefinedPackage} method which returns
+     * a {@code Package} for the specified class loader.
      *
-     * @param name a package name, for example, java.lang.
-     * @return the package of the requested name. It may be null if no package
-     *          information is available from the archive or codebase.
+     * @see ClassLoader#getDefinedPackage
      */
     @CallerSensitive
+    @Deprecated
+    @SuppressWarnings("deprecation")
     public static Package getPackage(String name) {
         ClassLoader l = ClassLoader.getClassLoader(Reflection.getCallerClass());
-        if (l != null) {
-            return l.getPackage(name);
-        } else {
-            return getSystemPackage(name);
-        }
+        return l != null ? l.getPackage(name) : BootLoader.getDefinedPackage(name);
     }
 
     /**
-     * Get all the packages currently known for the caller's {@code ClassLoader}
-     * instance.  Those packages correspond to classes loaded via or accessible by
-     * name to that {@code ClassLoader} instance.  If the caller's
-     * {@code ClassLoader} instance is the bootstrap {@code ClassLoader}
-     * instance, which may be represented by {@code null} in some implementations,
-     * only packages corresponding to classes loaded by the bootstrap
-     * {@code ClassLoader} instance will be returned.
+     * Returns all of the {@code Package}s defined by the caller's class loader
+     * and its ancestors.  The returned array may contain more than one
+     * {@code Package} object of the same package name, each defined by
+     * a different class loader in the class loader hierarchy.
+     * <p>
+     * Calling this method is equivalent to calling {@link ClassLoader#getPackages}
+     * on a {@code ClassLoader} instance which is the caller's class loader.
      *
-     * @return a new array of packages known to the callers {@code ClassLoader}
-     * instance.  An zero length array is returned if none are known.
+     * @return  The array of {@code Package} objects defined by this
+     *          class loader and its ancestors
+     *
+     * @see ClassLoader#getDefinedPackages
      */
     @CallerSensitive
     public static Package[] getPackages() {
-        ClassLoader l = ClassLoader.getClassLoader(Reflection.getCallerClass());
-        if (l != null) {
-            return l.getPackages();
-        } else {
-            return getSystemPackages();
-        }
-    }
-
-    /**
-     * Get the package for the specified class.
-     * The class's class loader is used to find the package instance
-     * corresponding to the specified class. If the class loader
-     * is the bootstrap class loader, which may be represented by
-     * {@code null} in some implementations, then the set of packages
-     * loaded by the bootstrap class loader is searched to find the package.
-     * <p>
-     * Packages have attributes for versions and specifications only
-     * if the class loader created the package
-     * instance with the appropriate attributes. Typically those
-     * attributes are defined in the manifests that accompany
-     * the classes.
-     *
-     * @param c the class to get the package of.
-     * @return the package of the class. It may be null if no package
-     *          information is available from the archive or codebase.  */
-    static Package getPackage(Class<?> c) {
-        String name = c.getName();
-        int i = name.lastIndexOf('.');
-        if (i != -1) {
-            name = name.substring(0, i);
-            ClassLoader cl = c.getClassLoader();
-            if (cl != null) {
-                return cl.getPackage(name);
-            } else {
-                return getSystemPackage(name);
-            }
-        } else {
-            return null;
-        }
+        ClassLoader cl = ClassLoader.getClassLoader(Reflection.getCallerClass());
+        return cl != null ? cl.getPackages() : BootLoader.packages().toArray(Package[]::new);
     }
 
     /**
      * Return the hash code computed from the package name.
      * @return the hash code computed from the package name.
      */
+    @Override
     public int hashCode(){
-        return pkgName.hashCode();
+        return packageName().hashCode();
     }
 
     /**
@@ -350,9 +376,10 @@
      * If the package version is defined it is appended.
      * @return the string representation of the package.
      */
+    @Override
     public String toString() {
-        String spec = specTitle;
-        String ver =  specVersion;
+        String spec = versionInfo.specTitle;
+        String ver =  versionInfo.specVersion;
         if (spec != null && spec.length() > 0)
             spec = ", " + spec;
         else
@@ -361,14 +388,20 @@
             ver = ", version " + ver;
         else
             ver = "";
-        return "package " + pkgName + spec + ver;
+        return "package " + packageName() + spec + ver;
     }
 
     private Class<?> getPackageInfo() {
         if (packageInfo == null) {
-            try {
-                packageInfo = Class.forName(pkgName + ".package-info", false, loader);
-            } catch (ClassNotFoundException ex) {
+            // find package-info.class defined by loader
+            String cn = packageName() + ".package-info";
+            PrivilegedAction<ClassLoader> pa = module()::getClassLoader;
+            ClassLoader loader = AccessController.doPrivileged(pa);
+            Class<?> c = loader != null ? loader.loadLocalClass(cn)
+                                        : BootLoader.loadClassOrNull(cn);
+            if (c != null) {
+                packageInfo = c;
+            } else {
                 // store a proxy for the package info that has no annotations
                 class PackageInfoProxy {}
                 packageInfo = PackageInfoProxy.class;
@@ -437,8 +470,12 @@
     }
 
     /**
-     * Construct a package instance with the specified version
-     * information.
+     * Construct a package instance for an unnamed module
+     * with the specified version information.
+     *
+     * @apiNote
+     * This method should not be called to define a Package for named module.
+     *
      * @param name the name of the package
      * @param spectitle the title of the specification
      * @param specversion the version of the specification
@@ -446,216 +483,73 @@
      * @param impltitle the title of the implementation
      * @param implversion the version of the implementation
      * @param implvendor the organization that maintains the implementation
+     * @param sealbase code source where this Package comes from
+     * @param loader defining class loader
      */
     Package(String name,
             String spectitle, String specversion, String specvendor,
             String impltitle, String implversion, String implvendor,
             URL sealbase, ClassLoader loader)
     {
-        pkgName = name;
-        implTitle = impltitle;
-        implVersion = implversion;
-        implVendor = implvendor;
-        specTitle = spectitle;
-        specVersion = specversion;
-        specVendor = specvendor;
-        sealBase = sealbase;
-        this.loader = loader;
+        super(Objects.requireNonNull(name),
+              loader != null ? loader.getUnnamedModule()
+                             : BootLoader.getUnnamedModule());
+
+        this.versionInfo = VersionInfo.getInstance(spectitle, specversion,
+                                                   specvendor, impltitle,
+                                                   implversion, implvendor,
+                                                   sealbase);
     }
 
-    /*
-     * Construct a package using the attributes from the specified manifest.
-     *
-     * @param name the package name
-     * @param man the optional manifest for the package
-     * @param url the optional code source url for the package
-     */
-    private Package(String name, Manifest man, URL url, ClassLoader loader) {
-        String path = name.replace('.', '/').concat("/");
-        String sealed = null;
-        String specTitle= null;
-        String specVersion= null;
-        String specVendor= null;
-        String implTitle= null;
-        String implVersion= null;
-        String implVendor= null;
-        URL sealBase= null;
-        Attributes attr = man.getAttributes(path);
-        if (attr != null) {
-            specTitle   = attr.getValue(Name.SPECIFICATION_TITLE);
-            specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
-            specVendor  = attr.getValue(Name.SPECIFICATION_VENDOR);
-            implTitle   = attr.getValue(Name.IMPLEMENTATION_TITLE);
-            implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
-            implVendor  = attr.getValue(Name.IMPLEMENTATION_VENDOR);
-            sealed      = attr.getValue(Name.SEALED);
-        }
-        attr = man.getMainAttributes();
-        if (attr != null) {
-            if (specTitle == null) {
-                specTitle = attr.getValue(Name.SPECIFICATION_TITLE);
-            }
-            if (specVersion == null) {
-                specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
-            }
-            if (specVendor == null) {
-                specVendor = attr.getValue(Name.SPECIFICATION_VENDOR);
-            }
-            if (implTitle == null) {
-                implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE);
-            }
-            if (implVersion == null) {
-                implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
-            }
-            if (implVendor == null) {
-                implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR);
-            }
-            if (sealed == null) {
-                sealed = attr.getValue(Name.SEALED);
-            }
-        }
-        if ("true".equalsIgnoreCase(sealed)) {
-            sealBase = url;
-        }
-        pkgName = name;
-        this.specTitle = specTitle;
-        this.specVersion = specVersion;
-        this.specVendor = specVendor;
-        this.implTitle = implTitle;
-        this.implVersion = implVersion;
-        this.implVendor = implVendor;
-        this.sealBase = sealBase;
-        this.loader = loader;
-    }
-
-    /*
-     * Returns the loaded system package for the specified name.
-     */
-    static Package getSystemPackage(String name) {
-        Package pkg = pkgs.get(name);
-        if (pkg == null) {
-            name = name.replace('.', '/').concat("/");
-            String fn = getSystemPackage0(name);
-            if (fn != null) {
-                pkg = defineSystemPackage(name, fn);
-            }
-        }
-        return pkg;
+    Package(String name, Module module) {
+        super(name, module);
+        this.versionInfo = VersionInfo.NULL_VERSION_INFO;
     }
 
     /*
-     * Return an array of loaded system packages.
+     * Versioning information.  Only for packages in unnamed modules.
      */
-    static Package[] getSystemPackages() {
-        // First, update the system package map with new package names
-        String[] names = getSystemPackages0();
-        for (String name : names) {
-            if (!pkgs.containsKey(name)) {
-                defineSystemPackage(name, getSystemPackage0(name));
-            }
-        }
-        return pkgs.values().toArray(new Package[pkgs.size()]);
-    }
-
-    private static Package defineSystemPackage(final String iname,
-                                               final String fn)
-    {
-        // Convert to "."-separated package name
-        String name = iname.substring(0, iname.length() - 1).replace('/', '.');
-        // Creates a cached manifest for the file name, allowing
-        // only-once, lazy reads of manifest from jar files
-        CachedManifest cachedManifest = createCachedManifest(fn);
-        pkgs.putIfAbsent(name, new Package(name, cachedManifest.getManifest(),
-                                           cachedManifest.getURL(), null));
-        // Ensure we only expose one Package object
-        return pkgs.get(name);
-    }
+    static class VersionInfo {
+        static final VersionInfo NULL_VERSION_INFO
+            = new VersionInfo(null, null, null, null, null, null, null);
 
-    private static CachedManifest createCachedManifest(String fn) {
-        if (!manifests.containsKey(fn)) {
-            manifests.putIfAbsent(fn, new CachedManifest(fn));
-        }
-        return manifests.get(fn);
-    }
-
-    // The map of loaded system packages
-    private static final ConcurrentHashMap<String, Package> pkgs
-            = new ConcurrentHashMap<>();
-
-    // Maps each directory or zip file name to its corresponding manifest, if
-    // it exists
-    private static final ConcurrentHashMap<String, CachedManifest> manifests
-            = new ConcurrentHashMap<>();
+        private final String specTitle;
+        private final String specVersion;
+        private final String specVendor;
+        private final String implTitle;
+        private final String implVersion;
+        private final String implVendor;
+        private final URL sealBase;
 
-    private static class CachedManifest {
-        private static final Manifest EMPTY_MANIFEST = new Manifest();
-        private final String fileName;
-        private final URL url;
-        private volatile Manifest manifest;
-
-        CachedManifest(final String fileName) {
-            this.fileName = fileName;
-            this.url = AccessController.doPrivileged(new PrivilegedAction<>() {
-                public URL run() {
-                    final File file = new File(fileName);
-                    if (file.isFile()) {
-                        try {
-                            return ParseUtil.fileToEncodedURL(file);
-                        } catch (MalformedURLException e) {
-                        }
-                    }
-                    return null;
-                }
-            });
+        static VersionInfo getInstance(String spectitle, String specversion,
+                                       String specvendor, String impltitle,
+                                       String implversion, String implvendor,
+                                       URL sealbase) {
+            if (spectitle == null && specversion == null &&
+                    specvendor == null && impltitle == null &&
+                    implvendor == null && sealbase == null) {
+                return NULL_VERSION_INFO;
+            }
+            return new VersionInfo(spectitle, specversion, specvendor,
+                    impltitle, implversion, implvendor,
+                    sealbase);
         }
 
-        public URL getURL() {
-            return url;
-        }
-
-        public Manifest getManifest() {
-            if (url == null) {
-                return EMPTY_MANIFEST;
-            }
-            Manifest m = manifest;
-            if (m != null) {
-                return m;
-            }
-            synchronized (this) {
-                m = manifest;
-                if (m != null) {
-                    return m;
-                }
-                m = AccessController.doPrivileged(new PrivilegedAction<>() {
-                    public Manifest run() {
-                        try (FileInputStream fis = new FileInputStream(fileName);
-                             JarInputStream jis = new JarInputStream(fis, false)) {
-                            return jis.getManifest();
-                        } catch (IOException e) {
-                            return null;
-                        }
-                    }
-                });
-                manifest = m = (m == null ? EMPTY_MANIFEST : m);
-            }
-            return m;
+        private VersionInfo(String spectitle, String specversion,
+                            String specvendor, String impltitle,
+                            String implversion, String implvendor,
+                            URL sealbase)
+        {
+            this.implTitle = impltitle;
+            this.implVersion = implversion;
+            this.implVendor = implvendor;
+            this.specTitle = spectitle;
+            this.specVersion = specversion;
+            this.specVendor = specvendor;
+            this.sealBase = sealbase;
         }
     }
 
-    private static native String getSystemPackage0(String name);
-    private static native String[] getSystemPackages0();
-
-    /*
-     * Private storage for the package name and attributes.
-     */
-    private final String pkgName;
-    private final String specTitle;
-    private final String specVersion;
-    private final String specVendor;
-    private final String implTitle;
-    private final String implVersion;
-    private final String implVendor;
-    private final URL sealBase;
-    private final transient ClassLoader loader;
-    private transient Class<?> packageInfo;
+    private final VersionInfo versionInfo;
+    private Class<?> packageInfo;
 }
--- a/src/java.base/share/classes/java/lang/StackFrameInfo.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/java/lang/StackFrameInfo.java	Thu Mar 17 19:04:16 2016 +0000
@@ -29,6 +29,7 @@
 
 import static java.lang.StackWalker.Option.*;
 import java.lang.StackWalker.StackFrame;
+import java.lang.reflect.Module;
 import java.util.Optional;
 import java.util.OptionalInt;
 
@@ -133,4 +134,21 @@
     static native void fillInStackFrames(int startIndex,
                                          Object[] stackframes,
                                          int fromIndex, int toIndex);
+
+    @Override
+    public StackTraceElement toStackTraceElement() {
+        ensureMethodInfoInitialized();
+
+        Module module = declaringClass.getModule();
+        String moduleName = module.isNamed() ? module.getName() : null;
+        String moduleVersion = null;
+        if (module.isNamed() && module.getDescriptor().version().isPresent()) {
+            moduleVersion = module.getDescriptor().version().get().toString();
+        }
+        return new StackTraceElement(moduleName, moduleVersion,
+                                     getClassName(), getMethodName(),
+                                     fileName,
+                                     lineNumber);
+    }
+
 }
--- a/src/java.base/share/classes/java/lang/StackTraceElement.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/java/lang/StackTraceElement.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -41,6 +41,8 @@
  */
 public final class StackTraceElement implements java.io.Serializable {
     // Normally initialized by VM (public constructor added in 1.5)
+    private String moduleName;
+    private String moduleVersion;
     private String declaringClass;
     private String methodName;
     private String fileName;
@@ -48,7 +50,9 @@
 
     /**
      * Creates a stack trace element representing the specified execution
-     * point.
+     * point. The {@link #getModuleName module name} and {@link
+     * #getModuleVersion module version} of the stack trace element will
+     * be {@code null}.
      *
      * @param declaringClass the fully qualified name of the class containing
      *        the execution point represented by the stack trace element
@@ -68,6 +72,40 @@
      */
     public StackTraceElement(String declaringClass, String methodName,
                              String fileName, int lineNumber) {
+        this(null, null, declaringClass, methodName, fileName, lineNumber);
+    }
+
+    /**
+     * Creates a stack trace element representing the specified execution
+     * point.
+     *
+     * @param moduleName the module name if the class containing the
+     *        execution point represented by the stack trace is in a named
+     *        module; can be {@code null}
+     * @param moduleVersion the module version if the class containing the
+     *        execution point represented by the stack trace is in a named
+     *        module that has a version; can be {@code null}
+     * @param declaringClass the fully qualified name of the class containing
+     *        the execution point represented by the stack trace element
+     * @param methodName the name of the method containing the execution point
+     *        represented by the stack trace element
+     * @param fileName the name of the file containing the execution point
+     *        represented by the stack trace element, or {@code null} if
+     *        this information is unavailable
+     * @param lineNumber the line number of the source line containing the
+     *        execution point represented by this stack trace element, or
+     *        a negative number if this information is unavailable. A value
+     *        of -2 indicates that the method containing the execution point
+     *        is a native method
+     * @throws NullPointerException if {@code declaringClass} is {@code null}
+     *         or {@code methodName} is {@code null}
+     * @since 9
+     */
+    public StackTraceElement(String moduleName, String moduleVersion,
+                             String declaringClass, String methodName,
+                             String fileName, int lineNumber) {
+        this.moduleName     = moduleName;
+        this.moduleVersion  = moduleVersion;
         this.declaringClass = Objects.requireNonNull(declaringClass, "Declaring class is null");
         this.methodName     = Objects.requireNonNull(methodName, "Method name is null");
         this.fileName       = fileName;
@@ -106,6 +144,34 @@
     }
 
     /**
+     * Returns the module name of the module containing the execution point
+     * represented by this stack trace element.
+     *
+     * @return the module name of the {@code Module} containing the execution
+     *         point represented by this stack trace element; {@code null}
+     *         if the module name is not available.
+     * @since 9
+     * @see java.lang.reflect.Module#getName()
+     */
+    public String getModuleName() {
+        return moduleName;
+    }
+
+    /**
+     * Returns the module version of the module containing the execution point
+     * represented by this stack trace element.
+     *
+     * @return the module version of the {@code Module} containing the execution
+     *         point represented by this stack trace element; {@code null}
+     *         if the module version is not available.
+     * @since 9
+     * @see java.lang.module.ModuleDescriptor.Version
+     */
+    public String getModuleVersion() {
+        return moduleVersion;
+    }
+
+    /**
      * Returns the fully qualified name of the class containing the
      * execution point represented by this stack trace element.
      *
@@ -148,32 +214,42 @@
      * examples may be regarded as typical:
      * <ul>
      * <li>
-     *   {@code "MyClass.mash(MyClass.java:9)"} - Here, {@code "MyClass"}
-     *   is the <i>fully-qualified name</i> of the class containing the
-     *   execution point represented by this stack trace element,
+     *   {@code "MyClass.mash(my.module@9.0/MyClass.java:101)"} - Here,
+     *   {@code "MyClass"} is the <i>fully-qualified name</i> of the class
+     *   containing the execution point represented by this stack trace element,
      *   {@code "mash"} is the name of the method containing the execution
-     *   point, {@code "MyClass.java"} is the source file containing the
-     *   execution point, and {@code "9"} is the line number of the source
+     *   point, {@code "my.module"} is the module name, {@code "9.0"} is the
+     *   module version, and {@code "101"} is the line number of the source
      *   line containing the execution point.
      * <li>
-     *   {@code "MyClass.mash(MyClass.java)"} - As above, but the line
-     *   number is unavailable.
+     *   {@code "MyClass.mash(my.module@9.0/MyClass.java)"} - As above, but the
+     *   line number is unavailable.
+     * <li>
+     *   {@code "MyClass.mash(my.module@9.0/Unknown Source)"} - As above, but
+     *   neither the file name nor the line  number are available.
      * <li>
-     *   {@code "MyClass.mash(Unknown Source)"} - As above, but neither
-     *   the file name nor the line  number are available.
-     * <li>
-     *   {@code "MyClass.mash(Native Method)"} - As above, but neither
-     *   the file name nor the line  number are available, and the method
-     *   containing the execution point is known to be a native method.
+     *   {@code "MyClass.mash(my.module@9.0/Native Method)"} - As above, but
+     *   neither the file name nor the line  number are available, and the
+     *   method containing the execution point is known to be a native method.
      * </ul>
+     * If the execution point is not in a named module, {@code "my.module@9.0/"}
+     * will be omitted from the above.
+     *
      * @see    Throwable#printStackTrace()
      */
     public String toString() {
-        return getClassName() + "." + methodName +
-            (isNativeMethod() ? "(Native Method)" :
-             (fileName != null && lineNumber >= 0 ?
-              "(" + fileName + ":" + lineNumber + ")" :
-              (fileName != null ?  "("+fileName+")" : "(Unknown Source)")));
+        String mid = "";
+        if (moduleName != null) {
+            mid = moduleName;
+            if (moduleVersion != null)
+                mid += "@" + moduleVersion;
+            mid += "/";
+        }
+        return getClassName() + "." + methodName + "(" + mid +
+             (isNativeMethod() ? "Native Method)" :
+              (fileName != null && lineNumber >= 0 ?
+               fileName + ":" + lineNumber + ")" :
+                (fileName != null ?  ""+fileName+")" : "Unknown Source)")));
     }
 
     /**
@@ -184,6 +260,8 @@
      * <pre>{@code
      *     equals(a.getFileName(), b.getFileName()) &&
      *     a.getLineNumber() == b.getLineNumber()) &&
+     *     equals(a.getModuleName(), b.getModuleName()) &&
+     *     equals(a.getModuleVersion(), b.getModuleVersion()) &&
      *     equals(a.getClassName(), b.getClassName()) &&
      *     equals(a.getMethodName(), b.getMethodName())
      * }</pre>
@@ -202,6 +280,8 @@
             return false;
         StackTraceElement e = (StackTraceElement)obj;
         return e.declaringClass.equals(declaringClass) &&
+            Objects.equals(moduleName, e.moduleName) &&
+            Objects.equals(moduleVersion, e.moduleVersion) &&
             e.lineNumber == lineNumber &&
             Objects.equals(methodName, e.methodName) &&
             Objects.equals(fileName, e.fileName);
@@ -212,6 +292,8 @@
      */
     public int hashCode() {
         int result = 31*declaringClass.hashCode() + methodName.hashCode();
+        result = 31*result + Objects.hashCode(moduleName);
+        result = 31*result + Objects.hashCode(moduleVersion);
         result = 31*result + Objects.hashCode(fileName);
         result = 31*result + lineNumber;
         return result;
--- a/src/java.base/share/classes/java/lang/StackWalker.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/java/lang/StackWalker.java	Thu Mar 17 19:04:16 2016 +0000
@@ -170,15 +170,8 @@
          * Gets a {@code StackTraceElement} for this stack frame.
          *
          * @return {@code StackTraceElement} for this stack frame.
-         *
-         * */
-        public default StackTraceElement toStackTraceElement() {
-            int lineNumber = isNativeMethod() ? -2
-                                              : getLineNumber().orElse(-1);
-            return new StackTraceElement(getClassName(), getMethodName(),
-                                         getFileName().orElse(null),
-                                         lineNumber);
-        }
+         */
+        public StackTraceElement toStackTraceElement();
     }
 
     /**
--- a/src/java.base/share/classes/java/lang/System.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/java/lang/System.java	Thu Mar 17 19:04:16 2016 +0000
@@ -24,9 +24,23 @@
  */
 package java.lang;
 
-import java.io.*;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.Console;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
 import java.lang.reflect.Executable;
-import java.lang.annotation.Annotation;
+import java.lang.reflect.Layer;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Module;
+import java.net.URL;
 import java.security.AccessControlContext;
 import java.util.Properties;
 import java.util.PropertyPermission;
@@ -35,6 +49,8 @@
 import java.security.PrivilegedAction;
 import java.nio.channels.Channel;
 import java.nio.channels.spi.SelectorProvider;
+import java.util.stream.Stream;
+
 import java.util.Objects;
 import java.util.ResourceBundle;
 import java.util.function.Supplier;
@@ -51,6 +67,10 @@
 import jdk.internal.logger.LazyLoggers;
 import jdk.internal.logger.LocalizedLoggerWrapper;
 
+import jdk.internal.module.ModuleBootstrap;
+import jdk.internal.module.Modules;
+import jdk.internal.module.ServicesCatalog;
+
 /**
  * The <code>System</code> class contains several useful class fields
  * and methods. It cannot be instantiated.
@@ -65,7 +85,6 @@
  * @since   1.0
  */
 public final class System {
-
     /* register the natives via the static initializer.
      *
      * VM will invoke the initializeSystemClass method to complete
@@ -619,6 +638,24 @@
      * <code>getProperties</code> operation, it may choose to permit the
      * {@link #getProperty(String)} operation.
      *
+     * @implNote In addition to the standard system properties, the {@code
+     * java} launcher may create the Java Virtual Machine with system
+     * properties that have the following keys:
+     * <table summary="Shows property keys and associated values">
+     * <tr><th>Key</th>
+     *     <th>Description of Associated Value</th></tr>
+     * <tr><td>{@code jdk.module.path}</td>
+     *     <td>Application module path</td></tr>
+     * <tr><td>{@code jdk.upgrade.module.path}</td>
+     *     <td>The upgrade module path</td></tr>
+     * <tr><td>{@code jdk.module.main}</td>
+     *     <td>The module name of the initial/main module</td></tr>
+     * <tr><td>{@code jdk.module.main.class}</td>
+     *     <td>The main class name of the initial module</td></tr>
+     * </table>
+     * These properties may also be set by custom launchers that use the JNI
+     * invocation API to create the Java Virtual Machine.
+     *
      * @return     the system properties
      * @exception  SecurityException  if a security manager exists and its
      *             <code>checkPropertiesAccess</code> method doesn't allow access
@@ -1795,11 +1832,10 @@
         return new PrintStream(new BufferedOutputStream(fos, 128), true);
     }
 
-
     /**
      * Initialize the system class.  Called after thread initialization.
      */
-    private static void initializeSystemClass() {
+    private static void initPhase1() {
 
         // VM might invoke JNU_NewStringPlatform() to set those encoding
         // sensitive properties (user.home, user.name, boot.class.path, etc.)
@@ -1828,7 +1864,6 @@
         // certain system properties that are not intended for public access.
         VM.saveAndRemoveProperties(props);
 
-
         lineSeparator = props.getProperty("line.separator");
         VersionProps.init();
 
@@ -1862,9 +1897,81 @@
 
         // Subsystems that are invoked during initialization can invoke
         // VM.isBooted() in order to avoid doing things that should
-        // wait until the application class loader has been set up.
+        // wait until the VM is fully initialized. The initialization level
+        // is incremented from 0 to 1 here to indicate the first phase of
+        // initialization has completed.
         // IMPORTANT: Ensure that this remains the last initialization action!
-        VM.booted();
+        VM.initLevel(1);
+    }
+
+    // @see #initPhase2()
+    private static Layer bootLayer;
+
+    /*
+     * Invoked by VM.  Phase 2 module system initialization.
+     * Only classes in java.base can be loaded in this phase.
+     */
+    private static void initPhase2() {
+        // initialize the module system
+        System.bootLayer = ModuleBootstrap.boot();
+
+        // base module needs to be loose (CODETOOLS-7901619)
+        Module base = Object.class.getModule();
+        Modules.addReads(base, null);
+
+        // module system initialized
+        VM.initLevel(2);
+    }
+
+    /*
+     * Invoked by VM.  Phase 3 is the final system initialization:
+     * 1. set security manager
+     * 2. set system class loader
+     * 3. set TCCL
+     *
+     * This method must be called after the module system initialization.
+     * The security manager and system class loader may be custom class from
+     * the application classpath or modulepath.
+     */
+    private static void initPhase3() {
+        // set security manager
+        String cn = System.getProperty("java.security.manager");
+        if (cn != null) {
+            if (cn.isEmpty() || "default".equals(cn)) {
+                System.setSecurityManager(new SecurityManager());
+            } else {
+                try {
+                    Class<?> c = Class.forName(cn, false, ClassLoader.getBuiltinAppClassLoader());
+                    Constructor<?> ctor = c.getConstructor();
+                    // Must be a public subclass of SecurityManager with
+                    // a public no-arg constructor
+                    if (!SecurityManager.class.isAssignableFrom(c) ||
+                            !Modifier.isPublic(c.getModifiers()) ||
+                            !Modifier.isPublic(ctor.getModifiers())) {
+                        throw new Error("Could not create SecurityManager: " + ctor.toString());
+                    }
+                    // custom security manager implementation may be in unnamed module
+                    // or a named module but non-exported package
+                    ctor.setAccessible(true);
+                    SecurityManager sm = (SecurityManager) ctor.newInstance();
+                    System.setSecurityManager(sm);
+                } catch (Exception e) {
+                    throw new Error("Could not create SecurityManager", e);
+                }
+            }
+        }
+
+        // initializing the system class loader
+        VM.initLevel(3);
+
+        // system class loader initialized
+        ClassLoader scl = ClassLoader.initSystemClassLoader();
+
+        // set TCCL
+        Thread.currentThread().setContextClassLoader(scl);
+
+        // system is fully initialized
+        VM.initLevel(4);
     }
 
     private static void setJavaLangAccess() {
@@ -1910,6 +2017,27 @@
             public void invokeFinalize(Object o) throws Throwable {
                 o.finalize();
             }
+            public Layer getBootLayer() {
+                return bootLayer;
+            }
+            public ServicesCatalog getServicesCatalog(ClassLoader cl) {
+                return cl.getServicesCatalog();
+            }
+            public ServicesCatalog createOrGetServicesCatalog(ClassLoader cl) {
+                return cl.createOrGetServicesCatalog();
+            }
+            public Class<?> findBootstrapClassOrNull(ClassLoader cl, String name) {
+                return cl.findBootstrapClassOrNull(name);
+            }
+            public URL findResource(ClassLoader cl, String mn, String name) throws IOException {
+                return cl.findResource(mn, name);
+            }
+            public Stream<Package> packages(ClassLoader cl) {
+                return cl.packages();
+            }
+            public Package definePackage(ClassLoader cl, String name, Module module) {
+                return cl.definePackage(name, module);
+            }
             public String fastUUID(long lsb, long msb) {
                 return Long.fastUUID(lsb, msb);
             }
--- a/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java	Thu Mar 17 19:04:16 2016 +0000
@@ -788,7 +788,8 @@
         static void setSpeciesDataToConcreteBMHClass(Class<? extends BoundMethodHandle> cbmh, SpeciesData speciesData) {
             try {
                 Field F_SPECIES_DATA = cbmh.getDeclaredField("SPECIES_DATA");
-                assert F_SPECIES_DATA.getDeclaredAnnotation(Stable.class) != null;
+                // ## FIXME: annotation parser can't create proxy classes until module system is fully initialzed
+                // assert F_SPECIES_DATA.getDeclaredAnnotation(Stable.class) != null;
                 F_SPECIES_DATA.set(null, speciesData);
             } catch (ReflectiveOperationException ex) {
                 throw newInternalError(ex);
--- a/src/java.base/share/classes/java/lang/invoke/MemberName.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/MemberName.java	Thu Mar 17 19:04:16 2016 +0000
@@ -33,6 +33,7 @@
 import java.lang.reflect.Method;
 import java.lang.reflect.Member;
 import java.lang.reflect.Modifier;
+import java.lang.reflect.Module;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -475,8 +476,9 @@
 
     /** Utility method to query whether this member is accessible from a given lookup class. */
     public boolean isAccessibleFrom(Class<?> lookupClass) {
+        int mode = (ALL_ACCESS|MethodHandles.Lookup.PACKAGE|MethodHandles.Lookup.MODULE);
         return VerifyAccess.isMemberAccessible(this.getDeclaringClass(), this.getDeclaringClass(), flags,
-                                               lookupClass, ALL_ACCESS|MethodHandles.Lookup.PACKAGE);
+                                               lookupClass, mode);
     }
 
     /** Initialize a query.   It is not resolved. */
@@ -851,7 +853,20 @@
 
     public IllegalAccessException makeAccessException(String message, Object from) {
         message = message + ": "+ toString();
-        if (from != null)  message += ", from " + from;
+        if (from != null)  {
+            if (from == MethodHandles.publicLookup()) {
+                message += ", from public Lookup";
+            } else {
+                Module m;
+                if (from instanceof MethodHandles.Lookup) {
+                    MethodHandles.Lookup lookup = (MethodHandles.Lookup)from;
+                    m = lookup.lookupClass().getModule();
+                } else {
+                    m = from.getClass().getModule();
+                }
+                message += ", from " + from + " (" + m + ")";
+            }
+        }
         return new IllegalAccessException(message);
     }
     private String message() {
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1191,14 +1191,9 @@
                             Class<T> tClass = T.class;
                             String tName = tClass.getName();
                             String tResource = tName.substring(tName.lastIndexOf('.')+1)+".class";
-                            java.net.URLConnection uconn = tClass.getResource(tResource).openConnection();
-                            int len = uconn.getContentLength();
-                            byte[] bytes = new byte[len];
-                            try (java.io.InputStream str = uconn.getInputStream()) {
-                                int nr = str.read(bytes);
-                                if (nr != len)  throw new java.io.IOException(tResource);
+                            try (java.io.InputStream in = tClass.getResourceAsStream(tResource)) {
+                                values[0] = in.readAllBytes();
                             }
-                            values[0] = bytes;
                         } catch (java.io.IOException ex) {
                             throw new InternalError(ex);
                         }
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Thu Mar 17 19:04:16 2016 +0000
@@ -26,7 +26,13 @@
 package java.lang.invoke;
 
 import java.lang.reflect.*;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.List;
+import java.util.Arrays;
+import java.util.Objects;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 
 import sun.invoke.util.ValueConversions;
 import sun.invoke.util.VerifyAccess;
@@ -44,6 +50,9 @@
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.Opcodes;
+
 /**
  * This class consists exclusively of static methods that operate on or return
  * method handles. They fall into several categories:
@@ -94,18 +103,16 @@
 
     /**
      * Returns a {@link Lookup lookup object} which is trusted minimally.
-     * It can only be used to create method handles to
-     * publicly accessible fields and methods.
+     * It can only be used to create method handles to public members in
+     * public classes in packages that are exported unconditionally.
      * <p>
-     * As a matter of pure convention, the {@linkplain Lookup#lookupClass lookup class}
-     * of this lookup object will be {@link java.lang.Object}.
+     * For now, the {@linkplain Lookup#lookupClass lookup class} of this lookup
+     * object is in an unnamed module.
      *
      * <p style="font-size:smaller;">
      * <em>Discussion:</em>
      * The lookup class can be changed to any other class {@code C} using an expression of the form
      * {@link Lookup#in publicLookup().in(C.class)}.
-     * Since all classes have equal access to public names,
-     * such a change would confer no new access rights.
      * A public lookup object is always subject to
      * <a href="MethodHandles.Lookup.html#secmgr">security manager checks</a>.
      * Also, it cannot access
@@ -113,7 +120,15 @@
      * @return a lookup object which is trusted minimally
      */
     public static Lookup publicLookup() {
-        return Lookup.PUBLIC_LOOKUP;
+        // During VM startup then only classes in the java.base module can be
+        // loaded and linked. This is because java.base exports aren't setup until
+        // the module system is initialized, hence types in the unnamed module
+        // (or any named module) can't link to java/lang/Object.
+        if (!jdk.internal.misc.VM.isModuleSystemInited()) {
+            return new Lookup(Object.class, Lookup.PUBLIC);
+        } else {
+            return LookupHelper.PUBLIC_LOOKUP;
+        }
     }
 
     /**
@@ -386,7 +401,7 @@
      * to a subset of members normally accessible to the lookup class.
      * For example, the {@link MethodHandles#publicLookup publicLookup}
      * method produces a lookup object which is only allowed to access
-     * public members in public classes.
+     * public members in public classes of exported packages.
      * The caller sensitive method {@link MethodHandles#lookup lookup}
      * produces a lookup object with full capabilities relative to
      * its caller class, to emulate all supported bytecode behaviors.
@@ -558,12 +573,24 @@
          */
         public static final int PACKAGE = Modifier.STATIC;
 
-        private static final int ALL_MODES = (PUBLIC | PRIVATE | PROTECTED | PACKAGE);
+        /** A single-bit mask representing {@code module} access (default access),
+         *  which may contribute to the result of {@link #lookupModes lookupModes}.
+         *  The value is {@code 0x10}, which does not correspond meaningfully to
+         *  any particular {@linkplain java.lang.reflect.Modifier modifier bit}.
+         *  In conjunction with the {@code PUBLIC} modifier bit, a {@code Lookup}
+         *  with this lookup mode can access all public types in the module of the
+         *  lookup class and public types in packages exported by other modules
+         *  to the module of the lookup class.
+         *  @since 9
+         */
+        public static final int MODULE = PACKAGE << 1;
+
+        private static final int ALL_MODES = (PUBLIC | PRIVATE | PROTECTED | PACKAGE | MODULE);
         private static final int TRUSTED   = -1;
 
         private static int fixmods(int mods) {
-            mods &= (ALL_MODES - PACKAGE);
-            return (mods != 0) ? mods : PACKAGE;
+            mods &= (ALL_MODES - PACKAGE - MODULE);
+            return (mods != 0) ? mods : (PACKAGE | MODULE);
         }
 
         /** Tells which class is performing the lookup.  It is this class against
@@ -589,11 +616,14 @@
          *  {@linkplain #PUBLIC PUBLIC (0x01)},
          *  {@linkplain #PRIVATE PRIVATE (0x02)},
          *  {@linkplain #PROTECTED PROTECTED (0x04)},
-         *  and {@linkplain #PACKAGE PACKAGE (0x08)}.
+         *  {@linkplain #PACKAGE PACKAGE (0x08)},
+         *  and {@linkplain #MODULE MODULE (0x10)}.
          *  <p>
          *  A freshly-created lookup object
          *  on the {@linkplain java.lang.invoke.MethodHandles#lookup() caller's class}
-         *  has all possible bits set, since the caller class can access all its own members.
+         *  has all possible bits set, since the caller class can access all its own members,
+         *  all public types in the caller's module, and all public types in packages exported
+         *  by other modules to the caller's module.
          *  A lookup object on a new lookup class
          *  {@linkplain java.lang.invoke.MethodHandles.Lookup#in created from a previous lookup object}
          *  may have some mode bits set to zero.
@@ -630,6 +660,12 @@
          * However, the resulting {@code Lookup} object is guaranteed
          * to have no more access capabilities than the original.
          * In particular, access capabilities can be lost as follows:<ul>
+         * <li>If the lookup class for this {@code Lookup} is not in a named module,
+         * and the new lookup class is in a named module {@code M}, then no members in
+         * {@code M}'s non-exported packages will be accessible.
+         * <li>If the lookup for this {@code Lookup} is in a named module, and the
+         * new lookup class is in a different module {@code M}, then no members, not even
+         * public members in {@code M}'s exported packages, will be accessible.
          * <li>If the new lookup class differs from the old one,
          * protected members will not be accessible by virtue of inheritance.
          * (Protected members may continue to be accessible because of package sharing.)
@@ -652,7 +688,17 @@
                 return new Lookup(requestedLookupClass, ALL_MODES);
             if (requestedLookupClass == this.lookupClass)
                 return this;  // keep same capabilities
+
             int newModes = (allowedModes & (ALL_MODES & ~PROTECTED));
+            if (!VerifyAccess.isSameModule(this.lookupClass, requestedLookupClass)) {
+                // Allowed to teleport from an unnamed to a named module but resulting
+                // Lookup has no access to module private members
+                if (this.lookupClass.getModule().isNamed()) {
+                    newModes = 0;
+                } else {
+                    newModes &= ~MODULE;
+                }
+            }
             if ((newModes & PACKAGE) != 0
                 && !VerifyAccess.isSamePackage(this.lookupClass, requestedLookupClass)) {
                 newModes &= ~(PACKAGE|PRIVATE);
@@ -668,6 +714,7 @@
                 // No permissions.
                 newModes = 0;
             }
+
             checkUnprivilegedlookupClass(requestedLookupClass, newModes);
             return new Lookup(requestedLookupClass, newModes);
         }
@@ -675,12 +722,6 @@
         // Make sure outer class is initialized first.
         static { IMPL_NAMES.getClass(); }
 
-        /** Version of lookup which is trusted minimally.
-         *  It can only be used to create method handles to
-         *  publicly accessible members.
-         */
-        static final Lookup PUBLIC_LOOKUP = new Lookup(Object.class, PUBLIC);
-
         /** Package-private version of lookup which is trusted. */
         static final Lookup IMPL_LOOKUP = new Lookup(Object.class, TRUSTED);
 
@@ -708,12 +749,13 @@
          * allowed access, and is chosen as follows:
          * <ul>
          * <li>If no access is allowed, the suffix is "/noaccess".
-         * <li>If only public access is allowed, the suffix is "/public".
-         * <li>If only public and package access are allowed, the suffix is "/package".
-         * <li>If only public, package, and private access are allowed, the suffix is "/private".
+         * <li>If only public access to types in exported packages is allowed, the suffix is "/public".
+         * <li>If only public and module access are allowed, the suffix is "/module".
+         * <li>If only public, module and package access are allowed, the suffix is "/package".
+         * <li>If only public, module, package, and private access are allowed, the suffix is "/private".
          * </ul>
          * If none of the above cases apply, it is the case that full
-         * access (public, package, private, and protected) is allowed.
+         * access (public, module, package, private, and protected) is allowed.
          * In this case, no suffix is added.
          * This is true only of an object obtained originally from
          * {@link java.lang.invoke.MethodHandles#lookup MethodHandles.lookup}.
@@ -735,7 +777,9 @@
                 return cname + "/noaccess";
             case PUBLIC:
                 return cname + "/public";
-            case PUBLIC|PACKAGE:
+            case PUBLIC|MODULE:
+                return cname + "/module";
+            case PUBLIC|MODULE|PACKAGE:
                 return cname + "/package";
             case ALL_MODES & ~PROTECTED:
                 return cname + "/private";
@@ -1455,7 +1499,7 @@
             Objects.requireNonNull(refc);
             Class<?> caller = lookupClassOrNull();
             if (caller != null && !VerifyAccess.isClassAccessible(refc, caller, allowedModes))
-                throw new MemberName(refc).makeAccessException("symbolic reference class is not public", this);
+                throw new MemberName(refc).makeAccessException("symbolic reference class is not accessible", this);
         }
 
         /** Check name for an illegal leading "&lt;" character. */
@@ -1584,8 +1628,6 @@
             if (Modifier.isFinal(mods) &&
                     MethodHandleNatives.refKindIsSetter(refKind))
                 throw m.makeAccessException("unexpected set of a final field", this);
-            if (Modifier.isPublic(mods) && Modifier.isPublic(refc.getModifiers()) && allowedModes != 0)
-                return;  // common case
             int requestedModes = fixmods(mods);  // adjust 0 => PACKAGE
             if ((requestedModes & allowedModes) != 0) {
                 if (VerifyAccess.isMemberAccessible(refc, m.getDeclaringClass(),
@@ -1615,7 +1657,7 @@
             if (!classOK)
                 return "class is not public";
             if (Modifier.isPublic(mods))
-                return "access to public member failed";  // (how?)
+                return "access to public member failed";  // (how?, module not readable?)
             if (Modifier.isPrivate(mods))
                 return "member is private";
             if (Modifier.isProtected(mods))
@@ -1877,6 +1919,61 @@
     }
 
     /**
+     * Helper class used to lazily create PUBLIC_LOOKUP with a lookup class
+     * in an <em>unnamed module</em>.
+     *
+     * @see Lookup#publicLookup
+     */
+    private static class LookupHelper {
+        private static final String UNNAMED = "Unnamed";
+        private static final String OBJECT  = "java/lang/Object";
+
+        private static Class<?> createClass() {
+            try {
+                ClassWriter cw = new ClassWriter(0);
+                cw.visit(Opcodes.V1_8,
+                         Opcodes.ACC_FINAL + Opcodes.ACC_SUPER,
+                         UNNAMED,
+                         null,
+                         OBJECT,
+                         null);
+                cw.visitSource(UNNAMED, null);
+                cw.visitEnd();
+                byte[] bytes = cw.toByteArray();
+                ClassLoader loader = new ClassLoader(null) {
+                    @Override
+                    protected Class<?> findClass(String cn) throws ClassNotFoundException {
+                        if (cn.equals(UNNAMED))
+                            return super.defineClass(UNNAMED, bytes, 0, bytes.length);
+                        throw new ClassNotFoundException(cn);
+                    }
+                };
+                return loader.loadClass(UNNAMED);
+            } catch (Exception e) {
+                throw new InternalError(e);
+            }
+        }
+
+        private static final Class<?> PUBLIC_LOOKUP_CLASS;
+        static {
+            PrivilegedAction<Class<?>> pa = new PrivilegedAction<Class<?>>() {
+                public Class<?> run() {
+                    return createClass();
+                }
+            };
+            PUBLIC_LOOKUP_CLASS = AccessController.doPrivileged(pa);
+        }
+
+        /**
+         * Lookup that is trusted minimally. It can only be used to create
+         * method handles to publicly accessible members in exported packages.
+         *
+         * @see MethodHandles#publicLookup
+         */
+        static final Lookup PUBLIC_LOOKUP = new Lookup(PUBLIC_LOOKUP_CLASS, Lookup.PUBLIC);
+    }
+
+    /**
      * Produces a method handle giving read access to elements of an array.
      * The type of the method handle will have a return type of the array's
      * element type.  Its first argument will be the array type,
--- a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java	Thu Mar 17 19:04:16 2016 +0000
@@ -697,8 +697,8 @@
             case BC_SB_SIZED:
             case BC_SB_SIZED_EXACT: {
                 if (CACHE_ENABLE) {
-                    Package pkg = hostClass.getPackage();
-                    return (pkg != null ? pkg.getName().replace('.', '/') + "/" : "") + "Stubs$$StringConcat";
+                    String pkgName = hostClass.getPackageName();
+                    return (pkgName != null && !pkgName.isEmpty() ? pkgName.replace('.', '/') + "/" : "") + "Stubs$$StringConcat";
                 } else {
                     return hostClass.getName().replace('.', '/') + "$$StringConcat";
                 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/module/Configuration.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,431 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.module;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * The configuration that is the result of resolution or resolution with
+ * service binding.
+ *
+ * <h2><a name="resolution">Resolution</a></h2>
+ *
+ * <p> Resolution is the process of computing the transitive closure of a set
+ * of root modules over a set of observable modules by resolving the
+ * dependences expressed by {@code requires} clauses.
+ *
+ * The <em>dependence graph</em> is augmented with edges that take account of
+ * implicitly declared dependences ({@code requires public}) to create a
+ * <em>readability graph</em>. A {@code Configuration} encapsulates the
+ * resulting graph of {@link ResolvedModule resolved modules}.
+ *
+ * <p> Suppose we have the following observable modules: </p>
+ * <pre> {@code
+ *     module m1 { requires m2; }
+ *     module m2 { requires public m3; }
+ *     module m3 { }
+ *     module m4 { }
+ * } </pre>
+ *
+ * <p> If the module {@code m1} is resolved then the resulting configuration
+ * contains three modules ({@code m1}, {@code m2}, {@code m3}). The edges in
+ * its readability graph are: </p>
+ * <pre> {@code
+ *     m1 --> m2  (meaning m1 reads m2)
+ *     m1 --> m3
+ *     m2 --> m3
+ * } </pre>
+ *
+ * <p> Resolution is an additive process. When computing the transitive closure
+ * then the dependence relation may include dependences on modules in parent
+ * configurations. The result is a <em>relative configuration</em> that is
+ * relative to a parent configuration and where the readability graph may have
+ * edges from modules in the configuration to modules in a parent configuration.
+ * </p>
+ *
+ * <p> Suppose we have the following observable modules: </p>
+ * <pre> {@code
+ *     module m1 { requires m2; requires java.xml; }
+ *     module m2 { }
+ * } </pre>
+ *
+ * <p> If module {@code m1} is resolved with the configuration for the {@link
+ * java.lang.reflect.Layer#boot() boot} layer as the parent then the resulting
+ * configuration contains two modules ({@code m1}, {@code m2}). The edges in
+ * its readability graph are:
+ * <pre> {@code
+ *     m1 --> m2
+ *     m1 --> java.xml
+ * } </pre>
+ * where module {@code java.xml} is in the parent configuration. For
+ * simplicity, this example omits the implicitly declared dependence on the
+ * {@code java.base} module.
+ *
+ * <a name="automaticmoduleresolution"></a>
+ * <p> {@link ModuleDescriptor#isAutomatic() Automatic} modules receive special
+ * treatment during resolution. Each automatic module is resolved so that it
+ * reads all other modules in the configuration and all parent configurations.
+ * Each automatic module is also resolved as if it {@code requires public} all
+ * other automatic modules in the configuration (and all automatic modules in
+ * parent configurations). </p>
+
+ * <h2><a name="servicebinding">Service binding</a></h2>
+ *
+ * <p> Service binding is the process of augmenting a graph of resolved modules
+ * from the set of observable modules induced by the service-use dependence
+ * ({@code uses} and {@code provides} clauses). Any module that was not
+ * previously in the graph requires resolution to compute its transitive
+ * closure. Service binding is an iterative process in that adding a module
+ * that satisfies some service-use dependence may introduce new service-use
+ * dependences. </p>
+ *
+ * <p> Suppose we have the following observable modules: </p>
+ * <pre> {@code
+ *     module m1 { exports p; uses p.S; }
+ *     module m2 { requires m1; provides p.S with p2.S2; }
+ *     module m3 { requires m1; requires m4; provides p.S with p3.S3; }
+ *     module m4 { }
+ * } </pre>
+ *
+ * <p> If the module {@code m1} is resolved then the resulting graph of modules
+ * has one module ({@code m1}). If the graph is augmented with modules induced
+ * by the service-use dependence relation then the configuration will contain
+ * four modules ({@code m1}, {@code m2}, {@code m3}, {@code m4}). The edges in
+ * its readability graph are: </p>
+ * <pre> {@code
+ *     m2 --> m1
+ *     m3 --> m1
+ *     m3 --> m4
+ * } </pre>
+ * <p> The edges in the conceptual service-use graph are: </p>
+ * <pre> {@code
+ *     m1 --> m2  (meaning m1 uses a service that is provided by m2)
+ *     m1 --> m3
+ * } </pre>
+ *
+ * <p> If this configuration is instantiated as a {@code Layer}, and if code in
+ * module {@code m1} uses {@link java.util.ServiceLoader ServiceLoader} to
+ * iterate over implementations of {@code p.S.class}, then it will iterate over
+ * an instance of {@code p2.S2} and {@code p3.S3}. </p>
+ *
+ * <h3> Example </h3>
+ *
+ * <p> The following example uses the {@code resolveRequires} method to resolve
+ * a module named <em>myapp</em> with the configuration for the boot layer as
+ * the parent configuration. It prints the name of each resolved module and
+ * the names of the modules that each module reads. </p>
+ *
+ * <pre>{@code
+ *    ModuleFinder finder = ModuleFinder.of(dir1, dir2, dir3);
+ *
+ *    Configuration parent = Layer.boot().configuration();
+ *
+ *    Configuration cf = parent.resolveRequires(finder,
+ *                                              ModuleFinder.empty(),
+ *                                              Set.of("myapp"));
+ *    cf.modules().forEach(m -> {
+ *        System.out.format("%s -> %s%n",
+ *            m.name(),
+ *            m.reads().stream()
+ *                .map(ResolvedModule::name)
+ *                .collect(Collectors.joining(", ")));
+ *    });
+ * }</pre>
+ *
+ * @since 9
+ * @see java.lang.reflect.Layer
+ */
+public final class Configuration {
+
+    // @see Configuration#empty()
+    private static final Configuration EMPTY_CONFIGURATION = new Configuration();
+
+    private final Configuration parent;
+
+    private final Map<ResolvedModule, Set<ResolvedModule>> graph;
+    private final Set<ResolvedModule> modules;
+    private final Map<String, ResolvedModule> nameToModule;
+
+    private Configuration() {
+        this.parent = null;
+        this.graph = Collections.emptyMap();
+        this.modules = Collections.emptySet();
+        this.nameToModule = Collections.emptyMap();
+    }
+
+    private Configuration(Configuration parent, Resolver resolver) {
+        Map<ResolvedModule, Set<ResolvedModule>> graph = resolver.finish(this);
+
+        Map<String, ResolvedModule> nameToModule = new HashMap<>();
+        for (ResolvedModule resolvedModule : graph.keySet()) {
+            nameToModule.put(resolvedModule.name(), resolvedModule);
+        }
+
+        this.parent = parent;
+        this.graph = graph;
+        this.modules = Collections.unmodifiableSet(graph.keySet());
+        this.nameToModule = Collections.unmodifiableMap(nameToModule);
+    }
+
+
+    /**
+     * Resolves a collection of root modules, with this configuration as its
+     * parent, to create a new configuration.
+     *
+     * <p> Each root module is located using the given {@code before} module
+     * finder. If a module is not found then it is located in the parent
+     * configuration as if by invoking the {@link #findModule(String)
+     * findModule} method. If not found then the module is located using the
+     * given {@code after} module finder. The same search order is used to
+     * locate transitive dependences. Root modules or dependences that are
+     * located in a parent configuration are resolved no further and are not
+     * included in the resulting configuration. </p>
+     *
+     * <p> When all modules have been resolved then the resulting dependency
+     * graph is checked to ensure that it does not contain cycles. A
+     * readability graph is constructed and then, in conjunction with the
+     * module exports and service use, checked for consistency. </p>
+     *
+     * <p> Resolution and the (post-resolution) consistency checks may fail for
+     * following reasons: </p>
+     *
+     * <ul>
+     *     <li><p> A root module, or a direct or transitive dependency, is not
+     *     found. </p></li>
+     *
+     *     <li><p> An error occurs when attempting to find a module.
+     *     Possible errors include I/O errors, errors detected parsing a module
+     *     descriptor ({@code module-info.class}) or two versions of the same
+     *     module are found in the same directory. </p></li>
+     *
+     *     <li><p> A cycle is detected, say where module {@code m1} requires
+     *     module {@code m2} and {@code m2} requires {@code m1}. </p></li>
+     *
+     *     <li><p> Two or more modules in the configuration export the same
+     *     package to a module that reads both. This includes the case where a
+     *     module {@code M} containing package {@code p} reads another module
+     *     that exports {@code p} to {@code M}. </p></li>
+     *
+     *     <li><p> A module {@code M} declares that it "{@code uses p.S}" or
+     *     "{@code provides p.S with ...}" but package {@code p} is neither in
+     *     module {@code M} nor exported to {@code M} by any module that
+     *     {@code M} reads. </p></li>
+     *
+     *     <li><p> A module {@code M} declares that it
+     *     "{@code provides ... with q.T}" but package {@code q} is not in
+     *     module {@code M}. </p></li>
+     *
+     *     <li><p> Two or more modules in the configuration are specific to
+     *     different {@link ModuleDescriptor#osName() operating systems},
+     *     {@link ModuleDescriptor#osArch() architectures}, or {@link
+     *     ModuleDescriptor#osVersion() versions}. </p></li>
+     *
+     *     <li><p> Other implementation specific checks, for example referential
+     *     integrity checks to ensure that different versions of tighly coupled
+     *     modules cannot be combined in the same configuration. </p></li>
+     *
+     * </ul>
+     *
+     * @param  before
+     *         The <em>before</em> module finder to find modules
+     * @param  after
+     *         The <em>after</em> module finder to locate modules when not
+     *         located by the {@code before} module finder or in parent
+     *         configurations
+     * @param  roots
+     *         The possibly-empty collection of module names of the modules
+     *         to resolve
+     *
+     * @return The configuration that is the result of resolving the given
+     *         root modules
+     *
+     * @throws ResolutionException
+     *         If resolution or the post-resolution checks fail for any of the
+     *         reasons listed
+     * @throws SecurityException
+     *         If locating a module is denied by the security manager
+     */
+    public Configuration resolveRequires(ModuleFinder before,
+                                         ModuleFinder after,
+                                         Collection<String> roots)
+    {
+        Objects.requireNonNull(before);
+        Objects.requireNonNull(after);
+        Objects.requireNonNull(roots);
+
+        Resolver resolver = new Resolver(before, this, after);
+        resolver.resolveRequires(roots);
+
+        return new Configuration(this, resolver);
+    }
+
+
+    /**
+     * Resolves a collection of root modules, with service binding, and with
+     * this configuration as its parent, to create a new configuration.
+     *
+     * <p> This method works exactly as specified by {@link #resolveRequires
+     * resolveRequires} except that the graph of resolved modules is augmented
+     * with modules induced by the service-use dependence relation. </p>
+     *
+     * <p> More specifically, the root modules are resolved as if by calling
+     * {@code resolveRequires}. The resolved modules, and all modules in the
+     * parent configurations, with {@link ModuleDescriptor#uses() service
+     * dependences} are then examined. All modules found by the given module
+     * finders that {@link ModuleDescriptor#provides() provide} an
+     * implementation of one or more of the service types are added to the
+     * module graph and then resolved as if by calling the {@code
+     * resolveRequires} method. Adding modules to the module graph may
+     * introduce new service-use dependences and so the process works
+     * iteratively until no more modules are added. </p>
+     *
+     * <p> As service binding involves resolution then it may fail with {@link
+     * ResolutionException} for exactly the same reasons specified in
+     * {@code resolveRequires}.  </p>
+     *
+     * @param  before
+     *         The <em>before</em> module finder to find modules
+     * @param  after
+     *         The <em>after</em> module finder to locate modules when not
+     *         located by the {@code before} module finder or in parent
+     *         configurations
+     * @param  roots
+     *         The possibly-empty collection of module names of the modules
+     *         to resolve
+     *
+     * @return The configuration that is the result of resolving the given
+     *         root modules
+     *
+     * @throws ResolutionException
+     *         If resolution or the post-resolution checks fail for any of the
+     *         reasons listed
+     * @throws SecurityException
+     *         If locating a module is denied by the security manager
+     */
+    public Configuration resolveRequiresAndUses(ModuleFinder before,
+                                                ModuleFinder after,
+                                                Collection<String> roots)
+    {
+        Objects.requireNonNull(before);
+        Objects.requireNonNull(after);
+        Objects.requireNonNull(roots);
+
+        Resolver resolver = new Resolver(before, this, after);
+        resolver.resolveRequires(roots).resolveUses();
+
+        return new Configuration(this, resolver);
+    }
+
+
+    /**
+     * Returns the <em>empty</em> configuration. The empty configuration does
+     * not contain any modules and does not have a parent.
+     *
+     * @return The empty configuration
+     */
+    public static Configuration empty() {
+        return EMPTY_CONFIGURATION;
+    }
+
+
+    /**
+     * Returns this configuration's parent unless this is the {@linkplain #empty
+     * empty configuration}, which has no parent.
+     *
+     * @return This configuration's parent
+     */
+    public Optional<Configuration> parent() {
+        return Optional.ofNullable(parent);
+    }
+
+
+    /**
+     * Returns an immutable set of the resolved modules in this configuration.
+     *
+     * @return A possibly-empty unmodifiable set of the resolved modules
+     *         in this configuration
+     */
+    public Set<ResolvedModule> modules() {
+        return modules;
+    }
+
+
+    /**
+     * Finds a resolved module in this configuration, or if not in this
+     * configuration, the {@linkplain #parent parent} configurations.
+     *
+     * @param  name
+     *         The module name of the resolved module to find
+     *
+     * @return The resolved module with the given name or an empty {@code
+     *         Optional} if there isn't a module with this name in this
+     *         configuration or any parent configuration
+     */
+    public Optional<ResolvedModule> findModule(String name) {
+        Objects.requireNonNull(name);
+        if (parent == null)
+            return Optional.empty();
+        ResolvedModule m = nameToModule.get(name);
+        if (m != null)
+            return Optional.of(m);
+        return parent().flatMap(x -> x.findModule(name));
+    }
+
+
+    Set<ModuleDescriptor> descriptors() {
+        if (modules.isEmpty()) {
+            return Collections.emptySet();
+        } else {
+            return modules.stream()
+                    .map(ResolvedModule::reference)
+                    .map(ModuleReference::descriptor)
+                    .collect(Collectors.toSet());
+        }
+    }
+
+    Set<ResolvedModule> reads(ResolvedModule m) {
+        return Collections.unmodifiableSet(graph.get(m));
+    }
+
+    /**
+     * Returns a string describing this configuration.
+     *
+     * @return A string describing this configuration
+     */
+    @Override
+    public String toString() {
+        return modules().stream()
+                .map(ResolvedModule::name)
+                .collect(Collectors.joining(", "));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/module/Dependence.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.module;
+
+import java.util.*;
+import java.util.stream.*;
+
+
+class Dependence {
+
+    private Dependence() { }
+
+    static <T> Stream<String> toStringStream(Set<T> s) {
+        return s.stream().map(e -> e.toString().toLowerCase());
+    }
+
+    static <M> String toString(Set<M> mods, String what) {
+        return (Stream.concat(toStringStream(mods), Stream.of(what)))
+                      .collect(Collectors.joining(" "));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/module/FindException.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.module;
+
+/**
+ * Thrown by module finders when finding a module fails.
+ *
+ * @see ModuleFinder
+ * @since 9
+ */
+
+public class FindException extends RuntimeException {
+    private static final long serialVersionUID = -5817081036963388391L;
+
+    /**
+     * Constructs a {@code FindException} with no detail message.
+     */
+    public FindException() {
+    }
+
+    /**
+     * Constructs a {@code FindException} with the given detail
+     * message.
+     *
+     * @param msg
+     *        The detail message; can be {@code null}
+     */
+    public FindException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Constructs a {@code FindException} with the given cause.
+     *
+     * @param cause
+     *        The cause; can be {@code null}
+     */
+    public FindException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * Constructs a {@code FindException} with the given detail message
+     * and cause.
+     *
+     * @param msg
+     *        The detail message; can be {@code null}
+     * @param cause
+     *        The cause; can be {@code null}
+     */
+    public FindException(String msg, Throwable cause) {
+        super(msg, cause);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/module/InvalidModuleDescriptorException.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.module;
+
+/**
+ * Thrown when reading a module descriptor and the module descriptor is found
+ * to be malformed or otherwise cannot be interpreted as a module descriptor.
+ *
+ * @see ModuleDescriptor#read
+ * @since 9
+ */
+public class InvalidModuleDescriptorException extends RuntimeException {
+    private static final long serialVersionUID = 4863390386809347380L;
+
+    /**
+     * Constructs an {@code InvalidModuleDescriptorException} with no detail
+     * message.
+     */
+    public InvalidModuleDescriptorException() {
+    }
+
+    /**
+     * Constructs an {@code InvalidModuleDescriptorException} with the
+     * specified detail message.
+     *
+     * @param msg
+     *        The detail message; can be {@code null}
+     */
+    public InvalidModuleDescriptorException(String msg) {
+        super(msg);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,1996 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.module;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Supplier;
+
+import static jdk.internal.module.Checks.*;
+import static java.util.Objects.*;
+
+import jdk.internal.module.Checks;
+import jdk.internal.module.Hasher.DependencyHashes;
+
+
+/**
+ * A module descriptor.
+ *
+ * <p> A {@code ModuleDescriptor} is typically created from the binary form
+ * of a module declaration. The associated {@link ModuleDescriptor.Builder}
+ * class can also be used to create a {@code ModuleDescriptor} from its
+ * components. </p>
+ *
+ * <p> {@code ModuleDescriptor} objects are immutable and safe for use by
+ * multiple concurrent threads.</p>
+ *
+ * @since 9
+ * @see java.lang.reflect.Module
+ */
+
+public class ModuleDescriptor
+    implements Comparable<ModuleDescriptor>
+{
+
+    /**
+     * <p> A dependence upon a module </p>
+     *
+     * @see ModuleDescriptor#requires()
+     * @since 9
+     */
+
+    public final static class Requires
+        implements Comparable<Requires>
+    {
+
+        /**
+         * A modifier on a module dependence.
+         *
+         * @since 9
+         */
+        public static enum Modifier {
+
+            /**
+             * The dependence causes any module which depends on the <i>current
+             * module</i> to have an implicitly declared dependence on the module
+             * named by the {@code Requires}.
+             */
+            PUBLIC,
+
+            /**
+             * The dependence was not explicitly or implicitly declared in the
+             * source of the module declaration.
+             */
+            SYNTHETIC,
+
+            /**
+             * The dependence was implicitly declared in the source of the module
+             * declaration.
+             */
+            MANDATED;
+
+        }
+
+        private final Set<Modifier> mods;
+        private final String name;
+
+        private Requires(Set<Modifier> ms, String mn) {
+            this(ms, mn, true);
+        }
+        private Requires(Set<Modifier> ms, String mn, boolean check) {
+            if (ms == null || ms.isEmpty()) {
+                mods = Collections.emptySet();
+            } else {
+                mods = check ? Collections.unmodifiableSet(EnumSet.copyOf(ms))
+                             : ms;
+            }
+            this.name = check ? requireModuleName(mn) : mn;
+        }
+
+        /**
+         * Returns the set of modifiers.
+         *
+         * @return A possibly-empty unmodifiable set of modifiers
+         */
+        public Set<Modifier> modifiers() {
+            return mods;
+        }
+
+        /**
+         * Return the module name.
+         *
+         * @return The module name
+         */
+        public String name() {
+            return name;
+        }
+
+        /**
+         * Compares this module dependence to another.
+         *
+         * <p> Two {@code Requires} objects are compared by comparing their
+         * module name lexicographically.  Where the module names are equal then
+         * the sets of modifiers are compared based on a value computed from the
+         * ordinal of each modifier. </p>
+         *
+         * @return A negative integer, zero, or a positive integer if this module
+         *         dependence is less than, equal to, or greater than the given
+         *         module dependence
+         */
+        @Override
+        public int compareTo(Requires that) {
+            int c = this.name().compareTo(that.name());
+            if (c != 0)
+                return c;
+            // same name, compare by modifiers
+            return Long.compare(this.modsValue(), that.modsValue());
+        }
+
+        /**
+         * Return a value for the modifiers to allow sets of modifiers to be
+         * compared.
+         */
+        private long modsValue() {
+            long value = 0;
+            for (Modifier m : mods) {
+                value += 1 << m.ordinal();
+            }
+            return value;
+        }
+
+        /**
+         * Tests this module dependence for equality with the given object.
+         *
+         * <p> If the given object is not a {@code Requires} then this method
+         * returns {@code false}. Two module dependence objects are equal if
+         * the module names are equal and set of modifiers are equal. </p>
+         *
+         * <p> This method satisfies the general contract of the {@link
+         * java.lang.Object#equals(Object) Object.equals} method. </p>
+         *
+         * @param   ob
+         *          the object to which this object is to be compared
+         *
+         * @return  {@code true} if, and only if, the given object is a module
+         *          dependence that is equal to this module dependence
+         */
+        @Override
+        public boolean equals(Object ob) {
+            if (!(ob instanceof Requires))
+                return false;
+            Requires that = (Requires)ob;
+            return (name.equals(that.name) && mods.equals(that.mods));
+        }
+
+        /**
+         * Computes a hash code for this module dependence.
+         *
+         * <p> The hash code is based upon the module name and modifiers. It
+         * satisfies the general contract of the {@link Object#hashCode
+         * Object.hashCode} method. </p>
+         *
+         * @return The hash-code value for this module dependence
+         */
+        @Override
+        public int hashCode() {
+            return name.hashCode() * 43 + mods.hashCode();
+        }
+
+        /**
+         * Returns a string describing module dependence.
+         *
+         * @return A string describing module dependence
+         */
+        @Override
+        public String toString() {
+            return Dependence.toString(mods, name);
+        }
+
+    }
+
+
+
+    /**
+     * <p> A module export, may be qualified or unqualified. </p>
+     *
+     * @see ModuleDescriptor#exports()
+     * @since 9
+     */
+
+    public final static class Exports {
+
+        private final String source;
+        private final Set<String> targets;  // empty if unqualified export
+
+        /**
+         * Constructs a qualified export.
+         */
+        private Exports(String source, Set<String> targets) {
+            this(source, targets, true);
+        }
+
+        private Exports(String source, Set<String> targets, boolean check) {
+            this.source = check ? requirePackageName(source) : source;
+            targets = check ? Collections.unmodifiableSet(new HashSet<>(targets))
+                            : Collections.unmodifiableSet(targets);
+            if (targets.isEmpty())
+                throw new IllegalArgumentException("Empty target set");
+            if (check)
+                targets.stream().forEach(Checks::requireModuleName);
+            this.targets = targets;
+        }
+
+        /**
+         * Constructs an unqualified export.
+         */
+        private Exports(String source) {
+            this(source, true);
+        }
+        private Exports(String source, boolean check) {
+            this.source = check ? requirePackageName(source) : source;
+            this.targets = Collections.emptySet();
+        }
+
+        /**
+         * Returns {@code true} if this is a qualified export.
+         *
+         * @return {@code true} if this is a qualified export
+         */
+        public boolean isQualified() {
+            return !targets.isEmpty();
+        }
+
+        /**
+         * Returns the package name.
+         *
+         * @return The package name
+         */
+        public String source() {
+            return source;
+        }
+
+        /**
+         * For a qualified export, returns the non-empty and immutable set
+         * of the module names to which the package is exported. For an
+         * unqualified export, returns an empty set.
+         *
+         * @return The set of target module names or for an unqualified
+         *         export, an empty set
+         */
+        public Set<String> targets() {
+            return targets;
+        }
+
+        /**
+         * Computes a hash code for this module export.
+         *
+         * <p> The hash code is based upon the package name, and for a
+         * qualified export, the set of modules names to which the package
+         * is exported. It satisfies the general contract of the {@link
+         * Object#hashCode Object.hashCode} method.
+         *
+         * @return The hash-code value for this module export
+         */
+        @Override
+        public int hashCode() {
+            return hash(source, targets);
+        }
+
+        /**
+         * Tests this module export for equality with the given object.
+         *
+         * <p> If the given object is not a {@code Exports} then this method
+         * returns {@code false}. Two module exports objects are equal if the
+         * package names are equal and the set of target module names is equal.
+         * </p>
+         *
+         * <p> This method satisfies the general contract of the {@link
+         * java.lang.Object#equals(Object) Object.equals} method. </p>
+         *
+         * @param   ob
+         *          the object to which this object is to be compared
+         *
+         * @return  {@code true} if, and only if, the given object is a module
+         *          dependence that is equal to this module dependence
+         */
+        @Override
+        public boolean equals(Object ob) {
+            if (!(ob instanceof Exports))
+                return false;
+            Exports other = (Exports)ob;
+            return Objects.equals(this.source, other.source) &&
+                Objects.equals(this.targets, other.targets);
+        }
+
+        /**
+         * Returns a string describing module export.
+         *
+         * @return A string describing module export
+         */
+        @Override
+        public String toString() {
+            if (targets.isEmpty())
+                return source;
+            else
+                return source + " to " + targets;
+        }
+
+    }
+
+
+
+    /**
+     * <p> A service that a module provides one or more implementations of. </p>
+     *
+     * @see ModuleDescriptor#provides()
+     * @since 9
+     */
+
+    public final static class Provides {
+
+        private final String service;
+        private final Set<String> providers;
+
+        private Provides(String service, Set<String> providers) {
+            this(service, providers, true);
+        }
+
+        private Provides(String service, Set<String> providers, boolean check) {
+            this.service = check ? requireServiceTypeName(service) : service;
+            providers = check ? Collections.unmodifiableSet(new HashSet<>(providers))
+                              : Collections.unmodifiableSet(providers);
+            if (providers.isEmpty())
+                throw new IllegalArgumentException("Empty providers set");
+            if (check)
+                providers.forEach(Checks::requireServiceProviderName);
+            this.providers = providers;
+        }
+
+        /**
+         * Returns the fully qualified class name of the service type.
+         *
+         * @return The fully qualified class name of the service type.
+         */
+        public String service() { return service; }
+
+        /**
+         * Returns the set of the fully qualified class names of the providers.
+         *
+         * @return A non-empty and unmodifiable set of the fully qualified class
+         *         names of the providers.
+         */
+        public Set<String> providers() { return providers; }
+
+        /**
+         * Computes a hash code for this provides.
+         *
+         * <p> The hash code is based upon the service type and the set of
+         * providers. It satisfies the general contract of the {@link
+         * Object#hashCode Object.hashCode} method. </p>
+         *
+         * @return The hash-code value for this module provides
+         */
+        @Override
+        public int hashCode() {
+            return hash(service, providers);
+        }
+
+        /**
+         * Tests this provides for equality with the given object.
+         *
+         * <p> If the given object is not a {@code Provides} then this method
+         * returns {@code false}. Two {@code Provides} objects are equal if the
+         * service type is equal and the set of providers is equal. </p>
+         *
+         * <p> This method satisfies the general contract of the {@link
+         * java.lang.Object#equals(Object) Object.equals} method. </p>
+         *
+         * @param   ob
+         *          the object to which this object is to be compared
+         *
+         * @return  {@code true} if, and only if, the given object is a
+         *          {@code Provides} that is equal to this {@code Provides}
+         */
+        @Override
+        public boolean equals(Object ob) {
+            if (!(ob instanceof Provides))
+                return false;
+            Provides other = (Provides)ob;
+            return Objects.equals(this.service, other.service) &&
+                    Objects.equals(this.providers, other.providers);
+        }
+
+        /**
+         * Returns a string describing this provides.
+         *
+         * @return A string describing this provides
+         */
+        @Override
+        public String toString() {
+            return service + " with " + providers;
+        }
+
+    }
+
+
+
+    /**
+     * A module's version string.
+     *
+     * <p> A version string has three components: The version number itself, an
+     * optional pre-release version, and an optional build version.  Each
+     * component is sequence of tokens; each token is either a non-negative
+     * integer or a string.  Tokens are separated by the punctuation characters
+     * {@code '.'}, {@code '-'}, or {@code '+'}, or by transitions from a
+     * sequence of digits to a sequence of characters that are neither digits
+     * nor punctuation characters, or vice versa.
+     *
+     * <ul>
+     *
+     *   <li> The <i>version number</i> is a sequence of tokens separated by
+     *   {@code '.'} characters, terminated by the first {@code '-'} or {@code
+     *   '+'} character. </li>
+     *
+     *   <li> The <i>pre-release version</i> is a sequence of tokens separated
+     *   by {@code '.'} or {@code '-'} characters, terminated by the first
+     *   {@code '+'} character. </li>
+     *
+     *   <li> The <i>build version</i> is a sequence of tokens separated by
+     *   {@code '.'}, {@code '-'}, or {@code '+'} characters.
+     *
+     * </ul>
+     *
+     * <p> When comparing two version strings, the elements of their
+     * corresponding components are compared in pointwise fashion.  If one
+     * component is longer than the other, but otherwise equal to it, then the
+     * first component is considered the greater of the two; otherwise, if two
+     * corresponding elements are integers then they are compared as such;
+     * otherwise, at least one of the elements is a string, so the other is
+     * converted into a string if it is an integer and the two are compared
+     * lexicographically.  Trailing integer elements with the value zero are
+     * ignored.
+     *
+     * <p> Given two version strings, if their version numbers differ then the
+     * result of comparing them is the result of comparing their version
+     * numbers; otherwise, if one of them has a pre-release version but the
+     * other does not then the first is considered to precede the second,
+     * otherwise the result of comparing them is the result of comparing their
+     * pre-release versions; otherwise, the result of comparing them is the
+     * result of comparing their build versions.
+     *
+     * @see ModuleDescriptor#version()
+     * @since 9
+     */
+
+    public final static class Version
+        implements Comparable<Version>
+    {
+
+        private final String version;
+
+        // If Java had disjunctive types then we'd write List<Integer|String> here
+        //
+        private final List<Object> sequence;
+        private final List<Object> pre;
+        private final List<Object> build;
+
+        // Take a numeric token starting at position i
+        // Append it to the given list
+        // Return the index of the first character not taken
+        // Requires: s.charAt(i) is (decimal) numeric
+        //
+        private static int takeNumber(String s, int i, List<Object> acc) {
+            char c = s.charAt(i);
+            int d = (c - '0');
+            int n = s.length();
+            while (++i < n) {
+                c = s.charAt(i);
+                if (c >= '0' && c <= '9') {
+                    d = d * 10 + (c - '0');
+                    continue;
+                }
+                break;
+            }
+            acc.add(d);
+            return i;
+        }
+
+        // Take a string token starting at position i
+        // Append it to the given list
+        // Return the index of the first character not taken
+        // Requires: s.charAt(i) is not '.'
+        //
+        private static int takeString(String s, int i, List<Object> acc) {
+            int b = i;
+            int n = s.length();
+            while (++i < n) {
+                char c = s.charAt(i);
+                if (c != '.' && c != '-' && c != '+' && !(c >= '0' && c <= '9'))
+                    continue;
+                break;
+            }
+            acc.add(s.substring(b, i));
+            return i;
+        }
+
+        // Syntax: tok+ ( '-' tok+)? ( '+' tok+)?
+        // First token string is sequence, second is pre, third is build
+        // Tokens are separated by '.' or '-', or by changes between alpha & numeric
+        // Numeric tokens are compared as decimal integers
+        // Non-numeric tokens are compared lexicographically
+        // A version with a non-empty pre is less than a version with same seq but no pre
+        // Tokens in build may contain '-' and '+'
+        //
+        private Version(String v) {
+
+            if (v == null)
+                throw new IllegalArgumentException("Null version string");
+            int n = v.length();
+            if (n == 0)
+                throw new IllegalArgumentException("Empty version string");
+
+            int i = 0;
+            char c = v.charAt(i);
+            if (!(c >= '0' && c <= '9'))
+                throw new IllegalArgumentException(v
+                                                   + ": Version string does not start"
+                                                   + " with a number");
+
+            List<Object> sequence = new ArrayList<>(4);
+            List<Object> pre = new ArrayList<>(2);
+            List<Object> build = new ArrayList<>(2);
+
+            i = takeNumber(v, i, sequence);
+
+            while (i < n) {
+                c = v.charAt(i);
+                if (c == '.') {
+                    i++;
+                    continue;
+                }
+                if (c == '-' || c == '+') {
+                    i++;
+                    break;
+                }
+                if (c >= '0' && c <= '9')
+                    i = takeNumber(v, i, sequence);
+                else
+                    i = takeString(v, i, sequence);
+            }
+
+            if (c == '-' && i >= n)
+                throw new IllegalArgumentException(v + ": Empty pre-release");
+
+            while (i < n) {
+                c = v.charAt(i);
+                if (c >= '0' && c <= '9')
+                    i = takeNumber(v, i, pre);
+                else
+                    i = takeString(v, i, pre);
+                if (i >= n)
+                    break;
+                c = v.charAt(i);
+                if (c == '.' || c == '-') {
+                    i++;
+                    continue;
+                }
+                if (c == '+') {
+                    i++;
+                    break;
+                }
+            }
+
+            if (c == '+' && i >= n)
+                throw new IllegalArgumentException(v + ": Empty pre-release");
+
+            while (i < n) {
+                c = v.charAt(i);
+                if (c >= '0' && c <= '9')
+                    i = takeNumber(v, i, build);
+                else
+                    i = takeString(v, i, build);
+                if (i >= n)
+                    break;
+                c = v.charAt(i);
+                if (c == '.' || c == '-' || c == '+') {
+                    i++;
+                    continue;
+                }
+            }
+
+            this.version = v;
+            this.sequence = sequence;
+            this.pre = pre;
+            this.build = build;
+        }
+
+        /**
+         * Parses the given string as a version string.
+         *
+         * @param  v
+         *         The string to parse
+         *
+         * @return The resulting {@code Version}
+         *
+         * @throws IllegalArgumentException
+         *         If {@code v} is {@code null}, an empty string, or cannot be
+         *         parsed as a version string
+         */
+        public static Version parse(String v) {
+            return new Version(v);
+        }
+
+        @SuppressWarnings("unchecked")
+        private int cmp(Object o1, Object o2) {
+            return ((Comparable)o1).compareTo(o2);
+        }
+
+        private int compareTokens(List<Object> ts1, List<Object> ts2) {
+            int n = Math.min(ts1.size(), ts2.size());
+            for (int i = 0; i < n; i++) {
+                Object o1 = ts1.get(i);
+                Object o2 = ts2.get(i);
+                if ((o1 instanceof Integer && o2 instanceof Integer)
+                    || (o1 instanceof String && o2 instanceof String))
+                {
+                    int c = cmp(o1, o2);
+                    if (c == 0)
+                        continue;
+                    return c;
+                }
+                // Types differ, so convert number to string form
+                int c = o1.toString().compareTo(o2.toString());
+                if (c == 0)
+                    continue;
+                return c;
+            }
+            List<Object> rest = ts1.size() > ts2.size() ? ts1 : ts2;
+            int e = rest.size();
+            for (int i = n; i < e; i++) {
+                Object o = rest.get(i);
+                if (o instanceof Integer && ((Integer)o) == 0)
+                    continue;
+                return ts1.size() - ts2.size();
+            }
+            return 0;
+        }
+
+        /**
+         * Compares this module version to another module version. Module
+         * versions are compared as described in the class description.
+         *
+         * @param that
+         *        The module version to compare
+         *
+         * @return A negative integer, zero, or a positive integer as this
+         *         module version is less than, equal to, or greater than the
+         *         given module version
+         */
+        @Override
+        public int compareTo(Version that) {
+            int c = compareTokens(this.sequence, that.sequence);
+            if (c != 0) return c;
+            if (this.pre.isEmpty()) {
+                if (!that.pre.isEmpty()) return +1;
+            } else {
+                if (that.pre.isEmpty()) return -1;
+            }
+            c = compareTokens(this.pre, that.pre);
+            if (c != 0) return c;
+            return compareTokens(this.build, that.build);
+        }
+
+        /**
+         * Tests this module version for equality with the given object.
+         *
+         * <p> If the given object is not a {@code Version} then this method
+         * returns {@code false}. Two module version are equal if their
+         * corresponding components are equal. </p>
+         *
+         * <p> This method satisfies the general contract of the {@link
+         * java.lang.Object#equals(Object) Object.equals} method. </p>
+         *
+         * @param   ob
+         *          the object to which this object is to be compared
+         *
+         * @return  {@code true} if, and only if, the given object is a module
+         *          reference that is equal to this module reference
+         */
+        @Override
+        public boolean equals(Object ob) {
+            if (!(ob instanceof Version))
+                return false;
+            return compareTo((Version)ob) == 0;
+        }
+
+        /**
+         * Computes a hash code for this module version.
+         *
+         * <p> The hash code is based upon the components of the version and
+         * satisfies the general contract of the {@link Object#hashCode
+         * Object.hashCode} method. </p>
+         *
+         * @return The hash-code value for this module version
+         */
+        @Override
+        public int hashCode() {
+            return version.hashCode();
+        }
+
+        /**
+         * Returns the string from which this version was parsed.
+         *
+         * @return The string from which this version was parsed.
+         */
+        @Override
+        public String toString() {
+            return version;
+        }
+
+    }
+
+
+
+    // From module declarations
+    private final String name;
+    private final Set<Requires> requires;
+    private final Set<Exports> exports;
+    private final Set<String> uses;
+    private final Map<String, Provides> provides;
+
+    // Indicates if synthesised for a JAR file found on the module path
+    private final boolean automatic;
+
+    // Not generated from a module-info.java
+    private final boolean synthetic;
+
+    // "Extended" information, added post-compilation by tools
+    private final Version version;
+    private final String mainClass;
+    private final String osName;
+    private final String osArch;
+    private final String osVersion;
+    private final Set<String> conceals;
+    private final Set<String> packages;
+    private final DependencyHashes hashes;
+
+    private ModuleDescriptor(String name,
+                             boolean automatic,
+                             boolean synthetic,
+                             Map<String, Requires> requires,
+                             Set<String> uses,
+                             Map<String, Exports> exports,
+                             Map<String, Provides> provides,
+                             Version version,
+                             String mainClass,
+                             String osName,
+                             String osArch,
+                             String osVersion,
+                             Set<String> conceals,
+                             DependencyHashes hashes)
+    {
+
+        this.name = name;
+        this.automatic = automatic;
+        this.synthetic = synthetic;
+
+        Set<Requires> rqs = new HashSet<>(requires.values());
+        assert (rqs.stream().map(Requires::name).sorted().distinct().count()
+                == rqs.size())
+            : "Module " + name + " has duplicate requires";
+        this.requires = emptyOrUnmodifiableSet(rqs);
+
+        Set<Exports> exs = new HashSet<>(exports.values());
+        assert (exs.stream().map(Exports::source).sorted().distinct().count()
+                == exs.size())
+            : "Module " + name + " has duplicate exports";
+        this.exports = emptyOrUnmodifiableSet(exs);
+
+        this.uses = emptyOrUnmodifiableSet(uses);
+        this.provides = emptyOrUnmodifiableMap(provides);
+
+        this.version = version;
+        this.mainClass = mainClass;
+        this.osName = osName;
+        this.osArch = osArch;
+        this.osVersion = osVersion;
+        this.hashes = hashes;
+
+        assert !exports.keySet().stream().anyMatch(conceals::contains)
+            : "Module " + name + ": Package sets overlap";
+        this.conceals = emptyOrUnmodifiableSet(conceals);
+        this.packages = computePackages(this.exports, this.conceals);
+    }
+
+    /**
+     * Clones the given module descriptor with an augmented set of packages
+     */
+    ModuleDescriptor(ModuleDescriptor md, Set<String> pkgs) {
+        this.name = md.name;
+        this.automatic = md.automatic;
+        this.synthetic = md.synthetic;
+
+        this.requires = md.requires;
+        this.exports = md.exports;
+        this.uses = md.uses;
+        this.provides = md.provides;
+
+        this.version = md.version;
+        this.mainClass = md.mainClass;
+        this.osName = md.osName;
+        this.osArch = md.osArch;
+        this.osVersion = md.osVersion;
+        this.hashes = null; // need to ignore
+
+        this.packages = emptyOrUnmodifiableSet(pkgs);
+        this.conceals = computeConcealedPackages(this.exports, this.packages);
+    }
+
+    /**
+     * Creates a module descriptor from its components. This method is intended
+     * for use by the jlink plugin.
+     */
+    ModuleDescriptor(String name,
+                     boolean automatic,
+                     boolean synthetic,
+                     Set<Requires> requires,
+                     Set<String> uses,
+                     Set<Exports> exports,
+                     Map<String, Provides> provides,
+                     Version version,
+                     String mainClass,
+                     String osName,
+                     String osArch,
+                     String osVersion,
+                     Set<String> conceals,
+                     Set<String> packages) {
+        this.name = name;
+        this.automatic = automatic;
+        this.synthetic = synthetic;
+        this.requires = Collections.unmodifiableSet(requires);
+        this.exports = Collections.unmodifiableSet(exports);
+        this.uses = Collections.unmodifiableSet(uses);
+        this.provides = Collections.unmodifiableMap(provides);
+        this.conceals = Collections.unmodifiableSet(conceals);
+        this.packages = Collections.unmodifiableSet(packages);
+
+        this.version = version;
+        this.mainClass = mainClass;
+        this.osName = osName;
+        this.osArch = osArch;
+        this.osVersion = osVersion;
+        this.hashes = null;
+    }
+
+    /**
+     * <p> The module name. </p>
+     *
+     * @return The module name
+     */
+    public String name() {
+        return name;
+    }
+
+    /**
+     * <p> Returns {@code true} if this is an automatic module. </p>
+     *
+     * <p> An automatic module is defined implicitly rather than explicitly
+     * and therefore does not have a module declaration. JAR files located on
+     * the application module path, or by the {@link ModuleFinder} returned by
+     * {@link ModuleFinder#of(java.nio.file.Path[]) ModuleFinder.of}, are
+     * treated as automatic modules if they do have not have a module
+     * declaration. </p>
+     *
+     * @return  {@code true} if this is an automatic module
+     */
+    public boolean isAutomatic() {
+        return automatic;
+    }
+
+    /**
+     * <p> Returns {@code true} if this module descriptor was not generated
+     * from an explicit module declaration ({@code module-info.java})
+     * or an implicit module declaration (an {@link #isAutomatic() automatic}
+     * module). </p>
+     *
+     * @return  {@code true} if this module descriptor was not generated by
+     *          an explicit or implicit module declaration
+     *
+     * @jvms 4.7.8 The {@code Synthetic} Attribute
+     */
+    public boolean isSynthetic() {
+        return synthetic;
+    }
+
+    /**
+     * <p> The dependences of this module. </p>
+     *
+     * @return  A possibly-empty unmodifiable set of {@link Requires} objects
+     */
+    public Set<Requires> requires() {
+        return requires;
+    }
+
+    /**
+     * <p> The service dependences of this module. </p>
+     *
+     * @return  A possibly-empty unmodifiable set of the fully qualified class
+     *          names of the service types used
+     */
+    public Set<String> uses() {
+        return uses;
+    }
+
+    /**
+     * <p> The services that this module provides. </p>
+     *
+     * @return The possibly-empty unmodifiable map of the services that this
+     *         module provides. The map key is fully qualified class name of
+     *         the service type.
+     */
+    public Map<String, Provides> provides() {
+        return provides;
+    }
+
+    /**
+     * <p> The module exports. </p>
+     *
+     * @return  A possibly-empty unmodifiable set of exported packages
+     */
+    public Set<Exports> exports() {
+        return exports;
+    }
+
+    /**
+     * Returns this module's version.
+     *
+     * @return This module's version
+     */
+    public Optional<Version> version() {
+        return Optional.ofNullable(version);
+    }
+
+    /**
+     * Returns a string containing this module's name and, if present, its
+     * version.
+     *
+     * @return A string containing this module's name and, if present, its
+     *         version.
+     */
+    public String toNameAndVersion() {
+        if (version != null) {
+            return name() + "@" + version;
+        } else {
+            return name();
+        }
+    }
+
+    /**
+     * Returns the module's main class.
+     *
+     * @return The fully qualified class name of this module's main class
+     */
+    public Optional<String> mainClass() {
+        return Optional.ofNullable(mainClass);
+    }
+
+    /**
+     * Returns the operating system name if this module is operating system
+     * specific.
+     *
+     * @return The operating system name or an empty {@code Optional}
+     *         if this module is not operating system specific
+     */
+    public Optional<String> osName() {
+        return Optional.ofNullable(osName);
+    }
+
+    /**
+     * Returns the operating system architecture if this module is operating
+     * system architecture specific.
+     *
+     * @return The operating system architecture or an empty {@code Optional}
+     *         if this module is not operating system architecture specific
+     */
+    public Optional<String> osArch() {
+        return Optional.ofNullable(osArch);
+    }
+
+    /**
+     * Returns the operating system version if this module is operating
+     * system version specific.
+     *
+     * @return The operating system version or an empty {@code Optional}
+     *         if this module is not operating system version specific
+     */
+    public Optional<String> osVersion() {
+        return Optional.ofNullable(osVersion);
+    }
+
+    /**
+     * Returns the names of the packages defined in, but not exported by, this
+     * module.
+     *
+     * @return A possibly-empty unmodifiable set of the concealed packages
+     */
+    public Set<String> conceals() {
+        return conceals;
+    }
+
+    /**
+     * Returns the names of all the packages defined in this module, whether
+     * exported or concealed.
+     *
+     * @return A possibly-empty unmodifiable set of the all packages
+     */
+    public Set<String> packages() {
+        return packages;
+    }
+
+    /**
+     * Returns the object with the hashes of the dependences.
+     */
+    Optional<DependencyHashes> hashes() {
+        return Optional.ofNullable(hashes);
+    }
+
+
+    /**
+     * A builder used for building {@link ModuleDescriptor} objects.
+     *
+     * <p> Example usage: </p>
+     *
+     * <pre>{@code
+     *     ModuleDescriptor descriptor = new ModuleDescriptor.Builder("m1")
+     *         .requires("m2")
+     *         .exports("p")
+     *         .build();
+     * }</pre>
+     *
+     * @apiNote A {@code Builder} cannot be used to create an {@link
+     * ModuleDescriptor#isAutomatic() automatic} or a {@link
+     * ModuleDescriptor#isSynthetic() synthetic} module.
+     *
+     * @since 9
+     */
+    public static final class Builder {
+
+        final String name;
+        final boolean automatic;
+        boolean synthetic;
+        final Map<String, Requires> requires = new HashMap<>();
+        final Set<String> uses = new HashSet<>();
+        final Map<String, Exports> exports = new HashMap<>();
+        final Map<String, Provides> provides = new HashMap<>();
+        Set<String> conceals = Collections.emptySet();
+        Version version;
+        String osName;
+        String osArch;
+        String osVersion;
+        String mainClass;
+        DependencyHashes hashes;
+
+        /**
+         * Initializes a new builder with the given module name.
+         *
+         * @param  name
+         *         The module name
+         *
+         * @throws IllegalArgumentException
+         *         If the module name is {@code null} or is not a legal Java
+         *         identifier
+         */
+        public Builder(String name) {
+            this(name, false);
+        }
+
+        /* package */ Builder(String name, boolean automatic) {
+            this.name = requireModuleName(name);
+            this.automatic = automatic;
+        }
+
+        /**
+         * Adds a dependence on a module.
+         *
+         * @param  req
+         *         The dependence
+         *
+         * @return This builder
+         *
+         * @throws IllegalArgumentException
+         *         If the dependence is on the module that this builder was
+         *         initialized to build
+         * @throws IllegalStateException
+         *         If the dependence on the module has already been declared
+         */
+        public Builder requires(Requires req) {
+            String mn = req.name();
+            if (name.equals(mn))
+                throw new IllegalArgumentException("Dependence on self");
+            if (requires.containsKey(mn))
+                throw new IllegalStateException("Dependence upon " + mn
+                                                + " already declared");
+            requires.put(mn, req);
+            return this;
+        }
+
+        /**
+         * Adds a dependence on a module with the given (and possibly empty)
+         * set of modifiers.
+         *
+         * @param  mods
+         *         The set of modifiers
+         * @param  mn
+         *         The module name
+         *
+         * @return This builder
+         *
+         * @throws IllegalArgumentException
+         *         If the module name is {@code null}, is not a legal Java
+         *         identifier, or is equal to the module name that this builder
+         *         was initialized to build
+         * @throws IllegalStateException
+         *         If the dependence on the module has already been declared
+         */
+        public Builder requires(Set<Requires.Modifier> mods, String mn) {
+            if (name.equals(mn))
+                throw new IllegalArgumentException("Dependence on self");
+            if (requires.containsKey(mn))
+                throw new IllegalStateException("Dependence upon " + mn
+                                                + " already declared");
+            requires.put(mn, new Requires(mods, mn)); // checks mn
+            return this;
+        }
+
+        /**
+         * Adds a dependence on a module with an empty set of modifiers.
+         *
+         * @param  mn
+         *         The module name
+         *
+         * @return This builder
+         *
+         * @throws IllegalArgumentException
+         *         If the module name is {@code null}, is not a legal Java
+         *         identifier, or is equal to the module name that this builder
+         *         was initialized to build
+         * @throws IllegalStateException
+         *         If the dependence on the module has already been declared
+         */
+        public Builder requires(String mn) {
+            return requires(EnumSet.noneOf(Requires.Modifier.class), mn);
+        }
+
+        /**
+         * Adds a dependence on a module with the given modifier.
+         *
+         * @param  mod
+         *         The modifier
+         * @param  mn
+         *         The module name
+         *
+         * @return This builder
+         *
+         * @throws IllegalArgumentException
+         *         If the module name is {@code null}, is not a legal Java
+         *         identifier, or is equal to the module name that this builder
+         *         was initialized to build
+         * @throws IllegalStateException
+         *         If the dependence on the module has already been declared
+         */
+        public Builder requires(Requires.Modifier mod, String mn) {
+            return requires(EnumSet.of(mod), mn);
+        }
+
+        /**
+         * Adds a service dependence.
+         *
+         * @param  st
+         *         The service type
+         *
+         * @return This builder
+         *
+         * @throws IllegalArgumentException
+         *         If the service type is {@code null} or is not a legal Java
+         *         identifier
+         * @throws IllegalStateException
+         *         If a dependency on the service type has already been declared
+         */
+        public Builder uses(String st) {
+            if (uses.contains(requireServiceTypeName(st)))
+                throw new IllegalStateException("Dependence upon service "
+                                                + st + " already declared");
+            uses.add(st);
+            return this;
+        }
+
+        /**
+         * Ensures that the given package name has not been declared as an
+         * exported or concealed package.
+         */
+        private void ensureNotExportedOrConcealed(String pn) {
+            if (exports.containsKey(pn))
+                throw new IllegalStateException("Export of package "
+                                                + pn + " already declared");
+            if (conceals.contains(pn))
+                throw new IllegalStateException("Concealed package "
+                                                + pn + " already declared");
+        }
+
+        /**
+         * Adds an export.
+         *
+         * @param  e
+         *         The export
+         *
+         * @return This builder
+         *
+         * @throws IllegalStateException
+         *         If the package is already declared as an exported or
+         *         concealed package
+         */
+        public Builder exports(Exports e) {
+            String pn = e.source();
+            ensureNotExportedOrConcealed(pn);
+            exports.put(pn, e);
+            return this;
+        }
+
+        /**
+         * Adds an export to a set of target modules.
+         *
+         * @param  pn
+         *         The package name
+         * @param  targets
+         *         The set of target modules names
+         *
+         * @return This builder
+         *
+         * @throws IllegalArgumentException
+         *         If the package name or any of the target modules is {@code
+         *         null} or is not a legal Java identifier, or the set of
+         *         targets is empty
+         * @throws IllegalStateException
+         *         If the package is already declared as an exported or
+         *         concealed package
+         */
+        public Builder exports(String pn, Set<String> targets) {
+            ensureNotExportedOrConcealed(pn);
+            exports.put(pn, new Exports(pn, targets)); // checks pn and targets
+            return this;
+        }
+
+        /**
+         * Adds an export to a target module.
+         *
+         * @param  pn
+         *         The package name
+         * @param  target
+         *         The target module name
+         *
+         * @return This builder
+         *
+         * @throws IllegalArgumentException
+         *         If the package name or target module is {@code null} or is
+         *         not a legal Java identifier
+         * @throws IllegalStateException
+         *         If the package is already declared as an exported or
+         *         concealed package
+         */
+        public Builder exports(String pn, String target) {
+            return exports(pn, Collections.singleton(target));
+        }
+
+        /**
+         * Adds an export.
+         *
+         * @param  pn
+         *         The package name
+         *
+         * @return This builder
+         *
+         * @throws IllegalArgumentException
+         *         If the package name is {@code null} or is not a legal Java
+         *         identifier
+         * @throws IllegalStateException
+         *         If the package is already declared as an exported or
+         *         concealed package
+         */
+        public Builder exports(String pn) {
+            ensureNotExportedOrConcealed(pn);
+            exports.put(pn, new Exports(pn)); // checks pn
+            return this;
+        }
+
+        // Used by ModuleInfo, after a packageFinder is invoked
+        /* package */ Set<String> exportedPackages() {
+            return exports.keySet();
+        }
+
+        /**
+         * Provides a service with one or more implementations.
+         *
+         * @param  p
+         *         The provides
+         *
+         * @return This builder
+         *
+         * @throws IllegalStateException
+         *         If the providers for the service type have already been
+         *         declared
+         */
+        public Builder provides(Provides p) {
+            String st = p.service();
+            if (provides.containsKey(st))
+                throw new IllegalStateException("Providers of service "
+                                                + st + " already declared");
+            provides.put(st, p);
+            return this;
+        }
+
+        /**
+         * Provides service {@code st} with implementations {@code pcs}.
+         *
+         * @param  st
+         *         The service type
+         * @param  pcs
+         *         The set of provider class names
+         *
+         * @return This builder
+         *
+         * @throws IllegalArgumentException
+         *         If the service type or any of the provider class names is
+         *         {@code null} or is not a legal Java identifier, or the set
+         *         of provider class names is empty
+         * @throws IllegalStateException
+         *         If the providers for the service type have already been
+         *         declared
+         */
+        public Builder provides(String st, Set<String> pcs) {
+            if (provides.containsKey(st))
+                throw new IllegalStateException("Providers of service "
+                                                + st + " already declared");
+            provides.put(st, new Provides(st, pcs)); // checks st and pcs
+            return this;
+        }
+
+        /**
+         * Provides service {@code st} with implementation {@code pc}.
+         *
+         * @param  st
+         *         The service type
+         * @param  pc
+         *         The provider class name
+         *
+         * @return This builder
+         *
+         * @throws IllegalArgumentException
+         *         If the service type or the provider class name is {@code
+         *         null} or is not a legal Java identifier
+         * @throws IllegalStateException
+         *         If the providers for the service type have already been
+         *         declared
+         */
+        public Builder provides(String st, String pc) {
+            return provides(st, Collections.singleton(pc));
+        }
+
+        /**
+         * Adds a set of (possible empty) concealed packages.
+         *
+         * @param  pns
+         *         The set of package names of the concealed packages
+         *
+         * @return This builder
+         *
+         * @throws IllegalArgumentException
+         *         If any of the package names is {@code null} or is not a
+         *         legal Java identifier
+         * @throws IllegalStateException
+         *         If any of packages are already declared as a concealed or
+         *         exported package
+         */
+        public Builder conceals(Set<String> pns) {
+            pns.forEach(this::conceals);
+            return this;
+        }
+
+        /**
+         * Adds a concealed package.
+         *
+         * @param  pn
+         *         The package name
+         *
+         * @return This builder
+         *
+         * @throws IllegalArgumentException
+         *         If the package name is {@code null}, or is not a legal Java
+         *         identifier
+         * @throws IllegalStateException
+         *         If the package is already declared as a concealed or exported
+         *         package
+         */
+        public Builder conceals(String pn) {
+            Checks.requirePackageName(pn);
+            ensureNotExportedOrConcealed(pn);
+            if (conceals.isEmpty())
+                conceals = new HashSet<>();
+            conceals.add(pn);
+            return this;
+        }
+
+        /**
+         * Sets the module version.
+         *
+         * @param  v
+         *         The version
+         *
+         * @return This builder
+         *
+         * @throws IllegalStateException
+         *         If the module version is already set
+         */
+        public Builder version(Version v) {
+            if (version != null)
+                throw new IllegalStateException("module version already set");
+            version = requireNonNull(v);
+            return this;
+        }
+
+        /**
+         * Sets the module version.
+         *
+         * @param  v
+         *         The version string to parse
+         *
+         * @return This builder
+         *
+         * @throws IllegalArgumentException
+         *         If {@code v} is null or cannot be parsed as a version string
+         * @throws IllegalStateException
+         *         If the module version is already set
+         *
+         * @see Version#parse(String)
+         */
+        public Builder version(String v) {
+            if (version != null)
+                throw new IllegalStateException("module version already set");
+            version = Version.parse(v);
+            return this;
+        }
+
+        /**
+         * Sets the module main class.
+         *
+         * @param  mc
+         *         The module main class
+         *
+         * @return This builder
+         *
+         * @throws IllegalArgumentException
+         *         If {@code mainClass} is null or is not a legal Java identifier
+         * @throws IllegalStateException
+         *         If the module main class is already set
+         */
+        public Builder mainClass(String mc) {
+            if (mainClass != null)
+                throw new IllegalStateException("main class already set");
+            mainClass = requireJavaIdentifier("main class name", mc);
+            return this;
+        }
+
+        /**
+         * Sets the operating system name.
+         *
+         * @param  name
+         *         The operating system name
+         *
+         * @return This builder
+         *
+         * @throws IllegalArgumentException
+         *         If {@code name} is null or the empty String
+         * @throws IllegalStateException
+         *         If the operating system name is already set
+         */
+        public Builder osName(String name) {
+            if (osName != null)
+                throw new IllegalStateException("OS name already set");
+            if (name == null || name.isEmpty())
+                throw new IllegalArgumentException("OS name is null or empty");
+            osName = name;
+            return this;
+        }
+
+        /**
+         * Sets the operating system architecture.
+         *
+         * @param  arch
+         *         The operating system architecture
+         *
+         * @return This builder
+         *
+         * @throws IllegalArgumentException
+         *         If {@code name} is null or the empty String
+         * @throws IllegalStateException
+         *         If the operating system architecture is already set
+         */
+        public Builder osArch(String arch) {
+            if (osArch != null)
+                throw new IllegalStateException("OS arch already set");
+            if (arch == null || arch.isEmpty())
+                throw new IllegalArgumentException("OS arch is null or empty");
+            osArch = arch;
+            return this;
+        }
+
+        /**
+         * Sets the operating system version.
+         *
+         * @param  version
+         *         The operating system version
+         *
+         * @return This builder
+         *
+         * @throws IllegalArgumentException
+         *         If {@code name} is null or the empty String
+         * @throws IllegalStateException
+         *         If the operating system version is already set
+         */
+        public Builder osVersion(String version) {
+            if (osVersion != null)
+                throw new IllegalStateException("OS version already set");
+            if (version == null || version.isEmpty())
+                throw new IllegalArgumentException("OS version is null or empty");
+            osVersion = version;
+            return this;
+        }
+
+        /* package */ Builder hashes(DependencyHashes hashes) {
+            this.hashes = hashes;
+            return this;
+        }
+
+
+        /* package */ Builder synthetic(boolean v) {
+            this.synthetic = v;
+            return this;
+        }
+
+        /**
+         * Builds and returns a {@code ModuleDescriptor} from its components.
+         *
+         * @return The module descriptor
+         */
+        public ModuleDescriptor build() {
+            assert name != null;
+
+            return new ModuleDescriptor(name,
+                                        automatic,
+                                        synthetic,
+                                        requires,
+                                        uses,
+                                        exports,
+                                        provides,
+                                        version,
+                                        mainClass,
+                                        osName,
+                                        osArch,
+                                        osVersion,
+                                        conceals,
+                                        hashes);
+        }
+
+    }
+
+
+    /**
+     * Compares this module descriptor to another.
+     *
+     * <p> Two {@code ModuleDescriptor} objects are compared by comparing their
+     * module name lexicographically.  Where the module names are equal then
+     * the versions, if present, are compared. </p>
+     *
+     * @apiNote For now, the natural ordering is not consistent with equals.
+     * If two module descriptors have equal module names, equal versions if
+     * present, but their corresponding components are not equal, then they
+     * will be considered equal by this method.
+     *
+     * @param  that
+     *         The object to which this module descriptor is to be compared
+     *
+     * @return A negative integer, zero, or a positive integer if this module
+     *         descriptor is less than, equal to, or greater than the given
+     *         module descriptor
+     */
+    @Override
+    public int compareTo(ModuleDescriptor that) {
+        int c = this.name().compareTo(that.name());
+        if (c != 0) return c;
+        if (version == null) {
+            if (that.version == null)
+                return 0;
+            return -1;
+        }
+        if (that.version == null)
+            return +1;
+        return version.compareTo(that.version);
+    }
+
+    /**
+     * Tests this module descriptor for equality with the given object.
+     *
+     * <p> If the given object is not a {@code ModuleDescriptor} then this
+     * method returns {@code false}. Two module descriptors are equal if each
+     * of their corresponding components is equal. </p>
+     *
+     * <p> This method satisfies the general contract of the {@link
+     * java.lang.Object#equals(Object) Object.equals} method. </p>
+     *
+     * @param   ob
+     *          the object to which this object is to be compared
+     *
+     * @return  {@code true} if, and only if, the given object is a module
+     *          descriptor that is equal to this module descriptor
+     */
+    @Override
+    public boolean equals(Object ob) {
+        if (ob == this)
+            return true;
+        if (!(ob instanceof ModuleDescriptor))
+            return false;
+        ModuleDescriptor that = (ModuleDescriptor)ob;
+        return (name.equals(that.name)
+                && automatic == that.automatic
+                && synthetic == that.synthetic
+                && requires.equals(that.requires)
+                && uses.equals(that.uses)
+                && exports.equals(that.exports)
+                && provides.equals(that.provides)
+                && Objects.equals(version, that.version)
+                && Objects.equals(mainClass, that.mainClass)
+                && Objects.equals(osName, that.osName)
+                && Objects.equals(osArch, that.osArch)
+                && Objects.equals(osVersion, that.osVersion)
+                && Objects.equals(conceals, that.conceals)
+                && Objects.equals(hashes, that.hashes));
+    }
+
+    private transient int hash;  // cached hash code
+
+    /**
+     * Computes a hash code for this module descriptor.
+     *
+     * <p> The hash code is based upon the components of the module descriptor,
+     * and satisfies the general contract of the {@link Object#hashCode
+     * Object.hashCode} method. </p>
+     *
+     * @return The hash-code value for this module descriptor
+     */
+    @Override
+    public int hashCode() {
+        int hc = hash;
+        if (hc == 0) {
+            hc = name.hashCode();
+            hc = hc * 43 + Boolean.hashCode(automatic);
+            hc = hc * 43 + Boolean.hashCode(synthetic);
+            hc = hc * 43 + requires.hashCode();
+            hc = hc * 43 + uses.hashCode();
+            hc = hc * 43 + exports.hashCode();
+            hc = hc * 43 + provides.hashCode();
+            hc = hc * 43 + Objects.hashCode(version);
+            hc = hc * 43 + Objects.hashCode(mainClass);
+            hc = hc * 43 + Objects.hashCode(osName);
+            hc = hc * 43 + Objects.hashCode(osArch);
+            hc = hc * 43 + Objects.hashCode(osVersion);
+            hc = hc * 43 + Objects.hashCode(conceals);
+            hc = hc * 43 + Objects.hashCode(hashes);
+            if (hc != 0) hash = hc;
+        }
+        return hc;
+    }
+
+    /**
+     * Returns a string describing this descriptor.
+     *
+     * @return A string describing this descriptor
+     */
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("Module { name: ").append(toNameAndVersion());
+        if (!requires.isEmpty())
+            sb.append(", ").append(requires);
+        if (!uses.isEmpty())
+            sb.append(", ").append(uses);
+        if (!exports.isEmpty())
+            sb.append(", exports: ").append(exports);
+        if (!provides.isEmpty()) {
+            sb.append(", provides: [");
+            for (Map.Entry<String, Provides> entry : provides.entrySet()) {
+                sb.append(entry.getKey())
+                   .append(" with ")
+                   .append(entry.getValue());
+            }
+            sb.append("]");
+        }
+        sb.append(" }");
+        return sb.toString();
+    }
+
+    /**
+     * Reads the binary form of a module declaration from an input stream
+     * as a module descriptor.
+     *
+     * <p> If the descriptor encoded in the input stream does not indicate a
+     * set of concealed packages then the {@code packageFinder} will be
+     * invoked.  The packages it returns, except for those indicated as
+     * exported in the encoded descriptor, will be considered to be concealed.
+     * If the {@code packageFinder} throws an {@link UncheckedIOException} then
+     * {@link IOException} cause will be re-thrown. </p>
+     *
+     * <p> If there are bytes following the module descriptor then it is
+     * implementation specific as to whether those bytes are read, ignored,
+     * or reported as an {@code InvalidModuleDescriptorException}. If this
+     * method fails with an {@code InvalidModuleDescriptorException} or {@code
+     * IOException} then it may do so after some, but not all, bytes have
+     * been read from the input stream. It is strongly recommended that the
+     * stream be promptly closed and discarded if an exception occurs. </p>
+     *
+     * @apiNote The {@code packageFinder} parameter is for use when reading
+     * module descriptors from legacy module-artifact formats that do not
+     * record the set of concealed packages in the descriptor itself.
+     *
+     * @param  in
+     *         The input stream
+     * @param  packageFinder
+     *         A supplier that can produce a set of package names
+     *
+     * @return The module descriptor
+     *
+     * @throws InvalidModuleDescriptorException
+     *         If an invalid module descriptor is detected
+     * @throws IOException
+     *         If an I/O error occurs reading from the input stream or {@code
+     *         UncheckedIOException} is thrown by the package finder
+     */
+    public static ModuleDescriptor read(InputStream in,
+                                        Supplier<Set<String>> packageFinder)
+        throws IOException
+    {
+        return ModuleInfo.read(in, requireNonNull(packageFinder));
+    }
+
+    /**
+     * Reads the binary form of a module declaration from an input stream
+     * as a module descriptor.
+     *
+     * @param  in
+     *         The input stream
+     *
+     * @return The module descriptor
+     *
+     * @throws InvalidModuleDescriptorException
+     *         If an invalid module descriptor is detected
+     * @throws IOException
+     *         If an I/O error occurs reading from the input stream
+     */
+    public static ModuleDescriptor read(InputStream in) throws IOException {
+        return ModuleInfo.read(in, null);
+    }
+
+    /**
+     * Reads the binary form of a module declaration from a byte buffer
+     * as a module descriptor.
+     *
+     * <p> If the descriptor encoded in the byte buffer does not indicate a
+     * set of concealed packages then the {@code packageFinder} will be
+     * invoked.  The packages it returns, except for those indicated as
+     * exported in the encoded descriptor, will be considered to be
+     * concealed. </p>
+     *
+     * <p> The module descriptor is read from the buffer stating at index
+     * {@code p}, where {@code p} is the buffer's {@link ByteBuffer#position()
+     * position} when this method is invoked. Upon return the buffer's position
+     * will be equal to {@code p + n} where {@code n} is the number of bytes
+     * read from the buffer. </p>
+     *
+     * <p> If there are bytes following the module descriptor then it is
+     * implementation specific as to whether those bytes are read, ignored,
+     * or reported as an {@code InvalidModuleDescriptorException}. If this
+     * method fails with an {@code InvalidModuleDescriptorException} then it
+     * may do so after some, but not all, bytes have been read. </p>
+     *
+     * @apiNote The {@code packageFinder} parameter is for use when reading
+     * module descriptors from legacy module-artifact formats that do not
+     * record the set of concealed packages in the descriptor itself.
+     *
+     * @param  bb
+     *         The byte buffer
+     * @param  packageFinder
+     *         A supplier that can produce a set of package names
+     *
+     * @return The module descriptor
+     *
+     * @throws InvalidModuleDescriptorException
+     *         If an invalid module descriptor is detected
+     */
+    public static ModuleDescriptor read(ByteBuffer bb,
+                                        Supplier<Set<String>> packageFinder)
+    {
+        return ModuleInfo.read(bb, requireNonNull(packageFinder));
+    }
+
+    /**
+     * Reads the binary form of a module declaration from a byte buffer
+     * as a module descriptor.
+     *
+     * @param  bb
+     *         The byte buffer
+     *
+     * @return The module descriptor
+     *
+     * @throws InvalidModuleDescriptorException
+     *         If an invalid module descriptor is detected
+     */
+    public static ModuleDescriptor read(ByteBuffer bb) {
+        return ModuleInfo.read(bb, null);
+    }
+
+
+    /**
+     * Computes the set of packages from exports and concealed packages.
+     * It returns the concealed packages set if there is no exported package.
+     */
+    private static Set<String> computePackages(Set<Exports> exports,
+                                               Set<String> conceals)
+    {
+        if (exports.isEmpty())
+            return conceals;
+
+        Set<String> pkgs = new HashSet<>(conceals);
+        exports.stream().map(Exports::source).forEach(pkgs::add);
+        return emptyOrUnmodifiableSet(pkgs);
+    }
+
+    /**
+     * Computes the set of concealed packages from exports and all packages.
+     * It returns the packages set if there are no exported packages.
+     */
+    private static Set<String> computeConcealedPackages(Set<Exports> exports,
+                                                        Set<String> pkgs)
+    {
+        if (exports.isEmpty())
+            return pkgs;
+
+        Set<String> conceals = new HashSet<>(pkgs);
+        exports.stream().map(Exports::source).forEach(conceals::remove);
+        return emptyOrUnmodifiableSet(conceals);
+    }
+
+    private static <K,V> Map<K,V> emptyOrUnmodifiableMap(Map<K,V> map) {
+        if (map.isEmpty()) {
+            return Collections.emptyMap();
+        } else if (map.size() == 1) {
+            Map.Entry<K, V> entry = map.entrySet().iterator().next();
+            return Collections.singletonMap(entry.getKey(), entry.getValue());
+        } else {
+            return Collections.unmodifiableMap(map);
+        }
+    }
+
+    private static <T> Set<T> emptyOrUnmodifiableSet(Set<T> set) {
+        if (set.isEmpty()) {
+            return Collections.emptySet();
+        } else if (set.size() == 1) {
+            return Collections.singleton(set.iterator().next());
+        } else {
+            return Collections.unmodifiableSet(set);
+        }
+    }
+
+    static {
+        /**
+         * Setup the shared secret to allow code in other packages create
+         * ModuleDescriptor and associated objects directly.
+         */
+        jdk.internal.misc.SharedSecrets
+            .setJavaLangModuleAccess(new jdk.internal.misc.JavaLangModuleAccess() {
+                @Override
+                public Requires newRequires(Set<Requires.Modifier> ms, String mn) {
+                    return new Requires(ms, mn, false);
+                }
+
+                @Override
+                public Exports newExports(String source, Set<String> targets) {
+                    return new Exports(source, targets, false);
+                }
+
+                @Override
+                public Exports newExports(String source) {
+                    return new Exports(source, false);
+                }
+
+                @Override
+                public Provides newProvides(String service, Set<String> providers) {
+                    return new Provides(service, providers, false);
+                }
+
+                @Override
+                public Version newVersion(String v) {
+                    return new Version(v);
+                }
+
+                @Override
+                public ModuleDescriptor newModuleDescriptor(ModuleDescriptor md,
+                                                            Set<String> pkgs) {
+                    return new ModuleDescriptor(md, pkgs);
+                }
+
+                @Override
+                public ModuleDescriptor newModuleDescriptor(String name,
+                                                            boolean automatic,
+                                                            boolean synthetic,
+                                                            Set<Requires> requires,
+                                                            Set<String> uses, Set<Exports> exports,
+                                                            Map<String, Provides> provides,
+                                                            Version version,
+                                                            String mainClass,
+                                                            String osName,
+                                                            String osArch,
+                                                            String osVersion,
+                                                            Set<String> conceals,
+                                                            Set<String> packages) {
+                    return new ModuleDescriptor(name,
+                                                automatic,
+                                                synthetic,
+                                                requires,
+                                                uses,
+                                                exports,
+                                                provides,
+                                                version,
+                                                mainClass,
+                                                osName,
+                                                osArch,
+                                                osVersion,
+                                                conceals,
+                                                packages);
+                }
+            });
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/module/ModuleFinder.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,362 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.module;
+
+import java.io.File;
+import java.io.FilePermission;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.AccessController;
+import java.security.Permission;
+import java.security.PrivilegedAction;
+import java.util.Collections;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * A finder of modules. A {@code ModuleFinder} is used to find modules during
+ * <a href="Configuration.html#resolution">resolution</a> or
+ * <a href="Configuration.html#servicebinding">service binding</a>.
+ *
+ * <p> A {@code ModuleFinder} can only find one module with a given name. A
+ * {@code ModuleFinder} that finds modules in a sequence of directories, for
+ * example, will locate the first occurrence of a module of a given name and
+ * will ignore other modules of that name that appear in directories later in
+ * the sequence. </p>
+ *
+ * <p> Example usage: </p>
+ *
+ * <pre>{@code
+ *     Path dir1, dir2, dir3;
+ *
+ *     ModuleFinder finder = ModuleFinder.of(dir1, dir2, dir3);
+ *
+ *     Optional<ModuleReference> omref = finder.find("jdk.foo");
+ *     if (omref.isPresent()) { ... }
+ *
+ * }</pre>
+ *
+ * <p> The {@link #find(String) find} and {@link #findAll() findAll} methods
+ * defined here can fail for several reasons. These include include I/O errors,
+ * errors detected parsing a module descriptor ({@code module-info.class}), or
+ * in the case of {@code ModuleFinder} returned by {@link #of ModuleFinder.of},
+ * that two or more modules with the same name are found in a directory.
+ * When an error is detected then these methods throw {@link FindException
+ * FindException} with an appropriate {@link Throwable#getCause cause}.
+ * The behavior of a {@code ModuleFinder} after a {@code FindException} is
+ * thrown is undefined. For example, invoking {@code find} after an exception
+ * is thrown may or may not scan the same modules that lead to the exception.
+ * It is recommended that a module finder be discarded after an exception is
+ * thrown. </p>
+ *
+ * <p> A {@code ModuleFinder} is not required to be thread safe. </p>
+ *
+ * @since 9
+ */
+
+public interface ModuleFinder {
+
+    /**
+     * Finds a reference to a module of a given name.
+     *
+     * <p> A {@code ModuleFinder} provides a consistent view of the
+     * modules that it locates. If {@code find} is invoked several times to
+     * locate the same module (by name) then it will return the same result
+     * each time. If a module is located then it is guaranteed to be a member
+     * of the set of modules returned by the {@link #findAll() findAll}
+     * method. </p>
+     *
+     * @param  name
+     *         The name of the module to find
+     *
+     * @return A reference to a module with the given name or an empty
+     *         {@code Optional} if not found
+     *
+     * @throws FindException
+     *         If an error occurs finding the module
+     *
+     * @throws SecurityException
+     *         If denied by the security manager
+     */
+    Optional<ModuleReference> find(String name);
+
+    /**
+     * Returns the set of all module references that this finder can locate.
+     *
+     * <p> A {@code ModuleFinder} provides a consistent view of the modules
+     * that it locates. If {@link #findAll() findAll} is invoked several times
+     * then it will return the same (equals) result each time. For each {@code
+     * ModuleReference} element in the returned set then it is guaranteed that
+     * {@link #find find} will locate the {@code ModuleReference} if invoked
+     * to find that module. </p>
+     *
+     * @apiNote This is important to have for methods such as {@link
+     * Configuration#resolveRequiresAndUses resolveRequiresAndUses} that need
+     * to scan the module path to find modules that provide a specific service.
+     *
+     * @return The set of all module references that this finder locates
+     *
+     * @throws FindException
+     *         If an error occurs finding all modules
+     *
+     * @throws SecurityException
+     *         If denied by the security manager
+     */
+    Set<ModuleReference> findAll();
+
+    /**
+     * Returns a module finder that locates the <em>system modules</em>. The
+     * system modules are typically linked into the Java run-time image.
+     * The module finder will always find {@code java.base}.
+     *
+     * <p> If there is a security manager set then its {@link
+     * SecurityManager#checkPermission(Permission) checkPermission} method is
+     * invoked to check that the caller has been granted {@link FilePermission}
+     * to recursively read the directory that is the value of the system
+     * property {@code java.home}. </p>
+     *
+     * @return A {@code ModuleFinder} that locates the system modules
+     *
+     * @throws SecurityException
+     *         If denied by the security manager
+     */
+    static ModuleFinder ofSystem() {
+        String home;
+
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            PrivilegedAction<String> pa = () -> System.getProperty("java.home");
+            home = AccessController.doPrivileged(pa);
+            Permission p = new FilePermission(home + File.separator + "-", "read");
+            sm.checkPermission(p);
+        } else {
+            home = System.getProperty("java.home");
+        }
+
+        Path modules = Paths.get(home, "lib", "modules");
+        if (Files.isRegularFile(modules)) {
+            return new SystemModuleFinder();
+        } else {
+            Path mlib = Paths.get(home, "modules");
+            if (Files.isDirectory(mlib)) {
+                return of(mlib);
+            } else {
+                throw new InternalError("Unable to detect the run-time image");
+            }
+        }
+    }
+
+    /**
+     * Returns a module finder that locates modules on the file system by
+     * searching a sequence of directories and/or packaged modules.
+     *
+     * Each element in the given array is one of:
+     * <ol>
+     *     <li><p> A path to a directory of modules.</p></li>
+     *     <li><p> A path to the <em>top-level</em> directory of an
+     *         <em>exploded module</em>. </p></li>
+     *     <li><p> A path to a <em>packaged module</em>. </p></li>
+     * </ol>
+     *
+     * The module finder locates modules by searching each directory, exploded
+     * module, or packaged module in array index order. It finds the first
+     * occurrence of a module with a given name and ignores other modules of
+     * that name that appear later in the sequence.
+     *
+     * <p> If an element is a path to a directory of modules then each entry in
+     * the directory is a packaged module or the top-level directory of an
+     * exploded module. The module finder's {@link #find(String) find} or
+     * {@link #findAll() findAll} methods throw {@link FindException} if a
+     * directory containing more than one module with the same name is
+     * encountered. </p>
+     *
+     * <p> If an element in the array is a path to a directory, and that
+     * directory contains a file named {@code module-info.class}, then the
+     * directory is treated as an exploded module rather than a directory of
+     * modules. </p>
+     *
+     * <p> The module finder returned by this method supports modules that are
+     * packaged as JAR files. A JAR file with a {@code module-info.class} in
+     * the top-level directory of the JAR file is a modular JAR and is an
+     * <em>explicit module</em>. A JAR file that does not have a {@code
+     * module-info.class} in the top-level directory is an {@link
+     * ModuleDescriptor#isAutomatic automatic} module. The {@link
+     * ModuleDescriptor} for an automatic module is created as follows:
+     *
+     * <ul>
+     *
+     *     <li><p> The module {@link ModuleDescriptor#name() name}, and {@link
+     *     ModuleDescriptor#version() version} if applicable, is derived from
+     *     the file name of the JAR file as follows: </p>
+     *
+     *     <ul>
+     *
+     *         <li><p> The {@code .jar} suffix is removed. </p></li>
+     *
+     *         <li><p> If the name matches the regular expression {@code
+     *         "-(\\d+(\\.|$))"} then the module name will be derived from the
+     *         subsequence proceeding the hyphen of the first occurrence. The
+     *         subsequence after the hyphen is parsed as a {@link
+     *         ModuleDescriptor.Version} and ignored if it cannot be parsed as
+     *         a {@code Version}. </p></li>
+     *
+     *         <li><p> For the module name, then all non-alphanumeric
+     *         characters ({@code [^A-Za-z0-9])} are replaced with a dot
+     *         ({@code "."}), all repeating dots are replaced with one dot,
+     *         and all leading and trailing dots are removed. </p></li>
+     *
+     *         <li><p> As an example, a JAR file named {@code foo-bar.jar} will
+     *         derive a module name {@code foo.bar} and no version. A JAR file
+     *         named {@code foo-1.2.3-SNAPSHOT.jar} will derive a module name
+     *         {@code foo} and {@code 1.2.3-SNAPSHOT} as the version. </p></li>
+     *
+     *     </ul></li>
+     *
+     *     <li><p> It {@link ModuleDescriptor#requires() requires} {@code
+     *     java.base}. </p></li>
+     *
+     *     <li><p> All entries in the JAR file with names ending with {@code
+     *     .class} are assumed to be class files where the name corresponds
+     *     to the fully qualified name of the class. The packages of all
+     *     classes are {@link ModuleDescriptor#exports() exported}. </p></li>
+     *
+     *     <li><p> The contents of all entries starting with {@code
+     *     META-INF/services/} are assumed to be service configuration files
+     *     (see {@link java.util.ServiceLoader}). The name of the file
+     *     (that follows {@code META-INF/services/}) is assumed to be the
+     *     fully-qualified binary name of a service type. The entries in the
+     *     file are assumed to be the fully-qualified binary names of
+     *     provider classes. </p></li>
+     *
+     *     <li><p> If the JAR file has a {@code Main-Class} attribute in its
+     *     main manifest then its value is the {@link
+     *     ModuleDescriptor#mainClass() main class}. </p></li>
+     *
+     * </ul>
+     *
+     * <p> In addition to JAR files, an implementation may also support modules
+     * that are packaged in other implementation specific module formats. As
+     * with automatic modules, the contents of a packaged or exploded module
+     * may need to be <em>scanned</em> in order to determine the packages in
+     * the module. If a {@code .class} file that corresponds to a class in an
+     * unnamed package is encountered then {@code FindException} is thrown. </p>
+     *
+     * <p> Finders created by this method are lazy and do not eagerly check
+     * that the given file paths are directories or packaged modules.
+     * Consequently, the {@code find} or {@code findAll} methods will only
+     * fail if invoking these methods results in searching a directory or
+     * packaged module and an error is encountered. Paths to files that do not
+     * exist are ignored. </p>
+     *
+     * @param entries
+     *        A possibly-empty array of paths to directories of modules
+     *        or paths to packaged or exploded modules
+     *
+     * @return A {@code ModuleFinder} that locates modules on the file system
+     */
+    static ModuleFinder of(Path... entries) {
+        return new ModulePath(entries);
+    }
+
+    /**
+     * Returns a module finder that is the equivalent to composing two
+     * module finders. The resulting finder will locate modules references
+     * using {@code first}; if not found then it will attempt to locate module
+     * references using {@code second}.
+     *
+     * <p> The {@link #findAll() findAll} method of the resulting module finder
+     * will locate all modules located by the first module finder. It will
+     * also locate all modules located by the second module finder that are not
+     * located by the first module finder. </p>
+     *
+     * @apiNote This method will eventually be changed to take a sequence of
+     *          module finders.
+     *
+     * @param first
+     *        The first module finder
+     * @param second
+     *        The second module finder
+     *
+     * @return A {@code ModuleFinder} that composes two module finders
+     */
+    static ModuleFinder compose(ModuleFinder first, ModuleFinder second) {
+        Objects.requireNonNull(first);
+        Objects.requireNonNull(second);
+
+        return new ModuleFinder() {
+            Set<ModuleReference> allModules;
+
+            @Override
+            public Optional<ModuleReference> find(String name) {
+                Optional<ModuleReference> om = first.find(name);
+                if (!om.isPresent())
+                    om = second.find(name);
+                return om;
+            }
+            @Override
+            public Set<ModuleReference> findAll() {
+                if (allModules == null) {
+                    allModules = Stream.concat(first.findAll().stream(),
+                                               second.findAll().stream())
+                                       .map(a -> a.descriptor().name())
+                                       .distinct()
+                                       .map(this::find)
+                                       .map(Optional::get)
+                                       .collect(Collectors.toSet());
+                }
+                return allModules;
+            }
+        };
+    }
+
+    /**
+     * Returns an empty module finder.  The empty finder does not find any
+     * modules.
+     *
+     * @apiNote This is useful when using methods such as {@link
+     * Configuration#resolveRequires resolveRequires} where two finders are
+     * specified. An alternative is {@code ModuleFinder.of()}.
+     *
+     * @return A {@code ModuleFinder} that does not find any modules
+     */
+    static ModuleFinder empty() {
+        // an alternative implementation of ModuleFinder.of()
+        return new ModuleFinder() {
+            @Override public Optional<ModuleReference> find(String name) {
+                Objects.requireNonNull(name);
+                return Optional.empty();
+            }
+            @Override public Set<ModuleReference> findAll() {
+                return Collections.emptySet();
+            }
+        };
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/module/ModuleInfo.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,790 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.module;
+
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
+import java.lang.module.ModuleDescriptor.Requires.Modifier;
+import java.nio.ByteBuffer;
+import java.nio.BufferUnderflowException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Supplier;
+
+import jdk.internal.module.Hasher.DependencyHashes;
+
+import static jdk.internal.module.ClassFileConstants.*;
+
+
+/**
+ * Read module information from a {@code module-info} class file.
+ *
+ * @implNote The rationale for the hand-coded reader is startup performance
+ * and fine control over the throwing of InvalidModuleDescriptorException.
+ */
+
+final class ModuleInfo {
+
+    // supplies the set of packages when ConcealedPackages not present
+    private final Supplier<Set<String>> packageFinder;
+
+    // indicates if the Hashes attribute should be parsed
+    private final boolean parseHashes;
+
+    // the builder, created when parsing
+    private ModuleDescriptor.Builder builder;
+
+    private ModuleInfo(Supplier<Set<String>> pf, boolean ph) {
+        packageFinder = pf;
+        parseHashes = ph;
+    }
+
+    private ModuleInfo(Supplier<Set<String>> pf) {
+        this(pf, true);
+    }
+
+    /**
+     * Reads a {@code module-info.class} from the given input stream.
+     *
+     * @throws InvalidModuleDescriptorException
+     * @throws IOException
+     */
+    public static ModuleDescriptor read(InputStream in,
+                                        Supplier<Set<String>> pf)
+        throws IOException
+    {
+        try {
+            return new ModuleInfo(pf).doRead(new DataInputStream(in));
+        } catch (IllegalArgumentException iae) {
+            // IllegalArgumentException means a malformed class
+            throw invalidModuleDescriptor(iae.getMessage());
+        } catch (EOFException x) {
+            throw truncatedModuleDescriptor();
+        }
+    }
+
+    /**
+     * Reads a {@code module-info.class} from the given byte buffer.
+     *
+     * @throws InvalidModuleDescriptorException
+     * @throws UncheckedIOException
+     */
+    public static ModuleDescriptor read(ByteBuffer bb,
+                                        Supplier<Set<String>> pf)
+    {
+        try {
+            return new ModuleInfo(pf).doRead(new DataInputWrapper(bb));
+        } catch (IllegalArgumentException iae) {
+            // IllegalArgumentException means a malformed class
+            throw invalidModuleDescriptor(iae.getMessage());
+        } catch (EOFException x) {
+            throw truncatedModuleDescriptor();
+        } catch (IOException ioe) {
+            throw new UncheckedIOException(ioe);
+        }
+    }
+
+    /**
+     * Reads a {@code module-info.class} from the given byte buffer
+     * but ignore the {@code Hashes} attribute.
+     *
+     * @throws InvalidModuleDescriptorException
+     * @throws UncheckedIOException
+     */
+    static ModuleDescriptor readIgnoringHashes(ByteBuffer bb,
+                                               Supplier<Set<String>> pf)
+    {
+        try {
+            return new ModuleInfo(pf, false).doRead(new DataInputWrapper(bb));
+        } catch (IllegalArgumentException iae) {
+            throw invalidModuleDescriptor(iae.getMessage());
+        } catch (EOFException x) {
+            throw truncatedModuleDescriptor();
+        } catch (IOException ioe) {
+            throw new UncheckedIOException(ioe);
+        }
+    }
+
+    /**
+     * Reads the input as a module-info class file.
+     *
+     * @throws IOException
+     * @throws InvalidModuleDescriptorException
+     * @throws IllegalArgumentException if thrown by the ModuleDescriptor.Builder
+     *         because an identifier is not a legal Java identifier, duplicate
+     *         exports, and many other reasons
+     */
+    private ModuleDescriptor doRead(DataInput in) throws IOException {
+
+        int magic = in.readInt();
+        if (magic != 0xCAFEBABE)
+            throw invalidModuleDescriptor("Bad magic number");
+
+        int minor_version = in.readUnsignedShort();
+        int major_version = in.readUnsignedShort();
+        if (major_version < 53) {
+            // throw invalidModuleDescriptor"Must be >= 53.0");
+        }
+
+        ConstantPool cpool = new ConstantPool(in);
+
+        int access_flags = in.readUnsignedShort();
+        if (access_flags != ACC_MODULE)
+            throw invalidModuleDescriptor("access_flags should be ACC_MODULE");
+
+        int this_class = in.readUnsignedShort();
+        String mn = cpool.getClassName(this_class);
+        int suffix = mn.indexOf("/module-info");
+        if (suffix < 1)
+            throw invalidModuleDescriptor("this_class not of form name/module-info");
+        mn = mn.substring(0, suffix).replace('/', '.');
+        builder = new ModuleDescriptor.Builder(mn);
+
+        int super_class = in.readUnsignedShort();
+        if (super_class > 0)
+            throw invalidModuleDescriptor("bad #super_class");
+
+        int interfaces_count = in.readUnsignedShort();
+        if (interfaces_count > 0)
+            throw invalidModuleDescriptor("Bad #interfaces");
+
+        int fields_count = in.readUnsignedShort();
+        if (fields_count > 0)
+            throw invalidModuleDescriptor("Bad #fields");
+
+        int methods_count = in.readUnsignedShort();
+        if (methods_count > 0)
+            throw invalidModuleDescriptor("Bad #methods");
+
+        int attributes_count = in.readUnsignedShort();
+
+        // the names of the attributes found in the class file
+        Set<String> attributes = new HashSet<>();
+
+        for (int i = 0; i < attributes_count ; i++) {
+            int name_index = in.readUnsignedShort();
+            String attribute_name = cpool.getUtf8(name_index);
+            int length = in.readInt();
+
+            boolean added = attributes.add(attribute_name);
+            if (!added && isAttributeAtMostOnce(attribute_name)) {
+                throw invalidModuleDescriptor("More than one "
+                                              + attribute_name + " attribute");
+            }
+
+            switch (attribute_name) {
+
+                case MODULE :
+                    readModuleAttribute(mn, in, cpool);
+                    break;
+
+                case CONCEALED_PACKAGES :
+                    readConcealedPackagesAttribute(in, cpool);
+                    break;
+
+                case VERSION :
+                    readVersionAttribute(in, cpool);
+                    break;
+
+                case MAIN_CLASS :
+                    readMainClassAttribute(in, cpool);
+                    break;
+
+                case TARGET_PLATFORM :
+                    readTargetPlatformAttribute(in, cpool);
+                    break;
+
+                case HASHES :
+                    if (parseHashes) {
+                        readHashesAttribute(in, cpool);
+                    } else {
+                        in.skipBytes(length);
+                    }
+                    break;
+
+                default:
+                    if (isAttributeDisallowed(attribute_name)) {
+                        throw invalidModuleDescriptor(attribute_name
+                                                      + " attribute not allowed");
+                    } else {
+                        in.skipBytes(length);
+                    }
+
+            }
+        }
+
+        // the Module attribute is required
+        if (!attributes.contains(MODULE)) {
+            throw invalidModuleDescriptor(MODULE + " attribute not found");
+        }
+
+        // If the ConcealedPackages attribute is not present then the
+        // packageFinder is used to to find any non-exported packages.
+        if (!attributes.contains(CONCEALED_PACKAGES) && packageFinder != null) {
+            Set<String> pkgs;
+            try {
+                pkgs = new HashSet<>(packageFinder.get());
+            } catch (UncheckedIOException x) {
+                throw x.getCause();
+            }
+            pkgs.removeAll(builder.exportedPackages());
+            builder.conceals(pkgs);
+        }
+
+        // Was the Synthetic attribute present?
+        if (attributes.contains(SYNTHETIC))
+            builder.synthetic(true);
+
+        return builder.build();
+    }
+
+    /**
+     * Reads the Module attribute.
+     */
+    private void readModuleAttribute(String mn, DataInput in, ConstantPool cpool)
+        throws IOException
+    {
+        int requires_count = in.readUnsignedShort();
+        if (requires_count == 0 && !mn.equals("java.base")) {
+            throw invalidModuleDescriptor("The requires table must have"
+                                          + " at least one entry");
+        }
+        for (int i=0; i<requires_count; i++) {
+            int index = in.readUnsignedShort();
+            int flags = in.readUnsignedShort();
+            String dn = cpool.getUtf8(index);
+            Set<Modifier> mods;
+            if (flags == 0) {
+                mods = Collections.emptySet();
+            } else {
+                mods = new HashSet<>();
+                if ((flags & ACC_PUBLIC) != 0)
+                    mods.add(Modifier.PUBLIC);
+                if ((flags & ACC_SYNTHETIC) != 0)
+                    mods.add(Modifier.SYNTHETIC);
+                if ((flags & ACC_MANDATED) != 0)
+                    mods.add(Modifier.MANDATED);
+            }
+            builder.requires(mods, dn);
+        }
+
+        int exports_count = in.readUnsignedShort();
+        if (exports_count > 0) {
+            for (int i=0; i<exports_count; i++) {
+                int index = in.readUnsignedShort();
+                String pkg = cpool.getUtf8(index).replace('/', '.');
+                int exports_to_count = in.readUnsignedShort();
+                if (exports_to_count > 0) {
+                    Set<String> targets = new HashSet<>(exports_to_count);
+                    for (int j=0; j<exports_to_count; j++) {
+                        int exports_to_index = in.readUnsignedShort();
+                        targets.add(cpool.getUtf8(exports_to_index));
+                    }
+                    builder.exports(pkg, targets);
+                } else {
+                    builder.exports(pkg);
+                }
+            }
+        }
+
+        int uses_count = in.readUnsignedShort();
+        if (uses_count > 0) {
+            for (int i=0; i<uses_count; i++) {
+                int index = in.readUnsignedShort();
+                String sn = cpool.getClassName(index).replace('/', '.');
+                builder.uses(sn);
+            }
+        }
+
+        int provides_count = in.readUnsignedShort();
+        if (provides_count > 0) {
+            Map<String, Set<String>> pm = new HashMap<>();
+            for (int i=0; i<provides_count; i++) {
+                int index = in.readUnsignedShort();
+                int with_index = in.readUnsignedShort();
+                String sn = cpool.getClassName(index).replace('/', '.');
+                String cn = cpool.getClassName(with_index).replace('/', '.');
+                // computeIfAbsent
+                Set<String> providers = pm.get(sn);
+                if (providers == null) {
+                    providers = new HashSet<>();
+                    pm.put(sn, providers);
+                }
+                providers.add(cn);
+            }
+            for (Map.Entry<String, Set<String>> e : pm.entrySet()) {
+                builder.provides(e.getKey(), e.getValue());
+            }
+        }
+    }
+
+    /**
+     * Reads the ConcealedPackages attribute
+     */
+    private void readConcealedPackagesAttribute(DataInput in, ConstantPool cpool)
+        throws IOException
+    {
+        int package_count = in.readUnsignedShort();
+        for (int i=0; i<package_count; i++) {
+            int index = in.readUnsignedShort();
+            String pn = cpool.getUtf8(index).replace('/', '.');
+            builder.conceals(pn);
+        }
+    }
+
+    /**
+     * Reads the Version attribute
+     */
+    private void readVersionAttribute(DataInput in, ConstantPool cpool)
+        throws IOException
+    {
+        int index = in.readUnsignedShort();
+        builder.version(cpool.getUtf8(index));
+    }
+
+    /**
+     * Reads the MainClass attribute
+     */
+    private void readMainClassAttribute(DataInput in, ConstantPool cpool)
+        throws IOException
+    {
+        int index = in.readUnsignedShort();
+        builder.mainClass(cpool.getClassName(index).replace('/', '.'));
+    }
+
+    /**
+     * Reads the TargetPlatform attribute
+     */
+    private void readTargetPlatformAttribute(DataInput in, ConstantPool cpool)
+        throws IOException
+    {
+        int name_index = in.readUnsignedShort();
+        if (name_index != 0)
+            builder.osName(cpool.getUtf8(name_index));
+
+        int arch_index = in.readUnsignedShort();
+        if (arch_index != 0)
+            builder.osArch(cpool.getUtf8(arch_index));
+
+        int version_index = in.readUnsignedShort();
+        if (version_index != 0)
+            builder.osVersion(cpool.getUtf8(version_index));
+    }
+
+
+    /**
+     * Reads the Hashes attribute
+     *
+     * @apiNote For now the hash is stored in base64 as a UTF-8 string, this
+     * should be changed to be an array of u1.
+     */
+    private void readHashesAttribute(DataInput in, ConstantPool cpool)
+        throws IOException
+    {
+        int index = in.readUnsignedShort();
+        String algorithm = cpool.getUtf8(index);
+
+        int hash_count = in.readUnsignedShort();
+
+        Map<String, String> map = new HashMap<>(hash_count);
+        for (int i=0; i<hash_count; i++) {
+            index = in.readUnsignedShort();
+            String dn = cpool.getUtf8(index);
+            index = in.readUnsignedShort();
+            String hash = cpool.getUtf8(index);
+            map.put(dn, hash);
+        }
+
+        builder.hashes(new DependencyHashes(algorithm, map));
+    }
+
+
+    /**
+     * Returns true if the given attribute can be present at most once
+     * in the class file. Returns false otherwise.
+     */
+    private static boolean isAttributeAtMostOnce(String name) {
+
+        if (name.equals(MODULE) ||
+                name.equals(SOURCE_FILE) ||
+                name.equals(SDE) ||
+                name.equals(CONCEALED_PACKAGES) ||
+                name.equals(VERSION) ||
+                name.equals(MAIN_CLASS) ||
+                name.equals(TARGET_PLATFORM) ||
+                name.equals(HASHES))
+            return true;
+
+        return false;
+    }
+
+    /**
+     * Return true if the given attribute name is the name of a pre-defined
+     * attribute that is not allowed in the class file.
+     *
+     * Except for Module, InnerClasses, Synthetic, SourceFile, SourceDebugExtension,
+     * and Deprecated, none of the pre-defined attributes in JVMS 4.7 may appear.
+     */
+    private static boolean isAttributeDisallowed(String name) {
+        Set<String> notAllowed = predefinedNotAllowed;
+        if (notAllowed == null) {
+            notAllowed = Set.of(
+                    "ConstantValue",
+                    "Code",
+                    "StackMapTable",
+                    "Exceptions",
+                    "EnclosingMethod",
+                    "Signature",
+                    "LineNumberTable",
+                    "LocalVariableTable",
+                    "LocalVariableTypeTable",
+                    "RuntimeVisibleAnnotations",
+                    "RuntimeInvisibleAnnotations",
+                    "RuntimeVisibleParameterAnnotations",
+                    "RuntimeInvisibleParameterAnnotations",
+                    "RuntimeVisibleTypeAnnotations",
+                    "RuntimeInvisibleTypeAnnotations",
+                    "AnnotationDefault",
+                    "BootstrapMethods",
+                    "MethodParameters");
+            predefinedNotAllowed = notAllowed;
+        }
+        return notAllowed.contains(name);
+    }
+
+    // lazily created set the pre-defined attributes that are not allowed
+    private static volatile Set<String> predefinedNotAllowed;
+
+
+
+    /**
+     * The constant pool in a class file.
+     */
+    private static class ConstantPool {
+        static final int CONSTANT_Utf8 = 1;
+        static final int CONSTANT_Integer = 3;
+        static final int CONSTANT_Float = 4;
+        static final int CONSTANT_Long = 5;
+        static final int CONSTANT_Double = 6;
+        static final int CONSTANT_Class = 7;
+        static final int CONSTANT_String = 8;
+        static final int CONSTANT_Fieldref = 9;
+        static final int CONSTANT_Methodref = 10;
+        static final int CONSTANT_InterfaceMethodref = 11;
+        static final int CONSTANT_NameAndType = 12;
+        static final int CONSTANT_MethodHandle = 15;
+        static final int CONSTANT_MethodType = 16;
+        static final int CONSTANT_InvokeDynamic = 18;
+
+        private static class Entry {
+            protected Entry(int tag) {
+                this.tag = tag;
+            }
+            final int tag;
+        }
+
+        private static class IndexEntry extends Entry {
+            IndexEntry(int tag, int index) {
+                super(tag);
+                this.index = index;
+            }
+            final int index;
+        }
+
+        private static class Index2Entry extends Entry {
+            Index2Entry(int tag, int index1, int index2) {
+                super(tag);
+                this.index1 = index1;
+                this.index2 = index2;
+            }
+            final int index1,  index2;
+        }
+
+        private static class ValueEntry extends Entry {
+            ValueEntry(int tag, Object value) {
+                super(tag);
+                this.value = value;
+            }
+            final Object value;
+        }
+
+        final Entry[] pool;
+
+        ConstantPool(DataInput in) throws IOException {
+            int count = in.readUnsignedShort();
+            pool = new Entry[count];
+
+            for (int i = 1; i < count; i++) {
+                int tag = in.readUnsignedByte();
+                switch (tag) {
+
+                    case CONSTANT_Utf8:
+                        String svalue = in.readUTF();
+                        pool[i] = new ValueEntry(tag, svalue);
+                        break;
+
+                    case CONSTANT_Class:
+                    case CONSTANT_String:
+                        int index = in.readUnsignedShort();
+                        pool[i] = new IndexEntry(tag, index);
+                        break;
+
+                    case CONSTANT_Double:
+                        double dvalue = in.readDouble();
+                        pool[i] = new ValueEntry(tag, dvalue);
+                        i++;
+                        break;
+
+                    case CONSTANT_Fieldref:
+                    case CONSTANT_InterfaceMethodref:
+                    case CONSTANT_Methodref:
+                    case CONSTANT_InvokeDynamic:
+                    case CONSTANT_NameAndType:
+                        int index1 = in.readUnsignedShort();
+                        int index2 = in.readUnsignedShort();
+                        pool[i] = new Index2Entry(tag, index1, index2);
+                        break;
+
+                    case CONSTANT_MethodHandle:
+                        int refKind = in.readUnsignedByte();
+                        index = in.readUnsignedShort();
+                        pool[i] = new Index2Entry(tag, refKind, index);
+                        break;
+
+                    case CONSTANT_MethodType:
+                        index = in.readUnsignedShort();
+                        pool[i] = new IndexEntry(tag, index);
+                        break;
+
+                    case CONSTANT_Float:
+                        float fvalue = in.readFloat();
+                        pool[i] = new ValueEntry(tag, fvalue);
+                        break;
+
+                    case CONSTANT_Integer:
+                        int ivalue = in.readInt();
+                        pool[i] = new ValueEntry(tag, ivalue);
+                        break;
+
+                    case CONSTANT_Long:
+                        long lvalue = in.readLong();
+                        pool[i] = new ValueEntry(tag, lvalue);
+                        i++;
+                        break;
+
+                    default:
+                        throw invalidModuleDescriptor("Bad constant pool entry: "
+                                                      + i);
+                }
+            }
+        }
+
+        String getClassName(int index) {
+            checkIndex(index);
+            Entry e = pool[index];
+            if (e.tag != CONSTANT_Class) {
+                throw invalidModuleDescriptor("CONSTANT_Class expected at entry: "
+                                              + index);
+            }
+            return getUtf8(((IndexEntry) e).index);
+        }
+
+        String getUtf8(int index) {
+            checkIndex(index);
+            Entry e = pool[index];
+            if (e.tag != CONSTANT_Utf8) {
+                throw invalidModuleDescriptor("CONSTANT_Utf8 expected at entry: "
+                                              + index);
+            }
+            return (String) (((ValueEntry) e).value);
+        }
+
+        void checkIndex(int index) {
+            if (index < 1 || index >= pool.length)
+                throw invalidModuleDescriptor("Index into constant pool out of range");
+        }
+    }
+
+    /**
+     * A DataInput implementation that reads from a ByteBuffer.
+     */
+    private static class DataInputWrapper implements DataInput {
+        private final ByteBuffer bb;
+
+        DataInputWrapper(ByteBuffer bb) {
+            this.bb = bb;
+        }
+
+        @Override
+        public void readFully(byte b[]) throws IOException {
+            readFully(b, 0, b.length);
+        }
+
+        @Override
+        public void readFully(byte b[], int off, int len) throws IOException {
+            try {
+                bb.get(b, off, len);
+            } catch (BufferUnderflowException e) {
+                throw new EOFException();
+            }
+        }
+
+        @Override
+        public int skipBytes(int n) {
+            int skip = Math.min(n, bb.remaining());
+            bb.position(bb.position() + skip);
+            return skip;
+        }
+
+        @Override
+        public boolean readBoolean() throws IOException {
+            try {
+                int ch = bb.get();
+                return (ch != 0);
+            } catch (BufferUnderflowException e) {
+                throw new EOFException();
+            }
+        }
+
+        @Override
+        public byte readByte() throws IOException {
+            try {
+                return bb.get();
+            } catch (BufferUnderflowException e) {
+                throw new EOFException();
+            }
+        }
+
+        @Override
+        public int readUnsignedByte() throws IOException {
+            try {
+                return ((int) bb.get()) & 0xff;
+            } catch (BufferUnderflowException e) {
+                throw new EOFException();
+            }
+        }
+
+        @Override
+        public short readShort() throws IOException {
+            try {
+                return bb.getShort();
+            } catch (BufferUnderflowException e) {
+                throw new EOFException();
+            }
+        }
+
+        @Override
+        public int readUnsignedShort() throws IOException {
+            try {
+                return ((int) bb.getShort()) & 0xffff;
+            } catch (BufferUnderflowException e) {
+                throw new EOFException();
+            }
+        }
+
+        @Override
+        public char readChar() throws IOException {
+            try {
+                return bb.getChar();
+            } catch (BufferUnderflowException e) {
+                throw new EOFException();
+            }
+        }
+
+        @Override
+        public int readInt() throws IOException {
+            try {
+                return bb.getInt();
+            } catch (BufferUnderflowException e) {
+                throw new EOFException();
+            }
+        }
+
+        @Override
+        public long readLong() throws IOException {
+            try {
+                return bb.getLong();
+            } catch (BufferUnderflowException e) {
+                throw new EOFException();
+            }
+        }
+
+        @Override
+        public float readFloat() throws IOException {
+            try {
+                return bb.getFloat();
+            } catch (BufferUnderflowException e) {
+                throw new EOFException();
+            }
+        }
+
+        @Override
+        public double readDouble() throws IOException {
+            try {
+                return bb.getDouble();
+            } catch (BufferUnderflowException e) {
+                throw new EOFException();
+            }
+        }
+
+        @Override
+        public String readLine() {
+            throw new RuntimeException("not implemented");
+        }
+
+        @Override
+        public String readUTF() throws IOException {
+            // ### Need to measure the performance and feasibility of using
+            // the UTF-8 decoder instead.
+            return DataInputStream.readUTF(this);
+        }
+    }
+
+    /**
+     * Returns an InvalidModuleDescriptorException with the given detail
+     * message
+     */
+    private static InvalidModuleDescriptorException
+    invalidModuleDescriptor(String msg) {
+        return new InvalidModuleDescriptorException(msg);
+    }
+
+    /**
+     * Returns an InvalidModuleDescriptorException with a detail message to
+     * indicate that the class file is truncated.
+     */
+    private static InvalidModuleDescriptorException truncatedModuleDescriptor() {
+        return invalidModuleDescriptor("Truncated module-info.class");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/module/ModulePath.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,590 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.module;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.UncheckedIOException;
+import java.lang.module.ModuleDescriptor.Requires;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import jdk.internal.module.Checks;
+import jdk.internal.module.ConfigurableModuleFinder;
+import jdk.internal.perf.PerfCounter;
+
+
+/**
+ * A {@code ModuleFinder} that locates modules on the file system by searching
+ * a sequence of directories or packaged modules.
+ *
+ * The {@code ModuleFinder} can be configured to work in either the run-time
+ * or link-time phases. In both cases it locates modular JAR and exploded
+ * modules. When configured for link-time then it additionally locates
+ * modules in JMOD files.
+ */
+
+class ModulePath implements ConfigurableModuleFinder {
+    private static final String MODULE_INFO = "module-info.class";
+
+    // the entries on this module path
+    private final Path[] entries;
+    private int next;
+
+    // true if in the link phase
+    private boolean isLinkPhase;
+
+    // map of module name to module reference map for modules already located
+    private final Map<String, ModuleReference> cachedModules = new HashMap<>();
+
+    ModulePath(Path... entries) {
+        this.entries = entries.clone();
+        for (Path entry : this.entries) {
+            Objects.requireNonNull(entry);
+        }
+    }
+
+    @Override
+    public void configurePhase(Phase phase) {
+        isLinkPhase = (phase == Phase.LINK_TIME);
+    }
+
+    @Override
+    public Optional<ModuleReference> find(String name) {
+        Objects.requireNonNull(name);
+
+        // try cached modules
+        ModuleReference m = cachedModules.get(name);
+        if (m != null)
+            return Optional.of(m);
+
+        // the module may not have been encountered yet
+        while (hasNextEntry()) {
+            scanNextEntry();
+            m = cachedModules.get(name);
+            if (m != null)
+                return Optional.of(m);
+        }
+        return Optional.empty();
+    }
+
+    @Override
+    public Set<ModuleReference> findAll() {
+        // need to ensure that all entries have been scanned
+        while (hasNextEntry()) {
+            scanNextEntry();
+        }
+        return cachedModules.values().stream().collect(Collectors.toSet());
+    }
+
+    /**
+     * Returns {@code true} if there are additional entries to scan
+     */
+    private boolean hasNextEntry() {
+        return next < entries.length;
+    }
+
+    /**
+     * Scans the next entry on the module path. A no-op if all entries have
+     * already been scanned.
+     *
+     * @throws FindException if an error occurs scanning the next entry
+     */
+    private void scanNextEntry() {
+        if (hasNextEntry()) {
+
+            long t0 = System.nanoTime();
+
+            Path entry = entries[next];
+            Map<String, ModuleReference> modules = scan(entry);
+            next++;
+
+            // update cache, ignoring duplicates
+            int initialSize = cachedModules.size();
+            for (Map.Entry<String, ModuleReference> e : modules.entrySet()) {
+                cachedModules.putIfAbsent(e.getKey(), e.getValue());
+            }
+
+            // update counters
+            int added = cachedModules.size() - initialSize;
+            moduleCount.add(added);
+
+            scanTime.addElapsedTimeFrom(t0);
+        }
+    }
+
+
+    /**
+     * Scan the given module path entry. If the entry is a directory then it is
+     * a directory of modules or an exploded module. If the entry is a regular
+     * file then it is assumed to be a packaged module.
+     *
+     * @throws FindException if an error occurs scanning the entry
+     */
+    private Map<String, ModuleReference> scan(Path entry) {
+
+        BasicFileAttributes attrs;
+        try {
+            attrs = Files.readAttributes(entry, BasicFileAttributes.class);
+        } catch (NoSuchFileException e) {
+            return Collections.emptyMap();
+        } catch (IOException ioe) {
+            throw new FindException(ioe);
+        }
+
+        try {
+
+            if (attrs.isDirectory()) {
+                Path mi = entry.resolve(MODULE_INFO);
+                if (!Files.exists(mi)) {
+                    // does not exist or unable to determine so assume a
+                    // directory of modules
+                    return scanDirectory(entry);
+                }
+            }
+
+            if (attrs.isRegularFile() || attrs.isDirectory()) {
+                // packaged or exploded module
+                ModuleReference mref = readModule(entry, attrs);
+                if (mref != null) {
+                    String name = mref.descriptor().name();
+                    return Collections.singletonMap(name, mref);
+                }
+            }
+
+            // not recognized
+            throw new FindException("Unrecognized module: " + entry);
+
+        } catch (IOException ioe) {
+            throw new FindException(ioe);
+        }
+    }
+
+
+    /**
+     * Scans the given directory for packaged or exploded modules.
+     *
+     * @return a map of module name to ModuleReference for the modules found
+     *         in the directory
+     *
+     * @throws IOException if an I/O error occurs
+     * @throws FindException if an error occurs scanning the entry or the
+     *         directory contains two or more modules with the same name
+     */
+    private Map<String, ModuleReference> scanDirectory(Path dir)
+        throws IOException
+    {
+        // The map of name -> mref of modules found in this directory.
+        Map<String, ModuleReference> nameToReference = new HashMap<>();
+
+        try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
+            for (Path entry : stream) {
+                BasicFileAttributes attrs;
+                try {
+                    attrs = Files.readAttributes(entry, BasicFileAttributes.class);
+                } catch (NoSuchFileException ignore) {
+                    // file has been removed or moved, ignore for now
+                    continue;
+                }
+
+                ModuleReference mref = readModule(entry, attrs);
+
+                // module found
+                if (mref != null) {
+
+                    // can have at most one version of a module in the directory
+                    String name = mref.descriptor().name();
+                    if (nameToReference.put(name, mref) != null) {
+                        throw new FindException("Two versions of module "
+                                + name + " found in " + dir);
+                    }
+
+                }
+
+            }
+        }
+
+        return nameToReference;
+    }
+
+
+    /**
+     * Locates a packaged or exploded module, returning a {@code ModuleReference}
+     * to the module. Returns {@code null} if the module is not recognized
+     * as a packaged or exploded module.
+     *
+     * @throws IOException if an I/O error occurs
+     * @throws FindException if an error occurs parsing the module descriptor
+     */
+    private ModuleReference readModule(Path entry, BasicFileAttributes attrs)
+        throws IOException
+    {
+        try {
+
+            ModuleReference mref = null;
+            if (attrs.isDirectory()) {
+                mref = readExplodedModule(entry);
+            } if (attrs.isRegularFile()) {
+                if (entry.toString().endsWith(".jar")) {
+                    mref = readJar(entry);
+                } else if (isLinkPhase && entry.toString().endsWith(".jmod")) {
+                    mref = readJMod(entry);
+                }
+            }
+            return mref;
+
+        } catch (InvalidModuleDescriptorException e) {
+            throw new FindException("Error reading module: " + entry, e);
+        }
+    }
+
+
+    // -- jmod files --
+
+    private Set<String> jmodPackages(ZipFile zf) {
+        return zf.stream()
+            .filter(e -> e.getName().startsWith("classes/") &&
+                    e.getName().endsWith(".class"))
+            .map(e -> toPackageName(e))
+            .filter(pkg -> pkg.length() > 0) // module-info
+            .distinct()
+            .collect(Collectors.toSet());
+    }
+
+    /**
+     * Returns a {@code ModuleReference} to a module in jmod file on the
+     * file system.
+     */
+    private ModuleReference readJMod(Path file) throws IOException {
+        try (ZipFile zf = new ZipFile(file.toString())) {
+            ZipEntry ze = zf.getEntry("classes/" + MODULE_INFO);
+            if (ze == null) {
+                throw new IOException(MODULE_INFO + " is missing: " + file);
+            }
+            ModuleDescriptor md;
+            try (InputStream in = zf.getInputStream(ze)) {
+                md = ModuleDescriptor.read(in, () -> jmodPackages(zf));
+            }
+            return ModuleReferences.newJModModule(md, file);
+        }
+    }
+
+
+    // -- JAR files --
+
+    private static final String SERVICES_PREFIX = "META-INF/services/";
+
+    /**
+     * Returns a container with the service type corresponding to the name of
+     * a services configuration file.
+     *
+     * For example, if called with "META-INF/services/p.S" then this method
+     * returns a container with the value "p.S".
+     */
+    private Optional<String> toServiceName(String cf) {
+        assert cf.startsWith(SERVICES_PREFIX);
+        int index = cf.lastIndexOf("/") + 1;
+        if (index < cf.length()) {
+            String prefix = cf.substring(0, index);
+            if (prefix.equals(SERVICES_PREFIX)) {
+                String sn = cf.substring(index);
+                if (Checks.isJavaIdentifier(sn))
+                    return Optional.of(sn);
+            }
+        }
+        return Optional.empty();
+    }
+
+    /**
+     * Reads the next line from the given reader and trims it of comments and
+     * leading/trailing white space.
+     *
+     * Returns null if the reader is at EOF.
+     */
+    private String nextLine(BufferedReader reader) throws IOException {
+        String ln = reader.readLine();
+        if (ln != null) {
+            int ci = ln.indexOf('#');
+            if (ci >= 0)
+                ln = ln.substring(0, ci);
+            ln = ln.trim();
+        }
+        return ln;
+    }
+
+    /**
+     * Treat the given JAR file as a module as follows:
+     *
+     * 1. The module name (and optionally the version) is derived from the file
+     *    name of the JAR file
+     * 2. The packages of all .class files in the JAR file are exported
+     * 3. It has no module-private/concealed packages
+     * 4. The contents of any META-INF/services configuration files are mapped
+     *    to "provides" declarations
+     * 5. The Main-Class attribute in the main attributes of the JAR manifest
+     *    is mapped to the module descriptor mainClass
+     *
+     * @apiNote This needs to move to somewhere where it can be used by tools,
+     * maybe even a standard API if automatic modules are a Java SE feature.
+     */
+    private ModuleDescriptor deriveModuleDescriptor(JarFile jf)
+        throws IOException
+    {
+        // Derive module name and version from JAR file name
+
+        String fn = jf.getName();
+        int i = fn.lastIndexOf(File.separator);
+        if (i != -1)
+            fn = fn.substring(i+1);
+
+        // drop .jar
+        String mn = fn.substring(0, fn.length()-4);
+        String vs = null;
+
+        // find first occurrence of -${NUMBER}. or -${NUMBER}$
+        Matcher matcher = Pattern.compile("-(\\d+(\\.|$))").matcher(mn);
+        if (matcher.find()) {
+            int start = matcher.start();
+
+            // attempt to parse the tail as a version string
+            try {
+                String tail = mn.substring(start+1);
+                ModuleDescriptor.Version.parse(tail);
+                vs = tail;
+            } catch (IllegalArgumentException ignore) { }
+
+            mn = mn.substring(0, start);
+        }
+
+        // finally clean up the module name
+        mn =  mn.replaceAll("[^A-Za-z0-9]", ".")  // replace non-alphanumeric
+                .replaceAll("(\\.)(\\1)+", ".")   // collapse repeating dots
+                .replaceAll("^\\.", "")           // drop leading dots
+                .replaceAll("\\.$", "");          // drop trailing dots
+
+
+        // Builder throws IAE if module name is empty or invalid
+        ModuleDescriptor.Builder builder
+            = new ModuleDescriptor.Builder(mn, true)
+                .requires(Requires.Modifier.MANDATED, "java.base");
+        if (vs != null)
+            builder.version(vs);
+
+        // scan the entries in the JAR file to locate the .class and service
+        // configuration file
+        Stream<String> stream = jf.stream()
+            .map(e -> e.getName())
+            .filter(e -> (e.endsWith(".class") || e.startsWith(SERVICES_PREFIX)))
+            .distinct();
+        Map<Boolean, Set<String>> map
+            = stream.collect(Collectors.partitioningBy(s -> s.endsWith(".class"),
+                             Collectors.toSet()));
+        Set<String> classFiles = map.get(Boolean.TRUE);
+        Set<String> configFiles = map.get(Boolean.FALSE);
+
+        // all packages are exported
+        classFiles.stream()
+            .map(c -> toPackageName(c))
+            .distinct()
+            .forEach(p -> builder.exports(p));
+
+        // map names of service configuration files to service names
+        Set<String> serviceNames = configFiles.stream()
+            .map(this::toServiceName)
+            .filter(Optional::isPresent)
+            .map(Optional::get)
+            .collect(Collectors.toSet());
+
+        // parse each service configuration file
+        for (String sn : serviceNames) {
+            JarEntry entry = jf.getJarEntry(SERVICES_PREFIX + sn);
+            Set<String> providerClasses = new HashSet<>();
+            try (InputStream in = jf.getInputStream(entry)) {
+                BufferedReader reader
+                    = new BufferedReader(new InputStreamReader(in, "UTF-8"));
+                String cn;
+                while ((cn = nextLine(reader)) != null) {
+                    if (Checks.isJavaIdentifier(cn)) {
+                        providerClasses.add(cn);
+                    }
+                }
+            }
+            if (!providerClasses.isEmpty())
+                builder.provides(sn, providerClasses);
+        }
+
+        // Main-Class attribute if it exists
+        Manifest man = jf.getManifest();
+        if (man != null) {
+            Attributes attrs = man.getMainAttributes();
+            String mainClass = attrs.getValue(Attributes.Name.MAIN_CLASS);
+            if (mainClass != null)
+                builder.mainClass(mainClass);
+        }
+
+        return builder.build();
+    }
+
+    private Set<String> jarPackages(JarFile jf) {
+        return jf.stream()
+            .filter(e -> e.getName().endsWith(".class"))
+            .map(e -> toPackageName(e))
+            .filter(pkg -> pkg.length() > 0)   // module-info
+            .distinct()
+            .collect(Collectors.toSet());
+    }
+
+    /**
+     * Returns a {@code ModuleReference} to a module in modular JAR file on
+     * the file system.
+     */
+    private ModuleReference readJar(Path file) throws IOException {
+        try (JarFile jf = new JarFile(file.toString())) {
+
+            ModuleDescriptor md;
+            JarEntry entry = jf.getJarEntry(MODULE_INFO);
+            if (entry == null) {
+
+                // no module-info.class so treat it as automatic module
+                try {
+                    md = deriveModuleDescriptor(jf);
+                } catch (IllegalArgumentException iae) {
+                    throw new FindException(
+                        "Unable to derive module descriptor for: "
+                        + jf.getName(), iae);
+                }
+
+            } else {
+                md = ModuleDescriptor.read(jf.getInputStream(entry),
+                                           () -> jarPackages(jf));
+            }
+
+            return ModuleReferences.newJarModule(md, file);
+        }
+    }
+
+
+    // -- exploded directories --
+
+    private Set<String> explodedPackages(Path dir) {
+        try {
+            return Files.find(dir, Integer.MAX_VALUE,
+                              ((path, attrs) -> attrs.isRegularFile() &&
+                               path.toString().endsWith(".class")))
+                .map(path -> toPackageName(dir.relativize(path)))
+                .filter(pkg -> pkg.length() > 0)   // module-info
+                .distinct()
+                .collect(Collectors.toSet());
+        } catch (IOException x) {
+            throw new UncheckedIOException(x);
+        }
+    }
+
+    /**
+     * Returns a {@code ModuleReference} to an exploded module on the file
+     * system or {@code null} if {@code module-info.class} not found.
+     */
+    private ModuleReference readExplodedModule(Path dir) throws IOException {
+        Path mi = dir.resolve(MODULE_INFO);
+        ModuleDescriptor md;
+        try (InputStream in = Files.newInputStream(mi)) {
+            md = ModuleDescriptor.read(new BufferedInputStream(in),
+                                       () -> explodedPackages(dir));
+        } catch (NoSuchFileException e) {
+            // for now
+            return null;
+        }
+        return ModuleReferences.newExplodedModule(md, dir);
+    }
+
+
+    //
+
+    // p/q/T.class => p.q
+    private String toPackageName(String cn) {
+        assert cn.endsWith(".class");
+        int start = 0;
+        int index = cn.lastIndexOf("/");
+        if (index > start) {
+            return cn.substring(start, index).replace('/', '.');
+        } else {
+            return "";
+        }
+    }
+
+    private String toPackageName(ZipEntry entry) {
+        String name = entry.getName();
+        assert name.endsWith(".class");
+        // jmod classes in classes/, jar in /
+        int start = name.startsWith("classes/") ? 8 : 0;
+        int index = name.lastIndexOf("/");
+        if (index > start) {
+            return name.substring(start, index).replace('/', '.');
+        } else {
+            return "";
+        }
+    }
+
+    private String toPackageName(Path path) {
+        String name = path.toString();
+        assert name.endsWith(".class");
+        int index = name.lastIndexOf(File.separatorChar);
+        if (index != -1) {
+            return name.substring(0, index).replace(File.separatorChar, '.');
+        } else {
+            return "";
+        }
+    }
+
+    private static final PerfCounter scanTime
+        = PerfCounter.newPerfCounter("jdk.module.finder.modulepath.scanTime");
+    private static final PerfCounter moduleCount
+        = PerfCounter.newPerfCounter("jdk.module.finder.modulepath.modules");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/module/ModuleReader.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.module;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.util.Optional;
+
+
+/**
+ * Provides access to the content of a module.
+ *
+ * <p> A module reader is intended for cases where access to the resources in a
+ * module is required, regardless of whether the module has been loaded.
+ * A framework that scans a collection of packaged modules on the file system,
+ * for example, may use a module reader to access a specific resource in each
+ * module. A module reader is also intended to be used by {@code ClassLoader}
+ * implementations that load classes and resources from modules. </p>
+ *
+ * <p> A {@code ModuleReader} is {@linkplain ModuleReference#open open} upon
+ * creation and is closed by invoking the {@link #close close} method.  Failure
+ * to close a module reader may result in a resource leak.  The {@code
+ * try-with-resources} statement provides a useful construct to ensure that
+ * module readers are closed. </p>
+ *
+ * <p> A {@code ModuleReader} implementation may require permissions to access
+ * resources in the module. Consequently the {@link #find find}, {@link #open
+ * open} and {@link #read read} methods may throw {@code SecurityException} if
+ * access is denied by the security manager. </p>
+ *
+ * @see ModuleReference
+ * @since 9
+ */
+
+public interface ModuleReader extends Closeable {
+
+    /**
+     * Finds a resource, returning a URI to the resource in the module.
+     *
+     * @param  name
+     *         The name of the resource to open for reading
+     *
+     * @return A URI to the resource; an empty {@code Optional} if the resource
+     *         is not found or a URI cannot be constructed to locate the
+     *         resource
+     *
+     * @throws IOException
+     *         If an I/O error occurs or the module reader is closed
+     * @throws SecurityException
+     *         If denied by the security manager
+     *
+     * @see ClassLoader#getResource(String)
+     */
+    Optional<URI> find(String name) throws IOException;
+
+    /**
+     * Opens a resource, returning an input stream to read the resource in
+     * the module.
+     *
+     * @implSpec The default implementation invokes the {@link #find(String)
+     * find} method to get a URI to the resource. If found, then it attempts
+     * to construct a {@link java.net.URL URL} and open a connection to the
+     * resource.
+     *
+     * @param  name
+     *         The name of the resource to open for reading
+     *
+     * @return An input stream to read the resource or an empty
+     *         {@code Optional} if not found
+     *
+     * @throws IOException
+     *         If an I/O error occurs or the module reader is closed
+     * @throws SecurityException
+     *         If denied by the security manager
+     */
+    default Optional<InputStream> open(String name) throws IOException {
+        Optional<URI> ouri = find(name);
+        if (ouri.isPresent()) {
+            return Optional.of(ouri.get().toURL().openStream());
+        } else {
+            return Optional.empty();
+        }
+    }
+
+    /**
+     * Reads a resource, returning a byte buffer with the contents of the
+     * resource.
+     *
+     * The element at the returned buffer's position is the first byte of the
+     * resource, the element at the buffer's limit is the last byte of the
+     * resource. Once consumed, the {@link #release(ByteBuffer) release} method
+     * must be invoked. Failure to invoke the {@code release} method may result
+     * in a resource leak.
+     *
+     * @apiNote This method is intended for high-performance class loading. It
+     * is not capable (or intended) to read arbitrary large resources that
+     * could potentially be 2GB or larger. The rational for using this method
+     * in conjunction with the {@code release} method is to allow module reader
+     * implementations manage buffers in an efficient manner.
+     *
+     * @implSpec The default implementation invokes the {@link #open(String)
+     * open} method and reads all bytes from the input stream into a byte
+     * buffer.
+     *
+     * @param  name
+     *         The name of the resource to read
+     *
+     * @return A byte buffer containing the contents of the resource or an
+     *         empty {@code Optional} if not found
+     *
+     * @throws IOException
+     *         If an I/O error occurs or the module reader is closed
+     * @throws SecurityException
+     *         If denied by the security manager
+     *
+     * @see ClassLoader#defineClass(String, ByteBuffer, java.security.ProtectionDomain)
+     */
+    default Optional<ByteBuffer> read(String name) throws IOException {
+        Optional<InputStream> in = open(name);
+        if (in.isPresent()) {
+            byte[] bytes = in.get().readAllBytes();
+            return Optional.of(ByteBuffer.wrap(bytes));
+        } else {
+            return Optional.empty();
+        }
+    }
+
+    /**
+     * Release a byte buffer. This method should be invoked after consuming
+     * the contents of the buffer returned by the {@code read} method.
+     * The behavior of this method when invoked to release a buffer that has
+     * already been released, or the behavior when invoked to release a buffer
+     * after a {@code ModuleReader} is closed is implementation specific and
+     * therefore not specified.
+     *
+     * @param  bb
+     *         The byte buffer to release
+     *
+     * @implSpec The default implementation does nothing.
+     */
+    default void release(ByteBuffer bb) { }
+
+    /**
+     * Closes the module reader. Once closed then subsequent calls to locate or
+     * read a resource will fail by returning {@code Optional.empty()} or
+     * throwing {@code IOException}.
+     *
+     * <p> A module reader is not required to be asynchronously closeable. If a
+     * thread is reading a resource and another thread invokes the close method,
+     * then the second thread may block until the read operation is complete.
+     *
+     * <p> The behavior of {@code InputStream}s obtained using the {@link
+     * #open(String) open} method and used after the module reader is closed
+     * is implementation specific and therefore not specified.
+     */
+    @Override
+    void close() throws IOException;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/module/ModuleReference.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.module;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.net.URI;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Supplier;
+
+import jdk.internal.module.Hasher.HashSupplier;
+
+
+/**
+ * A reference to a module's content.
+ *
+ * <p> A module reference contains the module's descriptor and its location, if
+ * known.  It also has the ability to create a {@link ModuleReader} in order to
+ * access the module's content, which may be inside the Java run-time system
+ * itself or in an artifact such as a modular JAR file.
+ *
+ * @see ModuleFinder
+ * @see ModuleReader
+ * @since 9
+ */
+
+public final class ModuleReference {
+
+    private final ModuleDescriptor descriptor;
+    private final URI location;
+    private final Supplier<ModuleReader> readerSupplier;
+
+    // the function that computes the hash of this module reference
+    private final HashSupplier hasher;
+
+    // cached hash string to avoid needing to compute it many times
+    private String cachedHash;
+
+    /**
+     * Constructs a new instance of this class.
+     */
+    ModuleReference(ModuleDescriptor descriptor,
+                    URI location,
+                    Supplier<ModuleReader> readerSupplier,
+                    HashSupplier hasher)
+    {
+        this.descriptor = Objects.requireNonNull(descriptor);
+        this.location = location;
+        this.readerSupplier = Objects.requireNonNull(readerSupplier);
+        this.hasher = hasher;
+    }
+
+
+    /**
+     * Constructs a new instance of this class.
+     *
+     * <p> The {@code readSupplier} parameter is the supplier of the {@link
+     * ModuleReader} that may be used to read the module content. Its {@link
+     * Supplier#get() get()} method throws {@link UncheckedIOException} if an
+     * I/O error occurs opening the module content. The {@code get()} method
+     * throws {@link SecurityException} if opening the module is denied by the
+     * security manager.
+     *
+     * @param descriptor
+     *        The module descriptor
+     * @param location
+     *        The module location or {@code null} if not known
+     * @param readerSupplier
+     *        The {@code Supplier} of the {@code ModuleReader}
+     */
+    public ModuleReference(ModuleDescriptor descriptor,
+                           URI location,
+                           Supplier<ModuleReader> readerSupplier)
+    {
+        this(descriptor, location, readerSupplier, null);
+    }
+
+
+    /**
+     * Returns the module descriptor.
+     *
+     * @return The module descriptor
+     */
+    public ModuleDescriptor descriptor() {
+        return descriptor;
+    }
+
+
+    /**
+     * Returns the location of this module's content, if known.
+     *
+     * <p> This URI, when present, is used as the {@linkplain
+     * java.security.CodeSource#getLocation location} value of a {@link
+     * java.security.CodeSource CodeSource} so that a module's classes can be
+     * granted specific permissions when loaded by a {@link
+     * java.security.SecureClassLoader SecureClassLoader}.
+     *
+     * @return The location or an empty {@code Optional} if not known
+     */
+    public Optional<URI> location() {
+        return Optional.ofNullable(location);
+    }
+
+
+    /**
+     * Opens the module content for reading.
+     *
+     * <p> This method opens the module content by invoking the {@link
+     * Supplier#get() get()} method of the {@code readSupplier} specified at
+     * construction time. </p>
+     *
+     * @return A {@code ModuleReader} to read the module
+     *
+     * @throws IOException
+     *         If an I/O error occurs
+     * @throws SecurityException
+     *         If denied by the security manager
+     */
+    public ModuleReader open() throws IOException {
+        try {
+            return readerSupplier.get();
+        } catch (UncheckedIOException e) {
+            throw e.getCause();
+        }
+
+    }
+
+
+    /**
+     * Computes the hash of this module, returning it as a hex string.
+     * Returns {@code null} if the hash cannot be computed.
+     *
+     * @throws java.io.UncheckedIOException if an I/O error occurs
+     */
+    String computeHash(String algorithm) {
+        String result = cachedHash;
+        if (result != null)
+            return result;
+        if (hasher == null)
+            return null;
+        cachedHash = result = hasher.generate(algorithm);
+        return result;
+    }
+
+    private int hash;
+
+    /**
+     * Computes a hash code for this module reference.
+     *
+     * <p> The hash code is based upon the components of the reference, and
+     * satisfies the general contract of the {@link Object#hashCode
+     * Object.hashCode} method. </p>
+     *
+     * @return The hash-code value for this module reference
+     */
+    @Override
+    public int hashCode() {
+        int hc = hash;
+        if (hc == 0) {
+            hc = Objects.hash(descriptor, location, readerSupplier, hasher);
+            if (hc != 0) hash = hc;
+        }
+        return hc;
+    }
+
+    /**
+     * Tests this module reference for equality with the given object.
+     *
+     * <p> If the given object is not a {@code ModuleReference} then this
+     * method returns {@code false}. Two module references are equal if their
+     * module descriptors are equal, their locations are equal or both unknown,
+     * and were created with equal supplier objects to access the module
+     * content. </p>
+     *
+     * <p> This method satisfies the general contract of the {@link
+     * java.lang.Object#equals(Object) Object.equals} method. </p>
+     *
+     * @param   ob
+     *          the object to which this object is to be compared
+     *
+     * @return  {@code true} if, and only if, the given object is a module
+     *          reference that is equal to this module reference
+     */
+    @Override
+    public boolean equals(Object ob) {
+        if (!(ob instanceof ModuleReference))
+            return false;
+        ModuleReference that = (ModuleReference)ob;
+
+        return Objects.equals(this.descriptor, that.descriptor)
+                && Objects.equals(this.location, that.location)
+                && Objects.equals(this.readerSupplier, that.readerSupplier)
+                && Objects.equals(this.hasher, that.hasher);
+    }
+
+    /**
+     * Returns a string describing this module reference.
+     *
+     * @return A string describing this module reference
+     */
+    @Override
+    public String toString() {
+        return ("[module " + descriptor().name()
+                + ", location=" + location + "]");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/module/ModuleReferences.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.module;
+
+import java.io.File;
+import java.io.IOError;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.function.Supplier;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import jdk.internal.misc.JavaLangAccess;
+import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.Hasher;
+import jdk.internal.module.Hasher.HashSupplier;
+import jdk.internal.module.ModulePatcher;
+import sun.net.www.ParseUtil;
+
+
+/**
+ * A factory for creating ModuleReference implementations where the modules are
+ * packaged as modular JAR file, JMOD files or where the modules are exploded
+ * on the file system.
+ */
+
+class ModuleReferences {
+
+    private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
+
+    private ModuleReferences() { }
+
+    /**
+     * Creates a ModuleReference to a module or to patched module when
+     * creating modules for the boot Layer and -Xpatch is specified.
+     */
+    private static ModuleReference newModule(ModuleDescriptor md,
+                                             URI uri,
+                                             Supplier<ModuleReader> supplier,
+                                             HashSupplier hasher) {
+
+        ModuleReference mref = new ModuleReference(md, uri, supplier, hasher);
+
+        if (JLA.getBootLayer() == null)
+            mref = ModulePatcher.interposeIfNeeded(mref);
+
+        return mref;
+    }
+
+    /**
+     * Creates a ModuleReference to a module packaged as a modular JAR.
+     */
+    static ModuleReference newJarModule(ModuleDescriptor md, Path file) {
+        URI uri = file.toUri();
+        Supplier<ModuleReader> supplier = () -> new JarModuleReader(file, uri);
+        HashSupplier hasher = (algorithm) -> Hasher.generate(file, algorithm);
+        return newModule(md, uri, supplier, hasher);
+    }
+
+    /**
+     * Creates a ModuleReference to a module packaged as a JMOD.
+     */
+    static ModuleReference newJModModule(ModuleDescriptor md, Path file) {
+        URI uri = file.toUri();
+        Supplier<ModuleReader> supplier = () -> new JModModuleReader(file, uri);
+        HashSupplier hasher = (algorithm) -> Hasher.generate(file, algorithm);
+        return newModule(md, file.toUri(), supplier, hasher);
+    }
+
+    /**
+     * Creates a ModuleReference to an exploded module.
+     */
+    static ModuleReference newExplodedModule(ModuleDescriptor md, Path dir) {
+        Supplier<ModuleReader> supplier = () -> new ExplodedModuleReader(dir);
+        return newModule(md, dir.toUri(), supplier, null);
+    }
+
+
+    /**
+     * A base module reader that encapsulates machinery required to close the
+     * module reader safely.
+     */
+    static abstract class SafeCloseModuleReader implements ModuleReader {
+
+        // RW lock to support safe close
+        private final ReadWriteLock lock = new ReentrantReadWriteLock();
+        private final Lock readLock = lock.readLock();
+        private final Lock writeLock = lock.writeLock();
+        private volatile boolean closed;
+
+        SafeCloseModuleReader() { }
+
+        /**
+         * Returns a URL to  resource. This method is invoked by the find
+         * method to do the actual work of finding the resource.
+         */
+        abstract Optional<URI> implFind(String name) throws IOException;
+
+        /**
+         * Returns an input stream for reading a resource. This method is
+         * invoked by the open method to do the actual work of opening
+         * an input stream to the resource.
+         */
+        abstract Optional<InputStream> implOpen(String name) throws IOException;
+
+        /**
+         * Closes the module reader. This method is invoked by close to do the
+         * actual work of closing the module reader.
+         */
+        abstract void implClose() throws IOException;
+
+        @Override
+        public final Optional<URI> find(String name) throws IOException {
+            readLock.lock();
+            try {
+                if (!closed) {
+                    return implFind(name);
+                } else {
+                    throw new IOException("ModuleReader is closed");
+                }
+            } finally {
+                readLock.unlock();
+            }
+        }
+
+
+        @Override
+        public final Optional<InputStream> open(String name) throws IOException {
+            readLock.lock();
+            try {
+                if (!closed) {
+                    return implOpen(name);
+                } else {
+                    throw new IOException("ModuleReader is closed");
+                }
+            } finally {
+                readLock.unlock();
+            }
+        }
+
+        @Override
+        public void close() throws IOException {
+            writeLock.lock();
+            try {
+                if (!closed) {
+                    closed = true;
+                    implClose();
+                }
+            } finally {
+                writeLock.unlock();
+            }
+        }
+    }
+
+
+    /**
+     * A ModuleReader for a modular JAR file.
+     */
+    static class JarModuleReader extends SafeCloseModuleReader {
+        private final JarFile jf;
+        private final URI uri;
+
+        static JarFile newJarFile(Path path) {
+            try {
+                return new JarFile(path.toFile());
+            } catch (IOException ioe) {
+                throw new UncheckedIOException(ioe);
+            }
+        }
+
+        JarModuleReader(Path path, URI uri) {
+            this.jf = newJarFile(path);
+            this.uri = uri;
+        }
+
+        private JarEntry getEntry(String name) {
+            return jf.getJarEntry(Objects.requireNonNull(name));
+        }
+
+        @Override
+        Optional<URI> implFind(String name) throws IOException {
+            JarEntry je = getEntry(name);
+            if (je != null) {
+                String encodedPath = ParseUtil.encodePath(name, false);
+                String uris = "jar:" + uri + "!/" + encodedPath;
+                return Optional.of(URI.create(uris));
+            } else {
+                return Optional.empty();
+            }
+        }
+
+        @Override
+        Optional<InputStream> implOpen(String name) throws IOException {
+            JarEntry je = getEntry(name);
+            if (je != null) {
+                return Optional.of(jf.getInputStream(je));
+            } else {
+                return Optional.empty();
+            }
+        }
+
+        @Override
+        void implClose() throws IOException {
+            jf.close();
+        }
+    }
+
+
+    /**
+     * A ModuleReader for a JMOD file.
+     */
+    static class JModModuleReader extends SafeCloseModuleReader {
+        private final ZipFile zf;
+        private final URI uri;
+
+        static ZipFile newZipFile(Path path) {
+            try {
+                return new ZipFile(path.toFile());
+            } catch (IOException ioe) {
+                throw new UncheckedIOException(ioe);
+            }
+        }
+
+        JModModuleReader(Path path, URI uri) {
+            this.zf = newZipFile(path);
+            this.uri = uri;
+        }
+
+        private ZipEntry getEntry(String name) {
+            return zf.getEntry("classes/" + Objects.requireNonNull(name));
+        }
+
+        @Override
+        Optional<URI> implFind(String name) {
+            ZipEntry ze = getEntry(name);
+            if (ze != null) {
+                String encodedPath = ParseUtil.encodePath(name, false);
+                String uris = "jmod:" + uri + "!/" + encodedPath;
+                return Optional.of(URI.create(uris));
+            } else {
+                return Optional.empty();
+            }
+        }
+
+        @Override
+        Optional<InputStream> implOpen(String name) throws IOException {
+            ZipEntry ze = getEntry(name);
+            if (ze != null) {
+                return Optional.of(zf.getInputStream(ze));
+            } else {
+                return Optional.empty();
+            }
+        }
+
+        @Override
+        void implClose() throws IOException {
+            zf.close();
+        }
+    }
+
+
+    /**
+     * A ModuleReader for an exploded module.
+     */
+    static class ExplodedModuleReader implements ModuleReader {
+        private final Path dir;
+        private volatile boolean closed;
+
+        ExplodedModuleReader(Path dir) {
+            this.dir = dir;
+
+            // when running with a security manager then check that the caller
+            // has access to the directory.
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                boolean unused = Files.isDirectory(dir);
+            }
+        }
+
+        /**
+         * Returns a Path to access to the given resource.
+         */
+        private Path toPath(String name) {
+            Path path = Paths.get(name.replace('/', File.separatorChar));
+            if (path.getRoot() == null) {
+                return dir.resolve(path);
+            } else {
+                // drop the root component so that the resource is
+                // located relative to the module directory
+                int n = path.getNameCount();
+                return (n > 0) ? dir.resolve(path.subpath(0, n)) : null;
+            }
+        }
+
+        /**
+         * Throws IOException if the module reader is closed;
+         */
+        private void ensureOpen() throws IOException {
+            if (closed) throw new IOException("ModuleReader is closed");
+        }
+
+        @Override
+        public Optional<URI> find(String name) throws IOException {
+            ensureOpen();
+            Path path = toPath(name);
+            if (path != null && Files.isRegularFile(path)) {
+                try {
+                    return Optional.of(path.toUri());
+                } catch (IOError e) {
+                    throw (IOException) e.getCause();
+                }
+            } else {
+                return Optional.empty();
+            }
+        }
+
+        @Override
+        public Optional<InputStream> open(String name) throws IOException {
+            ensureOpen();
+            Path path = toPath(name);
+            if (path != null && Files.isRegularFile(path)) {
+                return Optional.of(Files.newInputStream(path));
+            } else {
+                return Optional.empty();
+            }
+        }
+
+        @Override
+        public Optional<ByteBuffer> read(String name) throws IOException {
+            ensureOpen();
+            Path path = toPath(name);
+            if (path != null && Files.isRegularFile(path)) {
+                return Optional.of(ByteBuffer.wrap(Files.readAllBytes(path)));
+            } else {
+                return Optional.empty();
+            }
+        }
+
+        @Override
+        public void close() {
+            closed = true;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/module/ResolutionException.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.module;
+
+/**
+ * Thrown when resolving a set of modules or binding fails.
+ *
+ * @see Configuration
+ * @since 9
+ */
+public class ResolutionException extends RuntimeException {
+    private static final long serialVersionUID = -1031186845316729450L;
+
+    /**
+     * Constructs a {@code ResolutionException} with no detail message.
+     */
+    public ResolutionException() { }
+
+    /**
+     * Constructs a {@code ResolutionException} with the given detail
+     * message.
+     *
+     * @param msg
+     *        The detail message; can be {@code null}
+     */
+    public ResolutionException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Constructs an instance of this exception with the given cause.
+     *
+     * @param cause
+     *        The cause; can be {@code null}
+     */
+    public ResolutionException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * Constructs a {@code ResolutionException} with the given detail message
+     * and cause.
+     *
+     * @param msg
+     *        The detail message; can be {@code null}
+     * @param cause
+     *        The cause; can be {@code null}
+     */
+    public ResolutionException(String msg, Throwable cause) {
+        super(msg, cause);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/module/ResolvedModule.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.module;
+
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * A module in a graph of <em>resolved modules</em>.
+ *
+ * <p> {@code ResolvedModule} defines the {@link #configuration configuration}
+ * method to get the configuration that the resolved module is in. It defines
+ * the {@link #reference() reference} method to get the reference to the
+ * module's content.
+ *
+ * @since 9
+ * @see Configuration#modules()
+ */
+public final class ResolvedModule {
+
+    private final Configuration cf;
+    private final ModuleReference mref;
+
+    ResolvedModule(Configuration cf, ModuleReference mref) {
+        this.cf = Objects.requireNonNull(cf);
+        this.mref = Objects.requireNonNull(mref);
+    }
+
+    /**
+     * Returns the configuration that this resolved module is in.
+     *
+     * @return The configuration that this resolved module is in
+     */
+    public Configuration configuration() {
+        return cf;
+    }
+
+    /**
+     * Returns the reference to the module's content.
+     *
+     * @return The reference to the module's content
+     */
+    public ModuleReference reference() {
+        return mref;
+    }
+
+    /**
+     * Returns the module descriptor.
+     *
+     * This convenience method is the equivalent to invoking:
+     * <pre> {@code
+     *     reference().descriptor()
+     * }</pre>
+     *
+     * @return The module descriptor
+     */
+    ModuleDescriptor descriptor() {
+        return reference().descriptor();
+    }
+
+    /**
+     * Returns the module name.
+     *
+     * This convenience method is the equivalent to invoking:
+     * <pre> {@code
+     *     reference().descriptor().name()
+     * }</pre>
+     *
+     * @return The module name
+     */
+    public String name() {
+        return reference().descriptor().name();
+    }
+
+    /**
+     * Returns the set of resolved modules that this resolved module reads.
+     *
+     * @return A possibly-empty unmodifiable set of resolved modules that
+     *         this resolved module reads
+     */
+    public Set<ResolvedModule> reads() {
+        return cf.reads(this);
+    }
+
+    /**
+     * Computes a hash code for this resolved module.
+     *
+     * <p> The hash code is based upon the components of the resolved module
+     * and satisfies the general contract of the {@link Object#hashCode
+     * Object.hashCode} method. </p>
+     *
+     * @return The hash-code value for this resolved module
+     */
+    @Override
+    public int hashCode() {
+        return cf.hashCode() ^ mref.hashCode();
+    }
+
+    /**
+     * Tests this resolved module for equality with the given object.
+     *
+     * <p> If the given object is not a {@code ResolvedModule} then this
+     * method returns {@code false}. Two {@code ResolvedModule} objects are
+     * equal if they are in the same configuration and have equal references
+     * to the module content. </p>
+     *
+     * <p> This method satisfies the general contract of the {@link
+     * java.lang.Object#equals(Object) Object.equals} method. </p>
+     *
+     * @param   ob
+     *          the object to which this object is to be compared
+     *
+     * @return  {@code true} if, and only if, the given object is a module
+     *          reference that is equal to this module reference
+     */
+    @Override
+    public boolean equals(Object ob) {
+        if (!(ob instanceof ResolvedModule))
+            return false;
+
+        ResolvedModule that = (ResolvedModule) ob;
+        return Objects.equals(this.cf, that.cf)
+                && Objects.equals(this.mref, that.mref);
+    }
+
+    /**
+     * Returns a string describing this resolved module.
+     *
+     * @return A string describing this resolved module
+     */
+    @Override
+    public String toString() {
+        return System.identityHashCode(cf) + "/" + name();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/module/Resolver.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,823 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.module;
+
+import java.lang.module.ModuleDescriptor.Requires.Modifier;
+import java.lang.reflect.Layer;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.StringJoiner;
+import java.util.stream.Collectors;
+
+import jdk.internal.module.Hasher;
+
+/**
+ * The resolver used by {@link Configuration#resolveRequires} and
+ * {@link Configuration#resolveRequiresAndUses}.
+ */
+
+final class Resolver {
+
+    private final ModuleFinder beforeFinder;
+    private final Configuration parent;
+    private final ModuleFinder afterFinder;
+
+    // maps module name to module reference
+    private final Map<String, ModuleReference> nameToReference = new HashMap<>();
+
+
+    Resolver(ModuleFinder beforeFinder,
+             Configuration parent,
+             ModuleFinder afterFinder) {
+        this.beforeFinder = beforeFinder;
+        this.parent = parent;
+        this.afterFinder = afterFinder;
+    }
+
+
+    /**
+     * Resolves the given named modules.
+     *
+     * @throws ResolutionException
+     */
+    Resolver resolveRequires(Collection<String> roots) {
+
+        long start = trace_start("Resolve");
+
+        // create the visit stack to get us started
+        Deque<ModuleDescriptor> q = new ArrayDeque<>();
+        for (String root : roots) {
+
+            // find root module
+            ModuleReference mref = findWithBeforeFinder(root);
+            if (mref == null) {
+                if (parent.findModule(root).isPresent()) {
+                    // in parent, nothing to do
+                    continue;
+                }
+                mref = findWithAfterFinder(root);
+                if (mref == null) {
+                    fail("Module %s not found", root);
+                }
+            }
+
+            if (TRACE) {
+                trace("Root module %s located", root);
+                if (mref.location().isPresent())
+                    trace("  (%s)", mref.location().get());
+            }
+
+            assert mref.descriptor().name().equals(root);
+            nameToReference.put(root, mref);
+            q.push(mref.descriptor());
+        }
+
+        resolve(q);
+
+        if (TRACE) {
+            long duration = System.currentTimeMillis() - start;
+            Set<String> names = nameToReference.keySet();
+            trace("Resolver completed in %s ms", duration);
+            names.stream().sorted().forEach(name -> trace("  %s", name));
+        }
+
+        return this;
+    }
+
+    /**
+     * Resolve all modules in the given queue. On completion the queue will be
+     * empty and any resolved modules will be added to {@code nameToReference}.
+     *
+     * @return The set of module resolved by this invocation of resolve
+     */
+    private Set<ModuleDescriptor> resolve(Deque<ModuleDescriptor> q) {
+        Set<ModuleDescriptor> resolved = new HashSet<>();
+
+        while (!q.isEmpty()) {
+            ModuleDescriptor descriptor = q.poll();
+            assert nameToReference.containsKey(descriptor.name());
+
+            // process dependences
+            for (ModuleDescriptor.Requires requires : descriptor.requires()) {
+                String dn = requires.name();
+
+                // find dependence
+                ModuleReference mref = findWithBeforeFinder(dn);
+                if (mref == null) {
+                    if (parent.findModule(dn).isPresent())
+                        continue;
+
+                    mref = findWithAfterFinder(dn);
+                    if (mref == null) {
+                        fail("Module %s not found, required by %s",
+                                dn, descriptor.name());
+                    }
+                }
+
+                if (!nameToReference.containsKey(dn)) {
+                    nameToReference.put(dn, mref);
+                    q.offer(mref.descriptor());
+                    resolved.add(mref.descriptor());
+
+                    if (TRACE) {
+                        trace("Module %s located, required by %s",
+                                dn, descriptor.name());
+                        if (mref.location().isPresent())
+                            trace("  (%s)", mref.location().get());
+                    }
+                }
+
+            }
+
+            resolved.add(descriptor);
+        }
+
+        return resolved;
+    }
+
+    /**
+     * Augments the set of resolved modules with modules induced by the
+     * service-use relation.
+     */
+    Resolver resolveUses() {
+
+        long start = trace_start("Bind");
+
+        // Scan the finders for all available service provider modules. As
+        // java.base uses services then then module finders will be scanned
+        // anyway.
+        Map<String, Set<ModuleReference>> availableProviders = new HashMap<>();
+        for (ModuleReference mref : findAll()) {
+            ModuleDescriptor descriptor = mref.descriptor();
+            if (!descriptor.provides().isEmpty()) {
+
+                for (String sn : descriptor.provides().keySet()) {
+                    // computeIfAbsent
+                    Set<ModuleReference> providers = availableProviders.get(sn);
+                    if (providers == null) {
+                        providers = new HashSet<>();
+                        availableProviders.put(sn, providers);
+                    }
+                    providers.add(mref);
+                }
+
+            }
+        }
+
+        // create the visit stack
+        Deque<ModuleDescriptor> q = new ArrayDeque<>();
+
+        // the initial set of modules that may use services
+        Set<ModuleDescriptor> candidateConsumers = new HashSet<>();
+        Configuration p = parent;
+        while (p != null) {
+            candidateConsumers.addAll(p.descriptors());
+            p = p.parent().orElse(null);
+        }
+        for (ModuleReference mref : nameToReference.values()) {
+            candidateConsumers.add(mref.descriptor());
+        }
+
+
+        // Where there is a consumer of a service then resolve all modules
+        // that provide an implementation of that service
+        do {
+            for (ModuleDescriptor descriptor : candidateConsumers) {
+                if (!descriptor.uses().isEmpty()) {
+                    for (String service : descriptor.uses()) {
+                        Set<ModuleReference> mrefs = availableProviders.get(service);
+                        if (mrefs != null) {
+                            for (ModuleReference mref : mrefs) {
+                                ModuleDescriptor provider = mref.descriptor();
+                                if (!provider.equals(descriptor)) {
+
+                                    trace("Module %s provides %s, used by %s",
+                                            provider.name(), service, descriptor.name());
+
+                                    String pn = provider.name();
+                                    if (!nameToReference.containsKey(pn)) {
+
+                                        if (TRACE && mref.location().isPresent())
+                                            trace("  (%s)", mref.location().get());
+
+                                        nameToReference.put(pn, mref);
+                                        q.push(provider);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+
+            candidateConsumers = resolve(q);
+
+        } while (!candidateConsumers.isEmpty());
+
+
+        if (TRACE) {
+            long duration = System.currentTimeMillis() - start;
+            Set<String> names = nameToReference.keySet();
+            trace("Bind completed in %s ms", duration);
+            names.stream().sorted().forEach(name -> trace("  %s", name));
+        }
+
+        return this;
+    }
+
+
+    /**
+     * Execute post-resolution checks and returns the module graph of resolved
+     * modules as {@code Map}. The resolved modules will be in the given
+     * configuration.
+     */
+    Map<ResolvedModule, Set<ResolvedModule>> finish(Configuration cf) {
+
+        detectCycles();
+
+        checkPlatformConstraints();
+
+        checkHashes();
+
+        Map<ResolvedModule, Set<ResolvedModule>> graph = makeGraph(cf);
+
+        checkExportSuppliers(graph);
+
+        return graph;
+    }
+
+
+    /**
+     * Checks the given module graph for cycles.
+     *
+     * For now the implementation is a simple depth first search on the
+     * dependency graph. We'll replace this later, maybe with Tarjan.
+     */
+    private void detectCycles() {
+        visited = new HashSet<>();
+        visitPath = new LinkedHashSet<>(); // preserve insertion order
+        for (ModuleReference mref : nameToReference.values()) {
+            visit(mref.descriptor());
+        }
+        visited.clear();
+    }
+
+    // the modules that were visited
+    private Set<ModuleDescriptor> visited;
+
+    // the modules in the current visit path
+    private Set<ModuleDescriptor> visitPath;
+
+    private void visit(ModuleDescriptor descriptor) {
+        if (!visited.contains(descriptor)) {
+            boolean added = visitPath.add(descriptor);
+            if (!added) {
+                throw new ResolutionException("Cycle detected: " +
+                        cycleAsString(descriptor));
+            }
+            for (ModuleDescriptor.Requires requires : descriptor.requires()) {
+                String dn = requires.name();
+
+                ModuleReference mref = nameToReference.get(dn);
+                if (mref != null) {
+                    ModuleDescriptor other = mref.descriptor();
+                    if (other != descriptor) {
+                        // dependency is in this configuration
+                        visit(other);
+                    }
+                }
+            }
+            visitPath.remove(descriptor);
+            visited.add(descriptor);
+        }
+    }
+
+    /**
+     * Returns a String with a list of the modules in a detected cycle.
+     */
+    private String cycleAsString(ModuleDescriptor descriptor) {
+        List<ModuleDescriptor> list = new ArrayList<>(visitPath);
+        list.add(descriptor);
+        int index = list.indexOf(descriptor);
+        return list.stream()
+                .skip(index)
+                .map(ModuleDescriptor::name)
+                .collect(Collectors.joining(" -> "));
+    }
+
+
+    /**
+     * If there are platform specific modules then check that the OS name,
+     * architecture and version match.
+     *
+     * @apiNote This method does not currently check if the OS matches
+     *          platform specific modules in parent configurations.
+     */
+    private void checkPlatformConstraints() {
+
+        // first module encountered that is platform specific
+        String savedModuleName = null;
+        String savedOsName = null;
+        String savedOsArch = null;
+        String savedOsVersion = null;
+
+        for (ModuleReference mref : nameToReference.values()) {
+            ModuleDescriptor descriptor = mref.descriptor();
+
+            String osName = descriptor.osName().orElse(null);
+            String osArch = descriptor.osArch().orElse(null);
+            String osVersion = descriptor.osVersion().orElse(null);
+
+            if (osName != null || osArch != null || osVersion != null) {
+
+                if (savedModuleName == null) {
+
+                    savedModuleName = descriptor.name();
+                    savedOsName = osName;
+                    savedOsArch = osArch;
+                    savedOsVersion = osVersion;
+
+                } else {
+
+                    boolean matches = platformMatches(osName, savedOsName)
+                            && platformMatches(osArch, savedOsArch)
+                            && platformMatches(osVersion, savedOsVersion);
+
+                    if (!matches) {
+                        String s1 = platformAsString(savedOsName,
+                                                     savedOsArch,
+                                                     savedOsVersion);
+
+                        String s2 = platformAsString(osName, osArch, osVersion);
+                        fail("Mismatching constraints on target platform: "
+                                + savedModuleName + ": " + s1
+                                + ", " + descriptor.name() + ": " + s2);
+                    }
+
+                }
+
+            }
+        }
+
+    }
+
+    /**
+     * Returns true if the s1 and s2 are equal or one of them is null.
+     */
+    private boolean platformMatches(String s1, String s2) {
+        if (s1 == null || s2 == null)
+            return true;
+        else
+            return Objects.equals(s1, s2);
+    }
+
+    /**
+     * Return a string that encodes the OS name/arch/version.
+     */
+    private String platformAsString(String osName,
+                                    String osArch,
+                                    String osVersion) {
+
+        return new StringJoiner("-")
+                .add(Objects.toString(osName, "*"))
+                .add(Objects.toString(osArch, "*"))
+                .add(Objects.toString(osVersion, "*"))
+                .toString();
+
+    }
+
+
+    /**
+     * Checks the hashes in the module descriptor to ensure that they match
+     * the hash of the dependency's module reference.
+     */
+    private void checkHashes() {
+
+        for (ModuleReference mref : nameToReference.values()) {
+            ModuleDescriptor descriptor = mref.descriptor();
+
+            // get map of module names to hash
+            Optional<Hasher.DependencyHashes> ohashes = descriptor.hashes();
+            if (!ohashes.isPresent())
+                continue;
+            Hasher.DependencyHashes hashes = ohashes.get();
+
+            // check dependences
+            for (ModuleDescriptor.Requires d : descriptor.requires()) {
+                String dn = d.name();
+                String recordedHash = hashes.hashFor(dn);
+
+                if (recordedHash != null) {
+
+                    ModuleReference other = nameToReference.get(dn);
+                    if (other == null) {
+                        other = parent.findModule(dn)
+                                .map(ResolvedModule::reference)
+                                .orElse(null);
+                    }
+                    if (other == null)
+                        throw new InternalError(dn + " not found");
+
+                    String actualHash = other.computeHash(hashes.algorithm());
+                    if (actualHash == null)
+                        fail("Unable to compute the hash of module %s", dn);
+
+                    if (!recordedHash.equals(actualHash)) {
+                        fail("Hash of %s (%s) differs to expected hash (%s)",
+                                dn, actualHash, recordedHash);
+                    }
+
+                }
+
+            }
+        }
+
+    }
+
+
+    /**
+     * Computes and sets the readability graph for the modules in the given
+     * Resolution object.
+     *
+     * The readability graph is created by propagating "requires" through the
+     * "public requires" edges of the module dependence graph. So if the module
+     * dependence graph has m1 requires m2 && m2 requires public m3 then the
+     * resulting readability graph will contain m1 reads m2, m1
+     * reads m3, and m2 reads m3.
+     *
+     * TODO: Use a more efficient algorithm, maybe cache the requires public
+     *       in parent configurations.
+     */
+    private Map<ResolvedModule, Set<ResolvedModule>> makeGraph(Configuration cf) {
+
+        // the "reads" graph starts as a module dependence graph and
+        // is iteratively updated to be the readability graph
+        Map<ResolvedModule, Set<ResolvedModule>> g1 = new HashMap<>();
+
+        // the "requires public" graph, contains requires public edges only
+        Map<ResolvedModule, Set<ResolvedModule>> g2 = new HashMap<>();
+
+
+        // need "requires public" from the modules in parent configurations as
+        // there may be selected modules that have a dependency on modules in
+        // the parent configuration.
+
+        Configuration p = parent;
+        while (p != null) {
+            for (ModuleDescriptor descriptor : p.descriptors()) {
+                ResolvedModule x = p.findModule(descriptor.name()).orElse(null);
+                if (x == null)
+                    throw new InternalError();
+                for (ModuleDescriptor.Requires requires : descriptor.requires()) {
+                    if (requires.modifiers().contains(Modifier.PUBLIC)) {
+                        String dn = requires.name();
+                        ResolvedModule y = p.findModule(dn).orElse(null);
+                        if (y == null)
+                            throw new InternalError(dn + " not found");
+                        g2.computeIfAbsent(x, k -> new HashSet<>()).add(y);
+                    }
+                }
+            }
+
+            p = p.parent().orElse(null);
+        }
+
+        // populate g1 and g2 with the dependences from the selected modules
+        for (ModuleReference mref : nameToReference.values()) {
+            ModuleDescriptor descriptor = mref.descriptor();
+            ResolvedModule x = new ResolvedModule(cf, mref);
+
+            Set<ResolvedModule> reads = new HashSet<>();
+            g1.put(x, reads);
+
+            Set<ResolvedModule> requiresPublic = new HashSet<>();
+            g2.put(x, requiresPublic);
+
+            for (ModuleDescriptor.Requires requires : descriptor.requires()) {
+                String dn = requires.name();
+
+                ResolvedModule y;
+                ModuleReference other = nameToReference.get(dn);
+                if (other != null) {
+                    y = new ResolvedModule(cf, other);  // cache?
+                } else {
+                    y = parent.findModule(dn).orElse(null);
+                    if (y == null)
+                        throw new InternalError("unable to find " + dn);
+                }
+
+                // m requires other => m reads other
+                reads.add(y);
+
+                // m requires public other
+                if (requires.modifiers().contains(Modifier.PUBLIC)) {
+                    requiresPublic.add(y);
+                }
+
+            }
+
+            // automatic modules reads all selected modules and all modules
+            // in parent configurations
+            if (descriptor.isAutomatic()) {
+                String name = descriptor.name();
+
+                // reads all selected modules
+                // requires public` all selected automatic modules
+                for (ModuleReference mref2 : nameToReference.values()) {
+                    ModuleDescriptor descriptor2 = mref2.descriptor();
+                    if (!name.equals(descriptor2.name())) {
+                        ResolvedModule m = new ResolvedModule(cf, mref2);
+                        reads.add(m);
+                        if (descriptor2.isAutomatic())
+                            requiresPublic.add(m);
+                    }
+                }
+
+                // reads all modules in parent configurations
+                // `requires public` all automatic modules in parent configurations
+                p = parent;
+                while (p != null) {
+                    for (ResolvedModule m : p.modules()) {
+                        reads.add(m);
+                        if (m.reference().descriptor().isAutomatic())
+                            requiresPublic.add(m);
+                    }
+                    p = p.parent().orElse(null);
+                }
+
+            }
+
+        }
+
+        // Iteratively update g1 until there are no more requires public to propagate
+        boolean changed;
+        Map<ResolvedModule, Set<ResolvedModule>> changes = new HashMap<>();
+        do {
+            changed = false;
+            for (Entry<ResolvedModule, Set<ResolvedModule>> entry : g1.entrySet()) {
+
+                ResolvedModule m1 = entry.getKey();
+                Set<ResolvedModule> m1Reads = entry.getValue();
+
+                for (ResolvedModule m2 : m1Reads) {
+                    Set<ResolvedModule> m2RequiresPublic = g2.get(m2);
+                    if (m2RequiresPublic != null) {
+                        for (ResolvedModule m3 : m2RequiresPublic) {
+                            if (!m1Reads.contains(m3)) {
+
+                                // computeIfAbsent
+                                Set<ResolvedModule> s = changes.get(m1);
+                                if (s == null) {
+                                    s = new HashSet<>();
+                                    changes.put(m1, s);
+                                }
+                                s.add(m3);
+                                changed = true;
+
+                            }
+                        }
+                    }
+                }
+            }
+
+            if (changed) {
+                for (Map.Entry<ResolvedModule, Set<ResolvedModule>> e :
+                        changes.entrySet()) {
+                    ResolvedModule m = e.getKey();
+                    g1.get(m).addAll(e.getValue());
+                }
+                changes.clear();
+            }
+
+        } while (changed);
+
+
+        return g1;
+    }
+
+
+    /**
+     * Checks the readability graph to ensure that no two modules export the
+     * same package to a module. This includes the case where module M has
+     * a local package P and M reads another module that exports P to M.
+     * Also checks the uses/provides of module M to ensure that it reads a
+     * module that exports the package of the service type to M.
+     */
+    private void checkExportSuppliers(Map<ResolvedModule, Set<ResolvedModule>> graph) {
+
+        for (Map.Entry<ResolvedModule, Set<ResolvedModule>> e : graph.entrySet()) {
+            ModuleDescriptor descriptor1 = e.getKey().descriptor();
+
+            // the map of packages that are local or exported to descriptor1
+            Map<String, ModuleDescriptor> packageToExporter = new HashMap<>();
+
+            // local packages
+            Set<String> packages = descriptor1.packages();
+            for (String pn : packages) {
+                packageToExporter.put(pn, descriptor1);
+            }
+
+            // descriptor1 reads descriptor2
+            Set<ResolvedModule> reads = e.getValue();
+            for (ResolvedModule endpoint : reads) {
+                ModuleDescriptor descriptor2 = endpoint.descriptor();
+
+                for (ModuleDescriptor.Exports export : descriptor2.exports()) {
+
+                    if (export.isQualified()) {
+                        if (!export.targets().contains(descriptor1.name()))
+                            continue;
+                    }
+
+                    // source is exported to descriptor2
+                    String source = export.source();
+                    ModuleDescriptor other
+                            = packageToExporter.put(source, descriptor2);
+
+                    if (other != null && other != descriptor2) {
+                        // package might be local to descriptor1
+                        if (other == descriptor1) {
+                            fail("Module %s contains package %s"
+                                 + ", module %s exports package %s to %s",
+                                    descriptor1.name(),
+                                    source,
+                                    descriptor2.name(),
+                                    source,
+                                    descriptor1.name());
+                        } else {
+                            fail("Modules %s and %s export package %s to module %s",
+                                    descriptor2.name(),
+                                    other.name(),
+                                    source,
+                                    descriptor1.name());
+                        }
+
+                    }
+                }
+            }
+
+            // uses S
+            for (String service : descriptor1.uses()) {
+                String pn = packageName(service);
+                if (!packageToExporter.containsKey(pn)) {
+                    fail("Module %s does not read a module that exports %s",
+                            descriptor1.name(), pn);
+                }
+            }
+
+            // provides S
+            for (Map.Entry<String, ModuleDescriptor.Provides> entry :
+                    descriptor1.provides().entrySet()) {
+                String service = entry.getKey();
+                ModuleDescriptor.Provides provides = entry.getValue();
+
+                String pn = packageName(service);
+                if (!packageToExporter.containsKey(pn)) {
+                    fail("Module %s does not read a module that exports %s",
+                            descriptor1.name(), pn);
+                }
+
+                for (String provider : provides.providers()) {
+                    if (!packages.contains(packageName(provider))) {
+                        fail("Provider %s not in module %s",
+                                provider, descriptor1.name());
+                    }
+                }
+            }
+
+        }
+
+    }
+
+
+    /**
+     * Invokes the beforeFinder to find method to find the given module.
+     */
+    private ModuleReference findWithBeforeFinder(String mn) {
+        try {
+            return beforeFinder.find(mn).orElse(null);
+        } catch (FindException e) {
+            // unwrap
+            throw new ResolutionException(e.getMessage(), e.getCause());
+        }
+    }
+
+    /**
+     * Invokes the afterFinder to find method to find the given module.
+     */
+    private ModuleReference findWithAfterFinder(String mn) {
+        try {
+            return afterFinder.find(mn).orElse(null);
+        } catch (FindException e) {
+            // unwrap
+            throw new ResolutionException(e.getMessage(), e.getCause());
+        }
+    }
+
+    /**
+     * Returns the set of all modules that are observable with the before
+     * and after ModuleFinders.
+     */
+    private Set<ModuleReference> findAll() {
+        try {
+
+            Set<ModuleReference> beforeModules = beforeFinder.findAll();
+            Set<ModuleReference> afterModules = afterFinder.findAll();
+
+            if (afterModules.isEmpty())
+                return beforeModules;
+
+            if (beforeModules.isEmpty() && parent == Configuration.empty())
+                return afterModules;
+
+            Set<ModuleReference> result = new HashSet<>(beforeModules);
+            for (ModuleReference mref : afterModules) {
+                String name = mref.descriptor().name();
+                if (!beforeFinder.find(name).isPresent()
+                        && !parent.findModule(name).isPresent())
+                    result.add(mref);
+            }
+
+            return result;
+
+        } catch (FindException e) {
+            // unwrap
+            throw new ResolutionException(e.getMessage(), e.getCause());
+        }
+    }
+
+    /**
+     * Returns the package name
+     */
+    private static String packageName(String cn) {
+        int index = cn.lastIndexOf(".");
+        return (index == -1) ? "" : cn.substring(0, index);
+    }
+
+    /**
+     * Throw ResolutionException with the given format string and arguments
+     */
+    private static void fail(String fmt, Object ... args) {
+        String msg = String.format(fmt, args);
+        throw new ResolutionException(msg);
+    }
+
+
+    /**
+     * Tracing support, limited to boot layer for now.
+     */
+
+    private final static boolean TRACE
+        = Boolean.getBoolean("jdk.launcher.traceResolver")
+            && (Layer.boot() == null);
+
+    private String op;
+
+    private long trace_start(String op) {
+        this.op = op;
+        return System.currentTimeMillis();
+    }
+
+    private void trace(String fmt, Object ... args) {
+        if (TRACE) {
+            System.out.print("[" + op + "] ");
+            System.out.format(fmt, args);
+            System.out.println();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/module/SystemModuleFinder.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.module;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
+import java.net.URI;
+import java.net.URLConnection;
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Supplier;
+
+import jdk.internal.jimage.ImageLocation;
+import jdk.internal.jimage.ImageReader;
+import jdk.internal.jimage.ImageReaderFactory;
+import jdk.internal.module.SystemModules;
+import jdk.internal.module.ModulePatcher;
+import jdk.internal.perf.PerfCounter;
+
+/**
+ * A {@code ModuleFinder} that finds modules that are linked into the
+ * run-time image.
+ *
+ * The modules linked into the run-time image are assumed to have the
+ * ConcealedPackages attribute.
+ */
+
+class SystemModuleFinder implements ModuleFinder {
+
+    private static final PerfCounter initTime
+        = PerfCounter.newPerfCounter("jdk.module.finder.jimage.initTime");
+    private static final PerfCounter moduleCount
+        = PerfCounter.newPerfCounter("jdk.module.finder.jimage.modules");
+    private static final PerfCounter packageCount
+        = PerfCounter.newPerfCounter("jdk.module.finder.jimage.packages");
+    private static final PerfCounter exportsCount
+        = PerfCounter.newPerfCounter("jdk.module.finder.jimage.exports");
+    // ImageReader used to access all modules in the image
+    private static final ImageReader imageReader;
+
+    // the set of modules in the run-time image
+    private static final Set<ModuleReference> modules;
+
+    // maps module name to module reference
+    private static final Map<String, ModuleReference> nameToModule;
+
+    /**
+     * For now, the module references are created eagerly on the assumption
+     * that service binding will require all modules to be located.
+     */
+    static {
+        long t0 = System.nanoTime();
+        imageReader = ImageReaderFactory.getImageReader();
+
+        String[] moduleNames = SystemModules.MODULE_NAMES;
+        ModuleDescriptor[] descriptors = null;
+
+        boolean fastLoad = System.getProperty("jdk.installed.modules.disable") == null;
+        if (fastLoad) {
+            // fast loading of ModuleDescriptor of installed modules
+            descriptors = SystemModules.modules();
+        }
+
+        int n = moduleNames.length;
+        moduleCount.add(n);
+
+        Set<ModuleReference> mods = new HashSet<>(n);
+        Map<String, ModuleReference> map = new HashMap<>(n);
+
+        for (int i = 0; i < n; i++) {
+            String mn = moduleNames[i];
+            ModuleDescriptor md;
+            if (fastLoad) {
+                md = descriptors[i];
+            } else {
+                // fallback to read module-info.class
+                // if fast loading of ModuleDescriptors is disabled
+                ImageLocation location = imageReader.findLocation(mn, "module-info.class");
+                md = ModuleDescriptor.read(imageReader.getResourceBuffer(location));
+            }
+            if (!md.name().equals(mn))
+                throw new InternalError();
+
+            // create the ModuleReference
+
+            URI uri = URI.create("jrt:/" + mn);
+
+            Supplier<ModuleReader> readerSupplier = new Supplier<>() {
+                @Override
+                public ModuleReader get() {
+                    return new ImageModuleReader(mn, uri);
+                }
+            };
+
+            ModuleReference mref = new ModuleReference(md, uri, readerSupplier);
+
+            // may need a reference to a patched module if -Xpatch specified
+            mref = ModulePatcher.interposeIfNeeded(mref);
+
+            mods.add(mref);
+            map.put(mn, mref);
+
+            // counters
+            packageCount.add(md.packages().size());
+            exportsCount.add(md.exports().size());
+        }
+
+        modules = Collections.unmodifiableSet(mods);
+        nameToModule = map;
+
+        initTime.addElapsedTimeFrom(t0);
+    }
+
+    SystemModuleFinder() { }
+
+    @Override
+    public Optional<ModuleReference> find(String name) {
+        Objects.requireNonNull(name);
+        return Optional.ofNullable(nameToModule.get(name));
+    }
+
+    @Override
+    public Set<ModuleReference> findAll() {
+        return modules;
+    }
+
+
+    /**
+     * A ModuleReader for reading resources from a module linked into the
+     * run-time image.
+     */
+    static class ImageModuleReader implements ModuleReader {
+        private final String module;
+        private volatile boolean closed;
+
+        /**
+         * If there is a security manager set then check permission to
+         * connect to the run-time image.
+         */
+        private static void checkPermissionToConnect(URI uri) {
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                try {
+                    URLConnection uc = uri.toURL().openConnection();
+                    sm.checkPermission(uc.getPermission());
+                } catch (IOException ioe) {
+                    throw new UncheckedIOException(ioe);
+                }
+            }
+        }
+
+        ImageModuleReader(String module, URI uri) {
+            checkPermissionToConnect(uri);
+            this.module = module;
+        }
+
+        /**
+         * Returns the ImageLocation for the given resource, {@code null}
+         * if not found.
+         */
+        private ImageLocation findImageLocation(String name) throws IOException {
+            if (closed)
+                throw new IOException("ModuleReader is closed");
+
+            if (imageReader != null) {
+                return imageReader.findLocation(module, name);
+            } else {
+                // not an images build
+                return null;
+            }
+        }
+
+        @Override
+        public Optional<URI> find(String name) throws IOException {
+            ImageLocation location = findImageLocation(name);
+            if (location != null) {
+                URI u = URI.create("jrt:/" + module + "/" + name);
+                return Optional.of(u);
+            } else {
+                return Optional.empty();
+            }
+        }
+
+        @Override
+        public Optional<InputStream> open(String name) throws IOException {
+            return read(name).map(this::toInputStream);
+        }
+
+        private InputStream toInputStream(ByteBuffer bb) { // ## -> ByteBuffer?
+            try {
+                int rem = bb.remaining();
+                byte[] bytes = new byte[rem];
+                bb.get(bytes);
+                return new ByteArrayInputStream(bytes);
+            } finally {
+                release(bb);
+            }
+        }
+
+        @Override
+        public Optional<ByteBuffer> read(String name) throws IOException {
+            ImageLocation location = findImageLocation(name);
+            if (location != null) {
+                return Optional.of(imageReader.getResourceBuffer(location));
+            } else {
+                return Optional.empty();
+            }
+        }
+
+        @Override
+        public void release(ByteBuffer bb) {
+            ImageReader.releaseByteBuffer(bb);
+        }
+
+        @Override
+        public void close() {
+            // nothing else to do
+            closed = true;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/module/package-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013, 2016 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Classes to support module descriptors and creating configurations of modules
+ * by means of resolution and service binding.
+ *
+ * <p> Unless otherwise noted, passing a {@code null} argument to a constructor
+ * or method of any class or interface in this package will cause a {@link
+ * java.lang.NullPointerException NullPointerException} to be thrown. Additionally,
+ * invoking a method with an array or collection containing a {@code null} element
+ * will cause a {@code NullPointerException}, unless otherwise specified. </p>
+ *
+ * @since 9
+ */
+
+package java.lang.module;
--- a/src/java.base/share/classes/java/lang/ref/Finalizer.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/java/lang/ref/Finalizer.java	Thu Mar 17 19:04:16 2016 +0000
@@ -143,7 +143,7 @@
 
     /* Called by Runtime.runFinalization() */
     static void runFinalization() {
-        if (!VM.isBooted()) {
+        if (VM.initLevel() == 0) {
             return;
         }
 
@@ -166,7 +166,7 @@
 
     /* Invoked by java.lang.Shutdown */
     static void runAllFinalizers() {
-        if (!VM.isBooted()) {
+        if (VM.initLevel() == 0) {
             return;
         }
 
@@ -201,10 +201,10 @@
 
             // Finalizer thread starts before System.initializeSystemClass
             // is called.  Wait until JavaLangAccess is available
-            while (!VM.isBooted()) {
+            while (VM.initLevel() == 0) {
                 // delay until VM completes initialization
                 try {
-                    VM.awaitBooted();
+                    VM.awaitInitLevel(1);
                 } catch (InterruptedException x) {
                     // ignore and continue
                 }
--- a/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,8 @@
 package java.lang.reflect;
 
 import java.security.AccessController;
+
+import sun.reflect.CallerSensitive;
 import sun.reflect.Reflection;
 import sun.reflect.ReflectionFactory;
 import java.lang.annotation.Annotation;
@@ -34,11 +36,14 @@
  * The AccessibleObject class is the base class for Field, Method and
  * Constructor objects.  It provides the ability to flag a reflected
  * object as suppressing default Java language access control checks
- * when it is used.  The access checks--for public, default (package)
- * access, protected, and private members--are performed when Fields,
- * Methods or Constructors are used to set or get fields, to invoke
- * methods, or to create and initialize new instances of classes,
- * respectively.
+ * when it is used. The access checks -- <em>module boundaries</em>,
+ * public, default (package) access, protected, and private members --
+ * are performed when Fields, Methods or Constructors are used to set
+ * or get fields, to invoke methods or to create and initialize new
+ * instances of classes, respectively. Unlike access control specified
+ * in the <cite>The Java&trade; Language Specification</cite> and
+ * <cite>The Java Virtual Machine Specification</cite>, access checks
+ * with reflected objects assume {@link Module#canRead readability}.
  *
  * <p>Setting the {@code accessible} flag in a reflected object
  * permits sophisticated applications with sufficient privilege, such
@@ -64,37 +69,49 @@
     private static final java.security.Permission ACCESS_PERMISSION =
         new ReflectPermission("suppressAccessChecks");
 
+    static void checkPermission() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) sm.checkPermission(ACCESS_PERMISSION);
+    }
+
     /**
      * Convenience method to set the {@code accessible} flag for an
      * array of objects with a single security check (for efficiency).
      *
-     * <p>First, if there is a security manager, its
-     * {@code checkPermission} method is called with a
+     * <p>This method cannot be used to enable access to an object that is a
+     * {@link Member member} of a class in a different module to the caller and
+     * where the class is in a package that is not exported to the caller's
+     * module. Additionally, this method cannot be used to enable access to
+     * non-public members of {@code AccessibleObject} or {@link Module}.
+     *
+     * <p>If there is a security manager, its
+     * {@code checkPermission} method is first called with a
      * {@code ReflectPermission("suppressAccessChecks")} permission.
      *
-     * <p>A {@code SecurityException} is raised if {@code flag} is
-     * {@code true} but accessibility of any of the elements of the input
-     * {@code array} may not be changed (for example, if the element
-     * object is a {@link Constructor} object for the class {@link
-     * java.lang.Class}).  In the event of such a SecurityException, the
-     * accessibility of objects is set to {@code flag} for array elements
-     * up to (and excluding) the element for which the exception occurred; the
-     * accessibility of elements beyond (and including) the element for which
-     * the exception occurred is unchanged.
+     * <p>A {@code SecurityException} is also thrown if any of the elements of
+     * the input {@code array} is a {@link java.lang.reflect.Constructor}
+     * object for the class {@code java.lang.Class} and {@code flag} is true.
      *
      * @param array the array of AccessibleObjects
      * @param flag  the new value for the {@code accessible} flag
      *              in each object
+     * @throws InaccessibleObjectException if access cannot be enabled
      * @throws SecurityException if the request is denied.
      * @see SecurityManager#checkPermission
-     * @see java.lang.RuntimePermission
+     * @see ReflectPermission
      */
-    public static void setAccessible(AccessibleObject[] array, boolean flag)
-        throws SecurityException {
-        SecurityManager sm = System.getSecurityManager();
-        if (sm != null) sm.checkPermission(ACCESS_PERMISSION);
+    @CallerSensitive
+    public static void setAccessible(AccessibleObject[] array, boolean flag) {
+        checkPermission();
+        if (flag) {
+            Class<?> caller = Reflection.getCallerClass();
+            array = array.clone();
+            for (AccessibleObject ao : array) {
+                ao.checkCanSetAccessible(caller);
+            }
+        }
         for (AccessibleObject ao : array) {
-            setAccessible0(ao, flag);
+            ao.setAccessible0(flag);
         }
     }
 
@@ -103,45 +120,87 @@
      * the indicated boolean value.  A value of {@code true} indicates that
      * the reflected object should suppress Java language access
      * checking when it is used.  A value of {@code false} indicates
-     * that the reflected object should enforce Java language access checks.
-     *
-     * <p>First, if there is a security manager, its
-     * {@code checkPermission} method is called with a
-     * {@code ReflectPermission("suppressAccessChecks")} permission.
+     * that the reflected object should enforce Java language access checks
+     * while assuming readability (as noted in the class description).
      *
-     * <p>A {@code SecurityException} is raised if {@code flag} is
-     * {@code true} but accessibility of this object may not be changed
-     * (for example, if this element object is a {@link Constructor} object for
-     * the class {@link java.lang.Class}).
+     * <p>This method cannot be used to enable access to an object that is a
+     * {@link Member member} of a class in a different module to the caller and
+     * where the class is in a package that is not exported to the caller's
+     * module. Additionally, this method cannot be used to enable access to
+     * non-public members of {@code AccessibleObject} or {@link Module}.
      *
-     * <p>A {@code SecurityException} is raised if this object is a {@link
-     * java.lang.reflect.Constructor} object for the class
-     * {@code java.lang.Class}, and {@code flag} is true.
+     * <p>If there is a security manager, its
+     * {@code checkPermission} method is first called with a
+     * {@code ReflectPermission("suppressAccessChecks")} permission.
      *
      * @param flag the new value for the {@code accessible} flag
-     * @throws SecurityException if the request is denied.
+     * @throws InaccessibleObjectException if access cannot be enabled
+     * @throws SecurityException if the request is denied
      * @see SecurityManager#checkPermission
-     * @see java.lang.RuntimePermission
+     * @see ReflectPermission
      */
-    public void setAccessible(boolean flag) throws SecurityException {
-        SecurityManager sm = System.getSecurityManager();
-        if (sm != null) sm.checkPermission(ACCESS_PERMISSION);
-        setAccessible0(this, flag);
+    public void setAccessible(boolean flag) {
+        AccessibleObject.checkPermission();
+        setAccessible0(flag);
+    }
+
+    void setAccessible0(boolean flag) {
+        this.override = flag;
+    }
+
+   /**
+    * If the given AccessibleObject is a {@code Constructor}, {@code Method}
+    * or {@code Field} then checks that its declaring class is in a package
+    * that can be accessed by the given caller of setAccessible.
+    */
+    void checkCanSetAccessible(Class<?> caller) {
+        // do nothing, needs to be overridden by Constructor, Method, Field
     }
 
-    /* Check that you aren't exposing java.lang.Class.<init> or sensitive
-       fields in java.lang.Class. */
-    private static void setAccessible0(AccessibleObject obj, boolean flag)
-        throws SecurityException
-    {
-        if (obj instanceof Constructor && flag == true) {
-            Constructor<?> c = (Constructor<?>)obj;
-            if (c.getDeclaringClass() == Class.class) {
-                throw new SecurityException("Cannot make a java.lang.Class" +
-                                            " constructor accessible");
+    void checkCanSetAccessible(Class<?> caller, Class<?> declaringClass) {
+        Module callerModule = caller.getModule();
+        Module declaringModule = declaringClass.getModule();
+
+        if (callerModule != declaringModule
+                && callerModule != Object.class.getModule()) {
+
+            // check exports to target module
+            String pn = packageName(declaringClass);
+            if (!declaringModule.isExported(pn, callerModule)) {
+                String msg = "Unable to make member of "
+                        + declaringClass + " accessible:  "
+                        + declaringModule + " does not export "
+                        + pn + " to " + callerModule;
+                Reflection.throwInaccessibleObjectException(msg);
+            }
+
+        }
+
+        if (declaringClass == Module.class
+                || declaringClass == AccessibleObject.class) {
+            int modifiers;
+            if (this instanceof Executable) {
+                modifiers = ((Executable) this).getModifiers();
+            } else {
+                modifiers = ((Field) this).getModifiers();
+            }
+            if (!Modifier.isPublic(modifiers)) {
+                String msg = "Cannot make a non-public member of "
+                        + declaringClass + " accessible";
+                Reflection.throwInaccessibleObjectException(msg);
             }
         }
-        obj.override = flag;
+    }
+
+    /**
+     * Returns the package name of the given class.
+     */
+    private static String packageName(Class<?> c) {
+        while (c.isArray()) {
+            c = c.getComponentType();
+        }
+        String pn = c.getPackageName();
+        return (pn != null) ? pn : "";
     }
 
     /**
--- a/src/java.base/share/classes/java/lang/reflect/Constructor.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/java/lang/reflect/Constructor.java	Thu Mar 17 19:04:16 2016 +0000
@@ -159,6 +159,35 @@
         return res;
     }
 
+    /**
+     * {@inheritDoc}
+     *
+     * <p> A {@code SecurityException} is also thrown if this object is a
+     * {@code Constructor} object for the class {@code Class} and {@code flag}
+     * is true. </p>
+     *
+     * @param flag {@inheritDoc}
+     */
+    @Override
+    @CallerSensitive
+    public void setAccessible(boolean flag) {
+        AccessibleObject.checkPermission();
+        if (flag) {
+            checkCanSetAccessible(Reflection.getCallerClass());
+        }
+        setAccessible0(flag);
+    }
+
+    @Override
+    void checkCanSetAccessible(Class<?> caller) {
+        checkCanSetAccessible(caller, clazz);
+        if (clazz == Class.class) {
+            // can we change this to InaccessibleObjectException?
+            throw new SecurityException("Cannot make a java.lang.Class"
+                                        + " constructor accessible");
+        }
+    }
+
     @Override
     boolean hasGenericInformation() {
         return (getSignature() != null);
@@ -411,10 +440,8 @@
                IllegalArgumentException, InvocationTargetException
     {
         if (!override) {
-            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
-                Class<?> caller = Reflection.getCallerClass();
-                checkAccess(caller, clazz, null, modifiers);
-            }
+            Class<?> caller = Reflection.getCallerClass();
+            checkAccess(caller, clazz, null, modifiers);
         }
         if ((clazz.getModifiers() & Modifier.ENUM) != 0)
             throw new IllegalArgumentException("Cannot reflectively create enum objects");
--- a/src/java.base/share/classes/java/lang/reflect/Field.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/java/lang/reflect/Field.java	Thu Mar 17 19:04:16 2016 +0000
@@ -157,10 +157,24 @@
         return res;
     }
 
+    @Override
+    @CallerSensitive
+    public void setAccessible(boolean flag) {
+        AccessibleObject.checkPermission();
+        if (flag) checkCanSetAccessible(Reflection.getCallerClass());
+        setAccessible0(flag);
+    }
+
+    @Override
+    void checkCanSetAccessible(Class<?> caller) {
+        checkCanSetAccessible(caller, clazz);
+    }
+
     /**
      * Returns the {@code Class} object representing the class or interface
      * that declares the field represented by this {@code Field} object.
      */
+    @Override
     public Class<?> getDeclaringClass() {
         return clazz;
     }
@@ -386,10 +400,8 @@
         throws IllegalArgumentException, IllegalAccessException
     {
         if (!override) {
-            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
-                Class<?> caller = Reflection.getCallerClass();
-                checkAccess(caller, clazz, obj, modifiers);
-            }
+            Class<?> caller = Reflection.getCallerClass();
+            checkAccess(caller, clazz, obj, modifiers);
         }
         return getFieldAccessor(obj).get(obj);
     }
@@ -421,10 +433,8 @@
         throws IllegalArgumentException, IllegalAccessException
     {
         if (!override) {
-            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
-                Class<?> caller = Reflection.getCallerClass();
-                checkAccess(caller, clazz, obj, modifiers);
-            }
+            Class<?> caller = Reflection.getCallerClass();
+            checkAccess(caller, clazz, obj, modifiers);
         }
         return getFieldAccessor(obj).getBoolean(obj);
     }
@@ -456,10 +466,8 @@
         throws IllegalArgumentException, IllegalAccessException
     {
         if (!override) {
-            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
-                Class<?> caller = Reflection.getCallerClass();
-                checkAccess(caller, clazz, obj, modifiers);
-            }
+            Class<?> caller = Reflection.getCallerClass();
+            checkAccess(caller, clazz, obj, modifiers);
         }
         return getFieldAccessor(obj).getByte(obj);
     }
@@ -493,10 +501,8 @@
         throws IllegalArgumentException, IllegalAccessException
     {
         if (!override) {
-            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
-                Class<?> caller = Reflection.getCallerClass();
-                checkAccess(caller, clazz, obj, modifiers);
-            }
+            Class<?> caller = Reflection.getCallerClass();
+            checkAccess(caller, clazz, obj, modifiers);
         }
         return getFieldAccessor(obj).getChar(obj);
     }
@@ -530,10 +536,8 @@
         throws IllegalArgumentException, IllegalAccessException
     {
         if (!override) {
-            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
-                Class<?> caller = Reflection.getCallerClass();
-                checkAccess(caller, clazz, obj, modifiers);
-            }
+            Class<?> caller = Reflection.getCallerClass();
+            checkAccess(caller, clazz, obj, modifiers);
         }
         return getFieldAccessor(obj).getShort(obj);
     }
@@ -567,10 +571,8 @@
         throws IllegalArgumentException, IllegalAccessException
     {
         if (!override) {
-            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
-                Class<?> caller = Reflection.getCallerClass();
-                checkAccess(caller, clazz, obj, modifiers);
-            }
+            Class<?> caller = Reflection.getCallerClass();
+            checkAccess(caller, clazz, obj, modifiers);
         }
         return getFieldAccessor(obj).getInt(obj);
     }
@@ -604,10 +606,8 @@
         throws IllegalArgumentException, IllegalAccessException
     {
         if (!override) {
-            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
-                Class<?> caller = Reflection.getCallerClass();
-                checkAccess(caller, clazz, obj, modifiers);
-            }
+            Class<?> caller = Reflection.getCallerClass();
+            checkAccess(caller, clazz, obj, modifiers);
         }
         return getFieldAccessor(obj).getLong(obj);
     }
@@ -641,10 +641,8 @@
         throws IllegalArgumentException, IllegalAccessException
     {
         if (!override) {
-            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
-                Class<?> caller = Reflection.getCallerClass();
-                checkAccess(caller, clazz, obj, modifiers);
-            }
+            Class<?> caller = Reflection.getCallerClass();
+            checkAccess(caller, clazz, obj, modifiers);
         }
         return getFieldAccessor(obj).getFloat(obj);
     }
@@ -678,10 +676,8 @@
         throws IllegalArgumentException, IllegalAccessException
     {
         if (!override) {
-            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
-                Class<?> caller = Reflection.getCallerClass();
-                checkAccess(caller, clazz, obj, modifiers);
-            }
+            Class<?> caller = Reflection.getCallerClass();
+            checkAccess(caller, clazz, obj, modifiers);
         }
         return getFieldAccessor(obj).getDouble(obj);
     }
@@ -757,10 +753,8 @@
         throws IllegalArgumentException, IllegalAccessException
     {
         if (!override) {
-            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
-                Class<?> caller = Reflection.getCallerClass();
-                checkAccess(caller, clazz, obj, modifiers);
-            }
+            Class<?> caller = Reflection.getCallerClass();
+            checkAccess(caller, clazz, obj, modifiers);
         }
         getFieldAccessor(obj).set(obj, value);
     }
@@ -794,10 +788,8 @@
         throws IllegalArgumentException, IllegalAccessException
     {
         if (!override) {
-            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
-                Class<?> caller = Reflection.getCallerClass();
-                checkAccess(caller, clazz, obj, modifiers);
-            }
+            Class<?> caller = Reflection.getCallerClass();
+            checkAccess(caller, clazz, obj, modifiers);
         }
         getFieldAccessor(obj).setBoolean(obj, z);
     }
@@ -831,10 +823,8 @@
         throws IllegalArgumentException, IllegalAccessException
     {
         if (!override) {
-            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
-                Class<?> caller = Reflection.getCallerClass();
-                checkAccess(caller, clazz, obj, modifiers);
-            }
+            Class<?> caller = Reflection.getCallerClass();
+            checkAccess(caller, clazz, obj, modifiers);
         }
         getFieldAccessor(obj).setByte(obj, b);
     }
@@ -868,10 +858,8 @@
         throws IllegalArgumentException, IllegalAccessException
     {
         if (!override) {
-            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
-                Class<?> caller = Reflection.getCallerClass();
-                checkAccess(caller, clazz, obj, modifiers);
-            }
+            Class<?> caller = Reflection.getCallerClass();
+            checkAccess(caller, clazz, obj, modifiers);
         }
         getFieldAccessor(obj).setChar(obj, c);
     }
@@ -905,10 +893,8 @@
         throws IllegalArgumentException, IllegalAccessException
     {
         if (!override) {
-            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
-                Class<?> caller = Reflection.getCallerClass();
-                checkAccess(caller, clazz, obj, modifiers);
-            }
+            Class<?> caller = Reflection.getCallerClass();
+            checkAccess(caller, clazz, obj, modifiers);
         }
         getFieldAccessor(obj).setShort(obj, s);
     }
@@ -942,10 +928,8 @@
         throws IllegalArgumentException, IllegalAccessException
     {
         if (!override) {
-            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
-                Class<?> caller = Reflection.getCallerClass();
-                checkAccess(caller, clazz, obj, modifiers);
-            }
+            Class<?> caller = Reflection.getCallerClass();
+            checkAccess(caller, clazz, obj, modifiers);
         }
         getFieldAccessor(obj).setInt(obj, i);
     }
@@ -979,10 +963,8 @@
         throws IllegalArgumentException, IllegalAccessException
     {
         if (!override) {
-            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
-                Class<?> caller = Reflection.getCallerClass();
-                checkAccess(caller, clazz, obj, modifiers);
-            }
+            Class<?> caller = Reflection.getCallerClass();
+            checkAccess(caller, clazz, obj, modifiers);
         }
         getFieldAccessor(obj).setLong(obj, l);
     }
@@ -1016,10 +998,8 @@
         throws IllegalArgumentException, IllegalAccessException
     {
         if (!override) {
-            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
-                Class<?> caller = Reflection.getCallerClass();
-                checkAccess(caller, clazz, obj, modifiers);
-            }
+            Class<?> caller = Reflection.getCallerClass();
+            checkAccess(caller, clazz, obj, modifiers);
         }
         getFieldAccessor(obj).setFloat(obj, f);
     }
@@ -1053,10 +1033,8 @@
         throws IllegalArgumentException, IllegalAccessException
     {
         if (!override) {
-            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
-                Class<?> caller = Reflection.getCallerClass();
-                checkAccess(caller, clazz, obj, modifiers);
-            }
+            Class<?> caller = Reflection.getCallerClass();
+            checkAccess(caller, clazz, obj, modifiers);
         }
         getFieldAccessor(obj).setDouble(obj, d);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/reflect/InaccessibleObjectException.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.reflect;
+
+/**
+ * Thrown when Java language access checks cannot be suppressed.
+ *
+ * @see AccessibleObject#setAccessible(boolean)
+ * @since 9
+ */
+
+public class InaccessibleObjectException extends RuntimeException {
+    private static final long serialVersionUID = 4158786093378140901L;
+
+    /**
+     * Constructs a {@code InaccessibleObjectException} with no detail message.
+     */
+    public InaccessibleObjectException() {
+    }
+
+    /**
+     * Constructs a {@code InaccessibleObjectException} with the given detail
+     * message.
+     *
+     * @param msg
+     *        The detail message
+     */
+    public InaccessibleObjectException(String msg) {
+        super(msg);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/reflect/Layer.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,552 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.reflect;
+
+import java.lang.module.Configuration;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ResolvedModule;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import jdk.internal.loader.Loader;
+import jdk.internal.loader.LoaderPool;
+import jdk.internal.misc.SharedSecrets;
+import sun.security.util.SecurityConstants;
+
+
+/**
+ * A layer of modules in the Java virtual machine.
+ *
+ * <p> A layer is created from a graph of modules that is the {@link
+ * Configuration} and a function that maps each module to a {@link ClassLoader}.
+ * Creating a layer informs the Java virtual machine about the classes that
+ * may be loaded from modules so that the Java virtual machine knows which
+ * module that each class is a member of. Each layer, except the {@link
+ * #empty() empty} layer, has a {@link #parent() parent}. </p>
+ *
+ * <p> Creating a layer creates a {@link Module} object for each {@link
+ * ResolvedModule} in the configuration. For each resolved module that is
+ * {@link ResolvedModule#reads() read}, the {@code Module} {@link
+ * Module#canRead reads} the corresponding run-time {@code Module}, which may
+ * be in the same layer or a parent layer. The {@code Module} {@link
+ * Module#isExported(String) exports} the packages described by its {@link
+ * ModuleDescriptor}. </p>
+ *
+ * <p> The {@link #defineModulesWithOneLoader defineModulesWithOneLoader} and
+ * {@link #defineModulesWithManyLoaders defineModulesWithManyLoaders} methods
+ * provide convenient ways to create a {@code Layer} where all modules are
+ * mapped to a single class loader or where each module is mapped to its own
+ * class loader. The {@link #defineModules defineModules} method is for more
+ * advanced cases where modules are mapped to custom class loaders by means of
+ * a function specified to the method. </p>
+ *
+ * <p> A Java virtual machine has at least one non-empty layer, the {@link
+ * #boot() boot} layer, that is created when the Java virtual machine is
+ * started. The <em>system modules</em>, including {@code java.base}, are in
+ * the boot layer. The modules in the boot layer are mapped to the bootstrap
+ * class loader and other class loaders that are built-in into the ava virtual
+ * machine. The boot layer will often be the {@link #parent() parent} when
+ * creating additional layers. </p>
+ *
+ * <p> As when creating a {@code Configuration},
+ * {@link ModuleDescriptor#isAutomatic() automatic} modules receive
+ * <a href="../module/Configuration.html#automaticmoduleresolution">special
+ * treatment</a> when creating a layer. An automatic module is created in the
+ * Java virtual machine as a {@code Module} that reads every unnamed {@code
+ * Module} in the Java virtual machine. </p>
+ *
+ * <p> Unless otherwise specified, passing a {@code null} argument to a method
+ * in this class causes a {@link NullPointerException NullPointerException} to
+ * be thrown. </p>
+ *
+ * <h3> Example usage: </h3>
+ *
+ * <p> This example creates a configuration by resolving a module named
+ * "{@code myapp}" with the configuration for the boot layer as the parent. It
+ * then creates a new layer with the modules in this configuration. All modules
+ * are defined to the same class loader. </p>
+ *
+ * <pre>{@code
+ *     ModuleFinder finder = ModuleFinder.of(dir1, dir2, dir3);
+ *
+ *     Layer parent = Layer.boot();
+ *
+ *     Configuration cf = parent.configuration()
+ *         .resolveRequires(finder, ModuleFinder.empty(), Set.of("myapp"));
+ *
+ *     ClassLoader scl = ClassLoader.getSystemClassLoader();
+ *
+ *     Layer layer = parent.defineModulesWithOneLoader(cf, scl);
+ *
+ *     Class<?> c = layer.findLoader("myapp").loadClass("app.Main");
+ * }</pre>
+ *
+ * @since 9
+ * @see Module#getLayer()
+ */
+
+public final class Layer {
+
+    // the empty Layer
+    private static final Layer EMPTY_LAYER
+        = new Layer(Configuration.empty(), null, null);
+
+    // the configuration from which this Layer was created
+    private final Configuration cf;
+
+    // parent layer, null in the case of the empty layer
+    private final Layer parent;
+
+    // maps module name to jlr.Module
+    private final Map<String, Module> nameToModule;
+
+
+    /**
+     * Creates a new Layer from the modules in the given configuration.
+     */
+    private Layer(Configuration cf,
+                  Layer parent,
+                  Function<String, ClassLoader> clf)
+    {
+        this.cf = cf;
+        this.parent = parent;
+
+        Map<String, Module> map;
+        if (parent == null) {
+            map = Collections.emptyMap();
+        } else {
+            map = Module.defineModules(cf, clf, this);
+        }
+        this.nameToModule = map; // no need to do defensive copy
+    }
+
+
+    /**
+     * Creates a new layer, with this layer as its parent, by defining the
+     * modules in the given {@code Configuration} to the Java virtual machine.
+     * This method creates one class loader and defines all modules to that
+     * class loader.
+     *
+     * <p> The class loader created by this method implements <em>direct
+     * delegation</em> when loading types from modules. When its {@link
+     * ClassLoader#loadClass(String, boolean) loadClass} method is invoked to
+     * load a class then it uses the package name of the class to map it to a
+     * module. This may be a module in this layer and hence defined to the same
+     * class loader. It may be a package in a module in a parent layer that is
+     * exported to one or more of the modules in this layer. The class
+     * loader delegates to the class loader of the module, throwing {@code
+     * ClassNotFoundException} if not found by that class loader.
+     *
+     * When {@code loadClass} is invoked to load classes that do not map to a
+     * module then it delegates to the parent class loader. </p>
+     *
+     * <p> Attempting to create a layer with all modules defined to the same
+     * class loader can fail for the following reasons:
+     *
+     * <ul>
+     *
+     *     <li><p> <em>Overlapping packages</em>: Two or more modules in the
+     *     configuration have the same package (exported or concealed). </p></li>
+     *
+     *     <li><p> <em>Split delegation</em>: The resulting class loader would
+     *     need to delegate to more than one class loader in order to load types
+     *     in a specific package. </p></li>
+     *
+     * </ul>
+     *
+     * <p> If there is a security manager then the class loader created by
+     * this method will load classes and resources with privileges that are
+     * restricted by the calling context of this method. </p>
+     *
+     * @param  cf
+     *         The configuration for the layer
+     * @param  parentLoader
+     *         The parent class loader for the class loader created by this
+     *         method; may be {@code null} for the bootstrap class loader
+     *
+     * @return The newly created layer
+     *
+     * @throws IllegalArgumentException
+     *         If the parent of the given configuration is not the configuration
+     *         for this layer
+     * @throws LayerInstantiationException
+     *         If all modules cannot be defined to the same class loader for any
+     *         of the reasons listed above
+     * @throws SecurityException
+     *         If {@code RuntimePermission("createClassLoader")} or
+     *         {@code RuntimePermission("getClassLoader")} is denied by
+     *         the security manager
+     *
+     * @see #findLoader
+     */
+    public Layer defineModulesWithOneLoader(Configuration cf,
+                                            ClassLoader parentLoader)
+    {
+        checkConfiguration(cf);
+        checkCreateClassLoaderPermission();
+        checkGetClassLoaderPermission();
+
+        Loader loader;
+        try {
+            loader = new Loader(cf.modules(), parentLoader);
+            loader.initRemotePackageMap(cf, this);
+        } catch (IllegalArgumentException e) {
+            throw new LayerInstantiationException(e.getMessage());
+        }
+        return new Layer(cf, this, mn -> loader);
+    }
+
+
+    /**
+     * Creates a new layer, with this layer as its parent, by defining the
+     * modules in the given {@code Configuration} to the Java virtual machine.
+     * Each module is defined to its own {@link ClassLoader} created by this
+     * method. The {@link ClassLoader#getParent() parent} of each class loader
+     * is the given parent class loader.
+     *
+     * <p> The class loaders created by this method implement <em>direct
+     * delegation</em> when loading types from modules. When {@link
+     * ClassLoader#loadClass(String, boolean) loadClass} method is invoked to
+     * load a class then it uses the package name of the class to map it to a
+     * module. The package may be in the module defined to the class loader.
+     * The package may be exported by another module in this layer to the
+     * module defined to the class loader. It may be in a package exported by a
+     * module in a parent layer. The class loader delegates to the class loader
+     * of the module, throwing {@code ClassNotFoundException} if not found by
+     * that class loader.
+     *
+     * When {@code loadClass} is invoked to load classes that do not map to a
+     * module then it delegates to the parent class loader. </p>
+     *
+     * <p> If there is a security manager then the class loaders created by
+     * this method will load classes and resources with privileges that are
+     * restricted by the calling context of this method. </p>
+     *
+     * @param  cf
+     *         The configuration for the layer
+     * @param  parentLoader
+     *         The parent class loader for each of the class loaders created by
+     *         this method; may be {@code null} for the bootstrap class loader
+     *
+     * @return The newly created layer
+     *
+     * @throws IllegalArgumentException
+     *         If the parent of the given configuration is not the configuration
+     *         for this layer
+     * @throws SecurityException
+     *         If {@code RuntimePermission("createClassLoader")} or
+     *         {@code RuntimePermission("getClassLoader")} is denied by
+     *         the security manager
+     *
+     * @see #findLoader
+     */
+    public Layer defineModulesWithManyLoaders(Configuration cf,
+                                              ClassLoader parentLoader)
+    {
+        checkConfiguration(cf);
+        checkCreateClassLoaderPermission();
+        checkGetClassLoaderPermission();
+
+        LoaderPool pool = new LoaderPool(cf, this, parentLoader);
+        return new Layer(cf, this, pool::loaderFor);
+    }
+
+
+    /**
+     * Creates a new layer, with this layer as its parent, by defining the
+     * modules in the given {@code Configuration} to the Java virtual machine.
+     * Each module is mapped, by name, to its class loader by means of the
+     * given function. The class loader delegation implemented by these class
+     * loaders must respect module readability. In addition, the caller needs
+     * to arrange that the class loaders are ready to load from these module
+     * before there are any attempts to load classes or resources.
+     *
+     * <p> Creating a {@code Layer} can fail for the following reasons: </p>
+     *
+     * <ul>
+     *
+     *     <li><p> Two or more modules with the same package (exported or
+     *     concealed) are mapped to the same class loader. </p></li>
+     *
+     *     <li><p> A module is mapped to a class loader that already has a
+     *     module of the same name defined to it. </p></li>
+     *
+     *     <li><p> A module is mapped to a class loader that has already
+     *     defined types in any of the packages in the module. </p></li>
+     *
+     * </ul>
+     *
+     * <p> If the function to map a module name to class loader throws an error
+     * or runtime exception then it is propagated to the caller of this method.
+     * </p>
+     *
+     * @apiNote It is implementation specific as to whether creating a Layer
+     * with this method is an atomic operation or not. Consequentially it is
+     * possible for this method to fail with some modules, but not all, defined
+     * to Java virtual machine.
+     *
+     * @param  cf
+     *         The configuration for the layer
+     * @param  clf
+     *         The function to map a module name to a class loader
+     *
+     * @return The newly created layer
+     *
+     * @throws IllegalArgumentException
+     *         If the parent of the given configuration is not the configuration
+     *         for this layer
+     * @throws LayerInstantiationException
+     *         If creating the {@code Layer} fails for any of the reasons
+     *         listed above
+     * @throws SecurityException
+     *         If {@code RuntimePermission("getClassLoader")} is denied by
+     *         the security manager
+     */
+    public Layer defineModules(Configuration cf,
+                               Function<String, ClassLoader> clf)
+    {
+        checkConfiguration(cf);
+        Objects.requireNonNull(clf);
+
+        checkGetClassLoaderPermission();
+
+        // For now, no two modules in the boot Layer may contain the same
+        // package so we use a simple check for the boot Layer to keep
+        // the overhead at startup to a minimum
+        if (boot() == null) {
+            checkBootModulesForDuplicatePkgs(cf);
+        } else {
+            checkForDuplicatePkgs(cf, clf);
+        }
+
+        try {
+            return new Layer(cf, this, clf);
+        } catch (IllegalArgumentException iae) {
+            // IAE is thrown by VM when defining the module fails
+            throw new LayerInstantiationException(iae.getMessage());
+        }
+    }
+
+
+    private void checkConfiguration(Configuration cf) {
+        Objects.requireNonNull(cf);
+
+        Optional<Configuration> oparent = cf.parent();
+        if (!oparent.isPresent() || oparent.get() != this.configuration()) {
+            throw new IllegalArgumentException(
+                    "Parent of configuration != configuration of this Layer");
+        }
+    }
+
+    private static void checkCreateClassLoaderPermission() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null)
+            sm.checkPermission(SecurityConstants.CREATE_CLASSLOADER_PERMISSION);
+    }
+
+    private static void checkGetClassLoaderPermission() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null)
+            sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
+    }
+
+    /**
+     * Checks a configuration for the boot Layer to ensure that no two modules
+     * have the same package.
+     *
+     * @throws LayerInstantiationException
+     */
+    private static void checkBootModulesForDuplicatePkgs(Configuration cf) {
+        Map<String, String> packageToModule = new HashMap<>();
+        for (ResolvedModule resolvedModule : cf.modules()) {
+            ModuleDescriptor descriptor = resolvedModule.reference().descriptor();
+            String name = descriptor.name();
+            for (String p : descriptor.packages()) {
+                String other = packageToModule.putIfAbsent(p, name);
+                if (other != null) {
+                    throw fail("Package " + p + " in both module "
+                               + name + " and module " + other);
+                }
+            }
+        }
+    }
+
+    /**
+     * Checks a configuration and the module-to-loader mapping to ensure that
+     * no two modules mapped to the same class loader have the same package.
+     * It also checks that no two automatic modules have the same package.
+     *
+     * @throws LayerInstantiationException
+     */
+    private static void checkForDuplicatePkgs(Configuration cf,
+                                              Function<String, ClassLoader> clf)
+    {
+        // HashMap allows null keys
+        Map<ClassLoader, Set<String>> loaderToPackages = new HashMap<>();
+        for (ResolvedModule resolvedModule : cf.modules()) {
+            ModuleDescriptor descriptor = resolvedModule.reference().descriptor();
+            ClassLoader loader = clf.apply(descriptor.name());
+
+            Set<String> loaderPackages
+                = loaderToPackages.computeIfAbsent(loader, k -> new HashSet<>());
+
+            for (String pkg : descriptor.packages()) {
+                boolean added = loaderPackages.add(pkg);
+                if (!added) {
+                    throw fail("More than one module with package %s mapped" +
+                               " to the same class loader", pkg);
+                }
+            }
+        }
+    }
+
+    /**
+     * Creates a LayerInstantiationException with the a message formatted from
+     * the given format string and arguments.
+     */
+    private static LayerInstantiationException fail(String fmt, Object ... args) {
+        String msg = String.format(fmt, args);
+        return new LayerInstantiationException(msg);
+    }
+
+
+    /**
+     * Returns the configuration for this layer.
+     *
+     * @return The configuration for this layer
+     */
+    public Configuration configuration() {
+        return cf;
+    }
+
+
+    /**
+     * Returns this layer's parent unless this is the {@linkplain #empty empty
+     * layer}, which has no parent.
+     *
+     * @return This layer's parent
+     */
+    public Optional<Layer> parent() {
+        return Optional.ofNullable(parent);
+    }
+
+
+    /**
+     * Returns a set of the modules in this layer.
+     *
+     * @return A possibly-empty unmodifiable set of the modules in this layer
+     */
+    public Set<Module> modules() {
+        return Collections.unmodifiableSet(
+                nameToModule.values().stream().collect(Collectors.toSet()));
+    }
+
+
+    /**
+     * Returns the module with the given name in this layer, or if not in this
+     * layer, the {@linkplain #parent parent} layer.
+     *
+     * @param  name
+     *         The name of the module to find
+     *
+     * @return The module with the given name or an empty {@code Optional}
+     *         if there isn't a module with this name in this layer or any
+     *         parent layer
+     */
+    public Optional<Module> findModule(String name) {
+        Module m = nameToModule.get(Objects.requireNonNull(name));
+        if (m != null)
+            return Optional.of(m);
+        return parent().flatMap(l -> l.findModule(name));
+    }
+
+
+    /**
+     * Returns the {@code ClassLoader} for the module with the given name. If
+     * a module of the given name is not in this layer then the {@link #parent}
+     * layer is checked.
+     *
+     * <p> If there is a security manager then its {@code checkPermission}
+     * method is called with a {@code RuntimePermission("getClassLoader")}
+     * permission to check that the caller is allowed to get access to the
+     * class loader. </p>
+     *
+     * @apiNote This method does not return an {@code Optional<ClassLoader>}
+     * because `null` must be used to represent the bootstrap class loader.
+     *
+     * @param  name
+     *         The name of the module to find
+     *
+     * @return The ClassLoader that the module is defined to
+     *
+     * @throws IllegalArgumentException if a module of the given name is not
+     *         defined in this layer or any parent of this layer
+     *
+     * @throws SecurityException if denied by the security manager
+     */
+    public ClassLoader findLoader(String name) {
+        Module m = nameToModule.get(Objects.requireNonNull(name));
+        if (m != null)
+            return m.getClassLoader();
+        Optional<Layer> ol = parent();
+        if (ol.isPresent())
+            return ol.get().findLoader(name);
+        throw new IllegalArgumentException("Module " + name
+                                           + " not known to this layer");
+    }
+
+
+    /**
+     * Returns the <em>empty</em> layer. There are no modules in the empty
+     * layer. It has no parent.
+     *
+     * @return The empty layer
+     */
+    public static Layer empty() {
+        return EMPTY_LAYER;
+    }
+
+
+    /**
+     * Returns the boot layer. The boot layer contains at least one module,
+     * {@code java.base}. Its parent is the {@link #empty() empty} layer.
+     *
+     * @apiNote This method returns {@code null} during startup and before
+     *          the boot layer is fully initialized.
+     *
+     * @return The boot layer
+     */
+    public static Layer boot() {
+        return SharedSecrets.getJavaLangAccess().getBootLayer();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/reflect/LayerInstantiationException.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.reflect;
+
+/**
+ * Thrown when creating a Layer fails.
+ *
+ * @see Layer
+ *
+ * @since 9
+ */
+public class LayerInstantiationException extends RuntimeException {
+    private static final long serialVersionUID = -906239691613568347L;
+
+    /**
+     * Constructs a {@code LayerInstantiationException} with no detail message.
+     */
+    public LayerInstantiationException() {
+    }
+
+    /**
+     * Constructs a {@code LayerInstantiationException} with the given detail
+     * message.
+     *
+     * @param msg
+     *        The detail message; can be {@code null}
+     */
+    public LayerInstantiationException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Constructs a {@code LayerInstantiationException} with the given cause.
+     *
+     * @param cause
+     *        The cause; can be {@code null}
+     */
+    public LayerInstantiationException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * Constructs a {@code FindException} with the given detail message
+     * and cause.
+     *
+     * @param msg
+     *        The detail message; can be {@code null}
+     * @param cause
+     *        The cause; can be {@code null}
+     */
+    public LayerInstantiationException(String msg, Throwable cause) {
+        super(msg, cause);
+    }
+
+}
+
--- a/src/java.base/share/classes/java/lang/reflect/Method.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/java/lang/reflect/Method.java	Thu Mar 17 19:04:16 2016 +0000
@@ -176,6 +176,19 @@
         return res;
     }
 
+    @Override
+    @CallerSensitive
+    public void setAccessible(boolean flag) {
+        AccessibleObject.checkPermission();
+        if (flag) checkCanSetAccessible(Reflection.getCallerClass());
+        setAccessible0(flag);
+    }
+
+    @Override
+    void checkCanSetAccessible(Class<?> caller) {
+        checkCanSetAccessible(caller, clazz);
+    }
+
     /**
      * Used by Excecutable for annotation sharing.
      */
@@ -508,10 +521,8 @@
            InvocationTargetException
     {
         if (!override) {
-            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
-                Class<?> caller = Reflection.getCallerClass();
-                checkAccess(caller, clazz, obj, modifiers);
-            }
+            Class<?> caller = Reflection.getCallerClass();
+            checkAccess(caller, clazz, obj, modifiers);
         }
         MethodAccessor ma = methodAccessor;             // read volatile
         if (ma == null) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/reflect/Module.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,1216 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.reflect;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.module.Configuration;
+import java.lang.module.ModuleReference;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Exports;
+import java.lang.module.ModuleDescriptor.Provides;
+import java.lang.module.ModuleDescriptor.Version;
+import java.lang.module.ResolvedModule;
+import java.net.URI;
+import java.net.URL;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.WeakHashMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.function.Function;
+import java.util.stream.Stream;
+
+import jdk.internal.loader.BuiltinClassLoader;
+import jdk.internal.loader.BootLoader;
+import jdk.internal.misc.JavaLangReflectModuleAccess;
+import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.ServicesCatalog;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
+import sun.security.util.SecurityConstants;
+
+/**
+ * Represents a run-time module, either {@link #isNamed() named} or unnamed.
+ *
+ * <p> Named modules have a {@link #getName() name} and are constructed by the
+ * Java Virtual Machine when a graph of modules is defined to the Java virtual
+ * machine to create a module {@link Layer Layer}. </p>
+ *
+ * <p> An unnamed module does not have a name. There is an unnamed module
+ * per {@link ClassLoader ClassLoader} that is obtained by invoking the class
+ * loader's {@link ClassLoader#getUnnamedModule() getUnnamedModule} method. The
+ * {@link Class#getModule() getModule} method of all types defined by a class
+ * loader that are not in a named module return the class loader's unnamed
+ * module. </p>
+ *
+ * <p> The package names that are parameters or returned by methods defined in
+ * this class are the fully-qualified names of the packages as defined in
+ * section 6.5.3 of <cite>The Java&trade; Language Specification </cite>, for
+ * example, {@code "java.lang"}. </p>
+ *
+ * <p> Unless otherwise specified, passing a {@code null} argument to a method
+ * in this class causes a {@link NullPointerException NullPointerException} to
+ * be thrown. </p>
+ *
+ * @since 9
+ * @see java.lang.Class#getModule
+ */
+
+public final class Module {
+
+    // the layer that contains this module, can be null
+    private final Layer layer;
+
+    // module name and loader, these fields are read by VM
+    private final String name;
+    private final ClassLoader loader;
+
+    // the module descriptor
+    private final ModuleDescriptor descriptor;
+
+
+    /**
+     * Creates a new named Module. The resulting Module will be defined to the
+     * VM but will not read any other modules, will not have any exports setup
+     * and will not be registered in the service catalog.
+     */
+    private Module(Layer layer,
+                   ClassLoader loader,
+                   ModuleDescriptor descriptor,
+                   URI uri)
+    {
+        this.layer = layer;
+        this.name = descriptor.name();
+        this.loader = loader;
+        this.descriptor = descriptor;
+
+        // define module to VM
+
+        Set<String> packages = descriptor.packages();
+        int n = packages.size();
+        String[] array = new String[n];
+        int i = 0;
+        for (String pn : packages) {
+            array[i++] = pn.replace('.', '/');
+        }
+        Version version = descriptor.version().orElse(null);
+        String vs = Objects.toString(version, null);
+        String loc = Objects.toString(uri, null);
+
+        defineModule0(this, vs, loc, array);
+    }
+
+
+    /**
+     * Create the unnamed Module for the given ClassLoader.
+     *
+     * @see ClassLoader#getUnnamedModule
+     */
+    private Module(ClassLoader loader) {
+        this.layer = null;
+        this.name = null;
+        this.loader = loader;
+        this.descriptor = null;
+
+        // unnamed modules are loose
+        this.loose = true;
+    }
+
+
+    /**
+     * Creates a named module but without defining the module to the VM.
+     *
+     * @apiNote This constructor is for VM white-box testing.
+     */
+    Module(ClassLoader loader, ModuleDescriptor descriptor) {
+        this.layer = null;
+        this.name = descriptor.name();
+        this.loader = loader;
+        this.descriptor = descriptor;
+    }
+
+
+
+    /**
+     * Returns {@code true} if this module is a named module.
+     *
+     * @return {@code true} if this is a named module
+     *
+     * @see ClassLoader#getUnnamedModule()
+     */
+    public boolean isNamed() {
+        return name != null;
+    }
+
+    /**
+     * Returns the module name or {@code null} if this module is an unnamed
+     * module.
+     *
+     * @return The module name
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Returns the {@code ClassLoader} for this module.
+     *
+     * <p> If there is a security manager then its {@code checkPermission}
+     * method if first called with a {@code RuntimePermission("getClassLoader")}
+     * permission to check that the caller is allowed to get access to the
+     * class loader. </p>
+     *
+     * @return The class loader for this module
+     *
+     * @throws SecurityException
+     *         If denied by the security manager
+     */
+    public ClassLoader getClassLoader() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
+        }
+        return loader;
+    }
+
+    /**
+     * Returns the module descriptor for this module or {@code null} if this
+     * module is an unnamed module.
+     *
+     * @return The module descriptor for this module
+     */
+    public ModuleDescriptor getDescriptor() {
+        return descriptor;
+    }
+
+    /**
+     * Returns the layer that contains this module or {@code null} if this
+     * module is not in a layer.
+     *
+     * A module {@code Layer} contains named modules and therefore this
+     * method always returns {@code null} when invoked on an unnamed module.
+     *
+     * <p> <a href="Proxy.html#dynamicmodule">Dynamic modules</a> are named
+     * modules that are generated at runtime. A dynamic module may or may
+     * not be in a module Layer. </p>
+     *
+     * @return The layer that contains this module
+     *
+     * @see Proxy
+     */
+    public Layer getLayer() {
+        if (isNamed()) {
+            Layer layer = this.layer;
+            if (layer != null)
+                return layer;
+
+            // special-case java.base as it is created before the boot Layer
+            if (loader == null && name.equals("java.base")) {
+                return SharedSecrets.getJavaLangAccess().getBootLayer();
+            }
+        }
+
+        return null;
+    }
+
+
+    // -- readability --
+
+    // true if this module reads all unnamed modules (a.k.a. loose module)
+    private volatile boolean loose;
+
+    // the modules that this module permanently reads
+    // (will be final when the modules are defined in reverse topology order)
+    private volatile Set<Module> reads;
+
+    // created lazily, additional modules that this module reflectively reads
+    private volatile WeakSet<Module> transientReads;
+
+
+    /**
+     * Indicates if this module reads the given module. This method returns
+     * {@code true} if invoked to test if this module reads itself. It also
+     * returns {@code true} if invoked on an unnamed module (as unnamed
+     * modules read all modules).
+     *
+     * @param  other
+     *         The other module
+     *
+     * @return {@code true} if this module reads {@code other}
+     *
+     * @see #addReads(Module)
+     */
+    public boolean canRead(Module other) {
+        Objects.requireNonNull(other);
+
+        // an unnamed module reads all modules
+        if (!this.isNamed())
+            return true;
+
+        // all modules read themselves
+        if (other == this)
+            return true;
+
+        // check if this module reads other
+        if (other.isNamed()) {
+
+            Set<Module> reads = this.reads; // volatile read
+            if (reads != null && reads.contains(other))
+                return true;
+
+        } else {
+
+            // loose modules read all unnamed modules
+            if (this.loose)
+                return true;
+
+        }
+
+        // check if this module reads the other module reflectively
+        WeakSet<Module> tr = this.transientReads; // volatile read
+        if (tr != null && tr.contains(other))
+            return true;
+
+        return false;
+    }
+
+    /**
+     * If the caller's module is this module then update this module to read
+     * the given module.
+     *
+     * This method is a no-op if {@code other} is this module (all modules can
+     * read themselves) or this module is an unnamed module (as unnamed modules
+     * read all modules).
+     *
+     * @param  other
+     *         The other module
+     *
+     * @return this module
+     *
+     * @throws IllegalStateException
+     *         If this is a named module and the caller is not this module
+     *
+     * @see #canRead
+     */
+    @CallerSensitive
+    public Module addReads(Module other) {
+        Objects.requireNonNull(other);
+        if (this.isNamed()) {
+            Module caller = Reflection.getCallerClass().getModule();
+            if (caller != this) {
+                throw new IllegalStateException(caller + " != " + this);
+            }
+            implAddReads(other, true);
+        }
+        return this;
+    }
+
+    /**
+     * Updates this module to read another module.
+     *
+     * @apiNote This method is for Proxy use and white-box testing.
+     */
+    void implAddReads(Module other) {
+        implAddReads(other, true);
+    }
+
+    /**
+     * Makes the given {@code Module} readable to this module without
+     * notifying the VM.
+     *
+     * @apiNote This method is for VM white-box testing.
+     */
+    void implAddReadsNoSync(Module other) {
+        implAddReads(other, false);
+    }
+
+    /**
+     * Makes the given {@code Module} readable to this module.
+     *
+     * If {@code syncVM} is {@code true} then the VM is notified.
+     */
+    private void implAddReads(Module other, boolean syncVM) {
+
+        // nothing to do
+        if (other == this || !this.isNamed())
+            return;
+
+        // if the other is null then change this module to be loose.
+        if (other == null) {
+            if (syncVM)
+                addReads0(this, null);
+            this.loose = true;
+            return;
+        }
+
+        // check if we already read this module
+        Set<Module> reads = this.reads;
+        if (reads != null && reads.contains(other))
+            return;
+
+        // update VM first, just in case it fails
+        if (syncVM)
+            addReads0(this, other);
+
+        // add reflective read
+        WeakSet<Module> tr = this.transientReads;
+        if (tr == null) {
+            synchronized (this) {
+                tr = this.transientReads;
+                if (tr == null) {
+                    tr = new WeakSet<>();
+                    this.transientReads = tr;
+                }
+            }
+        }
+        tr.add(other);
+    }
+
+
+    // -- exports --
+
+    // the packages that are permanently exported
+    // (will be final when the modules are defined in reverse topology order)
+    private volatile Map<String, Set<Module>> exports;
+
+    // created lazily, additional exports added at run-time
+    private volatile Map<String, WeakSet<Module>> transientExports;
+
+    // the special Module to mean exported to all modules
+    private static final Module EVERYONE_MODULE = new Module(null);
+    private static final Set<Module> EVERYONE = Collections.singleton(EVERYONE_MODULE);
+
+    // the special Module to mean exported to all unnamed modules
+    private static final Module ALL_UNNAMED_MODULE = new Module(null);
+
+
+    /**
+     * Returns {@code true} if this module exports the given package to at
+     * least the given module.
+     *
+     * <p> This method always return {@code true} when invoked on an unnamed
+     * module. </p>
+     *
+     * <p> This method does not check if the given module reads this module </p>
+     *
+     * @param  pn
+     *         The package name
+     * @param  other
+     *         The other module
+     *
+     * @return {@code true} if this module exports the package to at least the
+     *         given module
+     */
+    public boolean isExported(String pn, Module other) {
+        Objects.requireNonNull(pn);
+        Objects.requireNonNull(other);
+        return implIsExported(pn, other);
+    }
+
+    /**
+     * Returns {@code true} if this module exports the given package
+     * unconditionally.
+     *
+     * <p> This method always return {@code true} when invoked on an unnamed
+     * module. </p>
+     *
+     * <p> This method does not check if the given module reads this module </p>
+     *
+     * @param  pn
+     *         The package name
+     *
+     * @return {@code true} if this module exports the package unconditionally
+     */
+    public boolean isExported(String pn) {
+        Objects.requireNonNull(pn);
+        return implIsExported(pn, EVERYONE_MODULE);
+    }
+
+    /**
+     * Returns {@code true} if this module exports the given package to the
+     * given module. If the other module is {@code EVERYONE_MODULE} then
+     * this method tests if the package is exported unconditionally.
+     */
+    private boolean implIsExported(String pn, Module other) {
+
+        // all packages are exported by unnamed modules
+        if (!isNamed())
+            return true;
+
+        // exported via module declaration/descriptor
+        if (isExportedPermanently(pn, other))
+            return true;
+
+        // exported via addExports
+        if (isExportedReflectively(pn, other))
+            return true;
+
+        // not exported or not exported to other
+        return false;
+    }
+
+    /**
+     * Returns {@code true} if this module permanently exports the given
+     * package to the given module.
+     */
+    private boolean isExportedPermanently(String pn, Module other) {
+        Map<String, Set<Module>> exports = this.exports;
+        if (exports != null) {
+            Set<Module> targets = exports.get(pn);
+
+            if (targets != null) {
+
+                // exported to all modules
+                if (targets.contains(EVERYONE_MODULE))
+                    return true;
+
+                if (other != EVERYONE_MODULE) {
+                    // exported to other
+                    if (targets.contains(other))
+                        return true;
+
+                    // other is an unnamed module && exported to all unnamed
+                    if (!other.isNamed() && targets.contains(ALL_UNNAMED_MODULE))
+                        return true;
+                }
+
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns {@code true} if this module reflectively exports the given
+     * package package to the given module.
+     */
+    private boolean isExportedReflectively(String pn, Module other) {
+        Map<String, WeakSet<Module>> te = this.transientExports;
+        if (te != null) {
+            WeakSet<Module> targets = te.get(pn);
+
+            if (targets != null) {
+
+                // exported to all modules
+                if (targets.contains(EVERYONE_MODULE))
+                    return true;
+
+                if (other != EVERYONE_MODULE) {
+
+                    // exported to other
+                    if (targets.contains(other))
+                        return true;
+
+                    // other is an unnamed module && exported to all unnamed
+                    if (!other.isNamed() && targets.contains(ALL_UNNAMED_MODULE))
+                        return true;
+                }
+            }
+
+        }
+        return false;
+    }
+
+
+    /**
+     * If the caller's module is this module then update this module to export
+     * package {@code pn} to the given module.
+     *
+     * <p> This method has no effect if the package is already exported to the
+     * given module. If also has no effect if invoked on an unnamed module (as
+     * unnamed modules export all packages). </p>
+     *
+     * @param  pn
+     *         The package name
+     * @param  other
+     *         The module
+     *
+     * @return this module
+     *
+     * @throws IllegalArgumentException
+     *         If {@code pn} is {@code null}, or this is a named module and the
+     *         package {@code pn} is not a package in this module
+     * @throws IllegalStateException
+     *         If this is a named module and the caller is not this module
+     */
+    @CallerSensitive
+    public Module addExports(String pn, Module other) {
+        if (pn == null)
+            throw new IllegalArgumentException("package is null");
+        Objects.requireNonNull(other);
+
+        if (isNamed()) {
+            Module caller = Reflection.getCallerClass().getModule();
+            if (caller != this) {
+                throw new IllegalStateException(caller + " != " + this);
+            }
+            implAddExports(pn, other, true);
+        }
+
+        return this;
+    }
+
+    /**
+     * Updates the exports so that package {@code pn} is exported to module
+     * {@code other} but without notifying the VM.
+     *
+     * @apiNote This method is for VM white-box testing.
+     */
+    void implAddExportsNoSync(String pn, Module other) {
+        if (other == null)
+            other = EVERYONE_MODULE;
+        implAddExports(pn.replace('/', '.'), other, false);
+    }
+
+    /**
+     * Updates the exports so that package {@code pn} is exported to module
+     * {@code other}.
+     *
+     * @apiNote This method is for white-box testing.
+     */
+    void implAddExports(String pn, Module other) {
+        implAddExports(pn, other, true);
+    }
+
+    /**
+     * Updates the exports so that package {@code pn} is exported to module
+     * {@code other}.
+     *
+     * If {@code syncVM} is {@code true} then the VM is notified.
+     */
+    private void implAddExports(String pn, Module other, boolean syncVM) {
+        Objects.requireNonNull(other);
+        Objects.requireNonNull(pn);
+
+        // unnamed modules export all packages
+        if (!isNamed())
+            return;
+
+        // nothing to do if already exported to other
+        if (implIsExported(pn, other))
+            return;
+
+        // can only export a package in the module
+        if (!containsPackage(pn)) {
+            throw new IllegalArgumentException("package " + pn
+                                               + " not in contents");
+        }
+
+        // update VM first, just in case it fails
+        if (syncVM) {
+            String pkgInternalForm = pn.replace('.', '/');
+            if (other == EVERYONE_MODULE) {
+                addExportsToAll0(this, pkgInternalForm);
+            } else if (other == ALL_UNNAMED_MODULE) {
+                addExportsToAllUnnamed0(this, pkgInternalForm);
+            } else {
+                addExports0(this, pkgInternalForm, other);
+            }
+        }
+
+        // create transientExports if needed
+        Map<String, WeakSet<Module>> te = this.transientExports; // read
+        if (te == null) {
+            synchronized (this) {
+                te = this.transientExports;
+                if (te == null) {
+                    te = new ConcurrentHashMap<>();
+                    this.transientExports = te;  // volatile write
+                }
+            }
+        }
+
+        // add package name to transientExports if absent
+        WeakSet<Module> s = te.get(pn);
+        if (s == null) {
+            s = new WeakSet<>();
+            WeakSet<Module> prev = te.putIfAbsent(pn, s);
+            if (prev != null)
+                s = prev;
+        }
+        s.add(other);
+    }
+
+
+    // -- services --
+
+    // created lazily, additional service types that this module uses
+    private volatile WeakSet<Class<?>> transientUses;
+
+    /**
+     * If the caller's module is this module then update this module to add a
+     * service dependence on the given service type. This method is intended
+     * for use by frameworks that invoke {@link java.util.ServiceLoader
+     * ServiceLoader} on behalf of other modules or where the framework is
+     * passed a reference to the service type by other code. This method is
+     * a no-op when invoked on an unnamed module.
+     *
+     * <p> This method does not cause {@link
+     * Configuration#resolveRequiresAndUses resolveRequiresAndUses} to be
+     * re-run. </p>
+     *
+     * @param  st
+     *         The service type
+     *
+     * @return this module
+     *
+     * @throws IllegalStateException
+     *         If this is a named module and the caller is not this module
+     *
+     * @see #canUse(Class)
+     * @see ModuleDescriptor#uses()
+     */
+    @CallerSensitive
+    public Module addUses(Class<?> st) {
+        Objects.requireNonNull(st);
+
+        if (isNamed()) {
+
+            Module caller = Reflection.getCallerClass().getModule();
+            if (caller != this) {
+                throw new IllegalStateException(caller + " != " + this);
+            }
+
+            if (!canUse(st)) {
+                WeakSet<Class<?>> uses = this.transientUses;
+                if (uses == null) {
+                    synchronized (this) {
+                        uses = this.transientUses;
+                        if (uses == null) {
+                            uses = new WeakSet<>();
+                            this.transientUses = uses;
+                        }
+                    }
+                }
+                uses.add(st);
+            }
+
+        }
+
+        return this;
+    }
+
+    /**
+     * Indicates if this module has a service dependence on the given service
+     * type. This method always returns {@code true} when invoked on an unnamed
+     * module.
+     *
+     * @param  st
+     *         The service type
+     *
+     * @return {@code true} if this module uses service type {@code st}
+     *
+     * @see #addUses(Class)
+     */
+    public boolean canUse(Class<?> st) {
+        Objects.requireNonNull(st);
+
+        if (!isNamed())
+            return true;
+
+        if (descriptor.isAutomatic())
+            return true;
+
+        // uses was declared
+        if (descriptor.uses().contains(st.getName()))
+            return true;
+
+        // uses added via addUses
+        WeakSet<Class<?>> uses = this.transientUses;
+        if (uses != null && uses.contains(st))
+            return true;
+
+        return false;
+    }
+
+
+
+    // -- packages --
+
+    // Additional packages that are added to the module at run-time.
+    // The field is volatile as it may be replaced at run-time
+    private volatile Set<String> extraPackages;
+
+    private boolean containsPackage(String pn) {
+        if (descriptor.packages().contains(pn))
+            return true;
+        Set<String> extraPackages = this.extraPackages;
+        if (extraPackages != null && extraPackages.contains(pn))
+            return true;
+        return false;
+    }
+
+
+    /**
+     * Returns an array of the package names of the packages in this module.
+     *
+     * <p> For named modules, the returned array contains an element for each
+     * package in the module. It may contain elements corresponding to packages
+     * added to the module, <a href="Proxy.html#dynamicmodule">dynamic modules</a>
+     * for example, after it was loaded.
+     *
+     * <p> For unnamed modules, this method is the equivalent of invoking the
+     * {@link ClassLoader#getDefinedPackages() getDefinedPackages} method of
+     * this module's class loader and returning the array of package names. </p>
+     *
+     * <p> A package name appears at most once in the returned array. </p>
+     *
+     * @apiNote This method returns an array rather than a {@code Set} for
+     * consistency with other {@code java.lang.reflect} types.
+     *
+     * @return an array of the package names of the packages in this module
+     */
+    public String[] getPackages() {
+        if (isNamed()) {
+
+            Set<String> packages = descriptor.packages();
+            Set<String> extraPackages = this.extraPackages;
+            if (extraPackages == null) {
+                return packages.toArray(new String[0]);
+            } else {
+                return Stream.concat(packages.stream(),
+                                     extraPackages.stream())
+                        .toArray(String[]::new);
+            }
+
+        } else {
+            // unnamed module
+            Stream<Package> packages;
+            if (loader == null) {
+                packages = BootLoader.packages();
+            } else {
+                packages = SharedSecrets.getJavaLangAccess().packages(loader);
+            }
+            return packages.map(Package::getName).toArray(String[]::new);
+        }
+    }
+
+    /**
+     * Add a package to this module.
+     *
+     * @apiNote This method is for Proxy use.
+     *
+     * @apiNote This is an expensive operation, not expected to be used often.
+     * At this time then it does not validate that the package name is a
+     * valid java identifier.
+     */
+    void addPackage(String pn) {
+        implAddPackage(pn, true);
+    }
+
+    /**
+     * Add a package to this module without notifying the VM.
+     *
+     * @apiNote This method is VM white-box testing.
+     */
+    void implAddPackageNoSync(String pn) {
+        implAddPackage(pn.replace('/', '.'), false);
+    }
+
+    /**
+     * Add a package to this module.
+     *
+     * If {@code syncVM} is {@code true} then the VM is notified.
+     */
+    private void implAddPackage(String pn, boolean syncVM) {
+        if (pn.length() == 0)
+            throw new IllegalArgumentException("<unnamed> package not allowed");
+
+        if (descriptor.packages().contains(pn)) {
+            // already in module
+            return;
+        }
+
+        Set<String> extraPackages = this.extraPackages;
+        if (extraPackages != null && extraPackages.contains(pn)) {
+            // already added
+            return;
+        }
+        synchronized (this) {
+            // recheck under lock
+            extraPackages = this.extraPackages;
+            if (extraPackages != null) {
+                if (extraPackages.contains(pn)) {
+                    // already added
+                    return;
+                }
+
+                // copy the set
+                extraPackages = new HashSet<>(extraPackages);
+                extraPackages.add(pn);
+            } else {
+                extraPackages = Collections.singleton(pn);
+            }
+
+            // update VM first, just in case it fails
+            if (syncVM)
+                addPackage0(this, pn.replace('.', '/'));
+
+            // replace with new set
+            this.extraPackages = extraPackages; // volatile write
+        }
+    }
+
+
+    // -- creating Module objects --
+
+    /**
+     * Find the runtime Module corresponding to the given ReadDependence
+     * in the given parent Layer (or its parents).
+     */
+    private static Module find(ResolvedModule resolvedModule, Layer layer) {
+        Configuration cf = resolvedModule.configuration();
+        String dn = resolvedModule.name();
+
+        Module m = null;
+        while (layer != null) {
+            if (layer.configuration() == cf) {
+                Optional<Module> om = layer.findModule(dn);
+                m = om.get();
+                assert m.getLayer() == layer;
+                break;
+            }
+            layer = layer.parent().orElse(null);
+        }
+        return m;
+    }
+
+    /**
+     * Defines each of the module in the given configuration to the runtime.
+     *
+     * @return a map of module name to runtime {@code Module}
+     *
+     * @throws IllegalArgumentException
+     *         If defining any of the modules to the VM fails
+     */
+    static Map<String, Module> defineModules(Configuration cf,
+                                             Function<String, ClassLoader> clf,
+                                             Layer layer)
+    {
+        Map<String, Module> modules = new HashMap<>();
+        Map<String, ClassLoader> loaders = new HashMap<>();
+
+        // define each module in the configuration to the VM
+        for (ResolvedModule resolvedModule : cf.modules()) {
+            ModuleReference mref = resolvedModule.reference();
+            ModuleDescriptor descriptor = mref.descriptor();
+            String name = descriptor.name();
+            ClassLoader loader = clf.apply(name);
+            URI uri = mref.location().orElse(null);
+
+            Module m;
+            if (loader == null && name.equals("java.base")) {
+                m = Object.class.getModule();
+            } else {
+                m = new Module(layer, loader, descriptor, uri);
+            }
+
+            modules.put(name, m);
+            loaders.put(name, loader);
+        }
+
+        // setup readability and exports
+        for (ResolvedModule resolvedModule : cf.modules()) {
+            ModuleReference mref = resolvedModule.reference();
+            ModuleDescriptor descriptor = mref.descriptor();
+
+            String mn = descriptor.name();
+            Module m = modules.get(mn);
+            assert m != null;
+
+            // reads
+            Set<Module> reads = new HashSet<>();
+            for (ResolvedModule d : resolvedModule.reads()) {
+                Module m2;
+                if (d.configuration() == cf) {
+                    String dn = d.reference().descriptor().name();
+                    m2 = modules.get(dn);
+                    assert m2 != null;
+                } else {
+                    m2 = find(d, layer.parent().orElse(null));
+                }
+
+                reads.add(m2);
+
+                // update VM view
+                addReads0(m, m2);
+            }
+            m.reads = reads;
+
+            // automatic modules reads all unnamed modules
+            if (descriptor.isAutomatic()) {
+                m.implAddReads(null, true);
+            }
+
+            // exports
+            Map<String, Set<Module>> exports = new HashMap<>();
+            for (Exports export : descriptor.exports()) {
+                String source = export.source();
+                String sourceInternalForm = source.replace('.', '/');
+
+                if (export.isQualified()) {
+
+                    // qualified export
+                    Set<Module> targets = new HashSet<>();
+                    for (String target : export.targets()) {
+                        // only export to modules that are in this configuration
+                        Module m2 = modules.get(target);
+                        if (m2 != null) {
+                            targets.add(m2);
+                            addExports0(m, sourceInternalForm, m2);
+                        }
+                    }
+                    if (!targets.isEmpty()) {
+                        exports.put(source, targets);
+                    }
+
+                } else {
+
+                    // unqualified export
+                    exports.put(source, EVERYONE);
+                    addExportsToAll0(m, sourceInternalForm);
+                }
+            }
+            m.exports = exports;
+        }
+
+        // register the modules in the service catalog if they provide services
+        for (ResolvedModule resolvedModule : cf.modules()) {
+            ModuleReference mref = resolvedModule.reference();
+            ModuleDescriptor descriptor = mref.descriptor();
+            Map<String, Provides> services = descriptor.provides();
+            if (!services.isEmpty()) {
+                String name = descriptor.name();
+                Module m = modules.get(name);
+                ClassLoader loader = loaders.get(name);
+                ServicesCatalog catalog;
+                if (loader == null) {
+                    catalog = BootLoader.getServicesCatalog();
+                } else {
+                    catalog = SharedSecrets.getJavaLangAccess()
+                                           .createOrGetServicesCatalog(loader);
+                }
+                catalog.register(m);
+            }
+        }
+
+        return modules;
+    }
+
+
+    // -- misc --
+
+
+    /**
+     * Returns an input stream for reading a resource in this module. Returns
+     * {@code null} if the resource is not in this module or access to the
+     * resource is denied by the security manager.
+     * The {@code name} is a {@code '/'}-separated path name that identifies
+     * the resource.
+     *
+     * <p> If this module is an unnamed module, and the {@code ClassLoader} for
+     * this module is not {@code null}, then this method is equivalent to
+     * invoking the {@link ClassLoader#getResourceAsStream(String)
+     * getResourceAsStream} method on the class loader for this module.
+     *
+     * @param  name
+     *         The resource name
+     *
+     * @return An input stream for reading the resource or {@code null}
+     *
+     * @throws IOException
+     *         If an I/O error occurs
+     *
+     * @see java.lang.module.ModuleReader#open(String)
+     */
+    public InputStream getResourceAsStream(String name) throws IOException {
+        Objects.requireNonNull(name);
+
+        URL url = null;
+
+        if (isNamed()) {
+            String mn = this.name;
+
+            // special-case built-in class loaders to avoid URL connection
+            if (loader == null) {
+                return BootLoader.findResourceAsStream(mn, name);
+            } else if (loader instanceof BuiltinClassLoader) {
+                return ((BuiltinClassLoader) loader).findResourceAsStream(mn, name);
+            }
+
+            // use SharedSecrets to invoke protected method
+            url = SharedSecrets.getJavaLangAccess().findResource(loader, mn, name);
+
+        } else {
+
+            // unnamed module
+            if (loader == null) {
+                url = BootLoader.findResource(name);
+            } else {
+                return loader.getResourceAsStream(name);
+            }
+
+        }
+
+        // fallthrough to URL case
+        if (url != null) {
+            try {
+                return url.openStream();
+            } catch (SecurityException e) { }
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns the string representation of this module. For a named module,
+     * the representation is the string {@code "module"}, followed by a space,
+     * and then the module name. For an unnamed module, the representation is
+     * the string {@code "unnamed module"}, followed by a space, and then an
+     * implementation specific identifier for the unnamed module.
+     *
+     * @return The string representation of this module
+     */
+    @Override
+    public String toString() {
+        if (isNamed()) {
+            return "module " + name;
+        } else {
+            String id = Integer.toHexString(System.identityHashCode(this));
+            return "unnamed module @" + id;
+        }
+    }
+
+
+    // -- supporting classes --
+
+
+    /**
+     * A "not-a-Set" set of weakly referenced objects that supports concurrent
+     * access.
+     */
+    private static class WeakSet<E> {
+        private final ReadWriteLock lock = new ReentrantReadWriteLock();
+        private final Lock readLock = lock.readLock();
+        private final Lock writeLock = lock.writeLock();
+
+        private final WeakHashMap<E, Boolean> map = new WeakHashMap<>();
+
+        /**
+         * Adds the specified element to the set.
+         */
+        void add(E e) {
+            writeLock.lock();
+            try {
+                map.put(e, Boolean.TRUE);
+            } finally {
+                writeLock.unlock();
+            }
+        }
+
+        /**
+         * Returns {@code true} if this set contains the specified element.
+         */
+        boolean contains(E e) {
+            readLock.lock();
+            try {
+                return map.containsKey(e);
+            } finally {
+                readLock.unlock();
+            }
+        }
+    }
+
+
+    // -- native methods --
+
+    // JVM_DefineModule
+    private static native void defineModule0(Module module,
+                                             String version,
+                                             String location,
+                                             String[] pns);
+
+    // JVM_AddReadsModule
+    private static native void addReads0(Module from, Module to);
+
+    // JVM_AddModuleExports
+    private static native void addExports0(Module from, String pn, Module to);
+
+    // JVM_AddModuleExportsToAll
+    private static native void addExportsToAll0(Module from, String pn);
+
+    // JVM_AddModuleExportsToAllUnnamed
+    private static native void addExportsToAllUnnamed0(Module from, String pn);
+
+    // JVM_AddModulePackage
+    private static native void addPackage0(Module m, String pn);
+
+    /**
+     * Register shared secret to provide access to package-private methods
+     */
+    static {
+        SharedSecrets.setJavaLangReflectModuleAccess(
+            new JavaLangReflectModuleAccess() {
+                @Override
+                public Module defineUnnamedModule(ClassLoader loader) {
+                    return new Module(loader);
+                }
+                @Override
+                public Module defineModule(ClassLoader loader,
+                                           ModuleDescriptor descriptor,
+                                           URI uri) {
+                   return new Module(null, loader, descriptor, uri);
+                }
+                @Override
+                public void addReads(Module m1, Module m2) {
+                    m1.implAddReads(m2, true);
+                }
+                @Override
+                public void addExports(Module m, String pn, Module other) {
+                    m.implAddExports(pn, Objects.requireNonNull(other), true);
+                }
+                @Override
+                public void addExportsToAll(Module m, String pn) {
+                    m.implAddExports(pn, Module.EVERYONE_MODULE, true);
+                }
+                @Override
+                public void addExportsToAllUnnamed(Module m, String pn) {
+                    m.implAddExports(pn, Module.ALL_UNNAMED_MODULE, true);
+                }
+                @Override
+                public void addPackage(Module m, String pn) {
+                    m.implAddPackage(pn, true);
+                }
+            });
+    }
+}
--- a/src/java.base/share/classes/java/lang/reflect/Proxy.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/java/lang/reflect/Proxy.java	Thu Mar 17 19:04:16 2016 +0000
@@ -29,45 +29,48 @@
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.IdentityHashMap;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
+import java.util.WeakHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.function.BiFunction;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import jdk.internal.loader.BootLoader;
+import jdk.internal.module.Modules;
 import jdk.internal.misc.VM;
+import sun.misc.Unsafe;
 import sun.reflect.CallerSensitive;
 import sun.reflect.Reflection;
 import sun.reflect.misc.ReflectUtil;
 import sun.security.util.SecurityConstants;
 
 /**
- * {@code Proxy} provides static methods for creating dynamic proxy
- * classes and instances, and it is also the superclass of all
- * dynamic proxy classes created by those methods.
  *
- * <p>To create a proxy for some interface {@code Foo}:
- * <pre>
+ * {@code Proxy} provides static methods for creating objects that act like instances
+ * of interfaces but allow for customized method invocation.
+ * To create a proxy instance for some interface {@code Foo}:
+ * <pre>{@code
  *     InvocationHandler handler = new MyInvocationHandler(...);
- *     Class&lt;?&gt; proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), Foo.class);
- *     Foo f = (Foo) proxyClass.getConstructor(InvocationHandler.class).
- *                     newInstance(handler);
- * </pre>
- * or more simply:
- * <pre>
  *     Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
- *                                          new Class&lt;?&gt;[] { Foo.class },
+ *                                          new Class<?>[] { Foo.class },
  *                                          handler);
- * </pre>
+ * }</pre>
  *
- * <p>A <i>dynamic proxy class</i> (simply referred to as a <i>proxy
- * class</i> below) is a class that implements a list of interfaces
- * specified at runtime when the class is created, with behavior as
- * described below.
- *
- * A <i>proxy interface</i> is such an interface that is implemented
- * by a proxy class.
- *
- * A <i>proxy instance</i> is an instance of a proxy class.
+ * <p>
+ * A <em>proxy class</em> is a class created at runtime that implements a specified
+ * list of interfaces, known as <em>proxy interfaces</em>. A <em>proxy instance</em>
+ * is an instance of a proxy class.
  *
  * Each proxy instance has an associated <i>invocation handler</i>
  * object, which implements the interface {@link InvocationHandler}.
@@ -84,65 +87,41 @@
  * <p>A proxy class has the following properties:
  *
  * <ul>
- * <li>Proxy classes are <em>public, final, and not abstract</em> if
- * all proxy interfaces are public.</li>
- *
- * <li>Proxy classes are <em>non-public, final, and not abstract</em> if
- * any of the proxy interfaces is non-public.</li>
- *
  * <li>The unqualified name of a proxy class is unspecified.  The space
  * of class names that begin with the string {@code "$Proxy"}
  * should be, however, reserved for proxy classes.
  *
+ * <li>The package and module in which a proxy class is defined is specified
+ * <a href="#membership">below</a>.
+ *
+ * <li>A proxy class is <em>final and non-abstract</em>.
+ *
  * <li>A proxy class extends {@code java.lang.reflect.Proxy}.
  *
  * <li>A proxy class implements exactly the interfaces specified at its
- * creation, in the same order.
- *
- * <li>If a proxy class implements a non-public interface, then it will
- * be defined in the same package as that interface.  Otherwise, the
- * package of a proxy class is also unspecified.  Note that package
- * sealing will not prevent a proxy class from being successfully defined
- * in a particular package at runtime, and neither will classes already
- * defined by the same class loader and the same package with particular
- * signers.
- *
- * <li>Since a proxy class implements all of the interfaces specified at
- * its creation, invoking {@code getInterfaces} on its
- * {@code Class} object will return an array containing the same
+ * creation, in the same order. Invoking {@link Class#getInterfaces getInterfaces}
+ * on its {@code Class} object will return an array containing the same
  * list of interfaces (in the order specified at its creation), invoking
- * {@code getMethods} on its {@code Class} object will return
+ * {@link Class#getMethods getMethods} on its {@code Class} object will return
  * an array of {@code Method} objects that include all of the
  * methods in those interfaces, and invoking {@code getMethod} will
  * find methods in the proxy interfaces as would be expected.
  *
- * <li>The {@link Proxy#isProxyClass Proxy.isProxyClass} method will
- * return true if it is passed a proxy class-- a class returned by
- * {@code Proxy.getProxyClass} or the class of an object returned by
- * {@code Proxy.newProxyInstance}-- and false otherwise.
- *
- * <li>The {@code java.security.ProtectionDomain} of a proxy class
+ * <li>The {@link java.security.ProtectionDomain} of a proxy class
  * is the same as that of system classes loaded by the bootstrap class
  * loader, such as {@code java.lang.Object}, because the code for a
  * proxy class is generated by trusted system code.  This protection
- * domain will typically be granted
- * {@code java.security.AllPermission}.
+ * domain will typically be granted {@code java.security.AllPermission}.
  *
- * <li>Each proxy class has one public constructor that takes one argument,
- * an implementation of the interface {@link InvocationHandler}, to set
- * the invocation handler for a proxy instance.  Rather than having to use
- * the reflection API to access the public constructor, a proxy instance
- * can be also be created by calling the {@link Proxy#newProxyInstance
- * Proxy.newProxyInstance} method, which combines the actions of calling
- * {@link Proxy#getProxyClass Proxy.getProxyClass} with invoking the
- * constructor with an invocation handler.
+ * <li>The {@link Proxy#isProxyClass Proxy.isProxyClass} method can be used
+ * to determine if a given class is a proxy class.
  * </ul>
  *
  * <p>A proxy instance has the following properties:
  *
  * <ul>
  * <li>Given a proxy instance {@code proxy} and one of the
- * interfaces implemented by its proxy class {@code Foo}, the
+ * interfaces, {@code Foo}, implemented by its proxy class, the
  * following expression will return true:
  * <pre>
  *     {@code proxy instanceof Foo}
@@ -177,9 +156,82 @@
  * like they do for instances of {@code java.lang.Object}.
  * </ul>
  *
+ * <h3><a name="membership">Package and Module Membership of Proxy Class</a></h3>
+ *
+ * The package and module to which a proxy class belongs are chosen such that
+ * the accessibility of the proxy class is in line with the accessibility of
+ * the proxy interfaces. Specifically, the package and the module membership
+ * of a proxy class defined via the
+ * {@link Proxy#getProxyClass(ClassLoader, Class[])} or
+ * {@link Proxy#newProxyInstance(ClassLoader, Class[], InvocationHandler)}
+ * methods is specified as follows:
+ *
+ * <ol>
+ * <li>If all the proxy interfaces are in <em>exported</em> packages:
+ * <ol type="a">
+ * <li>if all the proxy interfaces are <em>public</em>, then the proxy class is
+ *     <em>public</em> in a package exported by the
+ *     {@linkplain ClassLoader#getUnnamedModule() unnamed module} of the specified
+ *     loader. The name of the package is unspecified.</li>
+ *
+ * <li>if at least one of all the proxy interfaces is <em>non-public</em>, then
+ *     the proxy class is <em>non-public</em> in the package and module of the
+ *     non-public interfaces. All the non-public interfaces must be in the same
+ *     package and module; otherwise, proxying them is
+ *     <a href="#restrictions">not possible</a>.</li>
+ * </ol>
+ * </li>
+ * <li>If at least one proxy interface is a <em>non-exported</em> package:
+ * <ol type="a">
+ * <li>if all the proxy interfaces are <em>public</em>, then the proxy class is
+ *     <em>public</em> in a <em>non-exported</em> package of
+ *     <a href="#dynamicmodule"><em>dynamic module</em>.</a>
+ *     The names of the package and the module are unspecified.</li>
+ *
+ * <li>if at least one of all the proxy interfaces is <em>non-public</em>, then
+ *     the proxy class is <em>non-public</em> in the package and module of the
+ *     non-public interfaces. All the non-public interfaces must be in the same
+ *     package and module; otherwise, proxying them is
+ *     <a href="#restrictions">not possible</a>.</li>
+ * </ol>
+ * </li>
+ * </ol>
+ *
+ * <p>
+ * Note that if proxy interfaces with a mix of accessibilities --
+ * exported public, exported non-public, non-exported public, non-exported non-public --
+ * are proxied by the same instance, then the proxy class's accessibility is
+ * governed by the least accessible proxy interface.
+ * <p>
+ * Note that it is possible for arbitrary code to obtain access to a proxy class
+ * in an exported package with {@link AccessibleObject#setAccessible setAccessible},
+ * whereas a proxy class in a non-exported package is never accessible to
+ * code outside the module of the proxy class.
+ *
+ * <p>
+ * Throughout this specification, a "non-exported package" refers to a package that
+ * is not exported to all modules. Specifically, it refers to a package that
+ * either is not exported at all by its containing module or is exported in a
+ * qualified fashion by its containing module.
+ *
+ * <h3><a name="dynamicmodule">Dynamic Modules</a></h3>
+ * <p>
+ * A dynamic module is a named module generated at runtime. A proxy class
+ * defined in a dynamic module is encapsulated and not accessible to any module.
+ * Calling {@link Constructor#newInstance(Object...)} on a proxy class in
+ * a dynamic module will throw {@code IllegalAccessException};
+ * {@code Proxy.newProxyInstance} method should be used instead.
+ *
+ * <p>
+ * A dynamic module can read the modules of all of the superinterfaces of a proxy class
+ * and the modules of the types referenced by all public method signatures
+ * of a proxy class.  If a superinterface or a referenced type, say {@code T},
+ * is in a non-exported package, the {@linkplain java.lang.reflect.Module module}
+ * of {@code T} is updated to export the package of {@code T} to the dynamic module.
+ *
  * <h3>Methods Duplicated in Multiple Proxy Interfaces</h3>
  *
- * <p>When two or more interfaces of a proxy class contain a method with
+ * <p>When two or more proxy interfaces contain a method with
  * the same name and parameter signature, the order of the proxy class's
  * interfaces becomes significant.  When such a <i>duplicate method</i>
  * is invoked on a proxy instance, the {@code Method} object passed
@@ -225,7 +277,6 @@
  * @since       1.3
  */
 public class Proxy implements java.io.Serializable {
-
     private static final long serialVersionUID = -2222568056686623797L;
 
     /** parameter types of a proxy class constructor */
@@ -233,12 +284,6 @@
         { InvocationHandler.class };
 
     /**
-     * a cache of proxy classes
-     */
-    private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
-        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
-
-    /**
      * the invocation handler for this proxy instance.
      * @serial
      */
@@ -276,67 +321,13 @@
      * a proxy class for those interfaces will be generated dynamically
      * and defined by the class loader.
      *
-     * <p>There are several restrictions on the parameters that may be
-     * passed to {@code Proxy.getProxyClass}:
-     *
-     * <ul>
-     * <li>All of the {@code Class} objects in the
-     * {@code interfaces} array must represent interfaces, not
-     * classes or primitive types.
-     *
-     * <li>No two elements in the {@code interfaces} array may
-     * refer to identical {@code Class} objects.
-     *
-     * <li>All of the interface types must be visible by name through the
-     * specified class loader.  In other words, for class loader
-     * {@code cl} and every interface {@code i}, the following
-     * expression must be true:
-     * <pre>
-     *     Class.forName(i.getName(), false, cl) == i
-     * </pre>
-     *
-     * <li>All non-public interfaces must be in the same package;
-     * otherwise, it would not be possible for the proxy class to
-     * implement all of the interfaces, regardless of what package it is
-     * defined in.
-     *
-     * <li>For any set of member methods of the specified interfaces
-     * that have the same signature:
-     * <ul>
-     * <li>If the return type of any of the methods is a primitive
-     * type or void, then all of the methods must have that same
-     * return type.
-     * <li>Otherwise, one of the methods must have a return type that
-     * is assignable to all of the return types of the rest of the
-     * methods.
-     * </ul>
-     *
-     * <li>The resulting proxy class must not exceed any limits imposed
-     * on classes by the virtual machine.  For example, the VM may limit
-     * the number of interfaces that a class may implement to 65535; in
-     * that case, the size of the {@code interfaces} array must not
-     * exceed 65535.
-     * </ul>
-     *
-     * <p>If any of these restrictions are violated,
-     * {@code Proxy.getProxyClass} will throw an
-     * {@code IllegalArgumentException}.  If the {@code interfaces}
-     * array argument or any of its elements are {@code null}, a
-     * {@code NullPointerException} will be thrown.
-     *
-     * <p>Note that the order of the specified proxy interfaces is
-     * significant: two requests for a proxy class with the same combination
-     * of interfaces but in a different order will result in two distinct
-     * proxy classes.
-     *
      * @param   loader the class loader to define the proxy class
      * @param   interfaces the list of interfaces for the proxy class
      *          to implement
      * @return  a proxy class that is defined in the specified class loader
      *          and that implements the specified interfaces
-     * @throws  IllegalArgumentException if any of the restrictions on the
-     *          parameters that may be passed to {@code getProxyClass}
-     *          are violated
+     * @throws  IllegalArgumentException if any of the <a href="#restrictions">
+     *          restrictions</a> on the parameters are violated
      * @throws  SecurityException if a security manager, <em>s</em>, is present
      *          and any of the following conditions is met:
      *          <ul>
@@ -352,22 +343,32 @@
      *             invocation of {@link SecurityManager#checkPackageAccess
      *             s.checkPackageAccess()} denies access to {@code intf}.</li>
      *          </ul>
-
      * @throws  NullPointerException if the {@code interfaces} array
      *          argument or any of its elements are {@code null}
+     *
+     * @deprecated Proxy classes generated in a named module are encapsulated and not
+     *      accessible to code outside its module.
+     *      {@link Constructor#newInstance(Object...) Constructor.newInstance} will throw
+     *      {@code IllegalAccessException} when it is called on an inaccessible proxy class.
+     *      Use {@link #newProxyInstance(ClassLoader, Class[], InvocationHandler)}
+     *      to create a proxy instance instead.
+     *
+     * @see <a href="#membership">Package and Module Membership of Proxy Class</a>
      */
+    @Deprecated
     @CallerSensitive
     public static Class<?> getProxyClass(ClassLoader loader,
                                          Class<?>... interfaces)
         throws IllegalArgumentException
     {
-        final Class<?>[] intfs = interfaces.clone();
+        final List<Class<?>> intfs = List.of(interfaces);  // interfaces cloned
         final SecurityManager sm = System.getSecurityManager();
+        final Class<?> caller = Reflection.getCallerClass();
         if (sm != null) {
-            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
+            checkProxyAccess(caller, loader, intfs);
         }
 
-        return getProxyClass0(loader, intfs);
+        return new ProxyBuilder(loader, intfs).build();
     }
 
     /*
@@ -386,11 +387,11 @@
      * the defining loader of the interface.  If the caller's class loader
      * is not the same as the defining loader of the interface, the VM
      * will throw IllegalAccessError when the generated proxy class is
-     * being defined via the defineClass0 method.
+     * being defined.
      */
     private static void checkProxyAccess(Class<?> caller,
                                          ClassLoader loader,
-                                         Class<?>... interfaces)
+                                         List<Class<?>> interfaces)
     {
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
@@ -398,26 +399,10 @@
             if (VM.isSystemDomainLoader(loader) && !VM.isSystemDomainLoader(ccl)) {
                 sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
             }
-            ReflectUtil.checkProxyPackageAccess(ccl, interfaces);
+            ReflectUtil.checkProxyPackageAccess(ccl, interfaces.toArray(EMPTY_CLASS_ARRAY));
         }
     }
 
-    /**
-     * Generate a proxy class.  Must call the checkProxyAccess method
-     * to perform permission checks before calling this.
-     */
-    private static Class<?> getProxyClass0(ClassLoader loader,
-                                           Class<?>... interfaces) {
-        if (interfaces.length > 65535) {
-            throw new IllegalArgumentException("interface limit exceeded");
-        }
-
-        // If the proxy class defined by the given loader implementing
-        // the given interfaces exists, this will simply return the cached copy;
-        // otherwise, it will create the proxy class via the ProxyClassFactory
-        return proxyClassCache.get(loader, interfaces);
-    }
-
     /*
      * a key used for proxy class with 0 implemented interfaces
      */
@@ -495,11 +480,12 @@
         private final WeakReference<Class<?>>[] refs;
 
         @SuppressWarnings("unchecked")
-        KeyX(Class<?>[] interfaces) {
-            hash = Arrays.hashCode(interfaces);
-            refs = (WeakReference<Class<?>>[])new WeakReference<?>[interfaces.length];
-            for (int i = 0; i < interfaces.length; i++) {
-                refs[i] = new WeakReference<>(interfaces[i]);
+        KeyX(List<Class<?>> interfaces) {
+            hash = Arrays.hashCode(interfaces.toArray());
+            refs = (WeakReference<Class<?>>[])new WeakReference<?>[interfaces.size()];
+            int i = 0;
+            for (Class<?> intf : interfaces) {
+                refs[i++] = new WeakReference<>(intf);
             }
         }
 
@@ -535,14 +521,14 @@
      * A function that maps an array of interfaces to an optimal key where
      * Class objects representing interfaces are weakly referenced.
      */
-    private static final class KeyFactory
-        implements BiFunction<ClassLoader, Class<?>[], Object>
+    private static final class KeyFactory<T>
+        implements BiFunction<T, List<Class<?>>, Object>
     {
         @Override
-        public Object apply(ClassLoader classLoader, Class<?>[] interfaces) {
-            switch (interfaces.length) {
-                case 1: return new Key1(interfaces[0]); // the most frequent
-                case 2: return new Key2(interfaces[0], interfaces[1]);
+        public Object apply(T t, List<Class<?>> interfaces) {
+            switch (interfaces.size()) {
+                case 1: return new Key1(interfaces.get(0)); // the most frequent
+                case 2: return new Key2(interfaces.get(0), interfaces.get(1));
                 case 0: return key0;
                 default: return new KeyX(interfaces);
             }
@@ -550,53 +536,19 @@
     }
 
     /**
-     * A factory function that generates, defines and returns the proxy class given
-     * the ClassLoader and array of interfaces.
+     * A factory function that generates, defines and returns the proxy class
+     * given the ClassLoader and array of interfaces.
      */
-    private static final class ProxyClassFactory
-        implements BiFunction<ClassLoader, Class<?>[], Class<?>>
-    {
+    private static final class ProxyClassFactory {
+        private static final Unsafe UNSAFE = Unsafe.getUnsafe();
+
         // prefix for all proxy class names
         private static final String proxyClassNamePrefix = "$Proxy";
 
         // next number to use for generation of unique proxy class names
         private static final AtomicLong nextUniqueNumber = new AtomicLong();
 
-        @Override
-        public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
-
-            Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
-            for (Class<?> intf : interfaces) {
-                /*
-                 * Verify that the class loader resolves the name of this
-                 * interface to the same Class object.
-                 */
-                Class<?> interfaceClass = null;
-                try {
-                    interfaceClass = Class.forName(intf.getName(), false, loader);
-                } catch (ClassNotFoundException e) {
-                }
-                if (interfaceClass != intf) {
-                    throw new IllegalArgumentException(
-                        intf + " is not visible from class loader");
-                }
-                /*
-                 * Verify that the Class object actually represents an
-                 * interface.
-                 */
-                if (!interfaceClass.isInterface()) {
-                    throw new IllegalArgumentException(
-                        interfaceClass.getName() + " is not an interface");
-                }
-                /*
-                 * Verify that this interface is not a duplicate.
-                 */
-                if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
-                    throw new IllegalArgumentException(
-                        "repeated interface: " + interfaceClass.getName());
-                }
-            }
-
+        private static Class<?> defineProxyClass(Module m, List<Class<?>> interfaces) {
             String proxyPkg = null;     // package to define proxy class in
             int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
 
@@ -608,38 +560,49 @@
             for (Class<?> intf : interfaces) {
                 int flags = intf.getModifiers();
                 if (!Modifier.isPublic(flags)) {
-                    accessFlags = Modifier.FINAL;
-                    String name = intf.getName();
-                    int n = name.lastIndexOf('.');
-                    String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
+                    accessFlags = Modifier.FINAL;  // non-public, final
+                    String pkg = intf.getPackageName();
                     if (proxyPkg == null) {
                         proxyPkg = pkg;
                     } else if (!pkg.equals(proxyPkg)) {
                         throw new IllegalArgumentException(
-                            "non-public interfaces from different packages");
+                                "non-public interfaces from different packages");
                     }
                 }
             }
 
             if (proxyPkg == null) {
-                // if no non-public proxy interfaces, use com.sun.proxy package
-                proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
+                // all proxy interfaces are public
+                proxyPkg = m.isNamed() ? PROXY_PACKAGE_PREFIX + "." + m.getName()
+                                       : PROXY_PACKAGE_PREFIX;
+            } else if (proxyPkg.isEmpty() && m.isNamed()) {
+                throw new IllegalArgumentException(
+                        "Unnamed package cannot be added to " + m);
+            }
+
+            // add the package to the runtime module if not exists
+            if (m.isNamed()) {
+                m.addPackage(proxyPkg);
             }
 
             /*
              * Choose a name for the proxy class to generate.
              */
             long num = nextUniqueNumber.getAndIncrement();
-            String proxyName = proxyPkg + proxyClassNamePrefix + num;
+            String proxyName = proxyPkg.isEmpty() ? proxyClassNamePrefix + num
+                                                  : proxyPkg + "." + proxyClassNamePrefix + num;
+
+            ClassLoader loader = getLoader(m);
+            trace(proxyName, m, loader, interfaces);
 
             /*
              * Generate the specified proxy class.
              */
             byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
-                proxyName, interfaces, accessFlags);
+                    proxyName, interfaces.toArray(EMPTY_CLASS_ARRAY), accessFlags);
             try {
-                return defineClass0(loader, proxyName,
-                                    proxyClassFile, 0, proxyClassFile.length);
+                return UNSAFE.defineClass(proxyName, proxyClassFile, 0, proxyClassFile.length,
+                                          loader, null);
             } catch (ClassFormatError e) {
                 /*
                  * A ClassFormatError here means that (barring bugs in the
@@ -651,16 +614,410 @@
                 throw new IllegalArgumentException(e.toString());
             }
         }
+
+        /**
+         * Test if the given class is a proxy class
+         */
+        static boolean isProxyClass(Class<?> c) {
+            return proxyCache.containsValue(c);
+        }
+
+        /**
+         * Returns the proxy class.  It will return the cached proxy class
+         * if exists; otherwise, it will create the proxy class and store in
+         * the cache.
+         */
+        static Class<?> get(Module module, List<Class<?>> interfaces) {
+            return proxyCache.get(module, interfaces);
+        }
+
+        /**
+         * a cache of proxy classes in the named and unnamed module
+         */
+        private static final WeakCache<Module, List<Class<?>>, Class<?>> proxyCache =
+            new WeakCache<>(new KeyFactory<Module>(),
+                new BiFunction<Module, List<Class<?>>, Class<?>>()  {
+                    @Override
+                    public Class<?> apply(Module m, List<Class<?>> interfaces) {
+                        Objects.requireNonNull(m);
+                        return defineProxyClass(m, interfaces);
+                    }
+            });
+
+
+        private static boolean isExportedType(Class<?> c) {
+            String pn = c.getPackageName();
+            return Modifier.isPublic(c.getModifiers()) && c.getModule().isExported(pn);
+        }
+
+        private static boolean isPackagePrivateType(Class<?> c) {
+            return !Modifier.isPublic(c.getModifiers());
+        }
+
+        private static String toDetails(Class<?> c) {
+            String access = "unknown";
+            if (isExportedType(c)) {
+                access = "exported";
+            } else if (isPackagePrivateType(c)) {
+                access = "package-private";
+            } else {
+                access = "module-private";
+            }
+            ClassLoader ld = c.getClassLoader();
+            return String.format("   %s/%s %s loader %s",
+                    c.getModule().getName(), c.getName(), access, ld);
+        }
+
+        static void trace(String cn, Module module, ClassLoader loader, List<Class<?>> interfaces) {
+            if (isDebug()) {
+                System.out.format("PROXY: %s/%s defined by %s%n", module.getName(), cn, loader);
+            }
+            if (isDebug("debug")) {
+                interfaces.stream()
+                          .forEach(c -> System.out.println(toDetails(c)));
+            }
+        }
+
+        private static final String DEBUG =
+            AccessController.doPrivileged(new PrivilegedAction<>() {
+                public String run() {
+                    return System.getProperty("jdk.proxy.debug", "");
+                }
+            });
+
+        private static final boolean isDebug() {
+            return !DEBUG.isEmpty();
+        }
+        private static final boolean isDebug(String flag) {
+            return DEBUG.equals(flag);
+        }
     }
 
     /**
-     * Returns an instance of a proxy class for the specified interfaces
+     * Builder for a proxy class.
+     *
+     * If the module is not specified in this ProxyBuilder constructor,
+     * it will map from the given loader and interfaces to the module
+     * in which the proxy class will be defined.
+     */
+    private static final class ProxyBuilder {
+        final ClassLoader loader;
+        final List<Class<?>> interfaces;
+        final Module module;
+        ProxyBuilder(ClassLoader loader, List<Class<?>> interfaces) {
+            if (!VM.isModuleSystemInited()) {
+                throw new InternalError("Proxy is not supported until module system is fully initialzed");
+            }
+            if (interfaces.size() > 65535) {
+                throw new IllegalArgumentException("interface limit exceeded");
+            }
+
+            Set<Class<?>> refTypes = referencedTypes(loader, interfaces);
+
+            // IAE if violates any restrictions specified in newProxyInstance
+            validateProxyInterfaces(loader, interfaces, refTypes);
+
+            this.loader = loader;
+            this.interfaces = interfaces;
+            this.module = mapToModule(loader, interfaces, refTypes);
+            assert getLoader(module) == loader;
+        }
+
+        /**
+         * Generate a proxy class.  If the target module does not have any
+         * to any interface types, IllegalAccessError will be thrown by the VM
+         * at defineClass time.
+         *
+         * Must call the checkProxyAccess method to perform permission checks
+         * before calling this.
+         */
+        Class<?> build() {
+            return ProxyClassFactory.get(module, interfaces);
+        }
+
+        /**
+         * Validate the given proxy interfaces and the given referenced types
+         * are visible to the defining loader.
+         *
+         * @throws IllegalArgumentException if it violates the restrictions specified
+         *         in {@link Proxy#newProxyInstance}
+         */
+        static void validateProxyInterfaces(ClassLoader loader,
+                                            List<Class<?>> interfaces,
+                                            Set<Class<?>> refTypes)
+        {
+            Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.size());
+            for (Class<?> intf : interfaces) {
+                /*
+                 * Verify that the class loader resolves the name of this
+                 * interface to the same Class object.
+                 */
+                ensureVisible(loader, intf);
+
+                /*
+                 * Verify that the Class object actually represents an
+                 * interface.
+                 */
+                if (!intf.isInterface()) {
+                    throw new IllegalArgumentException(intf.getName() + " is not an interface");
+                }
+
+                /*
+                 * Verify that this interface is not a duplicate.
+                 */
+                if (interfaceSet.put(intf, Boolean.TRUE) != null) {
+                    throw new IllegalArgumentException("repeated interface: " + intf.getName());
+                }
+            }
+
+            for (Class<?> type : refTypes) {
+                ensureVisible(loader, type);
+            }
+        }
+
+        /*
+         * Returns all types referenced by all public method signatures of
+         * the proxy interfaces
+         */
+        static Set<Class<?>> referencedTypes(ClassLoader loader, List<Class<?>> interfaces) {
+            return interfaces.stream()
+                 .flatMap(intf -> Stream.of(intf.getMethods())
+                                        .flatMap(m -> methodRefTypes(m))
+                                        .map(ProxyBuilder::getElementType)
+                                        .filter(t -> !t.isPrimitive()))
+                 .collect(Collectors.toSet());
+        }
+
+        /*
+         * Extracts all types referenced on a method signature including
+         * its return type, parameter types, and exception types.
+         */
+        static Stream<Class<?>> methodRefTypes(Method m) {
+            return Stream.of(new Class<?>[] { m.getReturnType() },
+                             m.getParameterTypes(),
+                             m.getExceptionTypes())
+                         .flatMap(a -> Stream.of(a));
+        }
+
+        /**
+         * Returns the module that the generated proxy class belongs to.
+         *
+         * If all proxy interfaces are public and in exported packages,
+         * then the proxy class is in unnamed module.
+         *
+         * If any of proxy interface is package-private, then the proxy class
+         * is in the same module of the package-private interface.
+         *
+         * If all proxy interfaces are public and at least one in a non-exported
+         * package, then the proxy class is in a dynamic module in a non-exported
+         * package.  Reads edge and qualified exports are added for
+         * dynamic module to access.
+         */
+        static Module mapToModule(ClassLoader loader, List<Class<?>> interfaces, Set<Class<?>> refTypes) {
+            Map<Class<?>, Module> modulePrivateTypes = new HashMap<>();
+            Map<Class<?>, Module> packagePrivateTypes = new HashMap<>();
+            for (Class<?> intf : interfaces) {
+                Module m = intf.getModule();
+                if (Modifier.isPublic(intf.getModifiers())) {
+                    // module-private types
+                    if (!m.isExported(intf.getPackageName())) {
+                        modulePrivateTypes.put(intf, m);
+                    }
+                } else {
+                    packagePrivateTypes.put(intf, m);
+                }
+            }
+
+            // all proxy interfaces are public and exported, the proxy class is in unnamed module
+            // Such proxy class is accessible to any unnamed module and named module that
+            // can read unnamed module
+            if (packagePrivateTypes.isEmpty() && modulePrivateTypes.isEmpty()) {
+                return loader != null ? loader.getUnnamedModule() : BootLoader.getUnnamedModule();
+            }
+
+            if (packagePrivateTypes.size() > 0) {
+                // all package-private types must be in the same runtime package
+                // i.e. same package name and same module (named or unnamed)
+                //
+                // Configuration will fail if M1 and in M2 defined by the same loader
+                // and both have the same package p (so no need to check class loader)
+                if (packagePrivateTypes.size() > 1 &&
+                        (packagePrivateTypes.keySet().stream()  // more than one package
+                                 .map(Class::getPackageName).distinct().count() > 1 ||
+                         packagePrivateTypes.values().stream()  // or more than one module
+                                 .distinct().count() > 1)) {
+                    throw new IllegalArgumentException(
+                            "non-public interfaces from different packages");
+                }
+
+                // all package-private types are in the same module (named or unnamed)
+                Module target = null;
+                for (Module m : packagePrivateTypes.values()) {
+                    if (getLoader(m) != loader) {
+                        // the specified loader is not the same class loader of the non-public interface
+                        throw new IllegalArgumentException(
+                                "non-public interface is not defined by the given loader");
+                    }
+                    target = m;
+                }
+
+                // validate if the target module can access all other interfaces
+                for (Class<?> intf : interfaces) {
+                    Module m = intf.getModule();
+                    if (m == target) continue;
+
+                    if (!target.canRead(m) || !m.isExported(intf.getPackageName(), target)) {
+                        throw new IllegalArgumentException(target + " can't access " + intf.getName());
+                    }
+                }
+
+                // return the module of the package-private interface
+                return target;
+            }
+
+            // all proxy interfaces are public and at least one in a non-exported package
+            // map to dynamic proxy module and add reads edge and qualified exports, if necessary
+            Module target = getDynamicModule(loader);
+
+            // set up proxy class access to proxy interfaces and superinterfaces
+            Deque<Class<?>> deque = new LinkedList<>(interfaces);
+            Set<Class<?>> visited = new HashSet<>();
+            while (!deque.isEmpty()) {
+                Class<?> c = deque.poll();
+                if (visited.contains(c)) {
+                    continue;
+                }
+                visited.add(c);
+                ensureAccess(target, c);
+
+                // add all superinterfaces
+                for (Class<?> intf : c.getInterfaces()) {
+                    deque.add(intf);
+                }
+            }
+
+            // set up proxy class access to types referenced in the method signature
+            refTypes.stream()
+                    .filter(t -> !visited.contains(t))
+                    .forEach(t -> ensureAccess(target, t));
+            return target;
+        }
+
+        /*
+         * Ensure the given module can access the given class.
+         */
+        static void ensureAccess(Module target, Class<?> c) {
+            Module m = c.getModule();
+            // add read edge and qualified export for the target module to access
+            if (!target.canRead(m)) {
+                Modules.addReads(target, m);
+            }
+            String pn = c.getPackageName();
+            if (!m.isExported(pn, target)) {
+                Modules.addExports(m, pn, target);
+            }
+        }
+
+        /*
+         * Ensure the given class is visible to the class loader.
+         */
+        static void ensureVisible(ClassLoader ld, Class<?> c) {
+            Class<?> type = null;
+            try {
+                type = Class.forName(c.getName(), false, ld);
+            } catch (ClassNotFoundException e) {
+            }
+            if (type != c) {
+                throw new IllegalArgumentException(c.getName() +
+                        " referenced from a method is not visible from class loader");
+            }
+        }
+
+        static Class<?> getElementType(Class<?> type) {
+            Class<?> e = type;
+            while (e.isArray()) {
+                e = e.getComponentType();
+            }
+            return e;
+        }
+
+        private static final WeakHashMap<ClassLoader, Module> dynProxyModules = new WeakHashMap<>();
+        private static final AtomicInteger counter = new AtomicInteger();
+
+        /*
+         * Define a dynamic module for the generated proxy classes in a non-exported package
+         * named com.sun.proxy.$MODULE.
+         *
+         * Each class loader will have one dynamic module.
+         */
+        static Module getDynamicModule(ClassLoader loader) {
+            return dynProxyModules.computeIfAbsent(loader, ld -> {
+                // create a dynamic module and setup module access
+                String mn = "jdk.proxy" + counter.incrementAndGet();
+                String pn = PROXY_PACKAGE_PREFIX + "." + mn;
+                Module m = Modules.defineModule(loader, mn, Collections.singleton(pn));
+                Modules.addReads(m, Proxy.class.getModule());
+                // java.base to create proxy instance
+                Modules.addExports(m, pn, Object.class.getModule());
+                return m;
+            });
+        }
+    }
+
+    /**
+     * Returns a proxy instance for the specified interfaces
      * that dispatches method invocations to the specified invocation
      * handler.
+     * <p>
+     * <a name="restrictions">{@code IllegalArgumentException} will be thrown
+     * if any of the following restrictions is violated:</a>
+     * <ul>
+     * <li>All of {@code Class} objects in the given {@code interfaces} array
+     * must represent interfaces, not classes or primitive types.
      *
-     * <p>{@code Proxy.newProxyInstance} throws
-     * {@code IllegalArgumentException} for the same reasons that
-     * {@code Proxy.getProxyClass} does.
+     * <li>No two elements in the {@code interfaces} array may
+     * refer to identical {@code Class} objects.
+     *
+     * <li>All of the interface types must be visible by name through the
+     * specified class loader. In other words, for class loader
+     * {@code cl} and every interface {@code i}, the following
+     * expression must be true:<p>
+     * {@code Class.forName(i.getName(), false, cl) == i}
+     *
+     * <li>All of the types referenced by all
+     * public method signatures of the specified interfaces
+     * and those inherited by their superinterfaces
+     * must be visible by name through the specified class loader.
+     *
+     * <li>All non-public interfaces must be in the same package
+     * and module, defined by the specified class loader and
+     * the module of the non-public interfaces can access all of
+     * the interface types; otherwise, it would not be possible for
+     * the proxy class to implement all of the interfaces,
+     * regardless of what package it is defined in.
+     *
+     * <li>For any set of member methods of the specified interfaces
+     * that have the same signature:
+     * <ul>
+     * <li>If the return type of any of the methods is a primitive
+     * type or void, then all of the methods must have that same
+     * return type.
+     * <li>Otherwise, one of the methods must have a return type that
+     * is assignable to all of the return types of the rest of the
+     * methods.
+     * </ul>
+     *
+     * <li>The resulting proxy class must not exceed any limits imposed
+     * on classes by the virtual machine.  For example, the VM may limit
+     * the number of interfaces that a class may implement to 65535; in
+     * that case, the size of the {@code interfaces} array must not
+     * exceed 65535.
+     * </ul>
+     *
+     * <p>Note that the order of the specified proxy interfaces is
+     * significant: two requests for a proxy class with the same combination
+     * of interfaces but in a different order will result in two distinct
+     * proxy classes.
      *
      * @param   loader the class loader to define the proxy class
      * @param   interfaces the list of interfaces for the proxy class
@@ -669,9 +1026,8 @@
      * @return  a proxy instance with the specified invocation handler of a
      *          proxy class that is defined by the specified class loader
      *          and that implements the specified interfaces
-     * @throws  IllegalArgumentException if any of the restrictions on the
-     *          parameters that may be passed to {@code getProxyClass}
-     *          are violated
+     * @throws  IllegalArgumentException if any of the <a href="#restrictions">
+     *          restrictions</a> on the parameters are violated
      * @throws  SecurityException if a security manager, <em>s</em>, is present
      *          and any of the following conditions is met:
      *          <ul>
@@ -697,43 +1053,47 @@
      *          argument or any of its elements are {@code null}, or
      *          if the invocation handler, {@code h}, is
      *          {@code null}
+     *
+     * @see <a href="#membership">Package and Module Membership of Proxy Class</a>
      */
     @CallerSensitive
     public static Object newProxyInstance(ClassLoader loader,
                                           Class<?>[] interfaces,
-                                          InvocationHandler h)
-        throws IllegalArgumentException
-    {
+                                          InvocationHandler h) {
         Objects.requireNonNull(h);
 
-        final Class<?>[] intfs = interfaces.clone();
+        final List<Class<?>> intfs = List.of(interfaces);  // interfaces cloned
         final SecurityManager sm = System.getSecurityManager();
+        final Class<?> caller = Reflection.getCallerClass();
         if (sm != null) {
-            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
+            checkProxyAccess(caller, loader, intfs);
         }
 
         /*
          * Look up or generate the designated proxy class.
          */
-        Class<?> cl = getProxyClass0(loader, intfs);
+        Class<?> cl = new ProxyBuilder(loader, intfs).build();
 
+        return newProxyInstance(cl, caller, h);
+    }
+
+    private static Object newProxyInstance(Class<?> proxyClass, Class<?> caller, InvocationHandler h) {
         /*
          * Invoke its constructor with the designated invocation handler.
          */
         try {
+            final SecurityManager sm = System.getSecurityManager();
             if (sm != null) {
-                checkNewProxyPermission(Reflection.getCallerClass(), cl);
+                checkNewProxyPermission(caller, proxyClass);
             }
 
-            final Constructor<?> cons = cl.getConstructor(constructorParams);
-            if (!Modifier.isPublic(cl.getModifiers())) {
-                AccessController.doPrivileged(new PrivilegedAction<>() {
-                    public Void run() {
-                        cons.setAccessible(true);
-                        return null;
-                    }
-                });
-            }
+            final Constructor<?> cons = proxyClass.getConstructor(constructorParams);
+            AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                public Void run() {
+                    cons.setAccessible(true);
+                    return null;
+                }
+            });
             return cons.newInstance(new Object[]{h});
         } catch (IllegalAccessException | InstantiationException | NoSuchMethodException e) {
             throw new InternalError(e.toString(), e);
@@ -770,11 +1130,17 @@
     }
 
     /**
-     * Returns true if and only if the specified class was dynamically
-     * generated to be a proxy class using the {@code getProxyClass}
-     * method or the {@code newProxyInstance} method.
+     * Returns the class loader for the given module.
+     */
+    private static ClassLoader getLoader(Module m) {
+        PrivilegedAction<ClassLoader> pa = m::getClassLoader;
+        return AccessController.doPrivileged(pa);
+    }
+
+    /**
+     * Returns true if the given class is a proxy class.
      *
-     * <p>The reliability of this method is important for the ability
+     * @implNote The reliability of this method is important for the ability
      * to use it to make security decisions, so its implementation should
      * not just test if the class in question extends {@code Proxy}.
      *
@@ -784,7 +1150,7 @@
      * @throws  NullPointerException if {@code cl} is {@code null}
      */
     public static boolean isProxyClass(Class<?> cl) {
-        return Proxy.class.isAssignableFrom(cl) && proxyClassCache.containsValue(cl);
+        return Proxy.class.isAssignableFrom(cl) && ProxyClassFactory.isProxyClass(cl);
     }
 
     /**
@@ -827,6 +1193,6 @@
         return ih;
     }
 
-    private static native Class<?> defineClass0(ClassLoader loader, String name,
-                                                byte[] b, int off, int len);
+    private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
+    private static final String PROXY_PACKAGE_PREFIX = ReflectUtil.PROXY_PACKAGE;
 }
--- a/src/java.base/share/classes/java/lang/reflect/package-info.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/java/lang/reflect/package-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,12 +24,12 @@
  */
 
 /**
- * Provides classes and interfaces for obtaining reflective
- * information about classes and objects.  Reflection allows
- * programmatic access to information about the fields, methods and
- * constructors of loaded classes, and the use of reflected fields,
- * methods, and constructors to operate on their underlying
- * counterparts, within security restrictions.
+ * Provides classes and interfaces for obtaining reflective information about
+ * modules, classes and objects.  Reflection allows programmatic access to
+ * information about modules and to the fields, methods and constructors of
+ * loaded classes, and the use of reflected fields, methods, and constructors
+ * to operate on their underlying counterparts, within encapsulation and
+ * security restrictions.
  *
  * <p>{@code AccessibleObject} allows suppression of access checks if
  * the necessary {@code ReflectPermission} is available.
--- a/src/java.base/share/classes/java/net/URL.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/java/net/URL.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1213,11 +1213,15 @@
         String packagePrefixList = java.security.AccessController.doPrivileged(
                 new PrivilegedAction<>() {
                     public String run() {
-                        return System.getProperty(protocolPathProp, "");
+                        return System.getProperty(protocolPathProp, null);
                     }
                 });
+        if (packagePrefixList == null) {
+            // not set
+            return null;
+        }
+
         String[] packagePrefixes = packagePrefixList.split("\\|");
-
         URLStreamHandler handler = null;
         for (int i=0; handler == null && i<packagePrefixes.length; i++) {
             String packagePrefix = packagePrefixes[i].trim();
@@ -1287,9 +1291,6 @@
     private static ThreadLocal<Object> gate = new ThreadLocal<>();
 
     private static URLStreamHandler lookupViaProviders(final String protocol) {
-        if (!jdk.internal.misc.VM.isBooted())
-            return null;
-
         if (gate.get() != null)
             throw new Error("Circular loading of URL stream handler providers detected");
 
@@ -1359,7 +1360,7 @@
         URLStreamHandlerFactory fac;
         boolean checkedWithFactory = false;
 
-        if (isOverrideable(protocol)) {
+        if (isOverrideable(protocol) && jdk.internal.misc.VM.isBooted()) {
             // Use the factory (if any). Volatile read makes
             // URLStreamHandlerFactory appear fully initialized to current thread.
             fac = factory;
--- a/src/java.base/share/classes/java/net/URLClassLoader.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/java/net/URLClassLoader.java	Thu Mar 17 19:04:16 2016 +0000
@@ -42,7 +42,6 @@
 import java.util.Enumeration;
 import java.util.List;
 import java.util.NoSuchElementException;
-import java.util.Objects;
 import java.util.Set;
 import java.util.WeakHashMap;
 import java.util.jar.Attributes;
@@ -394,7 +393,7 @@
      */
     private Package getAndVerifyPackage(String pkgname,
                                         Manifest man, URL url) {
-        Package pkg = getPackage(pkgname);
+        Package pkg = getDefinedPackage(pkgname);
         if (pkg != null) {
             // Package found, so check package sealing.
             if (pkg.isSealed()) {
@@ -416,29 +415,6 @@
         return pkg;
     }
 
-    // Also called by VM to define Package for classes loaded from the CDS
-    // archive
-    private void definePackageInternal(String pkgname, Manifest man, URL url)
-    {
-        if (getAndVerifyPackage(pkgname, man, url) == null) {
-            try {
-                if (man != null) {
-                    definePackage(pkgname, man, url);
-                } else {
-                    definePackage(pkgname, null, null, null, null, null, null, null);
-                }
-            } catch (IllegalArgumentException iae) {
-                // parallel-capable class loaders: re-verify in case of a
-                // race condition
-                if (getAndVerifyPackage(pkgname, man, url) == null) {
-                    // Should never happen
-                    throw new AssertionError("Cannot find package " +
-                                             pkgname);
-                }
-            }
-        }
-    }
-
     /*
      * Defines a Class using the class bytes obtained from the specified
      * Resource. The resulting Class must be resolved before it can be
@@ -452,7 +428,23 @@
             String pkgname = name.substring(0, i);
             // Check if package already loaded.
             Manifest man = res.getManifest();
-            definePackageInternal(pkgname, man, url);
+            if (getAndVerifyPackage(pkgname, man, url) == null) {
+                try {
+                    if (man != null) {
+                        definePackage(pkgname, man, url);
+                    } else {
+                        definePackage(pkgname, null, null, null, null, null, null, null);
+                    }
+                } catch (IllegalArgumentException iae) {
+                    // parallel-capable class loaders: re-verify in case of a
+                    // race condition
+                    if (getAndVerifyPackage(pkgname, man, url) == null) {
+                        // Should never happen
+                        throw new AssertionError("Cannot find package " +
+                                                 pkgname);
+                    }
+                }
+            }
         }
         // Now read the class bytes and define the class
         java.nio.ByteBuffer bb = res.getByteBuffer();
@@ -574,7 +566,7 @@
                 }
             }, acc);
 
-        return url != null ? ucp.checkURL(url) : null;
+        return url != null ? URLClassPath.checkURL(url) : null;
     }
 
     /**
@@ -609,7 +601,7 @@
                         }, acc);
                     if (u == null)
                         break;
-                    url = ucp.checkURL(u);
+                    url = URLClassPath.checkURL(u);
                 } while (url == null);
                 return url != null;
             }
--- a/src/java.base/share/classes/java/nio/Bits.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/java/nio/Bits.java	Thu Mar 17 19:04:16 2016 +0000
@@ -614,7 +614,7 @@
     // which a process may access.  All sizes are specified in bytes.
     static void reserveMemory(long size, int cap) {
 
-        if (!memoryLimitSet && VM.isBooted()) {
+        if (!memoryLimitSet && VM.initLevel() >= 1) {
             maxMemory = VM.maxDirectMemory();
             memoryLimitSet = true;
         }
--- a/src/java.base/share/classes/java/nio/file/FileSystems.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/java/nio/file/FileSystems.java	Thu Mar 17 19:04:16 2016 +0000
@@ -30,8 +30,11 @@
 import java.io.IOException;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
-import java.util.*;
 import java.lang.reflect.Constructor;
+import java.util.Collections;
+import java.util.Map;
+import java.util.ServiceConfigurationError;
+import java.util.ServiceLoader;
 
 /**
  * Factory methods for file systems. This class defines the {@link #getDefault
@@ -51,8 +54,7 @@
  * installed file system providers. Installed providers are loaded using the
  * service-provider loading facility defined by the {@link ServiceLoader} class.
  * Installed providers are loaded using the system class loader. If the
- * system class loader cannot be found then the extension class loader is used;
- * if there is no extension class loader then the bootstrap class loader is used.
+ * system class loader cannot be found then the platform class loader is used.
  * Providers are typically installed by placing them in a JAR file on the
  * application class path, the JAR file contains a
  * provider-configuration file named {@code java.nio.file.spi.FileSystemProvider}
@@ -82,7 +84,16 @@
  */
 
 public final class FileSystems {
-    private FileSystems() {
+    private FileSystems() { }
+
+    // Built-in file system provider
+    private static final FileSystemProvider builtinFileSystemProvider =
+        sun.nio.fs.DefaultFileSystemProvider.create();
+
+    // built-in file system
+    private static class BuiltinFileSystemHolder {
+        static final FileSystem builtinFileSystem =
+            builtinFileSystemProvider.getFileSystem(URI.create("file:///"));
     }
 
     // lazy initialization of default file system
@@ -105,7 +116,7 @@
 
         // returns default provider
         private static FileSystemProvider getDefaultProvider() {
-            FileSystemProvider provider = sun.nio.fs.DefaultFileSystemProvider.create();
+            FileSystemProvider provider = builtinFileSystemProvider;
 
             // if the property java.nio.file.spi.DefaultFileSystemProvider is
             // set then its value is the name of the default provider (or a list)
@@ -173,7 +184,11 @@
      * @return  the default file system
      */
     public static FileSystem getDefault() {
-        return DefaultFileSystemHolder.defaultFileSystem;
+        if (jdk.internal.misc.VM.isBooted()) {
+            return DefaultFileSystemHolder.defaultFileSystem;
+        } else {
+            return BuiltinFileSystemHolder.builtinFileSystem;
+        }
     }
 
     /**
--- a/src/java.base/share/classes/java/nio/file/Files.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/java/nio/file/Files.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1579,9 +1579,8 @@
      * list of file type detectors. Installed file type detectors are loaded
      * using the service-provider loading facility defined by the {@link ServiceLoader}
      * class. Installed file type detectors are loaded using the system class
-     * loader. If the system class loader cannot be found then the extension class
-     * loader is used; If the extension class loader cannot be found then the
-     * bootstrap class loader is used. File type detectors are typically installed
+     * loader. If the system class loader cannot be found then the platform class
+     * loader is used. File type detectors are typically installed
      * by placing them in a JAR file on the application class path,
      * the JAR file contains a provider-configuration file
      * named {@code java.nio.file.spi.FileTypeDetector} in the resource directory
--- a/src/java.base/share/classes/java/util/ResourceBundle.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/java/util/ResourceBundle.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -45,6 +45,10 @@
 import java.lang.ref.ReferenceQueue;
 import java.lang.ref.SoftReference;
 import java.lang.ref.WeakReference;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Module;
 import java.net.JarURLConnection;
 import java.net.URL;
 import java.net.URLConnection;
@@ -56,11 +60,16 @@
 import java.util.concurrent.ConcurrentMap;
 import java.util.jar.JarEntry;
 import java.util.spi.ResourceBundleControlProvider;
+import java.util.spi.ResourceBundleProvider;
 
+import jdk.internal.misc.JavaUtilResourceBundleAccess;
+import jdk.internal.misc.SharedSecrets;
 import sun.reflect.CallerSensitive;
 import sun.reflect.Reflection;
 import sun.util.locale.BaseLocale;
 import sun.util.locale.LocaleObjectCache;
+import sun.util.locale.provider.ResourceBundleProviderSupport;
+import static sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION;
 
 
 /**
@@ -191,6 +200,56 @@
  * known concrete subclasses {@code ListResourceBundle} and
  * {@code PropertyResourceBundle} are thread-safe.
  *
+ * <h3><a name="bundleprovider">Resource Bundles in Named Modules</a></h3>
+ *
+ * When resource bundles are deployed in named modules, the following
+ * module-specific requirements and restrictions are applied.
+ *
+ * <ul>
+ * <li>Code in a named module that calls {@link #getBundle(String, Locale)}
+ * will locate resource bundles in the caller's module (<em>caller module</em>).</li>
+ * <li>If resource bundles are deployed in named modules separate from
+ * the caller module, those resource bundles need to be loaded from service
+ * providers of {@link ResourceBundleProvider}. The caller module must declare
+ * "{@code uses}" and the service interface name is the concatenation of the
+ * base name of the bundles and the string "{@code Provider}". The
+ * <em>bundle provider modules</em> containing resource bundles must
+ * declare "{@code provides}" with the service interface name and
+ * its implementation class name. For example, if the base name is
+ * "{@code com.example.app.MyResources}", the caller module must declare
+ * "{@code uses com.example.app.MyResourcesProvider;}" and a module containing resource
+ * bundles must declare "{@code provides com.example.app.MyResourcesProvider
+ * with com.example.app.internal.MyResourcesProviderImpl;}"
+ * where {@code com.example.app.internal.MyResourcesProviderImpl} is an
+ * implementation class of {@code com.example.app.MyResourcesProvider}.</li>
+ * <li>If you want to use non-standard formats in named modules, such as XML,
+ * {@link ResourceBundleProvider} needs to be used.</li>
+ * <li>The {@code getBundle} method with a {@code ClassLoader} may not be able to
+ * find resource bundles using the given {@code ClassLoader} in named modules.
+ * The {@code getBundle} method with a {@code Module} can be used, instead.</li>
+ * <li>{@code ResourceBundle.Control} is <em>not</em> supported in named modules.
+ * If the {@code getBundle} method with a {@code ResourceBundle.Control} is called
+ * in a named module, the method will throw an {@code UnsupportedOperationException}.
+ * Any service providers of {@link ResourceBundleControlProvider} are ignored in
+ * named modules.
+ * </li>
+ * </ul>
+ *
+ * <h3><a name="RBP_support">ResourceBundleProvider Service Providers</a></h3>
+ *
+ * The {@code getBundle} factory methods load service providers of
+ * {@link ResourceBundleProvider}, if available, using {@link ServiceLoader}.
+ * The service type is designated by {@code basename+"Provider"}. For
+ * example, if the base name is "{@code com.example.app.MyResources}", the service
+ * type is {@code com.example.app.MyResourcesProvider}.
+ * <p>
+ * In named modules, the loaded service providers for the given base name are
+ * used to load resource bundles. If no service provider is available, or if
+ * none of the service providers returns a resource bundle and the caller module
+ * doesn't have its own service provider, the {@code getBundle} factory method
+ * searches for resource bundles local to the caller module. The resource bundle
+ * formats for local module searching are "java.class" and "java.properties".
+ *
  * <h3>ResourceBundle.Control</h3>
  *
  * The {@link ResourceBundle.Control} class provides information necessary
@@ -282,6 +341,7 @@
  * @see ListResourceBundle
  * @see PropertyResourceBundle
  * @see MissingResourceException
+ * @see ResourceBundleProvider
  * @since 1.1
  */
 public abstract class ResourceBundle {
@@ -289,6 +349,32 @@
     /** initial size of the bundle cache */
     private static final int INITIAL_CACHE_SIZE = 32;
 
+    static {
+        SharedSecrets.setJavaUtilResourceBundleAccess(
+            new JavaUtilResourceBundleAccess() {
+                @Override
+                public void setParent(ResourceBundle bundle,
+                                      ResourceBundle parent) {
+                    bundle.setParent(parent);
+                }
+
+                @Override
+                public ResourceBundle getParent(ResourceBundle bundle) {
+                    return bundle.parent;
+                }
+
+                @Override
+                public void setLocale(ResourceBundle bundle, Locale locale) {
+                    bundle.locale = locale;
+                }
+
+                @Override
+                public void setName(ResourceBundle bundle, String name) {
+                    bundle.name = name;
+                }
+            });
+    }
+
     /** constant indicating that no resource bundle exists */
     private static final ResourceBundle NONEXISTENT_BUNDLE = new ResourceBundle() {
             public Enumeration<String> getKeys() { return null; }
@@ -484,6 +570,11 @@
         return cl;
     }
 
+    private static ClassLoader getLoader(Module module) {
+        PrivilegedAction<ClassLoader> pa = module::getClassLoader;
+        return AccessController.doPrivileged(pa);
+    }
+
     /**
      * A wrapper of ClassLoader.getSystemClassLoader().
      */
@@ -494,23 +585,24 @@
                             return new RBClassLoader();
                         }
                     });
-        private static final ClassLoader loader = ClassLoader.getSystemClassLoader();
-
         private RBClassLoader() {
         }
         public Class<?> loadClass(String name) throws ClassNotFoundException {
+            ClassLoader loader = ClassLoader.getSystemClassLoader();
             if (loader != null) {
                 return loader.loadClass(name);
             }
             return Class.forName(name);
         }
         public URL getResource(String name) {
+            ClassLoader loader = ClassLoader.getSystemClassLoader();
             if (loader != null) {
                 return loader.getResource(name);
             }
             return ClassLoader.getSystemResource(name);
         }
         public InputStream getResourceAsStream(String name) {
+            ClassLoader loader = ClassLoader.getSystemClassLoader();
             if (loader != null) {
                 return loader.getResourceAsStream(name);
             }
@@ -532,16 +624,18 @@
 
     /**
      * Key used for cached resource bundles.  The key checks the base
-     * name, the locale, and the class loader to determine if the
-     * resource is a match to the requested one. The loader may be
-     * null, but the base name and the locale must have a non-null
-     * value.
+     * name, the locale, the class loader, and the caller module
+     * to determine if the resource is a match to the requested one.
+     * The loader may be null, but the base name, the locale and
+     * module must have a non-null value.
      */
     private static class CacheKey implements Cloneable {
-        // These three are the actual keys for lookup in Map.
+        // These four are the actual keys for lookup in Map.
         private String name;
         private Locale locale;
-        private LoaderReference loaderRef;
+        private KeyElementReference<ClassLoader> loaderRef;
+        private KeyElementReference<Module> moduleRef;
+
 
         // bundle format which is necessary for calling
         // Control.needsReload().
@@ -564,14 +658,24 @@
         // of this instance.
         private int hashCodeCache;
 
-        CacheKey(String baseName, Locale locale, ClassLoader loader) {
+        // ResourceBundleProviders for loading ResourceBundles
+        private ServiceLoader<ResourceBundleProvider> providers;
+
+        // Boolean.TRUE if the factory method caller provides a ResourceBundleProvier.
+        private Boolean callerHasProvider;
+
+        CacheKey(String baseName, Locale locale, ClassLoader loader, Module module) {
+            Objects.requireNonNull(module);
+
             this.name = baseName;
             this.locale = locale;
             if (loader == null) {
                 this.loaderRef = null;
             } else {
-                loaderRef = new LoaderReference(loader, referenceQueue, this);
+                this.loaderRef = new KeyElementReference<>(loader, referenceQueue, this);
             }
+            this.moduleRef = new KeyElementReference<>(module, referenceQueue, this);
+            this.providers = getServiceLoader(module, baseName);
             calculateHashCode();
         }
 
@@ -603,6 +707,23 @@
             return (loaderRef != null) ? loaderRef.get() : null;
         }
 
+        Module getModule() {
+            return moduleRef.get();
+        }
+
+        ServiceLoader<ResourceBundleProvider> getProviders() {
+            return providers;
+        }
+
+        boolean hasProviders() {
+            return providers != null;
+        }
+
+        boolean callerHasProvider() {
+            return callerHasProvider == Boolean.TRUE;
+        }
+
+        @Override
         public boolean equals(Object other) {
             if (this == other) {
                 return true;
@@ -625,18 +746,22 @@
                 if (loaderRef == null) {
                     return otherEntry.loaderRef == null;
                 }
-                ClassLoader loader = loaderRef.get();
+                ClassLoader loader = getLoader();
+                Module module = getModule();
                 return (otherEntry.loaderRef != null)
                         // with a null reference we can no longer find
-                        // out which class loader was referenced; so
+                        // out which class loader or module was referenced; so
                         // treat it as unequal
                         && (loader != null)
-                        && (loader == otherEntry.loaderRef.get());
-            } catch (    NullPointerException | ClassCastException e) {
+                        && (loader == otherEntry.getLoader())
+                        && (module != null)
+                        && (module.equals(otherEntry.getModule()));
+            } catch (NullPointerException | ClassCastException e) {
             }
             return false;
         }
 
+        @Override
         public int hashCode() {
             return hashCodeCache;
         }
@@ -648,17 +773,28 @@
             if (loader != null) {
                 hashCodeCache ^= loader.hashCode();
             }
+            Module module = getModule();
+            if (module != null) {
+                hashCodeCache ^= module.hashCode();
+            }
         }
 
+        @Override
         public Object clone() {
             try {
                 CacheKey clone = (CacheKey) super.clone();
                 if (loaderRef != null) {
-                    clone.loaderRef = new LoaderReference(loaderRef.get(),
-                                                          referenceQueue, clone);
+                    clone.loaderRef = new KeyElementReference<>(getLoader(),
+                                                                referenceQueue, clone);
                 }
+                clone.moduleRef = new KeyElementReference<>(getModule(),
+                                                            referenceQueue, clone);
+                // Clear the reference to ResourceBundleProviders
+                clone.providers = null;
                 // Clear the reference to a Throwable
                 clone.cause = null;
+                // Clear callerHasProvider
+                clone.callerHasProvider = null;
                 return clone;
             } catch (CloneNotSupportedException e) {
                 //this should never happen
@@ -690,6 +826,7 @@
             return cause;
         }
 
+        @Override
         public String toString() {
             String l = locale.toString();
             if (l.length() == 0) {
@@ -713,19 +850,19 @@
     }
 
     /**
-     * References to class loaders are weak references, so that they can be
-     * garbage collected when nobody else is using them. The ResourceBundle
-     * class has no reason to keep class loaders alive.
+     * References to a CacheKey element as a WeakReference so that it can be
+     * garbage collected when nobody else is using it.
      */
-    private static class LoaderReference extends WeakReference<ClassLoader>
-                                         implements CacheKeyReference {
-        private CacheKey cacheKey;
+    private static class KeyElementReference<T> extends WeakReference<T>
+                                                implements CacheKeyReference {
+        private final CacheKey cacheKey;
 
-        LoaderReference(ClassLoader referent, ReferenceQueue<Object> q, CacheKey key) {
+        KeyElementReference(T referent, ReferenceQueue<Object> q, CacheKey key) {
             super(referent, q);
             cacheKey = key;
         }
 
+        @Override
         public CacheKey getCacheKey() {
             return cacheKey;
         }
@@ -737,13 +874,14 @@
      */
     private static class BundleReference extends SoftReference<ResourceBundle>
                                          implements CacheKeyReference {
-        private CacheKey cacheKey;
+        private final CacheKey cacheKey;
 
         BundleReference(ResourceBundle referent, ReferenceQueue<Object> q, CacheKey key) {
             super(referent, q);
             cacheKey = key;
         }
 
+        @Override
         public CacheKey getCacheKey() {
             return cacheKey;
         }
@@ -770,9 +908,9 @@
     @CallerSensitive
     public static final ResourceBundle getBundle(String baseName)
     {
+        Class<?> caller = Reflection.getCallerClass();
         return getBundleImpl(baseName, Locale.getDefault(),
-                             getLoader(Reflection.getCallerClass()),
-                             getDefaultControl(baseName));
+                             caller, getDefaultControl(caller, baseName));
     }
 
     /**
@@ -795,26 +933,28 @@
      * @param control
      *        the control which gives information for the resource bundle
      *        loading process
-     * @return a resource bundle for the given base name and the default
-     *        locale
-     * @exception NullPointerException
-     *        if <code>baseName</code> or <code>control</code> is
-     *        <code>null</code>
-     * @exception MissingResourceException
-     *        if no resource bundle for the specified base name can be found
-     * @exception IllegalArgumentException
-     *        if the given <code>control</code> doesn't perform properly
-     *        (e.g., <code>control.getCandidateLocales</code> returns null.)
-     *        Note that validation of <code>control</code> is performed as
-     *        needed.
+     * @return a resource bundle for the given base name and the default locale
+     * @throws NullPointerException
+     *         if <code>baseName</code> or <code>control</code> is
+     *         <code>null</code>
+     * @throws MissingResourceException
+     *         if no resource bundle for the specified base name can be found
+     * @throws IllegalArgumentException
+     *         if the given <code>control</code> doesn't perform properly
+     *         (e.g., <code>control.getCandidateLocales</code> returns null.)
+     *         Note that validation of <code>control</code> is performed as
+     *         needed.
+     * @throws UnsupportedOperationException
+     *         if this method is called in a named module
      * @since 1.6
      */
     @CallerSensitive
     public static final ResourceBundle getBundle(String baseName,
                                                  Control control) {
-        return getBundleImpl(baseName, Locale.getDefault(),
-                             getLoader(Reflection.getCallerClass()),
-                             control);
+        Class<?> caller = Reflection.getCallerClass();
+        Locale targetLocale = Locale.getDefault();
+        checkNamedModule(caller);
+        return getBundleImpl(baseName, targetLocale, caller, control);
     }
 
     /**
@@ -842,9 +982,78 @@
     public static final ResourceBundle getBundle(String baseName,
                                                  Locale locale)
     {
+        Class<?> caller = Reflection.getCallerClass();
         return getBundleImpl(baseName, locale,
-                             getLoader(Reflection.getCallerClass()),
-                             getDefaultControl(baseName));
+                             caller, getDefaultControl(caller, baseName));
+    }
+
+    /**
+     * Gets a resource bundle using the specified base name and the default locale
+     * on behalf of the specified module. This method is equivalent to calling
+     * <blockquote>
+     * <code>getBundle(baseName, Locale.getDefault(), module)</code>
+     * </blockquote>
+     *
+     * @param baseName the base name of the resource bundle,
+     *                 a fully qualified class name
+     * @param module   the module for which the resource bundle is searched
+     * @throws NullPointerException
+     *         if {@code baseName} or {@code module} is {@code null}
+     * @throws SecurityException
+     *         if a security manager exists and the caller is not the specified
+     *         module and doesn't have {@code RuntimePermission("getClassLoader")}
+     * @throws MissingResourceException
+     *         if no resource bundle for the specified base name can be found in the
+     *         specified module
+     * @return a resource bundle for the given base name and the default locale
+     * @since 9
+     * @see ResourceBundleProvider
+     */
+    @CallerSensitive
+    public static ResourceBundle getBundle(String baseName, Module module) {
+        return getBundleFromModule(Reflection.getCallerClass(), module, baseName,
+                                   Locale.getDefault(), Control.INSTANCE);
+    }
+
+    /**
+     * Gets a resource bundle using the specified base name and locale
+     * on behalf of the specified module.
+     *
+     * <p>
+     * If the given {@code module} is a named module, this method will
+     * load the service providers for {@link java.util.spi.ResourceBundleProvider}
+     * and also resource bundles local in the given module (refer to the
+     * <a href="#bundleprovider">Resource Bundles in Named Modules</a> section
+     * for details).
+     *
+     * <p>
+     * If the given {@code module} is an unnamed module, then this method is
+     * equivalent to calling {@link #getBundle(String, Locale, ClassLoader)
+     * getBundle(baseName, targetLocale, module.getClassLoader()} to load
+     * resource bundles that are in unnamed modules visible to the
+     * class loader of the given unnamed module.  It will not find resource
+     * bundles from named modules.
+     *
+     * @param baseName the base name of the resource bundle,
+     *                 a fully qualified class name
+     * @param targetLocale the locale for which a resource bundle is desired
+     * @param module   the module for which the resource bundle is searched
+     * @throws NullPointerException
+     *         if {@code baseName}, {@code targetLocale}, or {@code module} is
+     *         {@code null}
+     * @throws SecurityException
+     *         if a security manager exists and the caller is not the specified
+     *         module and doesn't have {@code RuntimePermission("getClassLoader")}
+     * @throws MissingResourceException
+     *         if no resource bundle for the specified base name and locale can
+     *         be found in the specified {@code module}
+     * @return a resource bundle for the given base name and locale in the module
+     * @since 9
+     */
+    @CallerSensitive
+    public static ResourceBundle getBundle(String baseName, Locale targetLocale, Module module) {
+        return getBundleFromModule(Reflection.getCallerClass(), module, baseName, targetLocale,
+                                   Control.INSTANCE);
     }
 
     /**
@@ -870,26 +1079,28 @@
      *        the control which gives information for the resource
      *        bundle loading process
      * @return a resource bundle for the given base name and a
-     *        <code>Locale</code> in <code>locales</code>
-     * @exception NullPointerException
-     *        if <code>baseName</code>, <code>locales</code> or
-     *        <code>control</code> is <code>null</code>
-     * @exception MissingResourceException
-     *        if no resource bundle for the specified base name in any
-     *        of the <code>locales</code> can be found.
-     * @exception IllegalArgumentException
-     *        if the given <code>control</code> doesn't perform properly
-     *        (e.g., <code>control.getCandidateLocales</code> returns null.)
-     *        Note that validation of <code>control</code> is performed as
-     *        needed.
+     *         <code>Locale</code> in <code>locales</code>
+     * @throws NullPointerException
+     *         if <code>baseName</code>, <code>locales</code> or
+     *         <code>control</code> is <code>null</code>
+     * @throws MissingResourceException
+     *         if no resource bundle for the specified base name in any
+     *         of the <code>locales</code> can be found.
+     * @throws IllegalArgumentException
+     *         if the given <code>control</code> doesn't perform properly
+     *         (e.g., <code>control.getCandidateLocales</code> returns null.)
+     *         Note that validation of <code>control</code> is performed as
+     *         needed.
+     * @throws UnsupportedOperationException
+     *         if this method is called in a named module
      * @since 1.6
      */
     @CallerSensitive
     public static final ResourceBundle getBundle(String baseName, Locale targetLocale,
                                                  Control control) {
-        return getBundleImpl(baseName, targetLocale,
-                             getLoader(Reflection.getCallerClass()),
-                             control);
+        Class<?> caller = Reflection.getCallerClass();
+        checkNamedModule(caller);
+        return getBundleImpl(baseName, targetLocale, caller, control);
     }
 
     /**
@@ -906,6 +1117,16 @@
      * <p><a name="default_behavior">The following describes the default
      * behavior</a>.
      *
+     * <p>
+     * Resource bundles in a named module are private to that module.  If
+     * the caller is in a named module, this method will find resource bundles
+     * from the service providers of {@link java.util.spi.ResourceBundleProvider}
+     * and also find resource bundles private to the caller's module.
+     * If the caller is in a named module and the given {@code loader} is
+     * different than the caller's class loader, or if the caller is not in
+     * a named module, this method will not find resource bundles from named
+     * modules.
+     *
      * <p><code>getBundle</code> uses the base name, the specified locale, and
      * the default locale (obtained from {@link java.util.Locale#getDefault()
      * Locale.getDefault}) to generate a sequence of <a
@@ -1063,6 +1284,13 @@
      * hidden by the MyResources_fr_CH.class. Likewise, MyResources.properties
      * is also hidden by MyResources.class.
      *
+     * @apiNote If the caller module is a named module and the given
+     * {@code loader} is the caller module's class loader, this method is
+     * equivalent to {@code getBundle(baseName, locale)}; otherwise, it will not
+     * find resource bundles from named modules.
+     * Use {@link #getBundle(String, Locale, Module)} to load resource bundles
+     * on behalf on a specific module instead.
+     *
      * @param baseName the base name of the resource bundle, a fully qualified class name
      * @param locale the locale for which a resource bundle is desired
      * @param loader the class loader from which to load the resource bundle
@@ -1073,13 +1301,15 @@
      *        if no resource bundle for the specified base name can be found
      * @since 1.2
      */
+    @CallerSensitive
     public static ResourceBundle getBundle(String baseName, Locale locale,
                                            ClassLoader loader)
     {
         if (loader == null) {
             throw new NullPointerException();
         }
-        return getBundleImpl(baseName, locale, loader, getDefaultControl(baseName));
+        Class<?> caller = Reflection.getCallerClass();
+        return getBundleImpl(baseName, locale, caller, loader, getDefaultControl(caller, baseName));
     }
 
     /**
@@ -1278,29 +1508,34 @@
      *        the control which gives information for the resource
      *        bundle loading process
      * @return a resource bundle for the given base name and locale
-     * @exception NullPointerException
-     *        if <code>baseName</code>, <code>targetLocale</code>,
-     *        <code>loader</code>, or <code>control</code> is
-     *        <code>null</code>
-     * @exception MissingResourceException
-     *        if no resource bundle for the specified base name can be found
-     * @exception IllegalArgumentException
-     *        if the given <code>control</code> doesn't perform properly
-     *        (e.g., <code>control.getCandidateLocales</code> returns null.)
-     *        Note that validation of <code>control</code> is performed as
-     *        needed.
+     * @throws NullPointerException
+     *         if <code>baseName</code>, <code>targetLocale</code>,
+     *         <code>loader</code>, or <code>control</code> is
+     *         <code>null</code>
+     * @throws MissingResourceException
+     *         if no resource bundle for the specified base name can be found
+     * @throws IllegalArgumentException
+     *         if the given <code>control</code> doesn't perform properly
+     *         (e.g., <code>control.getCandidateLocales</code> returns null.)
+     *         Note that validation of <code>control</code> is performed as
+     *         needed.
+     * @throws UnsupportedOperationException
+     *         if this method is called in a named module
      * @since 1.6
      */
+    @CallerSensitive
     public static ResourceBundle getBundle(String baseName, Locale targetLocale,
                                            ClassLoader loader, Control control) {
         if (loader == null || control == null) {
             throw new NullPointerException();
         }
-        return getBundleImpl(baseName, targetLocale, loader, control);
+        Class<?> caller = Reflection.getCallerClass();
+        checkNamedModule(caller);
+        return getBundleImpl(baseName, targetLocale, caller, loader, control);
     }
 
-    private static Control getDefaultControl(String baseName) {
-        if (providers != null) {
+    private static Control getDefaultControl(Class<?> caller, String baseName) {
+        if (providers != null && !caller.getModule().isNamed()) {
             for (ResourceBundleControlProvider provider : providers) {
                 Control control = provider.getControl(baseName);
                 if (control != null) {
@@ -1311,17 +1546,80 @@
         return Control.INSTANCE;
     }
 
-    private static ResourceBundle getBundleImpl(String baseName, Locale locale,
-                                                ClassLoader loader, Control control) {
+    private static void checkNamedModule(Class<?> caller) {
+        if (caller.getModule().isNamed()) {
+            throw new UnsupportedOperationException(
+                    "ResourceBundle.Control not supported in named modules");
+        }
+    }
+
+    private static ResourceBundle getBundleImpl(String baseName,
+                                                Locale locale,
+                                                Class<?> caller,
+                                                Control control) {
+        return getBundleImpl(baseName, locale, caller, getLoader(caller), control);
+    }
+
+    /**
+     * This method will find resource bundles using the legacy mechanism
+     * if the caller is unnamed module or the given class loader is
+     * not the class loader of the caller module getting the resource
+     * bundle, i.e. find the class that is visible to the class loader
+     * and properties from unnamed module.
+     *
+     * The module-aware resource bundle lookup mechanism will load
+     * the service providers using the service loader mechanism
+     * as well as properties local in the caller module.
+     */
+    private static ResourceBundle getBundleImpl(String baseName,
+                                                Locale locale,
+                                                Class<?> caller,
+                                                ClassLoader loader,
+                                                Control control) {
+        if (caller != null && caller.getModule().isNamed()) {
+            Module module = caller.getModule();
+            ClassLoader ml = getLoader(module);
+            // get resource bundles for a named module only
+            // if loader is the module's class loader
+            if (loader == ml || (ml == null && loader == RBClassLoader.INSTANCE)) {
+                return getBundleImpl(baseName, locale, loader, module, control);
+            }
+        }
+        // find resource bundles from unnamed module
+        Module module = loader != null ? loader.getUnnamedModule()
+                                       : ClassLoader.getSystemClassLoader().getUnnamedModule();
+        return getBundleImpl(baseName, locale, loader, module, control);
+    }
+
+    private static ResourceBundle getBundleFromModule(Class<?> caller,
+                                                      Module module,
+                                                      String baseName,
+                                                      Locale locale,
+                                                      Control control) {
+        Objects.requireNonNull(module);
+        if (caller.getModule() != module) {
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                sm.checkPermission(GET_CLASSLOADER_PERMISSION);
+            }
+        }
+        return getBundleImpl(baseName, locale, getLoader(module), module, control);
+    }
+
+    private static ResourceBundle getBundleImpl(String baseName,
+                                                Locale locale,
+                                                ClassLoader loader,
+                                                Module module,
+                                                Control control) {
         if (locale == null || control == null) {
             throw new NullPointerException();
         }
 
-        // We create a CacheKey here for use by this call. The base
-        // name and loader will never change during the bundle loading
+        // We create a CacheKey here for use by this call. The base name
+        // loader, and module will never change during the bundle loading
         // process. We have to make sure that the locale is set before
         // using it as a cache key.
-        CacheKey cacheKey = new CacheKey(baseName, locale, loader);
+        CacheKey cacheKey = new CacheKey(baseName, locale, loader, module);
         ResourceBundle bundle = null;
 
         // Quick lookup of the cache.
@@ -1358,7 +1656,7 @@
                 throw new IllegalArgumentException("Invalid Control: getCandidateLocales");
             }
 
-            bundle = findBundle(cacheKey, candidateLocales, formats, 0, control, baseBundle);
+            bundle = findBundle(cacheKey, module, candidateLocales, formats, 0, control, baseBundle);
 
             // If the loaded bundle is the base bundle and exactly for the
             // requested locale or the only candidate locale, then take the
@@ -1408,6 +1706,7 @@
     }
 
     private static ResourceBundle findBundle(CacheKey cacheKey,
+                                             Module module,
                                              List<Locale> candidateLocales,
                                              List<String> formats,
                                              int index,
@@ -1416,7 +1715,7 @@
         Locale targetLocale = candidateLocales.get(index);
         ResourceBundle parent = null;
         if (index != candidateLocales.size() - 1) {
-            parent = findBundle(cacheKey, candidateLocales, formats, index + 1,
+            parent = findBundle(cacheKey, module, candidateLocales, formats, index + 1,
                                 control, baseBundle);
         } else if (baseBundle != null && Locale.ROOT.equals(targetLocale)) {
             return baseBundle;
@@ -1462,7 +1761,11 @@
             CacheKey constKey = (CacheKey) cacheKey.clone();
 
             try {
-                bundle = loadBundle(cacheKey, formats, control, expiredBundle);
+                if (module.isNamed()) {
+                    bundle = loadBundle(cacheKey, formats, control, module);
+                } else {
+                    bundle = loadBundle(cacheKey, formats, control, expiredBundle);
+                }
                 if (bundle != null) {
                     if (bundle.parent == null) {
                         bundle.setParent(parent);
@@ -1484,6 +1787,146 @@
         return parent;
     }
 
+    private static final String UNKNOWN_FORMAT = "";
+
+    /*
+     * Loads a ResourceBundle in named modules
+     */
+    private static ResourceBundle loadBundle(CacheKey cacheKey,
+                                             List<String> formats,
+                                             Control control,
+                                             Module module) {
+        String baseName = cacheKey.getName();
+        Locale targetLocale = cacheKey.getLocale();
+
+        ResourceBundle bundle = null;
+        if (cacheKey.hasProviders()) {
+            bundle = loadBundleFromProviders(baseName, targetLocale,
+                                             cacheKey.getProviders(), cacheKey);
+            if (bundle != null) {
+                cacheKey.setFormat(UNKNOWN_FORMAT);
+            }
+        }
+        // If none of providers returned a bundle and the caller has no provider,
+        // look up module-local bundles.
+        if (bundle == null && !cacheKey.callerHasProvider()) {
+            String bundleName = control.toBundleName(baseName, targetLocale);
+            for (String format : formats) {
+                try {
+                    switch (format) {
+                    case "java.class":
+                        PrivilegedAction<ResourceBundle> pa = ()
+                                -> ResourceBundleProviderSupport
+                                    .loadResourceBundle(module, bundleName);
+                        bundle = AccessController.doPrivileged(pa, null, GET_CLASSLOADER_PERMISSION);
+                        break;
+                    case "java.properties":
+                        bundle = ResourceBundleProviderSupport.loadPropertyResourceBundle(module, bundleName);
+                        break;
+                    default:
+                        throw new InternalError("unexpected format: " + format);
+                    }
+
+                    if (bundle != null) {
+                        cacheKey.setFormat(format);
+                        break;
+                    }
+                } catch (Exception e) {
+                    cacheKey.setCause(e);
+                }
+            }
+        }
+        return bundle;
+    }
+
+    private static ServiceLoader<ResourceBundleProvider> getServiceLoader(Module module,
+                                                                          String baseName) {
+        PrivilegedAction<ClassLoader> pa = module::getClassLoader;
+        ClassLoader loader = AccessController.doPrivileged(pa);
+        return getServiceLoader(module, loader, baseName);
+    }
+
+        /**
+         * Returns a ServiceLoader that will find providers that are bound to
+         * a given module that may be named or unnamed.
+         */
+    private static ServiceLoader<ResourceBundleProvider> getServiceLoader(Module module,
+                                                                          ClassLoader loader,
+                                                                          String baseName)
+    {
+        // Look up <baseName> + "Provider"
+        String providerName = baseName + "Provider";
+        // Use the class loader of the getBundle caller so that the caller's
+        // visibility of the provider type is checked.
+        Class<ResourceBundleProvider> service = AccessController.doPrivileged(
+            new PrivilegedAction<>() {
+                @Override
+                public Class<ResourceBundleProvider> run() {
+                    try {
+                        Class<?> c = Class.forName(providerName, false, loader);
+                        if (ResourceBundleProvider.class.isAssignableFrom(c)) {
+                            @SuppressWarnings("unchecked")
+                            Class<ResourceBundleProvider> s = (Class<ResourceBundleProvider>) c;
+                            return s;
+                        }
+                    } catch (ClassNotFoundException e) {}
+                    return null;
+                }
+            });
+
+        if (service != null && Reflection.verifyModuleAccess(module, service)) {
+            try {
+                return ServiceLoader.load(service, loader, module);
+            } catch (ServiceConfigurationError e) {
+                // "uses" not declared: load bundle local in the module
+                return null;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Loads ResourceBundle from service providers.
+     */
+    private static ResourceBundle loadBundleFromProviders(String baseName,
+                                                          Locale locale,
+                                                          ServiceLoader<ResourceBundleProvider> providers,
+                                                          CacheKey cacheKey)
+    {
+        if (providers == null) return null;
+
+        return AccessController.doPrivileged(
+                new PrivilegedAction<>() {
+                    public ResourceBundle run() {
+                        for (Iterator<ResourceBundleProvider> itr = providers.iterator(); itr.hasNext(); ) {
+                            try {
+                                ResourceBundleProvider provider = itr.next();
+                                if (cacheKey != null && cacheKey.callerHasProvider == null
+                                        && cacheKey.getModule() == provider.getClass().getModule()) {
+                                    cacheKey.callerHasProvider = Boolean.TRUE;
+                                }
+                                ResourceBundle bundle = provider.getBundle(baseName, locale);
+                                if (bundle != null) {
+                                    return bundle;
+                                }
+                            } catch (ServiceConfigurationError | SecurityException e) {
+                                if (cacheKey != null) {
+                                    cacheKey.setCause(e);
+                                }
+                            }
+                        }
+                        if (cacheKey != null && cacheKey.callerHasProvider == null) {
+                            cacheKey.callerHasProvider = Boolean.FALSE;
+                        }
+                        return null;
+                    }
+                });
+
+    }
+
+    /*
+     * Legacy mechanism to load resource bundles
+     */
     private static ResourceBundle loadBundle(CacheKey cacheKey,
                                              List<String> formats,
                                              Control control,
@@ -1496,6 +1939,7 @@
         ResourceBundle bundle = null;
         for (String format : formats) {
             try {
+                // ResourceBundle.Control.newBundle may be overridden
                 bundle = control.newBundle(cacheKey.getName(), targetLocale, format,
                                            cacheKey.getLoader(), reload);
             } catch (LinkageError | Exception error) {
@@ -1732,35 +2176,54 @@
 
     /**
      * Removes all resource bundles from the cache that have been loaded
-     * using the caller's class loader.
+     * by the caller's module using the caller's class loader.
      *
      * @since 1.6
      * @see ResourceBundle.Control#getTimeToLive(String,Locale)
      */
     @CallerSensitive
     public static final void clearCache() {
-        clearCache(getLoader(Reflection.getCallerClass()));
+        Class<?> caller = Reflection.getCallerClass();
+        clearCache(getLoader(caller), caller.getModule());
     }
 
     /**
      * Removes all resource bundles from the cache that have been loaded
-     * using the given class loader.
+     * by the caller's module using the given class loader.
      *
      * @param loader the class loader
      * @exception NullPointerException if <code>loader</code> is null
      * @since 1.6
      * @see ResourceBundle.Control#getTimeToLive(String,Locale)
      */
+    @CallerSensitive
     public static final void clearCache(ClassLoader loader) {
-        if (loader == null) {
-            throw new NullPointerException();
-        }
+        Objects.requireNonNull(loader);
+        clearCache(loader, Reflection.getCallerClass().getModule());
+    }
+
+    /**
+     * Removes all resource bundles from the cache that have been loaded by the
+     * given {@code module}.
+     *
+     * @param module the module
+     * @throws NullPointerException
+     *         if {@code module} is {@code null}
+     * @throws SecurityException
+     *         if the caller doesn't have the permission to
+     *         {@linkplain Module#getClassLoader() get the class loader}
+     *         of the given {@code module}
+     * @since 9
+     * @see ResourceBundle.Control#getTimeToLive(String,Locale)
+     */
+    public static final void clearCache(Module module) {
+        clearCache(module.getClassLoader(), module);
+    }
+
+    private static void clearCache(ClassLoader loader, Module module) {
         Set<CacheKey> set = cacheList.keySet();
-        for (CacheKey key : set) {
-            if (key.getLoader() == loader) {
-                set.remove(key);
-            }
-        }
+        set.stream().filter((key) -> (key.getLoader() == loader && key.getModule() == module))
+                .forEach(set::remove);
     }
 
     /**
@@ -1871,6 +2334,7 @@
      * the callback methods provides the information necessary for the
      * factory methods to perform the <a
      * href="./ResourceBundle.html#default_behavior">default behavior</a>.
+     * <a href="#note">Note that this class is not supported in named modules.</a>
      *
      * <p>In addition to the callback methods, the {@link
      * #toBundleName(String, Locale) toBundleName} and {@link
@@ -2006,7 +2470,14 @@
      * }
      * </pre>
      *
+     * @apiNote <a name="note">{@code ResourceBundle.Control} is not supported
+     * in named modules.</a> If the {@code ResourceBundle.getBundle} method with
+     * a {@code ResourceBundle.Control} is called in a named module, the method
+     * will throw an {@link UnsupportedOperationException}. Any service providers
+     * of {@link ResourceBundleControlProvider} are ignored in named modules.
+     *
      * @since 1.6
+     * @see java.util.spi.ResourceBundleProvider
      */
     public static class Control {
         /**
@@ -2623,56 +3094,81 @@
          * @exception IOException
          *        if an error occurred when reading resources using
          *        any I/O operations
+         * @see java.util.spi.ResourceBundleProvider#getBundle(String, Locale)
          */
         public ResourceBundle newBundle(String baseName, Locale locale, String format,
                                         ClassLoader loader, boolean reload)
                     throws IllegalAccessException, InstantiationException, IOException {
+            /*
+             * Legacy mechanism to locate resource bundle in unnamed module only
+             * that is visible to the given loader and accessible to the given caller.
+             * This only finds resources on the class path but not in named modules.
+             */
             String bundleName = toBundleName(baseName, locale);
             ResourceBundle bundle = null;
             if (format.equals("java.class")) {
                 try {
-                    @SuppressWarnings("unchecked")
-                    Class<? extends ResourceBundle> bundleClass
-                        = (Class<? extends ResourceBundle>)loader.loadClass(bundleName);
-
+                    Class<?> c = loader.loadClass(bundleName);
                     // If the class isn't a ResourceBundle subclass, throw a
                     // ClassCastException.
-                    if (ResourceBundle.class.isAssignableFrom(bundleClass)) {
-                        bundle = bundleClass.newInstance();
+                    if (ResourceBundle.class.isAssignableFrom(c)) {
+                        @SuppressWarnings("unchecked")
+                        Class<ResourceBundle> bundleClass = (Class<ResourceBundle>)c;
+
+                        // This doesn't allow unnamed modules to find bundles in
+                        // named modules other than via the service loader mechanism.
+                        // Otherwise, this will make the newBundle method to be
+                        // caller-sensitive in order to verify access check.
+                        // So migrating resource bundles to named module can't
+                        // just export the package (in general, legacy resource
+                        // bundles have split package if they are packaged separate
+                        // from the consumer.)
+                        if (bundleClass.getModule().isNamed()) {
+                            throw new IllegalAccessException("unnamed modules can't load " + bundleName
+                                     + " in named module " + bundleClass.getModule().getName());
+                        }
+                        try {
+                            // bundle in a unnamed module
+                            Constructor<ResourceBundle> ctor = bundleClass.getConstructor();
+                            if (!Modifier.isPublic(ctor.getModifiers())) {
+                                return null;
+                            }
+
+                            // java.base may not be able to read the bundleClass's module.
+                            PrivilegedAction<Void> pa1 = () -> { ctor.setAccessible(true); return null; };
+                            AccessController.doPrivileged(pa1);
+                            bundle = ctor.newInstance((Object[]) null);
+                        } catch (InvocationTargetException e) {
+                            uncheckedThrow(e);
+                        }
                     } else {
-                        throw new ClassCastException(bundleClass.getName()
-                                     + " cannot be cast to ResourceBundle");
+                        throw new ClassCastException(c.getName()
+                                + " cannot be cast to ResourceBundle");
                     }
-                } catch (ClassNotFoundException e) {
+                } catch (ClassNotFoundException|NoSuchMethodException e) {
                 }
             } else if (format.equals("java.properties")) {
                 final String resourceName = toResourceName0(bundleName, "properties");
                 if (resourceName == null) {
                     return bundle;
                 }
-                final ClassLoader classLoader = loader;
+
                 final boolean reloadFlag = reload;
                 InputStream stream = null;
                 try {
                     stream = AccessController.doPrivileged(
                         new PrivilegedExceptionAction<>() {
                             public InputStream run() throws IOException {
-                                InputStream is = null;
+                                URL url = loader.getResource(resourceName);
+                                if (url == null) return null;
+
+                                URLConnection connection = url.openConnection();
                                 if (reloadFlag) {
-                                    URL url = classLoader.getResource(resourceName);
-                                    if (url != null) {
-                                        URLConnection connection = url.openConnection();
-                                        if (connection != null) {
-                                            // Disable caches to get fresh data for
-                                            // reloading.
-                                            connection.setUseCaches(false);
-                                            is = connection.getInputStream();
-                                        }
-                                    }
-                                } else {
-                                    is = classLoader.getResourceAsStream(resourceName);
+                                    // Disable caches to get fresh data for
+                                    // reloading.
+                                    connection.setUseCaches(false);
                                 }
-                                return is;
+                                return connection.getInputStream();
                             }
                         });
                 } catch (PrivilegedActionException e) {
@@ -2753,6 +3249,7 @@
          * the <a href="Calendar.html#Epoch"> <code>Calendar</code>
          * Epoch</a>.
          *
+         * <p>
          * The calling <code>ResourceBundle.getBundle</code> factory method
          * calls this method on the <code>ResourceBundle.Control</code>
          * instance used for its current invocation, not on the instance
@@ -2877,6 +3374,7 @@
          * @exception NullPointerException
          *        if <code>baseName</code> or <code>locale</code>
          *        is <code>null</code>
+         * @see java.util.spi.AbstractResourceBundleProvider#toBundleName(String, Locale)
          */
         public String toBundleName(String baseName, Locale locale) {
             if (locale == Locale.ROOT) {
@@ -2951,6 +3449,14 @@
         }
     }
 
+    @SuppressWarnings("unchecked")
+    private static <T extends Throwable> void uncheckedThrow(Throwable t) throws T {
+        if (t != null)
+            throw (T)t;
+        else
+            throw new Error("Unknown Exception");
+    }
+
     private static class SingleFormatControl extends Control {
         private static final Control PROPERTIES_ONLY
             = new SingleFormatControl(FORMAT_PROPERTIES);
--- a/src/java.base/share/classes/java/util/ServiceLoader.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/java/util/ServiceLoader.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,15 +29,30 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Provides;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Layer;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Module;
 import java.net.URL;
+import java.net.URLConnection;
 import java.security.AccessController;
 import java.security.AccessControlContext;
 import java.security.PrivilegedAction;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.Iterator;
-import java.util.List;
-import java.util.NoSuchElementException;
+
+import jdk.internal.loader.BootLoader;
+import jdk.internal.loader.Loader;
+import jdk.internal.loader.LoaderPool;
+import jdk.internal.misc.JavaLangAccess;
+import jdk.internal.misc.SharedSecrets;
+import jdk.internal.misc.VM;
+import jdk.internal.module.ServicesCatalog;
+import jdk.internal.module.ServicesCatalog.ServiceProvider;
+
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
 
 
 /**
@@ -47,8 +62,11 @@
  * abstract) classes.  A <i>service provider</i> is a specific implementation
  * of a service.  The classes in a provider typically implement the interfaces
  * and subclass the classes defined in the service itself.
- * Providers can be made available by adding them to the
- * application's class path or by some other platform-specific means.
+ * Providers may be developed and deployed as modules and made available using
+ * the application module path. Providers may alternatively be packaged as JAR
+ * files and made available by adding them to the application class path. The
+ * advantage of developing a provider as a module is that the provider can be
+ * fully encapsulated to hide all details of its implementation.
  *
  * <p> For the purpose of loading, a service is represented by a single type,
  * that is, a single interface or abstract class.  (A concrete class can be
@@ -60,27 +78,38 @@
  * request together with code that can create the actual provider on demand.
  * The details of provider classes tend to be highly service-specific; no
  * single class or interface could possibly unify them, so no such type is
- * defined here.  The only requirement enforced by this facility is that
- * provider classes must have a zero-argument constructor so that they can be
- * instantiated during loading.
+ * defined here. A requirement enforced by this facility is that each provider
+ * class must have a {@code public} zero-argument constructor.
  *
- * <p><a name="format"> A service provider is identified by placing a
- * <i>provider-configuration file</i> in the resource directory
- * <tt>META-INF/services</tt>.</a>  The file's name is the fully-qualified <a
- * href="../lang/ClassLoader.html#name">binary name</a> of the service's type.
- * The file contains a list of fully-qualified binary names of concrete
+ * <p> An application or library using this loading facility and developed
+ * and deployed as a named module must have an appropriate <i>uses</i> clause
+ * in its <i>module descriptor</i> to declare that the module uses
+ * implementations of the service. A corresponding requirement is that a
+ * provider deployed as a named modules must have an appropriate
+ * <i>provides</i> clause in its module descriptor to declare that the module
+ * provides an implementation of the service. The <i>uses</i> and
+ * <i>provides</i> allow consumers of a service to be <i>linked</i> to
+ * providers of the service. In the case of {@code load} methods that locate
+ * service providers using a class loader, then provider modules defined to
+ * that class loader, or a class loader <i>reachable</i> using {@link
+ * ClassLoader#getParent() parent} delegation, will be located.
+ *
+ * <p> A service provider that is packaged as a JAR file for the class path is
+ * identified by placing a <i>provider-configuration file</i> in the resource
+ * directory <tt>META-INF/services</tt>. The file's name is the fully-qualified
+ * <a href="../lang/ClassLoader.html#name">binary name</a> of the service's
+ * type. The file contains a list of fully-qualified binary names of concrete
  * provider classes, one per line.  Space and tab characters surrounding each
  * name, as well as blank lines, are ignored.  The comment character is
  * <tt>'#'</tt> (<tt>'&#92;u0023'</tt>,
  * <font style="font-size:smaller;">NUMBER SIGN</font>); on
  * each line all characters following the first comment character are ignored.
  * The file must be encoded in UTF-8.
- *
- * <p> If a particular concrete provider class is named in more than one
+ * If a particular concrete provider class is named in more than one
  * configuration file, or is named in the same configuration file more than
  * once, then the duplicates are ignored.  The configuration file naming a
- * particular provider need not be in the same jar file or other distribution
- * unit as the provider itself.  The provider must be accessible from the same
+ * particular provider need not be in the same JAR file or other distribution
+ * unit as the provider itself. The provider must be visible from the same
  * class loader that was initially queried to locate the configuration file;
  * note that this is not necessarily the class loader from which the file was
  * actually loaded.
@@ -93,7 +122,9 @@
  * providers, adding each one to the cache in turn.  The cache can be cleared
  * via the {@link #reload reload} method.
  *
- * <p> Service loaders always execute in the security context of the caller.
+ * <p> Service loaders always execute in the security context of the caller
+ * of the iterator methods and may also be restricted by the security
+ * context of the caller that created the service loader.
  * Trusted system code should typically invoke the methods in this class, and
  * the methods of the iterators which they return, from within a privileged
  * security context.
@@ -104,7 +135,6 @@
  * <p> Unless otherwise specified, passing a <tt>null</tt> argument to any
  * method in this class will cause a {@link NullPointerException} to be thrown.
  *
- *
  * <p><span style="font-weight: bold; padding-right: 1em">Example</span>
  * Suppose we have a service type <tt>com.example.CodecSet</tt> which is
  * intended to represent sets of encoder/decoder pairs for some protocol.  In
@@ -118,30 +148,20 @@
  * does not support the given encoding.  Typical providers support more than
  * one encoding.
  *
- * <p> If <tt>com.example.impl.StandardCodecs</tt> is an implementation of the
- * <tt>CodecSet</tt> service then its jar file also contains a file named
- *
- * <blockquote><pre>
- * META-INF/services/com.example.CodecSet</pre></blockquote>
- *
- * <p> This file contains the single line:
- *
- * <blockquote><pre>
- * com.example.impl.StandardCodecs    # Standard codecs</pre></blockquote>
- *
  * <p> The <tt>CodecSet</tt> class creates and saves a single service instance
  * at initialization:
  *
- * <blockquote><pre>
- * private static ServiceLoader&lt;CodecSet&gt; codecSetLoader
- *     = ServiceLoader.load(CodecSet.class);</pre></blockquote>
+ * <pre>{@code
+ * private static ServiceLoader<CodecSet> codecSetLoader
+ *     = ServiceLoader.load(CodecSet.class);
+ * }</pre>
  *
  * <p> To locate an encoder for a given encoding name it defines a static
  * factory method which iterates through the known and available providers,
  * returning only when it has located a suitable encoder or has run out of
  * providers.
  *
- * <blockquote><pre>
+ * <pre>{@code
  * public static Encoder getEncoder(String encodingName) {
  *     for (CodecSet cp : codecSetLoader) {
  *         Encoder enc = cp.getEncoder(encodingName);
@@ -149,10 +169,27 @@
  *             return enc;
  *     }
  *     return null;
- * }</pre></blockquote>
+ * }}</pre>
+ *
+ * <p> A {@code getDecoder} method is defined similarly.
+ *
+ * <p> If the code creating and using the service loader is developed as
+ * a module then its module descriptor will declare the usage with:
+ * <pre>{@code uses com.example.CodecSet;}</pre>
  *
- * <p> A <tt>getDecoder</tt> method is defined similarly.
+ * <p> Now suppose that {@code com.example.impl.StandardCodecs} is an
+ * implementation of the {@code CodecSet} service and developed as a module.
+ * In that case then the module with the service provider module will declare
+ * this in its module descriptor:
+ * <pre>{@code provides com.example.CodecSet with com.example.impl.StandardCodecs;
+ * }</pre>
  *
+ * <p> On the other hand, suppose {@code com.example.impl.StandardCodecs} is
+ * packaged in a JAR file for the class path then the JAR file will contain a
+ * file named:
+ * <pre>{@code META-INF/services/com.example.CodecSet}</pre>
+ * that contains the single line:
+ * <pre>{@code com.example.impl.StandardCodecs    # Standard codecs}</pre>
  *
  * <p><span style="font-weight: bold; padding-right: 1em">Usage Note</span> If
  * the class path of a class loader that is used for provider loading includes
@@ -183,23 +220,43 @@
 public final class ServiceLoader<S>
     implements Iterable<S>
 {
-
     private static final String PREFIX = "META-INF/services/";
 
     // The class or interface representing the service being loaded
     private final Class<S> service;
 
-    // The class loader used to locate, load, and instantiate providers
+    // The module Layer used to locate providers; null when locating
+    // providers using a class loader
+    private final Layer layer;
+
+    // The class loader used to locate, load, and instantiate providers;
+    // null when locating provider using a module Layer
     private final ClassLoader loader;
 
     // The access control context taken when the ServiceLoader is created
     private final AccessControlContext acc;
 
     // Cached providers, in instantiation order
-    private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
+    private List<S> providers = new ArrayList<>();
+
+    // The class names of the cached providers, only used when locating
+    // service providers via a class loader
+    private Set<String> providerNames = new HashSet<>();
+
+    // Incremented when reload is called
+    private int reloadCount;
 
-    // The current lazy-lookup iterator
-    private LazyIterator lookupIterator;
+    // the service iterator when locating services via a module layer
+    private LayerLookupIterator layerLookupIterator;
+
+    // The module services iterator when locating services in modules
+    // defined to a class loader
+    private ModuleServicesIterator moduleServicesIterator;
+
+    // The current lazy-lookup iterator for locating legacy provider on the
+    // class path via a class loader
+    private LazyClassPathIterator lazyClassPathIterator;
+
 
     /**
      * Clear this loader's provider cache so that all providers will be
@@ -214,16 +271,110 @@
      */
     public void reload() {
         providers.clear();
-        lookupIterator = new LazyIterator(service, loader);
+
+        assert layer == null || loader == null;
+        if (layer != null) {
+            layerLookupIterator = new LayerLookupIterator();
+        } else {
+            providerNames.clear();
+            moduleServicesIterator = new ModuleServicesIterator();
+            lazyClassPathIterator = new LazyClassPathIterator();
+        }
+
+        reloadCount++;
+    }
+
+
+    /**
+     * Initializes a new instance of this class for locating service providers
+     * in a module Layer.
+     *
+     * @throws ServiceConfigurationError
+     *         If {@code svc} is not accessible to {@code caller} or that the
+     *         caller's module does not declare that it uses the service type.
+     */
+    private ServiceLoader(Class<?> caller, Layer layer, Class<S> svc) {
+
+        checkModule(caller.getModule(), svc);
+
+        this.service = svc;
+        this.layer = layer;
+        this.loader = null;
+        this.acc = (System.getSecurityManager() != null)
+                ? AccessController.getContext()
+                : null;
+
+        reload();
     }
 
-    private ServiceLoader(Class<S> svc, ClassLoader cl) {
-        service = Objects.requireNonNull(svc, "Service interface cannot be null");
-        loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
-        acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
+    /**
+     * Initializes a new instance of this class for locating service providers
+     * via a class loader.
+     *
+     * @throws ServiceConfigurationError
+     *         If {@code svc} is not accessible to {@code caller} or that the
+     *         caller's module does not declare that it uses the service type.
+     */
+    private ServiceLoader(Module callerModule, Class<S> svc, ClassLoader cl) {
+        if (VM.isBooted()) {
+
+            checkModule(callerModule, svc);
+
+            if (cl == null) {
+                cl = ClassLoader.getSystemClassLoader();
+            }
+
+        } else {
+
+            // if we get here then it means that ServiceLoader is being used
+            // before the VM initialization has completed. At this point then
+            // only code in the java.base should be executing.
+            Module base = Object.class.getModule();
+            Module svcModule = svc.getModule();
+            if (callerModule != base || svcModule != base) {
+                fail(svc, "not accessible to " + callerModule + " during VM init");
+            }
+
+            // restricted to boot loader during startup
+            cl = null;
+        }
+
+        this.service = svc;
+        this.layer = null;
+        this.loader = cl;
+        this.acc = (System.getSecurityManager() != null)
+                ? AccessController.getContext()
+                : null;
+
         reload();
     }
 
+    private ServiceLoader(Class<?> caller, Class<S> svc, ClassLoader cl) {
+        this(caller.getModule(), svc, cl);
+    }
+
+
+
+    /**
+     * Checks that the given service type is accessible to types in the given
+     * module, and check that the module declare that it uses the service type.
+     */
+    private static void checkModule(Module module, Class<?> svc) {
+
+        // Check that the service type is in a package that is
+        // exported to the caller.
+        if (!Reflection.verifyModuleAccess(module, svc)) {
+            fail(svc, "not accessible to " + module);
+        }
+
+        // If the caller is in a named module then it should "uses" the
+        // service type
+        if (!module.canUse(svc)) {
+            fail(svc, "use not declared in " + module);
+        }
+
+    }
+
     private static void fail(Class<?> service, String msg, Throwable cause)
         throws ServiceConfigurationError
     {
@@ -269,71 +420,373 @@
                 if (!Character.isJavaIdentifierPart(cp) && (cp != '.'))
                     fail(service, u, lc, "Illegal provider-class name: " + ln);
             }
-            if (!providers.containsKey(ln) && !names.contains(ln))
+            if (!providerNames.contains(ln) && !names.contains(ln))
                 names.add(ln);
         }
         return lc + 1;
     }
 
-    // Parse the content of the given URL as a provider-configuration file.
-    //
-    // @param  service
-    //         The service type for which providers are being sought;
-    //         used to construct error detail strings
-    //
-    // @param  u
-    //         The URL naming the configuration file to be parsed
-    //
-    // @return A (possibly empty) iterator that will yield the provider-class
-    //         names in the given configuration file that are not yet members
-    //         of the returned set
-    //
-    // @throws ServiceConfigurationError
-    //         If an I/O error occurs while reading from the given URL, or
-    //         if a configuration-file format error is detected
-    //
+    /**
+     * Parse the content of the given URL as a provider-configuration file.
+     *
+     * @param  service
+     *         The service type for which providers are being sought;
+     *         used to construct error detail strings
+     *
+     * @param  u
+     *         The URL naming the configuration file to be parsed
+     *
+     * @return A (possibly empty) iterator that will yield the provider-class
+     *         names in the given configuration file that are not yet members
+     *         of the returned set
+     *
+     * @throws ServiceConfigurationError
+     *         If an I/O error occurs while reading from the given URL, or
+     *         if a configuration-file format error is detected
+     *
+     */
     private Iterator<String> parse(Class<?> service, URL u)
         throws ServiceConfigurationError
     {
-        InputStream in = null;
-        BufferedReader r = null;
         ArrayList<String> names = new ArrayList<>();
         try {
-            in = u.openStream();
-            r = new BufferedReader(new InputStreamReader(in, "utf-8"));
-            int lc = 1;
-            while ((lc = parseLine(service, u, r, lc, names)) >= 0);
+            URLConnection uc = u.openConnection();
+            uc.setUseCaches(false);
+            try (InputStream in = uc.getInputStream();
+                 BufferedReader r
+                     = new BufferedReader(new InputStreamReader(in, "utf-8")))
+            {
+                int lc = 1;
+                while ((lc = parseLine(service, u, r, lc, names)) >= 0);
+            }
         } catch (IOException x) {
-            fail(service, "Error reading configuration file", x);
-        } finally {
-            try {
-                if (r != null) r.close();
-                if (in != null) in.close();
-            } catch (IOException y) {
-                fail(service, "Error closing configuration file", y);
-            }
+            fail(service, "Error accessing configuration file", x);
         }
         return names.iterator();
     }
 
-    // Private inner class implementing fully-lazy provider lookup
-    //
-    private class LazyIterator
+    /**
+     * Returns the {@code Constructor} to instantiate the service provider.
+     * The constructor has its accessible flag set so that the access check
+     * is suppressed when instantiating the provider. This is necessary
+     * because newInstance is a caller sensitive method and ServiceLoader
+     * is instantiating the service provider on behalf of the service
+     * consumer.
+     */
+    private static Constructor<?> checkAndGetConstructor(Class<?> c)
+        throws NoSuchMethodException, IllegalAccessException
+    {
+        Constructor<?> ctor = c.getConstructor();
+
+        // check class and no-arg constructor are public
+        int modifiers = ctor.getModifiers();
+        if (!Modifier.isPublic(Reflection.getClassAccessFlags(c) & modifiers)) {
+            String cn = c.getName();
+            throw new IllegalAccessException(cn + " is not public");
+        }
+
+        // return Constructor to create the service implementation
+        PrivilegedAction<Void> action = new PrivilegedAction<Void>() {
+            public Void run() { ctor.setAccessible(true); return null; }
+        };
+        AccessController.doPrivileged(action);
+        return ctor;
+    }
+
+    /**
+     * Uses Class.forName to load a class in a module.
+     */
+    private static Class<?> loadClassInModule(Module module, String cn) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm == null) {
+            return Class.forName(module, cn);
+        } else {
+            PrivilegedAction<Class<?>> pa = () -> Class.forName(module, cn);
+            return AccessController.doPrivileged(pa);
+        }
+    }
+
+    /**
+     * An Iterator that runs the next and hasNext methods with permissions
+     * restricted by the {@code AccessControlContext} obtained when the
+     * ServiceLoader was created.
+     */
+    private abstract class RestrictedIterator<S>
         implements Iterator<S>
     {
+        /**
+         * Returns {@code true} if the iteration has more elements.
+         */
+        abstract boolean hasNextService();
 
-        Class<S> service;
-        ClassLoader loader;
-        Enumeration<URL> configs = null;
-        Iterator<String> pending = null;
-        String nextName = null;
+        /**
+         * Returns the next element in the iteration
+         */
+        abstract S nextService();
+
+        public final boolean hasNext() {
+            if (acc == null) {
+                return hasNextService();
+            } else {
+                PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() {
+                    public Boolean run() { return hasNextService(); }
+                };
+                return AccessController.doPrivileged(action, acc);
+            }
+        }
+
+        public final S next() {
+            if (acc == null) {
+                return nextService();
+            } else {
+                PrivilegedAction<S> action = new PrivilegedAction<S>() {
+                    public S run() { return nextService(); }
+                };
+                return AccessController.doPrivileged(action, acc);
+            }
+        }
+    }
+
+    /**
+     * Implements lazy service provider lookup of service providers that
+     * are provided by modules in a module Layer.
+     *
+     * For now, this iterator examines all modules in each Layer. This will
+     * be replaced once we decide on how the service-use graph is exposed
+     * in the module API.
+     */
+    private class LayerLookupIterator
+        extends RestrictedIterator<S>
+    {
+        final String serviceName;
+        Layer currentLayer;
+        Iterator<ModuleDescriptor> descriptorIterator;
+        Iterator<String> providersIterator;
+
+        Module nextModule;
+        String nextProvider;
 
-        private LazyIterator(Class<S> service, ClassLoader loader) {
-            this.service = service;
-            this.loader = loader;
+        LayerLookupIterator() {
+            serviceName = service.getName();
+            currentLayer = layer;
+
+            // need to get us started
+            descriptorIterator = descriptors(layer, serviceName);
+        }
+
+        Iterator<ModuleDescriptor> descriptors(Layer layer, String service) {
+            return layer.modules().stream()
+                    .map(Module::getDescriptor)
+                    .filter(d -> d.provides().get(service) != null)
+                    .iterator();
+        }
+
+        @Override
+        boolean hasNextService() {
+
+            // already have the next provider cached
+            if (nextProvider != null)
+                return true;
+
+            while (true) {
+
+                // next provider
+                if (providersIterator != null && providersIterator.hasNext()) {
+                    nextProvider = providersIterator.next();
+                    return true;
+                }
+
+                // next descriptor
+                if (descriptorIterator.hasNext()) {
+                    ModuleDescriptor descriptor = descriptorIterator.next();
+
+                    nextModule = currentLayer.findModule(descriptor.name()).get();
+
+                    Provides provides = descriptor.provides().get(serviceName);
+                    providersIterator = provides.providers().iterator();
+
+                    continue;
+                }
+
+                // next layer
+                Layer parent = currentLayer.parent().orElse(null);
+                if (parent == null)
+                    return false;
+
+                currentLayer = parent;
+                descriptorIterator = descriptors(currentLayer, serviceName);
+            }
         }
 
-        private boolean hasNextService() {
+        @Override
+        S nextService() {
+            if (!hasNextService())
+                throw new NoSuchElementException();
+
+            assert nextModule != null && nextProvider != null;
+
+            String cn = nextProvider;
+            nextProvider = null;
+
+            // attempt to load the provider
+            Class<?> c = loadClassInModule(nextModule, cn);
+            if (c == null)
+                fail(service, "Provider " + cn  + " not found");
+            if (!service.isAssignableFrom(c))
+                fail(service, "Provider " + cn  + " not a subtype");
+
+            // instantiate the provider
+            S p = null;
+            try {
+                Constructor<?> ctor = checkAndGetConstructor(c);
+                p = service.cast(ctor.newInstance());
+            } catch (Throwable x) {
+                if (x instanceof InvocationTargetException)
+                    x = x.getCause();
+                fail(service,
+                        "Provider " + cn + " could not be instantiated", x);
+            }
+
+            // add to cached provider list
+            providers.add(p);
+
+            return p;
+        }
+    }
+
+    /**
+     * Implements lazy service provider lookup of service providers that
+     * are provided by modules defined to a class loader.
+     */
+    private class ModuleServicesIterator
+        extends RestrictedIterator<S>
+    {
+        final JavaLangAccess langAccess = SharedSecrets.getJavaLangAccess();
+
+        ClassLoader currentLoader;
+        Iterator<ServiceProvider> iterator;
+        ServiceProvider nextProvider;
+
+        ModuleServicesIterator() {
+            this.currentLoader = loader;
+            this.iterator = iteratorFor(loader);
+        }
+
+        /**
+         * Returns an iterator to iterate over the implementations of {@code
+         * service} in modules defined to the given class loader.
+         */
+        private Iterator<ServiceProvider> iteratorFor(ClassLoader loader) {
+
+            // if the class loader is in a loader pool then return an Iterator
+            // that iterates over all service providers in the pool that provide
+            // an implementation of the service
+            if (currentLoader instanceof Loader) {
+                LoaderPool pool = ((Loader) loader).pool();
+                if (pool != null) {
+                    return pool.loaders()
+                            .map(l -> langAccess.getServicesCatalog(l))
+                            .filter(sc -> sc != null)
+                            .map(sc -> sc.findServices(service.getName()))
+                            .flatMap(Set::stream)
+                            .iterator();
+                }
+            }
+
+            ServicesCatalog catalog;
+            if (currentLoader == null) {
+                catalog = BootLoader.getServicesCatalog();
+            } else {
+                catalog = langAccess.getServicesCatalog(currentLoader);
+            }
+            if (catalog == null) {
+                return Collections.emptyIterator();
+            } else {
+                return catalog.findServices(service.getName()).iterator();
+            }
+        }
+
+        @Override
+        boolean hasNextService() {
+            // already have the next provider cached
+            if (nextProvider != null)
+                return true;
+
+            while (true) {
+                if (iterator.hasNext()) {
+                    nextProvider = iterator.next();
+                    return true;
+                }
+
+                // move to the next class loader if possible
+                if (currentLoader == null) {
+                    return false;
+                } else {
+                    currentLoader = currentLoader.getParent();
+                    iterator = iteratorFor(currentLoader);
+                }
+            }
+        }
+
+        @Override
+        S nextService() {
+            if (!hasNextService())
+                throw new NoSuchElementException();
+
+            ServiceProvider provider = nextProvider;
+            nextProvider = null;
+
+            // attempt to load the provider
+            Module module = provider.module();
+            String cn = provider.providerName();
+
+            Class<?> c = loadClassInModule(module, cn);
+            if (c == null) {
+                fail(service,
+                    "Provider " + cn + " not found in " + module.getName());
+            }
+            if (!service.isAssignableFrom(c)) {
+                fail(service, "Provider " + cn  + " not a subtype");
+            }
+
+            // instantiate the provider
+            S p = null;
+            try {
+                Constructor<?> ctor = checkAndGetConstructor(c);
+                p = service.cast(ctor.newInstance());
+            } catch (Throwable x) {
+                if (x instanceof InvocationTargetException)
+                    x = x.getCause();
+                fail(service,
+                    "Provider " + cn + " could not be instantiated", x);
+            }
+
+            // add to provider list
+            providers.add(p);
+
+            // record the class name of the service provider, this is
+            // needed for cases where there a module has both a "uses"
+            // and a services configuration file listing the same
+            // provider
+            providerNames.add(cn);
+
+            return p;
+        }
+    }
+
+    /**
+     * Implements lazy service provider lookup where the service providers
+     * are configured via service configuration files.
+     */
+    private class LazyClassPathIterator
+        extends RestrictedIterator<S>
+    {
+        Enumeration<URL> configs;
+        Iterator<String> pending;
+        String nextName;
+
+        @Override
+        boolean hasNextService() {
             if (nextName != null) {
                 return true;
             }
@@ -358,7 +811,8 @@
             return true;
         }
 
-        private S nextService() {
+        @Override
+        S nextService() {
             if (!hasNextService())
                 throw new NoSuchElementException();
             String cn = nextName;
@@ -374,44 +828,18 @@
                 fail(service,
                      "Provider " + cn  + " not a subtype");
             }
+            S p = null;
             try {
-                S p = service.cast(c.newInstance());
-                providers.put(cn, p);
-                return p;
+                p = service.cast(c.newInstance());
             } catch (Throwable x) {
                 fail(service,
                      "Provider " + cn + " could not be instantiated",
                      x);
             }
-            throw new Error();          // This cannot happen
-        }
-
-        public boolean hasNext() {
-            if (acc == null) {
-                return hasNextService();
-            } else {
-                PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() {
-                    public Boolean run() { return hasNextService(); }
-                };
-                return AccessController.doPrivileged(action, acc);
-            }
+            providers.add(p);
+            providerNames.add(cn);
+            return p;
         }
-
-        public S next() {
-            if (acc == null) {
-                return nextService();
-            } else {
-                PrivilegedAction<S> action = new PrivilegedAction<S>() {
-                    public S run() { return nextService(); }
-                };
-                return AccessController.doPrivileged(action, acc);
-            }
-        }
-
-        public void remove() {
-            throw new UnsupportedOperationException();
-        }
-
     }
 
     /**
@@ -422,16 +850,14 @@
      * loads and instantiates any remaining providers, adding each one to the
      * cache in turn.
      *
-     * <p> To achieve laziness the actual work of parsing the available
-     * provider-configuration files and instantiating providers must be done by
-     * the iterator itself.  Its {@link java.util.Iterator#hasNext hasNext} and
-     * {@link java.util.Iterator#next next} methods can therefore throw a
-     * {@link ServiceConfigurationError} if a provider-configuration file
-     * violates the specified format, or if it names a provider class that
-     * cannot be found and instantiated, or if the result of instantiating the
-     * class is not assignable to the service type, or if any other kind of
-     * exception or error is thrown as the next provider is located and
-     * instantiated.  To write robust code it is only necessary to catch {@link
+     * <p> To achieve laziness the actual work of locating and instantiating
+     * providers must be done by the iterator itself. Its {@link
+     * java.util.Iterator#hasNext hasNext} and {@link java.util.Iterator#next
+     * next} methods can therefore throw a {@link ServiceConfigurationError}
+     * if a provider class cannot be loaded, doesn't have the appropriate
+     * constructor, can't be assigned to the service type or if any other kind
+     * of exception or error is thrown as the next provider is located and
+     * instantiated. To write robust code it is only necessary to catch {@link
      * ServiceConfigurationError} when using a service iterator.
      *
      * <p> If such an error is thrown then subsequent invocations of the
@@ -447,6 +873,14 @@
      * preferable to throw an error rather than try to recover or, even worse,
      * fail silently.</blockquote>
      *
+     * <p> If this loader's provider cache is cleared by invoking the {@link
+     * #reload() reload} method then existing iterators for this service
+     * loader should be discarded.
+     * The {@link java.util.Iterator#hasNext() hasNext} and {@link
+     * java.util.Iterator#next() next} methods of the iterator throw {@link
+     * java.util.ConcurrentModificationException ConcurrentModificationException}
+     * if used after the provider cache has been cleared.
+     *
      * <p> The iterator returned by this method does not support removal.
      * Invoking its {@link java.util.Iterator#remove() remove} method will
      * cause an {@link UnsupportedOperationException} to be thrown.
@@ -463,29 +897,85 @@
     public Iterator<S> iterator() {
         return new Iterator<S>() {
 
-            Iterator<Map.Entry<String,S>> knownProviders
-                = providers.entrySet().iterator();
+            // record reload count
+            final int expectedReloadCount = ServiceLoader.this.reloadCount;
+
+            // index into the cached providers list
+            int index;
+
+            /**
+             * Throws ConcurrentModificationException if the list of cached
+             * providers has been cleared by reload.
+             */
+            private void checkReloadCount() {
+                if (ServiceLoader.this.reloadCount != expectedReloadCount)
+                    throw new ConcurrentModificationException();
+            }
 
             public boolean hasNext() {
-                if (knownProviders.hasNext())
+                checkReloadCount();
+                if (index < providers.size())
                     return true;
-                return lookupIterator.hasNext();
+
+                if (layerLookupIterator != null) {
+                    return layerLookupIterator.hasNext();
+                } else {
+                    return moduleServicesIterator.hasNext() ||
+                            lazyClassPathIterator.hasNext();
+                }
             }
 
             public S next() {
-                if (knownProviders.hasNext())
-                    return knownProviders.next().getValue();
-                return lookupIterator.next();
-            }
-
-            public void remove() {
-                throw new UnsupportedOperationException();
+                checkReloadCount();
+                S next;
+                if (index < providers.size()) {
+                    next = providers.get(index);
+                } else {
+                    if (layerLookupIterator != null) {
+                        next = layerLookupIterator.next();
+                    } else {
+                        if (moduleServicesIterator.hasNext()) {
+                            next = moduleServicesIterator.next();
+                        } else {
+                            next = lazyClassPathIterator.next();
+                        }
+                    }
+                }
+                index++;
+                return next;
             }
 
         };
     }
 
     /**
+     * Creates a new service loader for the given service type, class
+     * loader, and caller.
+     *
+     * @param  <S> the class of the service type
+     *
+     * @param  service
+     *         The interface or abstract class representing the service
+     *
+     * @param  loader
+     *         The class loader to be used to load provider-configuration files
+     *         and provider classes, or <tt>null</tt> if the system class
+     *         loader (or, failing that, the bootstrap class loader) is to be
+     *         used
+     *
+     * @param  callerModule
+     *         The caller's module for which a new service loader is created
+     *
+     * @return A new service loader
+     */
+    static <S> ServiceLoader<S> load(Class<S> service,
+                                     ClassLoader loader,
+                                     Module callerModule)
+    {
+        return new ServiceLoader<>(callerModule, service, loader);
+    }
+
+    /**
      * Creates a new service loader for the given service type and class
      * loader.
      *
@@ -496,16 +986,22 @@
      *
      * @param  loader
      *         The class loader to be used to load provider-configuration files
-     *         and provider classes, or <tt>null</tt> if the system class
+     *         and provider classes, or {@code null} if the system class
      *         loader (or, failing that, the bootstrap class loader) is to be
      *         used
      *
      * @return A new service loader
+     *
+     * @throws ServiceConfigurationError
+     *         if the service type is not accessible to the caller or the
+     *         caller is in a named module and its module descriptor does
+     *         not declare that it uses {@code service}
      */
+    @CallerSensitive
     public static <S> ServiceLoader<S> load(Class<S> service,
                                             ClassLoader loader)
     {
-        return new ServiceLoader<>(service, loader);
+        return new ServiceLoader<>(Reflection.getCallerClass(), service, loader);
     }
 
     /**
@@ -530,30 +1026,32 @@
      *         The interface or abstract class representing the service
      *
      * @return A new service loader
+     *
+     * @throws ServiceConfigurationError
+     *         if the service type is not accessible to the caller or the
+     *         caller is in a named module and its module descriptor does
+     *         not declare that it uses {@code service}
      */
+    @CallerSensitive
     public static <S> ServiceLoader<S> load(Class<S> service) {
         ClassLoader cl = Thread.currentThread().getContextClassLoader();
-        return ServiceLoader.load(service, cl);
+        return new ServiceLoader<>(Reflection.getCallerClass(), service, cl);
     }
 
     /**
      * Creates a new service loader for the given service type, using the
-     * extension class loader.
+     * {@linkplain ClassLoader#getPlatformClassLoader() platform class loader}.
      *
-     * <p> This convenience method simply locates the extension class loader,
-     * call it <tt><i>extClassLoader</i></tt>, and then returns
+     * <p> This convenience method is equivalent to: </p>
      *
      * <blockquote><pre>
-     * ServiceLoader.load(<i>service</i>, <i>extClassLoader</i>)</pre></blockquote>
-     *
-     * <p> If the extension class loader cannot be found then the system class
-     * loader is used; if there is no system class loader then the bootstrap
-     * class loader is used.
+     * ServiceLoader.load(<i>service</i>, <i>ClassLoader.getPlatformClassLoader())</i>
+     * </pre></blockquote>
      *
      * <p> This method is intended for use when only installed providers are
      * desired.  The resulting service will only find and load providers that
      * have been installed into the current Java virtual machine; providers on
-     * the application's class path will be ignored.
+     * the application's module path or class path will be ignored.
      *
      * @param  <S> the class of the service type
      *
@@ -561,7 +1059,13 @@
      *         The interface or abstract class representing the service
      *
      * @return A new service loader
+     *
+     * @throws ServiceConfigurationError
+     *         if the service type is not accessible to the caller or the
+     *         caller is in a named module and its module descriptor does
+     *         not declare that it uses {@code service}
      */
+    @CallerSensitive
     public static <S> ServiceLoader<S> loadInstalled(Class<S> service) {
         ClassLoader cl = ClassLoader.getSystemClassLoader();
         ClassLoader prev = null;
@@ -569,7 +1073,40 @@
             prev = cl;
             cl = cl.getParent();
         }
-        return ServiceLoader.load(service, prev);
+        return new ServiceLoader<>(Reflection.getCallerClass(), service, prev);
+    }
+
+    /**
+     * Creates a new service loader for the given service type that loads
+     * service providers from modules in the given {@code Layer} and its
+     * ancestors.
+     *
+     * @apiNote Unlike the other load methods defined here, the service type
+     * is the second parameter. The reason for this is to avoid source
+     * compatibility issues for code that uses {@code load(S, null)}.
+     *
+     * @param  <S> the class of the service type
+     *
+     * @param  layer
+     *         The module Layer
+     *
+     * @param  service
+     *         The interface or abstract class representing the service
+     *
+     * @return A new service loader
+     *
+     * @throws ServiceConfigurationError
+     *         if the service type is not accessible to the caller or the
+     *         caller is in a named module and its module descriptor does
+     *         not declare that it uses {@code service}
+     *
+     * @since 9
+     */
+    @CallerSensitive
+    public static <S> ServiceLoader<S> load(Layer layer, Class<S> service) {
+        return new ServiceLoader<>(Reflection.getCallerClass(),
+                                   Objects.requireNonNull(layer),
+                                   Objects.requireNonNull(service));
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/util/spi/AbstractResourceBundleProvider.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.spi;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.lang.reflect.Module;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import sun.util.locale.provider.ResourceBundleProviderSupport;
+import static sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION;
+
+
+/**
+ * {@code AbstractResourceBundleProvider} is an abstract class for helping
+ * implement the {@link ResourceBundleProvider} interface.
+ *
+ * @since 9
+ */
+public abstract class AbstractResourceBundleProvider implements ResourceBundleProvider {
+    private static final String FORMAT_CLASS = "java.class";
+    private static final String FORMAT_PROPERTIES = "java.properties";
+
+    private final String[] formats;
+
+    /**
+     * Constructs an {@code AbstractResourceBundleProvider} with the
+     * "java.properties" format. This constructor is equivalent to
+     * {@code AbstractResourceBundleProvider("java.properties")}.
+     */
+    protected AbstractResourceBundleProvider() {
+        this(FORMAT_PROPERTIES);
+    }
+
+    /**
+     * Constructs an {@code AbstractResourceBundleProvider} with the specified
+     * {@code formats}. The {@link #getBundle(String, Locale)} method looks up
+     * resource bundles for the given {@code formats}. {@code formats} must
+     * be "java.class" or "java.properties".
+     *
+     * @param formats the formats to be used for loading resource bundles
+     * @throws NullPointerException if the given {@code formats} is null
+     * @throws IllegalArgumentException if the given {@code formats} is not
+     *         "java.class" or "java.properties".
+     */
+    protected AbstractResourceBundleProvider(String... formats) {
+        this.formats = formats.clone();  // defensive copy
+        if (this.formats.length == 0) {
+            throw new IllegalArgumentException("empty formats");
+        }
+        for (String f : this.formats) {
+            if (!FORMAT_CLASS.equals(f) && !FORMAT_PROPERTIES.equals(f)) {
+                throw new IllegalArgumentException(f);
+            }
+        }
+    }
+
+    /**
+     * Returns the bundle name for the given {@code baseName} and {@code
+     * locale}.  This method is called from the default implementation of the
+     * {@link #getBundle(String, Locale)} method.
+     *
+     * @implNote The default implementation of this method is the same as the
+     * implementation of
+     * {@link java.util.ResourceBundle.Control#toBundleName(String, Locale)}.
+     *
+     * @param baseName the base name of the resource bundle, a fully qualified
+     *                 class name
+     * @param locale   the locale for which a resource bundle should be loaded
+     * @return the bundle name for the resource bundle
+     */
+    protected String toBundleName(String baseName, Locale locale) {
+        return ResourceBundle.Control.getControl(ResourceBundle.Control.FORMAT_DEFAULT)
+                   .toBundleName(baseName, locale);
+    }
+
+    /**
+     * Returns a {@code ResourceBundle} for the given {@code baseName} and
+     * {@code locale}. This method calls the
+     * {@link #toBundleName(String, Locale) toBundleName} method to get the
+     * bundle name for the {@code baseName} and {@code locale}. The formats
+     * specified by the constructor will be searched to find the resource
+     * bundle.
+     *
+     * @implNote
+     * The default implementation of this method will find the resource bundle
+     * local to the module of this provider.
+     *
+     * @param baseName the base bundle name of the resource bundle, a fully
+     *                 qualified class name.
+     * @param locale the locale for which the resource bundle should be instantiated
+     * @return {@code ResourceBundle} of the given {@code baseName} and {@code locale},
+     *         or null if no resource bundle is found
+     * @throws NullPointerException if {@code baseName} or {@code locale} is null
+     * @throws UncheckedIOException if any IO exception occurred during resource
+     *         bundle loading
+     */
+    @Override
+    public ResourceBundle getBundle(String baseName, Locale locale) {
+        Module module = this.getClass().getModule();
+        String bundleName = toBundleName(baseName, locale);
+        ResourceBundle bundle = null;
+        for (String format : formats) {
+            try {
+                if (FORMAT_CLASS.equals(format)) {
+                    PrivilegedAction<ResourceBundle> pa = () ->
+                                    ResourceBundleProviderSupport
+                                         .loadResourceBundle(module, bundleName);
+                    bundle = AccessController.doPrivileged(pa, null, GET_CLASSLOADER_PERMISSION);
+                } else if (FORMAT_PROPERTIES.equals(format)) {
+                    bundle = ResourceBundleProviderSupport
+                                 .loadPropertyResourceBundle(module, bundleName);
+                }
+                if (bundle != null) {
+                    break;
+                }
+            } catch (IOException e) {
+                throw new UncheckedIOException(e);
+            }
+        }
+        return bundle;
+    }
+}
--- a/src/java.base/share/classes/java/util/spi/ResourceBundleControlProvider.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/java/util/spi/ResourceBundleControlProvider.java	Thu Mar 17 19:04:16 2016 +0000
@@ -42,6 +42,8 @@
  * ResourceBundleControlProvider} implementations are loaded using {@link
  * java.util.ServiceLoader} at the {@code ResourceBundle} class loading time.
  *
+ * <p>All {@code ResourceBundleControlProvider}s are ignored in named modules.
+ *
  * @author Masayoshi Okutsu
  * @since 1.8
  * @see ResourceBundle#getBundle(String, java.util.Locale, ClassLoader, ResourceBundle.Control)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/util/spi/ResourceBundleProvider.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.spi;
+
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+/**
+ * {@code ResourceBundleProvider} is a provider interface that is used for
+ * loading resource bundles. Implementation classes of this interface are loaded
+ * with {@link java.util.ServiceLoader ServiceLoader} during a call to the
+ * {@link ResourceBundle#getBundle(String, Locale, ClassLoader)
+ * ResourceBundle.getBundle} method. The provider service type is determined by
+ * {@code basename+"Provider"}. For example, if the base name is
+ * "com.example.app.MyResources", {@code com.example.app.MyResourcesProvider}
+ * will be the provider service type.
+ * <p>
+ * This providers's {@link #getBundle(String, Locale) getBundle} method is called
+ * through the resource bundle loading process instead of {@link
+ * java.util.ResourceBundle.Control#newBundle(String, Locale, String, ClassLoader, boolean)
+ * ResourceBundle.Control.newBundle()}. Refer to {@link ResourceBundle} for
+ * details.
+ *
+ * @since 9
+ */
+public interface ResourceBundleProvider {
+    /**
+     * Returns a {@code ResourceBundle} for the given bundle name and locale.
+     * This method returns null if there is no {@code ResourceBundle} found
+     * for the given parameters.
+     *
+     *
+     * @param baseName
+     *        the base bundle name of the resource bundle, a fully
+     *        qualified class name
+     * @param locale
+     *        the locale for which the resource bundle should be loaded
+     * @return the ResourceBundle created for the given parameters, or null if no
+     *         {@code ResourceBundle} for the given parameters is found
+     */
+    public ResourceBundle getBundle(String baseName, Locale locale);
+}
--- a/src/java.base/share/classes/javax/crypto/JceSecurity.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/javax/crypto/JceSecurity.java	Thu Mar 17 19:04:16 2016 +0000
@@ -251,11 +251,8 @@
 
         File exportJar = new File(pathToPolicyJar, "US_export_policy.jar");
         File importJar = new File(pathToPolicyJar, "local_policy.jar");
-        URL jceCipherURL = ClassLoader.getSystemResource
-                ("javax/crypto/Cipher.class");
 
-        if ((jceCipherURL == null) ||
-                !exportJar.exists() || !importJar.exists()) {
+        if (!exportJar.exists() || !importJar.exists()) {
             throw new SecurityException
                                 ("Cannot locate policy or framework files!");
         }
--- a/src/java.base/share/classes/javax/crypto/SealedObject.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/javax/crypto/SealedObject.java	Thu Mar 17 19:04:16 2016 +0000
@@ -453,9 +453,6 @@
 }
 
 final class extObjectInputStream extends ObjectInputStream {
-
-    private static ClassLoader systemClassLoader = null;
-
     extObjectInputStream(InputStream in)
         throws IOException, StreamCorruptedException {
         super(in);
@@ -478,10 +475,7 @@
              */
             ClassLoader loader = Thread.currentThread().getContextClassLoader();
             if (loader == null) {
-                if (systemClassLoader == null) {
-                    systemClassLoader = ClassLoader.getSystemClassLoader();
-                }
-                loader = systemClassLoader;
+                loader = ClassLoader.getSystemClassLoader();
                 if (loader == null) {
                     throw new ClassNotFoundException(v.getName());
                 }
--- a/src/java.base/share/classes/jdk/internal/jimage/Archive.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,118 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.internal.jimage;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.stream.Stream;
-
-/**
- * An Archive of all content, classes, resources, configuration files, and
- * other, for a module.
- */
-public interface Archive {
-
-    /**
-     * Entry is contained in an Archive
-     */
-    public abstract class Entry {
-
-        public static enum EntryType {
-
-            MODULE_NAME,
-            CLASS_OR_RESOURCE,
-            NATIVE_LIB,
-            NATIVE_CMD,
-            CONFIG,
-            SERVICE;
-        }
-
-        private final String name;
-        private final EntryType type;
-        private final Archive archive;
-        private final String path;
-
-        public Entry(Archive archive, String path, String name, EntryType type) {
-            this.archive = archive;
-            this.path = path;
-            this.name = name;
-            this.type = type;
-        }
-
-        public Archive archive() {
-            return archive;
-        }
-
-        public String path() {
-            return path;
-        }
-
-        public EntryType type() {
-            return type;
-        }
-
-        /**
-         * Returns the name of this entry.
-         */
-        public String name() {
-            return name;
-        }
-
-        @Override
-        public String toString() {
-            return "type " + type.name() + " path " + path;
-        }
-
-        /**
-         * Returns the number of uncompressed bytes for this entry.
-         */
-        public abstract long size();
-
-        public abstract InputStream stream() throws IOException;
-    }
-
-    /**
-     * The module name.
-     */
-    String moduleName();
-
-    /**
-     * Stream of Entry.
-     * The stream of entries needs to be closed after use
-     * since it might cover lazy I/O based resources.
-     * So callers need to use a try-with-resources block.
-     */
-    Stream<Entry> entries();
-
-    /**
-     * Open the archive
-     */
-    void open() throws IOException;
-
-    /**
-     * Close the archive
-     */
-    void close() throws IOException;
-}
--- a/src/java.base/share/classes/jdk/internal/jimage/BasicImageReader.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/jimage/BasicImageReader.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,183 +26,288 @@
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
-import java.io.File;
 import java.io.InputStream;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.nio.IntBuffer;
-import java.util.Comparator;
+import java.nio.channels.FileChannel;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Objects;
 import java.util.stream.IntStream;
+import jdk.internal.jimage.decompressor.Decompressor;
 
+/**
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
+ */
 public class BasicImageReader implements AutoCloseable {
-    private final String imagePath;
-    private final ImageSubstrate substrate;
-    private final ByteOrder byteOrder;
-    private final ImageStringsReader strings;
-
-    protected BasicImageReader(String imagePath, ByteOrder byteOrder)
-            throws IOException {
-        this.imagePath = imagePath;
-        this.substrate = openImageSubstrate(imagePath, byteOrder);
-        this.byteOrder = byteOrder;
-        this.strings = new ImageStringsReader(this);
+    private static boolean isSystemProperty(String key, String value, String def) {
+        // No lambdas during bootstrap
+        return AccessController.doPrivileged(
+            new PrivilegedAction<Boolean>() {
+                @Override
+                public Boolean run() {
+                    return value.equals(System.getProperty(key, def));
+                }
+            });
     }
 
-    protected BasicImageReader(String imagePath) throws IOException {
+    static private final boolean IS_64_BIT =
+            isSystemProperty("sun.arch.data.model", "64", "32");
+    static private final boolean USE_JVM_MAP =
+            isSystemProperty("jdk.image.use.jvm.map", "true", "true");
+    static private final boolean MAP_ALL =
+            isSystemProperty("jdk.image.map.all", "true", IS_64_BIT ? "true" : "false");
+
+    private final String name;
+    private final ByteOrder byteOrder;
+    private final Path imagePath;
+    private final ByteBuffer memoryMap;
+    private final FileChannel channel;
+    private final ImageHeader header;
+    private final long indexSize;
+    private final IntBuffer redirect;
+    private final IntBuffer offsets;
+    private final ByteBuffer locations;
+    private final ByteBuffer strings;
+    private final ImageStringsReader stringsReader;
+    private final Decompressor decompressor;
+
+    protected BasicImageReader(Path path, ByteOrder byteOrder)
+            throws IOException {
+        Objects.requireNonNull(path);
+        Objects.requireNonNull(byteOrder);
+        this.name = path.toString();
+        this.byteOrder = byteOrder;
+        imagePath = path;
+
+        ByteBuffer map;
+
+        if (USE_JVM_MAP && BasicImageReader.class.getClassLoader() == null) {
+            // Check to see if the jvm has opened the file using libjimage
+            // native entry when loading the image for this runtime
+            map = NativeImageBuffer.getNativeMap(name);
+         } else {
+            map = null;
+        }
+
+        // Open the file only if no memory map yet or is 32 bit jvm
+        channel = map != null && MAP_ALL ? null :
+                  FileChannel.open(imagePath, StandardOpenOption.READ);
+
+        // If no memory map yet and 64 bit jvm then memory map entire file
+        if (MAP_ALL && map == null) {
+            map = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
+        }
+
+        // Assume we have a memory map to read image file header
+        ByteBuffer headerBuffer = map;
+        int headerSize = ImageHeader.getHeaderSize();
+
+        // If no memory map then read header from image file
+        if (map == null) {
+            headerBuffer = ByteBuffer.allocateDirect(headerSize);
+            channel.read(headerBuffer, 0L);
+            headerBuffer.rewind();
+        }
+
+        // Interpret the image file header
+        header = readHeader(intBuffer(headerBuffer, 0, headerSize));
+        indexSize = header.getIndexSize();
+
+        // If no memory map yet then must be 32 bit jvm not previously mapped
+        if (map == null) {
+            // Just map the image index
+            map = channel.map(FileChannel.MapMode.READ_ONLY, 0, indexSize);
+        }
+
+        memoryMap = map.asReadOnlyBuffer();
+
+        // Interpret the image index
+        redirect = intBuffer(memoryMap, header.getRedirectOffset(), header.getRedirectSize());
+        offsets = intBuffer(memoryMap, header.getOffsetsOffset(), header.getOffsetsSize());
+        locations = slice(memoryMap, header.getLocationsOffset(), header.getLocationsSize());
+        strings = slice(memoryMap, header.getStringsOffset(), header.getStringsSize());
+
+        stringsReader = new ImageStringsReader(this);
+        decompressor = new Decompressor();
+    }
+
+    protected BasicImageReader(Path imagePath) throws IOException {
         this(imagePath, ByteOrder.nativeOrder());
     }
 
-    private static ImageSubstrate openImageSubstrate(String imagePath, ByteOrder byteOrder)
-            throws IOException {
-        ImageSubstrate substrate;
+    public static BasicImageReader open(Path imagePath) throws IOException {
+        return new BasicImageReader(imagePath, ByteOrder.nativeOrder());
+    }
 
-        try {
-            substrate = ImageNativeSubstrate.openImage(imagePath, byteOrder);
-        } catch (UnsatisfiedLinkError | NoClassDefFoundError ex) {
-            substrate = ImageJavaSubstrate.openImage(imagePath, byteOrder);
+    public ImageHeader getHeader() {
+        return header;
+    }
+
+    private ImageHeader readHeader(IntBuffer buffer) throws IOException {
+        ImageHeader result = ImageHeader.readFrom(buffer);
+
+        if (result.getMagic() != ImageHeader.MAGIC) {
+            throw new IOException("\"" + name + "\" is not an image file");
         }
 
-        return substrate;
+        if (result.getMajorVersion() != ImageHeader.MAJOR_VERSION ||
+            result.getMinorVersion() != ImageHeader.MINOR_VERSION) {
+            throw new IOException("The image file \"" + name + "\" is not the correct version");
+        }
+
+        return result;
     }
 
-    public static BasicImageReader open(String imagePath) throws IOException {
-        return new BasicImageReader(imagePath, ByteOrder.nativeOrder());
+    private static ByteBuffer slice(ByteBuffer buffer, int position, int capacity) {
+        // Note that this is the only limit and position manipulation of
+        // BasicImageReader private ByteBuffers.  The synchronize could be avoided
+        // by cloning the buffer to make a local copy, but at the cost of creating
+        // a new object.
+        synchronized(buffer) {
+            buffer.limit(position + capacity);
+            buffer.position(position);
+            return buffer.slice();
+        }
+    }
+
+    private IntBuffer intBuffer(ByteBuffer buffer, int offset, int size) {
+        return slice(buffer, offset, size).order(byteOrder).asIntBuffer();
     }
 
     public static void releaseByteBuffer(ByteBuffer buffer) {
         ImageBufferCache.releaseBuffer(buffer);
     }
 
+    public String getName() {
+        return name;
+    }
+
     public ByteOrder getByteOrder() {
         return byteOrder;
     }
 
-    public String imagePath() {
+    public Path getImagePath() {
         return imagePath;
     }
 
-    public String imagePathName() {
-        int slash = imagePath().lastIndexOf(File.separator);
-
-        if (slash != -1) {
-            return imagePath().substring(slash + 1);
+    @Override
+    public void close() throws IOException {
+        if (channel != null) {
+            channel.close();
         }
-
-        return imagePath();
-    }
-
-    public boolean isOpen() {
-        return true;
-    }
-
-    public void close() throws IOException {
-        substrate.close();
-    }
-
-    public ImageHeader getHeader() throws IOException {
-        return ImageHeader.readFrom(
-                getIndexIntBuffer(0, ImageHeader.getHeaderSize()));
     }
 
     public ImageStringsReader getStrings() {
-        return strings;
+        return stringsReader;
     }
 
-    public ImageLocation findLocation(String name) {
-        return findLocation(new UTF8String(name));
+    public ImageLocation findLocation(String mn, String rn) {
+        return findLocation("/" + mn + "/" + rn);
     }
 
-    public ImageLocation findLocation(byte[] name) {
-        return findLocation(new UTF8String(name));
-    }
+    public synchronized ImageLocation findLocation(String name) {
+        // Details of the algorithm used here can be found in
+        // jdk.tools.jlink.internal.PerfectHashBuilder.
+        byte[] bytes = ImageStringsReader.mutf8FromString(name);
+        int count = header.getTableLength();
+        int index = redirect.get(ImageStringsReader.hashCode(bytes) % count);
 
-    public synchronized ImageLocation findLocation(UTF8String name) {
-        return substrate.findLocation(name, strings);
+        if (index < 0) {
+            // index is twos complement of location attributes index.
+            index = -index - 1;
+        } else if (index > 0) {
+            // index is hash seed needed to compute location attributes index.
+            index = ImageStringsReader.hashCode(bytes, index) % count;
+        } else {
+            // No entry.
+            return null;
+        }
+
+        long[] attributes = getAttributes(offsets.get(index));
+
+        ImageLocation imageLocation = new ImageLocation(attributes, stringsReader);
+
+        if (!imageLocation.verify(name)) {
+            return null;
+        }
+
+        return imageLocation;
     }
 
     public String[] getEntryNames() {
-        return IntStream.of(substrate.attributeOffsets())
+        int[] attributeOffsets = new int[offsets.capacity()];
+        offsets.get(attributeOffsets);
+        return IntStream.of(attributeOffsets)
                         .filter(o -> o != 0)
-                        .mapToObj(o -> ImageLocation.readFrom(this, o).getFullNameString())
+                        .mapToObj(o -> ImageLocation.readFrom(this, o).getFullName())
                         .sorted()
                         .toArray(String[]::new);
     }
 
-    protected ImageLocation[] getAllLocations(boolean sorted) {
-        return IntStream.of(substrate.attributeOffsets())
-                        .filter(o -> o != 0)
-                        .mapToObj(o -> ImageLocation.readFrom(this, o))
-                        .sorted(Comparator.comparing(ImageLocation::getFullNameString))
-                        .toArray(ImageLocation[]::new);
-    }
-
-    private IntBuffer getIndexIntBuffer(long offset, long size)
-            throws IOException {
-        ByteBuffer buffer = substrate.getIndexBuffer(offset, size);
-        buffer.order(byteOrder);
-
-        return buffer.asIntBuffer();
-    }
-
     ImageLocation getLocation(int offset) {
         return ImageLocation.readFrom(this, offset);
     }
 
     public long[] getAttributes(int offset) {
-        return substrate.getAttributes(offset);
+        ByteBuffer buffer = slice(locations, offset, locations.limit() - offset);
+        return ImageLocation.decompress(buffer);
     }
 
     public String getString(int offset) {
-        return getUTF8String(offset).toString();
+        ByteBuffer buffer = slice(strings, offset, strings.limit() - offset);
+        return ImageStringsReader.stringFromByteBuffer(buffer);
     }
 
-    public UTF8String getUTF8String(int offset) {
-        return new UTF8String(substrate.getStringBytes(offset));
-    }
-
-    private byte[] getBufferBytes(ByteBuffer buffer, long size) {
-        assert size < Integer.MAX_VALUE;
-        byte[] bytes = new byte[(int)size];
+    private byte[] getBufferBytes(ByteBuffer buffer) {
+        byte[] bytes = new byte[buffer.limit()];
         buffer.get(bytes);
 
         return bytes;
     }
 
-    private byte[] getBufferBytes(long offset, long size) {
-        ByteBuffer buffer = substrate.getDataBuffer(offset, size);
-
-        return getBufferBytes(buffer, size);
-    }
+    private ByteBuffer readBuffer(long offset, long size) {
+        if (offset < 0 || Integer.MAX_VALUE <= offset) {
+            throw new IndexOutOfBoundsException("offset");
+        }
 
-    public byte[] getResource(ImageLocation loc) {
-        long offset = loc.getContentOffset();
-        long compressedSize = loc.getCompressedSize();
-        long uncompressedSize = loc.getUncompressedSize();
-        assert compressedSize < Integer.MAX_VALUE;
-        assert uncompressedSize < Integer.MAX_VALUE;
-
-        if (substrate.supportsDataBuffer() && compressedSize == 0) {
-            return getBufferBytes(offset, uncompressedSize);
+        if (size < 0 || Integer.MAX_VALUE <= size) {
+            throw new IndexOutOfBoundsException("size");
         }
 
-        ByteBuffer uncompressedBuffer = ImageBufferCache.getBuffer(uncompressedSize);
-        boolean isRead;
+        if (MAP_ALL) {
+            ByteBuffer buffer = slice(memoryMap, (int)offset, (int)size);
+            buffer.order(ByteOrder.BIG_ENDIAN);
 
-        if (compressedSize != 0) {
-            ByteBuffer compressedBuffer = ImageBufferCache.getBuffer(compressedSize);
-            isRead = substrate.read(offset, compressedBuffer, compressedSize,
-                                          uncompressedBuffer, uncompressedSize);
-            ImageBufferCache.releaseBuffer(compressedBuffer);
+            return buffer;
         } else {
-            isRead = substrate.read(offset, uncompressedBuffer, uncompressedSize);
-        }
+            ByteBuffer buffer = ImageBufferCache.getBuffer(size);
+            int read = 0;
+
+            try {
+                if (channel == null) {
+                    throw new InternalError("Image file channel not open");
+                }
 
-        byte[] bytes = isRead ? getBufferBytes(uncompressedBuffer,
-                                               uncompressedSize) : null;
+                read = channel.read(buffer, offset);
+                buffer.rewind();
+            } catch (IOException ex) {
+                throw new RuntimeException(ex);
+            }
 
-        ImageBufferCache.releaseBuffer(uncompressedBuffer);
+            if (read != size) {
+                ImageBufferCache.releaseBuffer(buffer);
+            }
 
-        return bytes;
+            return buffer;
+        }
     }
 
     public byte[] getResource(String name) {
@@ -211,42 +316,54 @@
         return location != null ? getResource(location) : null;
     }
 
+    public byte[] getResource(ImageLocation loc) {
+        ByteBuffer buffer = getResourceBuffer(loc);
+
+        if (buffer != null) {
+            byte[] bytes = getBufferBytes(buffer);
+            ImageBufferCache.releaseBuffer(buffer);
+
+            return bytes;
+        }
+
+        return null;
+    }
+
     public ByteBuffer getResourceBuffer(ImageLocation loc) {
-        long offset = loc.getContentOffset();
+        long offset = loc.getContentOffset() + indexSize;
         long compressedSize = loc.getCompressedSize();
         long uncompressedSize = loc.getUncompressedSize();
-        assert compressedSize < Integer.MAX_VALUE;
-        assert uncompressedSize < Integer.MAX_VALUE;
 
-        if (substrate.supportsDataBuffer() && compressedSize == 0) {
-            return substrate.getDataBuffer(offset, uncompressedSize);
+        if (compressedSize < 0 || Integer.MAX_VALUE < compressedSize) {
+            throw new IndexOutOfBoundsException("Compressed size");
         }
 
-        ByteBuffer uncompressedBuffer = ImageBufferCache.getBuffer(uncompressedSize);
-        boolean isRead;
-
-        if (compressedSize != 0) {
-            ByteBuffer compressedBuffer = ImageBufferCache.getBuffer(compressedSize);
-            isRead = substrate.read(offset, compressedBuffer, compressedSize,
-                                          uncompressedBuffer, uncompressedSize);
-            ImageBufferCache.releaseBuffer(compressedBuffer);
-        } else {
-            isRead = substrate.read(offset, uncompressedBuffer, uncompressedSize);
+        if (uncompressedSize < 0 || Integer.MAX_VALUE < uncompressedSize) {
+            throw new IndexOutOfBoundsException("Uncompressed size");
         }
 
-        if (isRead) {
-            return uncompressedBuffer;
+        if (compressedSize == 0) {
+            return readBuffer(offset, uncompressedSize);
         } else {
-            ImageBufferCache.releaseBuffer(uncompressedBuffer);
+            ByteBuffer buffer = readBuffer(offset, compressedSize);
+
+            if (buffer != null) {
+                byte[] bytesIn = getBufferBytes(buffer);
+                ImageBufferCache.releaseBuffer(buffer);
+                byte[] bytesOut;
 
-            return null;
+                try {
+                    bytesOut = decompressor.decompressResource(byteOrder,
+                            (int strOffset) -> getString(strOffset), bytesIn);
+                } catch (IOException ex) {
+                    throw new RuntimeException(ex);
+                }
+
+                return ByteBuffer.wrap(bytesOut);
+            }
         }
-    }
 
-    public ByteBuffer getResourceBuffer(String name) {
-        ImageLocation location = findLocation(name);
-
-        return location != null ? getResourceBuffer(location) : null;
+        return null;
     }
 
     public InputStream getResourceStream(ImageLocation loc) {
@@ -254,10 +371,4 @@
 
         return new ByteArrayInputStream(bytes);
     }
-
-    public InputStream getResourceStream(String name) {
-        ImageLocation location = findLocation(name);
-
-        return location != null ? getResourceStream(location) : null;
-    }
 }
--- a/src/java.base/share/classes/jdk/internal/jimage/BasicImageWriter.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,195 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
-*/
-
-package jdk.internal.jimage;
-
-import java.nio.ByteOrder;
-import java.util.ArrayList;
-import java.util.List;
-
-public final class BasicImageWriter {
-
-    public static final String IMAGE_EXT = ".jimage";
-    public static final String BOOT_NAME = "bootmodules";
-    public static final String BOOT_IMAGE_NAME = BOOT_NAME + IMAGE_EXT;
-
-    private static final int RETRY_LIMIT = 1000;
-
-    private ByteOrder byteOrder;
-    private ImageStringsWriter strings;
-    private int length;
-    private int[] redirect;
-    private ImageLocationWriter[] locations;
-    private List<ImageLocationWriter> input;
-    private ImageStream headerStream;
-    private ImageStream redirectStream;
-    private ImageStream locationOffsetStream;
-    private ImageStream locationStream;
-    private ImageStream allIndexStream;
-
-    public BasicImageWriter() {
-        this(ByteOrder.nativeOrder());
-    }
-
-    public BasicImageWriter(ByteOrder byteOrder) {
-        this.byteOrder = byteOrder;
-        this.input = new ArrayList<>();
-        this.strings = new ImageStringsWriter();
-        this.headerStream = new ImageStream(byteOrder);
-        this.redirectStream = new ImageStream(byteOrder);
-        this.locationOffsetStream = new ImageStream(byteOrder);
-        this.locationStream = new ImageStream(byteOrder);
-        this.allIndexStream = new ImageStream(byteOrder);
-    }
-
-    public ByteOrder getByteOrder() {
-        return byteOrder;
-    }
-
-    public int addString(String string) {
-        return addString(new UTF8String(string));
-    }
-
-    public int addString(UTF8String string) {
-        return strings.add(string);
-    }
-
-    public String getString(int offset) {
-        UTF8String utf8 = strings.get(offset);
-        return utf8 != null? utf8.toString() : null;
-    }
-
-    public void addLocation(String fullname, long contentOffset,
-            long compressedSize, long uncompressedSize) {
-        ImageLocationWriter location =
-                ImageLocationWriter.newLocation(new UTF8String(fullname), strings,
-                        contentOffset, compressedSize, uncompressedSize);
-        input.add(location);
-        length++;
-    }
-
-    ImageLocationWriter[] getLocations() {
-        return locations;
-    }
-
-    int getLocationsCount() {
-        return input.size();
-    }
-
-    private void generatePerfectHash() {
-        PerfectHashBuilder<ImageLocationWriter> builder =
-            new PerfectHashBuilder<>(
-                new PerfectHashBuilder.Entry<ImageLocationWriter>().getClass(),
-                new PerfectHashBuilder.Bucket<ImageLocationWriter>().getClass());
-
-        input.forEach((location) -> {
-            builder.put(location.getFullName(), location);
-        });
-
-        builder.generate();
-
-        length = builder.getCount();
-        redirect = builder.getRedirect();
-        PerfectHashBuilder.Entry<ImageLocationWriter>[] order = builder.getOrder();
-        locations = new ImageLocationWriter[length];
-
-        for (int i = 0; i < length; i++) {
-            locations[i] = order[i].getValue();
-        }
-    }
-
-    private void prepareStringBytes() {
-        strings.getStream().align(2);
-    }
-
-    private void prepareRedirectBytes() {
-        for (int i = 0; i < length; i++) {
-            redirectStream.putInt(redirect[i]);
-        }
-    }
-
-    private void prepareLocationBytes() {
-        // Reserve location offset zero for empty locations
-        locationStream.put(ImageLocationWriter.ATTRIBUTE_END << 3);
-
-        for (int i = 0; i < length; i++) {
-            ImageLocationWriter location = locations[i];
-
-            if (location != null) {
-                location.writeTo(locationStream);
-            }
-        }
-
-        locationStream.align(2);
-    }
-
-    private void prepareOffsetBytes() {
-        for (int i = 0; i < length; i++) {
-            ImageLocationWriter location = locations[i];
-            int offset = location != null ? location.getLocationOffset() : 0;
-            locationOffsetStream.putInt(offset);
-        }
-    }
-
-    private void prepareHeaderBytes() {
-        ImageHeader header = new ImageHeader(input.size(), length,
-                locationStream.getSize(), strings.getSize());
-        header.writeTo(headerStream);
-    }
-
-    private void prepareTableBytes() {
-        allIndexStream.put(headerStream);
-        allIndexStream.put(redirectStream);
-        allIndexStream.put(locationOffsetStream);
-        allIndexStream.put(locationStream);
-        allIndexStream.put(strings.getStream());
-    }
-
-    public byte[] getBytes() {
-        if (allIndexStream.getSize() == 0) {
-            generatePerfectHash();
-            prepareStringBytes();
-            prepareRedirectBytes();
-            prepareLocationBytes();
-            prepareOffsetBytes();
-            prepareHeaderBytes();
-            prepareTableBytes();
-        }
-
-        return allIndexStream.toArray();
-    }
-
-    ImageLocationWriter find(UTF8String key) {
-        int index = redirect[key.hashCode() % length];
-
-        if (index < 0) {
-            index = -index - 1;
-        } else {
-            index = key.hashCode(index) % length;
-        }
-
-        return locations[index];
-    }
-}
--- a/src/java.base/share/classes/jdk/internal/jimage/ExternalFilesWriter.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,105 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.internal.jimage;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UncheckedIOException;
-import java.nio.file.FileAlreadyExistsException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.function.Consumer;
-import jdk.internal.jimage.Archive.Entry;
-
-/**
- * A Consumer suitable for processing non resources Archive Entry and writing it to the
- * appropriate location.
- */
-class ExternalFilesWriter implements Consumer<Entry> {
-    private final Path root;
-
-    ExternalFilesWriter(Path root) {
-        this.root = root;
-    }
-
-    @Override
-    public void accept(Entry entry) {
-        String name = entry.path();
-        try {
-            String filename = entry.path();
-            try (InputStream in = entry.stream()) {
-                switch (entry.type()) {
-                    case NATIVE_LIB:
-                        writeEntry(in, destFile(nativeDir(filename), filename));
-                        break;
-                    case NATIVE_CMD:
-                        Path path = destFile("bin", filename);
-                        writeEntry(in, path);
-                        path.toFile().setExecutable(true, false);
-                        break;
-                    case CONFIG:
-                        writeEntry(in, destFile("conf", filename));
-                        break;
-                    case MODULE_NAME:
-                        // skip
-                        break;
-                    case SERVICE:
-                        //throw new UnsupportedOperationException(name + " in " + zipfile.toString()); //TODO
-                        throw new UnsupportedOperationException(name + " in " + name);
-                    default:
-                        //throw new InternalError("unexpected entry: " + name + " " + zipfile.toString()); //TODO
-                        throw new InternalError("unexpected entry: " + name + " " + name);
-                }
-            }
-        } catch (FileAlreadyExistsException x) {
-            System.err.println("File already exists (skipped) " + name);
-        } catch (IOException x) {
-            throw new UncheckedIOException(x);
-        }
-    }
-
-    private Path destFile(String dir, String filename) {
-        return root.resolve(dir).resolve(filename);
-    }
-
-    private void writeEntry(InputStream in, Path dstFile) throws IOException {
-        Files.createDirectories(dstFile.getParent());
-        Files.copy(in, dstFile);
-    }
-
-    private static String nativeDir(String filename) {
-        if (System.getProperty("os.name").startsWith("Windows")) {
-            if (filename.endsWith(".dll") || filename.endsWith(".diz")
-                || filename.endsWith(".pdb") || filename.endsWith(".map")) {
-                return "bin";
-            } else {
-                return "lib";
-            }
-        } else {
-            return "lib";
-        }
-    }
-}
--- a/src/java.base/share/classes/jdk/internal/jimage/ImageBufferCache.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/jimage/ImageBufferCache.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,13 @@
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 
+/**
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
+ */
 class ImageBufferCache {
     private static final int MAX_FREE_BUFFERS = 3;
     private static final int LARGE_BUFFER = 0x10000;
@@ -37,7 +44,10 @@
     private boolean isUsed;
 
     static ByteBuffer getBuffer(long size) {
-        assert size < Integer.MAX_VALUE;
+        if (size < 0 || Integer.MAX_VALUE < size) {
+            throw new IndexOutOfBoundsException("size");
+        }
+
         ByteBuffer buffer = null;
 
         if (size > LARGE_BUFFER) {
@@ -84,7 +94,7 @@
     static void releaseBuffer(ByteBuffer buffer) {
         ArrayList<ImageBufferCache> buffers = threadLocal.get();
 
-        if (buffers == null ) {
+        if (buffers == null) {
             return;
         }
 
--- a/src/java.base/share/classes/jdk/internal/jimage/ImageFileCreator.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,381 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.internal.jimage;
-
-import java.io.BufferedOutputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.function.Consumer;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import jdk.internal.jimage.Archive.Entry;
-import jdk.internal.jimage.Archive.Entry.EntryType;
-import static jdk.internal.jimage.BasicImageWriter.BOOT_NAME;
-import static jdk.internal.jimage.BasicImageWriter.IMAGE_EXT;
-
-/**
- * An image (native endian.)
- * <pre>{@code
- * {
- *   u4 magic;
- *   u2 major_version;
- *   u2 minor_version;
- *   u4 resource_count;
- *   u4 table_length;
- *   u4 location_attributes_size;
- *   u4 strings_size;
- *   u4 redirect[table_length];
- *   u4 offsets[table_length];
- *   u1 location_attributes[location_attributes_size];
- *   u1 strings[strings_size];
- *   u1 content[if !EOF];
- * }
- * }</pre>
- */
-public final class ImageFileCreator {
-    private final Path root;
-    private final Path mdir;
-    private final Map<String, List<Entry>> entriesForModule = new HashMap<>();
-    private ImageFileCreator(Path path) {
-        this.root = path;
-        this.mdir = root.resolve(path.getFileSystem().getPath("lib", "modules"));
-    }
-
-    public static ImageFileCreator create(Path output,
-            Set<Archive> archives)
-            throws IOException {
-        return create(output, BOOT_NAME, archives, ByteOrder.nativeOrder());
-    }
-
-    public static ImageFileCreator create(Path output,
-            Set<Archive> archives,
-            ByteOrder byteOrder)
-            throws IOException {
-        return create(output, BOOT_NAME, archives, byteOrder);
-    }
-
-    public static ImageFileCreator create(Path output,
-                                   String fileName,
-                                   Set<Archive> archives,
-                                   ByteOrder byteOrder)
-        throws IOException
-    {
-        ImageFileCreator image = new ImageFileCreator(output);
-        // get all entries
-        Map<String, Set<String>> modulePackagesMap = new HashMap<>();
-        image.readAllEntries(modulePackagesMap, archives);
-        // write to modular image
-        image.writeImage(fileName, modulePackagesMap, archives, byteOrder);
-        return image;
-    }
-
-    private void readAllEntries(Map<String, Set<String>> modulePackagesMap,
-                                  Set<Archive> archives) {
-        archives.stream().forEach((archive) -> {
-            Map<Boolean, List<Entry>> es;
-            try(Stream<Entry> entries = archive.entries()) {
-                es = entries.collect(Collectors.partitioningBy(n -> n.type()
-                        == EntryType.CLASS_OR_RESOURCE));
-            }
-            String mn = archive.moduleName();
-            List<Entry> all = new ArrayList<>();
-            all.addAll(es.get(false));
-            all.addAll(es.get(true));
-            entriesForModule.put(mn, all);
-            // Extract package names
-            Set<String> pkgs = es.get(true).stream().map(Entry::name)
-                    .filter(n -> isClassPackage(n))
-                    .map(ImageFileCreator::toPackage)
-                    .collect(Collectors.toSet());
-            modulePackagesMap.put(mn, pkgs);
-        });
-    }
-
-    public static boolean isClassPackage(String path) {
-        return path.endsWith(".class");
-    }
-
-    public static boolean isResourcePackage(String path) {
-        path = path.substring(1);
-        path = path.substring(path.indexOf("/")+1);
-        return !path.startsWith("META-INF/");
-    }
-
-    public static void recreateJimage(Path jimageFile,
-            String jdataName,
-            Set<Archive> archives,
-            Map<String, Set<String>> modulePackages)
-            throws IOException {
-        Map<String, List<Entry>> entriesForModule
-                = archives.stream().collect(Collectors.toMap(
-                                Archive::moduleName,
-                                a -> {
-                                    try(Stream<Entry> entries = a.entries()) {
-                                        return entries.collect(Collectors.toList());
-                                    }
-                                }));
-        Map<String, Archive> nameToArchive
-                = archives.stream()
-                .collect(Collectors.toMap(Archive::moduleName, Function.identity()));
-        ByteOrder order = ByteOrder.nativeOrder();
-        ResourcePoolImpl resources = createResources(modulePackages, nameToArchive,
-                (Entry t) -> {
-            throw new UnsupportedOperationException("Not supported, no external file "
-                    + "in a jimage file");
-        }, entriesForModule, order);
-        generateJImage(jimageFile, jdataName, resources, order);
-    }
-
-    private void writeImage(String fileName,
-            Map<String, Set<String>> modulePackagesMap,
-            Set<Archive> archives,
-            ByteOrder byteOrder)
-            throws IOException {
-        Files.createDirectories(mdir);
-        ExternalFilesWriter filesWriter = new ExternalFilesWriter(root);
-        // name to Archive file
-        Map<String, Archive> nameToArchive
-                = archives.stream()
-                .collect(Collectors.toMap(Archive::moduleName, Function.identity()));
-        ResourcePoolImpl resources = createResources(modulePackagesMap,
-                nameToArchive, filesWriter,
-                entriesForModule, byteOrder);
-        generateJImage(mdir.resolve(fileName + IMAGE_EXT), fileName, resources,
-                byteOrder);
-    }
-
-    private static void generateJImage(Path img,
-            String fileName,
-            ResourcePoolImpl resources,
-            ByteOrder byteOrder
-    ) throws IOException {
-        BasicImageWriter writer = new BasicImageWriter(byteOrder);
-
-        Map<String, Set<String>> modulePackagesMap = resources.getModulePackages();
-
-        try (OutputStream fos = Files.newOutputStream(img);
-                BufferedOutputStream bos = new BufferedOutputStream(fos);
-                DataOutputStream out = new DataOutputStream(bos)) {
-            Set<String> duplicates = new HashSet<>();
-            ImageModuleDataWriter moduleData =
-            ImageModuleDataWriter.buildModuleData(writer, modulePackagesMap);
-            moduleData.addLocation(fileName, writer);
-            long offset = moduleData.size();
-
-            List<ResourcePool.Resource> content = new ArrayList<>();
-            List<String> paths = new ArrayList<>();
-                 // the order of traversing the resources and the order of
-            // the module content being written must be the same
-            for (ResourcePool.Resource res : resources.getResources()) {
-                String path = res.getPath();
-                int index = path.indexOf("/META-INF/");
-                if (index != -1) {
-                    path = path.substring(index + 1);
-                }
-
-                content.add(res);
-                long uncompressedSize = res.getLength();
-                long compressedSize = 0;
-                if (res instanceof ResourcePool.CompressedResource) {
-                    ResourcePool.CompressedResource comp =
-                            (ResourcePool.CompressedResource) res;
-                    compressedSize = res.getLength();
-                    uncompressedSize = comp.getUncompressedSize();
-                }
-                long onFileSize = res.getLength();
-
-                if (duplicates.contains(path)) {
-                    System.err.format("duplicate resource \"%s\", skipping%n",
-                            path);
-                     // TODO Need to hang bytes on resource and write
-                    // from resource not zip.
-                    // Skipping resource throws off writing from zip.
-                    offset += onFileSize;
-                    continue;
-                }
-                duplicates.add(path);
-                writer.addLocation(path, offset, compressedSize, uncompressedSize);
-                paths.add(path);
-                offset += onFileSize;
-            }
-
-            ImageResourcesTree tree = new ImageResourcesTree(offset, writer, paths);
-
-            // write header and indices
-            byte[] bytes = writer.getBytes();
-            out.write(bytes, 0, bytes.length);
-
-            // write module meta data
-            moduleData.writeTo(out);
-
-            // write module content
-            for(ResourcePool.Resource res : content) {
-                byte[] buf = res.getByteArray();
-                out.write(buf, 0, buf.length);
-            }
-
-            tree.addContent(out);
-        }
-    }
-
-    private static ResourcePoolImpl createResources(Map<String, Set<String>> modulePackagesMap,
-            Map<String, Archive> nameToArchive,
-            Consumer<Entry> externalFileHandler,
-            Map<String, List<Entry>> entriesForModule,
-            ByteOrder byteOrder) throws IOException {
-        ResourcePoolImpl resources = new ResourcePoolImpl(byteOrder);
-        // Doesn't contain META-INF
-        Set<String> mods = modulePackagesMap.keySet();
-        for (String mn : mods) {
-            for (Entry entry : entriesForModule.get(mn)) {
-                String path = entry.name();
-                if (entry.type() == EntryType.CLASS_OR_RESOURCE) {
-                    if (!entry.path().endsWith(BOOT_NAME)) {
-                        try (InputStream stream = entry.stream()) {
-                            byte[] bytes = readAllBytes(stream);
-                            path = "/" + mn + "/" + path;
-                            try {
-                                resources.addResource(new ResourcePool.Resource(path,
-                                        ByteBuffer.wrap(bytes)));
-                            } catch (Exception ex) {
-                                throw new IOException(ex);
-                            }
-                        }
-                    }
-                } else {
-                    externalFileHandler.accept(entry);
-                }
-            }
-            // Done with this archive, close it.
-            Archive archive = nameToArchive.get(mn);
-            archive.close();
-        }
-        // Fix for 8136365. Do we have an archive with module name "META-INF"?
-        // If yes, we are recreating a jimage.
-        // This is a workaround for META-INF being at the top level of resource path
-        String mn = "META-INF";
-        Archive archive = nameToArchive.get(mn);
-        if (archive != null) {
-            try {
-                for (Entry entry : entriesForModule.get(mn)) {
-                    String path = entry.name();
-                    try (InputStream stream = entry.stream()) {
-                        byte[] bytes = readAllBytes(stream);
-                        path = mn + "/" + path;
-                        try {
-                            resources.addResource(new ResourcePool.Resource(path,
-                                    ByteBuffer.wrap(bytes)));
-                        } catch (Exception ex) {
-                            throw new IOException(ex);
-                        }
-                    }
-                }
-            } finally {
-                // Done with this archive, close it.
-                archive.close();
-            }
-        }
-        return resources;
-    }
-
-    private static final int BUF_SIZE = 8192;
-
-    private static byte[] readAllBytes(InputStream is) throws IOException {
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        byte[] buf = new byte[BUF_SIZE];
-        while (true) {
-            int n = is.read(buf);
-            if (n < 0) {
-                break;
-            }
-            baos.write(buf, 0, n);
-        }
-        return baos.toByteArray();
-    }
-
-    /**
-     * Helper method that splits a Resource path onto 3 items: module, parent
-     * and resource name.
-     *
-     * @param path
-     * @return An array containing module, parent and name.
-     */
-    public static String[] splitPath(String path) {
-        Objects.requireNonNull(path);
-        String noRoot = path.substring(1);
-        int pkgStart = noRoot.indexOf("/");
-        String module = noRoot.substring(0, pkgStart);
-        List<String> result = new ArrayList<>();
-        result.add(module);
-        String pkg = noRoot.substring(pkgStart + 1);
-        String resName;
-        int pkgEnd = pkg.lastIndexOf("/");
-        if (pkgEnd == -1) { // No package.
-            resName = pkg;
-        } else {
-            resName = pkg.substring(pkgEnd + 1);
-        }
-
-        pkg = toPackage(pkg, false);
-        result.add(pkg);
-        result.add(resName);
-
-        String[] array = new String[result.size()];
-        return result.toArray(array);
-    }
-
-    private static String toPackage(String name) {
-        String pkg = toPackage(name, true);
-        return pkg;
-    }
-
-    private static String toPackage(String name, boolean log) {
-        int index = name.lastIndexOf('/');
-        if (index > 0) {
-            return name.substring(0, index).replace('/', '.');
-        } else {
-            // ## unnamed package
-            if (log) {
-                System.err.format("Warning: %s in unnamed package%n", name);
-            }
-            return "";
-        }
-    }
-}
--- a/src/java.base/share/classes/jdk/internal/jimage/ImageHeader.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/jimage/ImageHeader.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,11 +28,18 @@
 import java.nio.ByteBuffer;
 import java.nio.IntBuffer;
 
+/**
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
+ */
 public final class ImageHeader {
     public static final int MAGIC = 0xCAFEDADA;
-    public static final int BADMAGIC = 0xDADAFECA;
     public static final int MAJOR_VERSION = 1;
     public static final int MINOR_VERSION = 0;
+    private static final int HEADER_SLOTS = 7;
 
     private final int magic;
     private final int majorVersion;
@@ -64,10 +71,14 @@
     }
 
     public static int getHeaderSize() {
-       return 7 * 4;
+       return HEADER_SLOTS * 4;
     }
 
     static ImageHeader readFrom(IntBuffer buffer) {
+        if (buffer.capacity() != HEADER_SLOTS) {
+            throw new InternalError("jimage header not the correct size");
+        }
+
         int magic = buffer.get(0);
         int version = buffer.get(1);
         int majorVersion = version >>> 16;
@@ -82,7 +93,7 @@
             resourceCount, tableLength, locationsSize, stringsSize);
     }
 
-    void writeTo(ImageStream stream) {
+    public void writeTo(ImageStream stream) {
         stream.ensure(getHeaderSize());
         writeTo(stream.getBuffer());
     }
--- a/src/java.base/share/classes/jdk/internal/jimage/ImageJavaSubstrate.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,242 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.internal.jimage;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.IntBuffer;
-import java.nio.channels.FileChannel;
-import java.nio.file.Paths;
-import static java.nio.file.StandardOpenOption.READ;
-import jdk.internal.jimage.decompressor.Decompressor;
-
-final class ImageJavaSubstrate implements ImageSubstrate {
-
-    private final String imagePath;
-    private final ByteOrder byteOrder;
-    private final FileChannel channel;
-    private final ImageHeader header;
-    private final long indexSize;
-    private final int[] redirect;
-    private final int[] offsets;
-    private final byte[] locations;
-    private final byte[] strings;
-
-    private final Decompressor decompressor = new Decompressor();
-
-  private ImageJavaSubstrate(String imagePath, ByteOrder byteOrder)
-          throws IOException {
-        this.imagePath = imagePath;
-        this.byteOrder = byteOrder;
-        channel = FileChannel.open(Paths.get(imagePath), READ);
-
-        int headerSize = ImageHeader.getHeaderSize();
-        ByteBuffer buffer = getIndexBuffer(0, headerSize);
-        header = ImageHeader.readFrom(buffer.asIntBuffer());
-
-        if (header.getMagic() != ImageHeader.MAGIC ||
-            header.getMajorVersion() != ImageHeader.MAJOR_VERSION ||
-            header.getMinorVersion() != ImageHeader.MINOR_VERSION) {
-            throw new IOException("Image not found \"" + imagePath + "\"");
-        }
-
-        indexSize = header.getIndexSize();
-
-        redirect = readIntegers(header.getRedirectOffset(),
-                                header.getRedirectSize());
-        offsets = readIntegers(header.getOffsetsOffset(),
-                               header.getOffsetsSize());
-        locations = readBytes(header.getLocationsOffset(),
-                              header.getLocationsSize());
-        strings = readBytes(header.getStringsOffset(),
-                            header.getStringsSize());
-    }
-
-    static ImageSubstrate openImage(String imagePath, ByteOrder byteOrder)
-            throws IOException {
-        return new ImageJavaSubstrate(imagePath, byteOrder);
-    }
-
-    @Override
-    public void close() {
-        try {
-            channel.close();
-        } catch (IOException ex) {
-            // Mostly harmless
-        }
-    }
-
-    @Override
-    public boolean supportsDataBuffer() {
-        return false;
-    }
-
-    private int[] readIntegers(long offset, long size) {
-        assert size < Integer.MAX_VALUE;
-        IntBuffer buffer = readBuffer(offset, size).asIntBuffer();
-        int[] integers = new int[(int)size / 4];
-        buffer.get(integers);
-
-        return integers;
-    }
-
-    private byte[] readBytes(long offset, long size) {
-        assert size < Integer.MAX_VALUE;
-        ByteBuffer buffer = readBuffer(offset, size);
-        byte[] bytes = new byte[(int)size];
-        buffer.get(bytes);
-
-        return bytes;
-    }
-
-    private ByteBuffer readBuffer(long offset, long size) {
-        assert size < Integer.MAX_VALUE;
-        ByteBuffer buffer = ByteBuffer.allocate((int)size);
-        buffer.order(byteOrder);
-
-        if (!readBuffer(buffer, offset, size)) {
-            return null;
-        }
-
-        return buffer;
-    }
-
-    private boolean readBuffer(ByteBuffer buffer, long offset, long size) {
-        assert size < Integer.MAX_VALUE;
-        assert buffer.limit() == size;
-        int read = 0;
-
-        try {
-            read = channel.read(buffer, offset);
-            buffer.rewind();
-        } catch (IOException ex) {
-            // fall thru
-        }
-
-        return read == size;
-    }
-
-    @Override
-    public ByteBuffer getIndexBuffer(long offset, long size) {
-        assert size < Integer.MAX_VALUE;
-        return readBuffer(offset, size);
-    }
-
-    @Override
-    public ByteBuffer getDataBuffer(long offset, long size) {
-        assert size < Integer.MAX_VALUE;
-        return getIndexBuffer(indexSize + offset, size);
-    }
-
-    @Override
-    public boolean read(long offset,
-                 ByteBuffer compressedBuffer, long compressedSize,
-                 ByteBuffer uncompressedBuffer, long uncompressedSize) {
-        assert compressedSize < Integer.MAX_VALUE;
-        assert uncompressedSize < Integer.MAX_VALUE;
-        boolean isRead = readBuffer(compressedBuffer,
-                                    indexSize + offset, compressedSize);
-        if (isRead) {
-            byte[] bytesIn = new byte[(int)compressedSize];
-            compressedBuffer.get(bytesIn);
-            byte[] bytesOut;
-            try {
-                bytesOut = decompressor.decompressResource(byteOrder, (int strOffset) -> {
-                    return new UTF8String(getStringBytes(strOffset)).toString();
-                }, bytesIn);
-            } catch (IOException ex) {
-                throw new RuntimeException(ex);
-            }
-            uncompressedBuffer.put(bytesOut);
-            uncompressedBuffer.rewind();
-        }
-
-        return isRead;
-    }
-
-    @Override
-    public boolean read(long offset,
-                 ByteBuffer uncompressedBuffer, long uncompressedSize) {
-        assert uncompressedSize < Integer.MAX_VALUE;
-        boolean isRead = readBuffer(uncompressedBuffer,
-                                    indexSize + offset, uncompressedSize);
-
-        return isRead;
-    }
-
-    @Override
-    public byte[] getStringBytes(int offset) {
-        if (offset == 0) {
-            return new byte[0];
-        }
-
-        int length = strings.length - offset;
-
-        for (int i = offset; i < strings.length; i++) {
-            if (strings[i] == 0) {
-                length = i - offset;
-                break;
-            }
-        }
-
-        byte[] bytes = new byte[length];
-        System.arraycopy(strings, offset, bytes, 0, length);
-
-        return bytes;
-    }
-
-    @Override
-    public long[] getAttributes(int offset) {
-        return ImageLocationBase.decompress(locations, offset);
-    }
-
-    @Override
-    public ImageLocation findLocation(UTF8String name, ImageStringsReader strings) {
-        int count = header.getTableLength();
-        int index = redirect[name.hashCode() % count];
-
-        if (index < 0) {
-            index = -index - 1;
-        } else {
-            index = name.hashCode(index) % count;
-        }
-
-        long[] attributes = getAttributes(offsets[index]);
-
-        ImageLocation imageLocation = new ImageLocation(attributes, strings);
-
-        if (!imageLocation.verify(name)) {
-            return null;
-        }
-
-        return imageLocation;
-   }
-
-    @Override
-    public int[] attributeOffsets() {
-        return offsets;
-    }
-}
--- a/src/java.base/share/classes/jdk/internal/jimage/ImageLocation.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/jimage/ImageLocation.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,9 +25,228 @@
 
 package jdk.internal.jimage;
 
-public final class ImageLocation  extends ImageLocationBase {
-    ImageLocation(long[] attributes, ImageStringsReader strings) {
-        super(attributes, strings);
+import java.nio.ByteBuffer;
+
+/**
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
+ */
+public class ImageLocation {
+    public static final int ATTRIBUTE_END = 0;
+    public static final int ATTRIBUTE_MODULE = 1;
+    public static final int ATTRIBUTE_PARENT = 2;
+    public static final int ATTRIBUTE_BASE = 3;
+    public static final int ATTRIBUTE_EXTENSION = 4;
+    public static final int ATTRIBUTE_OFFSET = 5;
+    public static final int ATTRIBUTE_COMPRESSED = 6;
+    public static final int ATTRIBUTE_UNCOMPRESSED = 7;
+    public static final int ATTRIBUTE_COUNT = 8;
+
+    protected final long[] attributes;
+
+    protected final ImageStrings strings;
+
+    public ImageLocation(long[] attributes, ImageStrings strings) {
+        this.attributes = attributes;
+        this.strings = strings;
+    }
+
+    ImageStrings getStrings() {
+        return strings;
+    }
+
+    private static int attributeLength(int data) {
+        return (data & 0x7) + 1;
+    }
+
+    private static int attributeKind(int data) {
+        return data >>> 3;
+    }
+
+    static long[] decompress(ByteBuffer bytes) {
+        long[] attributes = new long[ATTRIBUTE_COUNT];
+
+        if (bytes != null) {
+            while (bytes.hasRemaining()) {
+                int data = bytes.get() & 0xFF;
+                int kind = attributeKind(data);
+
+                if (kind == ATTRIBUTE_END) {
+                    break;
+                }
+
+                if (kind < ATTRIBUTE_END || ATTRIBUTE_COUNT <= kind) {
+                    throw new InternalError("Invalid jimage attribute kind");
+                }
+
+                int length = attributeLength(data);
+                long value = 0;
+
+                for (int j = 0; j < length; j++) {
+                    value <<= 8;
+
+                    if (!bytes.hasRemaining()) {
+                        throw new InternalError("\"Missing jimage attribute datad");
+                    }
+
+                    value |= bytes.get() & 0xFF;
+                }
+
+                 attributes[kind] = value;
+            }
+        }
+
+        return attributes;
+    }
+
+    public static byte[] compress(long[] attributes) {
+        ImageStream stream = new ImageStream(16);
+
+        for (int kind = ATTRIBUTE_END + 1; kind < ATTRIBUTE_COUNT; kind++) {
+            long value = attributes[kind];
+
+            if (value != 0) {
+                int n = (63 - Long.numberOfLeadingZeros(value)) >> 3;
+                stream.put((kind << 3) | n);
+
+                for (int i = n; i >= 0; i--) {
+                    stream.put((int)(value >> (i << 3)));
+                }
+            }
+        }
+
+        stream.put(ATTRIBUTE_END << 3);
+
+        return stream.toArray();
+     }
+
+    public boolean verify(String name) {
+        return name.equals(getFullName());
+    }
+
+    long getAttribute(int kind) {
+        if (kind < ATTRIBUTE_END || ATTRIBUTE_COUNT <= kind) {
+            throw new InternalError("Invalid jimage attribute kind");
+        }
+
+        return attributes[kind];
+    }
+
+    String getAttributeString(int kind) {
+        if (kind < ATTRIBUTE_END || ATTRIBUTE_COUNT <= kind) {
+            throw new InternalError("Invalid jimage attribute kind");
+        }
+
+        return getStrings().get((int)attributes[kind]);
+    }
+
+    public String getModule() {
+        return getAttributeString(ATTRIBUTE_MODULE);
+    }
+
+    public int getModuleOffset() {
+        return (int)getAttribute(ATTRIBUTE_MODULE);
+    }
+
+    public String getBase() {
+        return getAttributeString(ATTRIBUTE_BASE);
+    }
+
+    public int getBaseOffset() {
+        return (int)getAttribute(ATTRIBUTE_BASE);
+    }
+
+    public String getParent() {
+        return getAttributeString(ATTRIBUTE_PARENT);
+    }
+
+    public int getParentOffset() {
+        return (int)getAttribute(ATTRIBUTE_PARENT);
+    }
+
+    public String getExtension() {
+        return getAttributeString(ATTRIBUTE_EXTENSION);
+    }
+
+    public int getExtensionOffset() {
+        return (int)getAttribute(ATTRIBUTE_EXTENSION);
+    }
+
+    public String getFullName() {
+        return getFullName(false);
+    }
+
+    public String getFullName(boolean modulesPrefix) {
+        StringBuilder builder = new StringBuilder();
+
+        if (getModuleOffset() != 0) {
+            if (modulesPrefix) {
+                builder.append("/modules");
+            }
+
+            builder.append('/');
+            builder.append(getModule());
+            builder.append('/');
+        }
+
+        if (getParentOffset() != 0) {
+            builder.append(getParent());
+            builder.append('/');
+        }
+
+        builder.append(getBase());
+
+        if (getExtensionOffset() != 0) {
+            builder.append('.');
+            builder.append(getExtension());
+        }
+
+        return builder.toString();
+    }
+
+    String buildName(boolean includeModule, boolean includeParent,
+            boolean includeName) {
+        StringBuilder builder = new StringBuilder();
+
+        if (includeModule && getModuleOffset() != 0) {
+            builder.append("/modules/");
+            builder.append(getModule());
+         }
+
+        if (includeParent && getParentOffset() != 0) {
+            builder.append('/');
+            builder.append(getParent());
+        }
+
+        if (includeName) {
+            if (includeModule || includeParent) {
+                builder.append('/');
+            }
+
+            builder.append(getBase());
+
+            if (getExtensionOffset() != 0) {
+                builder.append('.');
+                builder.append(getExtension());
+            }
+        }
+
+        return builder.toString();
+   }
+
+    public long getContentOffset() {
+        return getAttribute(ATTRIBUTE_OFFSET);
+    }
+
+    public long getCompressedSize() {
+        return getAttribute(ATTRIBUTE_COMPRESSED);
+    }
+
+    public long getUncompressedSize() {
+        return getAttribute(ATTRIBUTE_UNCOMPRESSED);
     }
 
     static ImageLocation readFrom(BasicImageReader reader, int offset) {
--- a/src/java.base/share/classes/jdk/internal/jimage/ImageLocationBase.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,264 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.internal.jimage;
-
-public class ImageLocationBase {
-    static final int ATTRIBUTE_END = 0;
-    static final int ATTRIBUTE_MODULE = 1;
-    static final int ATTRIBUTE_PARENT = 2;
-    static final int ATTRIBUTE_BASE = 3;
-    static final int ATTRIBUTE_EXTENSION = 4;
-    static final int ATTRIBUTE_OFFSET = 5;
-    static final int ATTRIBUTE_COMPRESSED = 6;
-    static final int ATTRIBUTE_UNCOMPRESSED = 7;
-    static final int ATTRIBUTE_COUNT = 8;
-
-    protected final long[] attributes;
-
-    protected final ImageStrings strings;
-
-    protected ImageLocationBase(long[] attributes, ImageStrings strings) {
-        this.attributes = attributes;
-        this.strings = strings;
-    }
-
-    ImageStrings getStrings() {
-        return strings;
-    }
-
-    private static int attributeLength(int data) {
-        return (data & 0x7) + 1;
-    }
-
-    private static int attributeKind(int data) {
-        return data >>> 3;
-    }
-
-    static long[] decompress(byte[] bytes) {
-        return decompress(bytes, 0);
-    }
-
-    static long[] decompress(byte[] bytes, int offset) {
-        long[] attributes = new long[ATTRIBUTE_COUNT];
-
-        if (bytes != null) {
-            for (int i = offset; i < bytes.length; ) {
-                int data = bytes[i++] & 0xFF;
-                int kind = attributeKind(data);
-
-                if (kind == ATTRIBUTE_END) {
-                    break;
-                }
-
-                assert ATTRIBUTE_END < kind &&
-                       kind < ATTRIBUTE_COUNT : "Invalid attribute kind";
-                int length = attributeLength(data);
-                long value = 0;
-
-                for (int j = 0; j < length; j++) {
-                    value <<= 8;
-                    value |= bytes[i++] & 0xFF;
-                }
-
-                 attributes[kind] = value;
-            }
-        }
-
-        return attributes;
-    }
-
-    static byte[] compress(long[] attributes) {
-        ImageStream stream = new ImageStream(16);
-
-        for (int kind = ATTRIBUTE_END + 1; kind < ATTRIBUTE_COUNT; kind++) {
-            long value = attributes[kind];
-
-            if (value != 0) {
-                int n = (63 - Long.numberOfLeadingZeros(value)) >> 3;
-                stream.put((kind << 3) | n);
-
-                for (int i = n; i >= 0; i--) {
-                    stream.put((int)(value >> (i << 3)));
-                }
-            }
-        }
-
-        stream.put(ATTRIBUTE_END << 3);
-
-        return stream.toArray();
-     }
-
-    public boolean verify(UTF8String name) {
-        return UTF8String.equals(getFullName(), name);
-    }
-
-    protected long getAttribute(int kind) {
-        assert ATTRIBUTE_END < kind &&
-               kind < ATTRIBUTE_COUNT : "Invalid attribute kind";
-
-        return attributes[kind];
-    }
-
-    protected UTF8String getAttributeUTF8String(int kind) {
-        assert ATTRIBUTE_END < kind &&
-               kind < ATTRIBUTE_COUNT : "Invalid attribute kind";
-
-        return getStrings().get((int)attributes[kind]);
-    }
-
-    protected String getAttributeString(int kind) {
-        return getAttributeUTF8String(kind).toString();
-    }
-
-    UTF8String getModule() {
-        return getAttributeUTF8String(ATTRIBUTE_MODULE);
-    }
-
-    public String getModuleString() {
-        return getModule().toString();
-    }
-
-    int getModuleOffset() {
-        return (int)getAttribute(ATTRIBUTE_MODULE);
-    }
-
-    UTF8String getBase() {
-        return getAttributeUTF8String(ATTRIBUTE_BASE);
-    }
-
-    public String getBaseString() {
-        return  getBase().toString();
-    }
-
-    int getBaseOffset() {
-        return (int)getAttribute(ATTRIBUTE_BASE);
-    }
-
-    UTF8String getParent() {
-        return getAttributeUTF8String(ATTRIBUTE_PARENT);
-    }
-
-    public String getParentString() {
-        return getParent().toString();
-    }
-
-    int getParentOffset() {
-        return (int)getAttribute(ATTRIBUTE_PARENT);
-    }
-
-    UTF8String getExtension() {
-        return getAttributeUTF8String(ATTRIBUTE_EXTENSION);
-    }
-
-    public String getExtensionString() {
-        return getExtension().toString();
-    }
-
-    int getExtensionOffset() {
-        return (int)getAttribute(ATTRIBUTE_EXTENSION);
-    }
-
-    UTF8String getFullName() {
-        return getFullName(false);
-    }
-
-    UTF8String getFullName(boolean modulesPrefix) {
-        // Note: Consider a UTF8StringBuilder.
-        UTF8String fullName = UTF8String.EMPTY_STRING;
-
-        if (getModuleOffset() != 0) {
-            fullName = fullName.concat(
-                // TODO The use of UTF8String.MODULES_STRING does not belong here.
-                modulesPrefix? UTF8String.MODULES_STRING :
-                               UTF8String.EMPTY_STRING,
-                UTF8String.SLASH_STRING,
-                getModule(),
-                UTF8String.SLASH_STRING);
-        }
-
-        if (getParentOffset() != 0) {
-            fullName = fullName.concat(getParent(),
-                                       UTF8String.SLASH_STRING);
-        }
-
-        fullName = fullName.concat(getBase());
-
-        if (getExtensionOffset() != 0) {
-                fullName = fullName.concat(UTF8String.DOT_STRING,
-                                           getExtension());
-        }
-
-        return fullName;
-    }
-
-    UTF8String buildName(boolean includeModule, boolean includeParent,
-            boolean includeName) {
-        // Note: Consider a UTF8StringBuilder.
-        UTF8String name = UTF8String.EMPTY_STRING;
-
-        if (includeModule && getModuleOffset() != 0) {
-            name = name.concat(UTF8String.MODULES_STRING,
-                               UTF8String.SLASH_STRING,
-                               getModule());
-        }
-
-        if (includeParent && getParentOffset() != 0) {
-            name = name.concat(UTF8String.SLASH_STRING,
-                                       getParent());
-        }
-
-        if (includeName) {
-            if (includeModule || includeParent) {
-                name = name.concat(UTF8String.SLASH_STRING);
-            }
-
-            name = name.concat(getBase());
-
-            if (getExtensionOffset() != 0) {
-                name = name.concat(UTF8String.DOT_STRING,
-                                           getExtension());
-            }
-        }
-
-        return name;
-    }
-
-    String getFullNameString() {
-        return getFullName().toString();
-    }
-
-    public long getContentOffset() {
-        return getAttribute(ATTRIBUTE_OFFSET);
-    }
-
-    public long getCompressedSize() {
-        return getAttribute(ATTRIBUTE_COMPRESSED);
-    }
-
-    public long getUncompressedSize() {
-        return getAttribute(ATTRIBUTE_UNCOMPRESSED);
-    }
-}
--- a/src/java.base/share/classes/jdk/internal/jimage/ImageLocationWriter.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,140 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.internal.jimage;
-
-public final class ImageLocationWriter extends ImageLocationBase {
-    private int locationOffset;
-
-    private ImageLocationWriter(ImageStringsWriter strings) {
-        super(new long[ATTRIBUTE_COUNT], strings);
-    }
-
-    void writeTo(ImageStream stream) {
-        byte[] bytes = ImageLocation.compress(attributes);
-        locationOffset = stream.getPosition();
-        stream.put(bytes, 0, bytes.length);
-    }
-
-    private ImageLocationWriter addAttribute(int kind, long value) {
-        assert ATTRIBUTE_END < kind &&
-               kind < ATTRIBUTE_COUNT : "Invalid attribute kind";
-        attributes[kind] = value;
-        return this;
-    }
-
-    private ImageLocationWriter addAttribute(int kind, UTF8String value) {
-        return addAttribute(kind, strings.add(value));
-    }
-
-    static ImageLocationWriter newLocation(UTF8String fullName,
-            ImageStringsWriter strings,
-            long contentOffset, long compressedSize, long uncompressedSize) {
-        UTF8String moduleName = UTF8String.EMPTY_STRING;
-        UTF8String parentName = UTF8String.EMPTY_STRING;
-        UTF8String baseName;
-        UTF8String extensionName = UTF8String.EMPTY_STRING;
-
-        int offset = fullName.indexOf('/', 1);
-        if (fullName.length() >= 2 && fullName.charAt(0) == '/' && offset != -1) {
-            moduleName = fullName.substring(1, offset - 1);
-            fullName = fullName.substring(offset + 1);
-        }
-
-        offset = fullName.lastIndexOf('/');
-        if (offset != -1) {
-            parentName = fullName.substring(0, offset);
-            fullName = fullName.substring(offset + 1);
-        }
-
-        offset = fullName.lastIndexOf('.');
-        if (offset != -1) {
-            baseName = fullName.substring(0, offset);
-            extensionName = fullName.substring(offset + 1);
-        } else {
-            baseName = fullName;
-        }
-
-        return new ImageLocationWriter(strings)
-               .addAttribute(ATTRIBUTE_MODULE, moduleName)
-               .addAttribute(ATTRIBUTE_PARENT, parentName)
-               .addAttribute(ATTRIBUTE_BASE, baseName)
-               .addAttribute(ATTRIBUTE_EXTENSION, extensionName)
-               .addAttribute(ATTRIBUTE_OFFSET, contentOffset)
-               .addAttribute(ATTRIBUTE_COMPRESSED, compressedSize)
-               .addAttribute(ATTRIBUTE_UNCOMPRESSED, uncompressedSize);
-    }
-
-    @Override
-    public int hashCode() {
-        return hashCode(UTF8String.HASH_MULTIPLIER);
-    }
-
-    int hashCode(int seed) {
-        int hash = seed;
-
-        if (getModuleOffset() != 0) {
-            hash = UTF8String.SLASH_STRING.hashCode(hash);
-            hash = getModule().hashCode(hash);
-            hash = UTF8String.SLASH_STRING.hashCode(hash);
-        }
-
-        if (getParentOffset() != 0) {
-            hash = getParent().hashCode(hash);
-            hash = UTF8String.SLASH_STRING.hashCode(hash);
-        }
-
-        hash = getBase().hashCode(hash);
-
-        if (getExtensionOffset() != 0) {
-            hash = UTF8String.DOT_STRING.hashCode(hash);
-            hash = getExtension().hashCode(hash);
-        }
-
-        return hash;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-
-        if (!(obj instanceof ImageLocationWriter)) {
-            return false;
-        }
-
-        ImageLocation other = (ImageLocation)obj;
-
-        return getModuleOffset() == other.getModuleOffset() &&
-               getParentOffset() == other.getParentOffset() &&
-               getBaseOffset() == other.getBaseOffset() &&
-               getExtensionOffset() == other.getExtensionOffset();
-    }
-
-    int getLocationOffset() {
-        return locationOffset;
-    }
-}
--- a/src/java.base/share/classes/jdk/internal/jimage/ImageModuleData.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,288 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.internal.jimage;
-
-import java.nio.ByteBuffer;
-import java.nio.IntBuffer;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-
-/*
- * Manage module meta data.
- *
- * NOTE: needs revision.
- * Each loader requires set of module meta data to identify which modules and
- * packages are managed by that loader.  Currently, there is one image file per
- * loader, so only one  module meta data resource per file.
- *
- * Each element in the module meta data is a native endian 4 byte integer.  Note
- * that entries with zero offsets for string table entries should be ignored (
- * padding for hash table lookup.)
- *
- * Format:
- *    Count of package to module entries
- *    Count of module to package entries
- *    Perfect Hash redirect table[Count of package to module entries]
- *    Package to module entries[Count of package to module entries]
- *        Offset to package name in string table
- *        Offset to module name in string table
- *    Perfect Hash redirect table[Count of module to package entries]
- *    Module to package entries[Count of module to package entries]
- *        Offset to module name in string table
- *        Count of packages in module
- *        Offset to first package in packages table
- *    Packages[]
- *        Offset to package name in string table
- */
-
-public final class ImageModuleData {
-    public static final String META_DATA_EXTENSION = ".jdata";
-    public static final String SEPARATOR = "\t";
-    public static final int NOT_FOUND = -1;
-    private static final int ptmCountOffset = 0;
-    private static final int mtpCountOffset = 1;
-    private static final int ptmRedirectOffset = 2;
-    private static final int dataNameOffset = 0;
-    private static final int ptmDataWidth = 2;
-    private static final int ptmDataModuleOffset = 1;
-    private static final int mtpDataWidth = 3;
-    private static final int mtpDataCountOffset = 1;
-    private static final int mtpDataOffsetOffset = 2;
-
-    private final BasicImageReader reader;
-    private final IntBuffer intBuffer;
-    private final int ptmRedirectLength;
-    private final int mtpRedirectLength;
-    private final int ptmDataOffset;
-    private final int mtpRedirectOffset;
-    private final int mtpDataOffset;
-    private final int mtpPackagesOffset;
-
-    public ImageModuleData(BasicImageReader reader) {
-         this(reader, getBytes(reader));
-    }
-
-    public ImageModuleData(BasicImageReader reader, byte[] bytes) {
-        this.reader = reader;
-
-        ByteBuffer byteBuffer = ByteBuffer.wrap(bytes).order(reader.getByteOrder());
-        this.intBuffer = byteBuffer.asIntBuffer();
-
-        this.ptmRedirectLength = get(ptmCountOffset);
-        this.mtpRedirectLength = get(mtpCountOffset);
-
-        this.ptmDataOffset = ptmRedirectOffset + ptmRedirectLength;
-        this.mtpRedirectOffset = ptmDataOffset + ptmRedirectLength * ptmDataWidth;
-        this.mtpDataOffset = mtpRedirectOffset + mtpRedirectLength;
-        this.mtpPackagesOffset = mtpDataOffset + mtpRedirectLength * mtpDataWidth;
-    }
-
-    private static byte[] getBytes(BasicImageReader reader) {
-        String loaderName = reader.imagePathName();
-
-        if (loaderName.endsWith(BasicImageWriter.IMAGE_EXT)) {
-            loaderName = loaderName.substring(0, loaderName.length() -
-                    BasicImageWriter.IMAGE_EXT.length());
-        }
-
-        byte[] bytes = reader.getResource(getModuleDataName(loaderName));
-
-        if (bytes == null) {
-            throw new InternalError("module data missing");
-        }
-
-        return bytes;
-    }
-
-    public List<String> fromModulePackages() {
-        List<String> lines = new ArrayList<>();
-
-        for (int i = 0; i < mtpRedirectLength; i++) {
-            int index = mtpDataOffset + i * mtpDataWidth;
-            int offset = get(index + dataNameOffset);
-
-            if (offset != 0) {
-                StringBuilder sb = new StringBuilder();
-
-                sb.append(getString(offset));
-
-                int count = get(index + mtpDataCountOffset);
-                int base = get(index + mtpDataOffsetOffset) + mtpPackagesOffset;
-
-                for (int j = 0; j < count; j++) {
-                    sb.append(SEPARATOR);
-                    sb.append(stringAt(base + j));
-                }
-
-                lines.add(sb.toString());
-            }
-        }
-
-        return lines;
-    }
-
-    public static String getModuleDataName(String loaderName) {
-        return loaderName + META_DATA_EXTENSION;
-    }
-
-    private int get(int index) {
-        return intBuffer.get(index);
-    }
-
-    private String getString(int offset) {
-        return reader.getString(offset);
-    }
-
-    private String stringAt(int index) {
-        return reader.getString(get(index));
-    }
-
-    private UTF8String getUTF8String(int offset) {
-        return reader.getUTF8String(offset);
-    }
-
-    private UTF8String utf8StringAt(int index) {
-        return reader.getUTF8String(get(index));
-    }
-
-    private int find(UTF8String name, int baseOffset, int length, int width) {
-        if (length == 0) {
-            return NOT_FOUND;
-        }
-
-        int hashCode = name.hashCode();
-        int index = hashCode % length;
-        int value = get(baseOffset + index);
-
-        if (value > 0 ) {
-            hashCode = name.hashCode(value);
-            index = hashCode % length;
-        } else if (value < 0) {
-            index = -1 - value;
-        } else {
-            return NOT_FOUND;
-        }
-
-        index = baseOffset + length + index * width;
-
-        if (!utf8StringAt(index + dataNameOffset).equals(name)) {
-            return NOT_FOUND;
-        }
-
-        return index;
-    }
-
-    public String packageToModule(String packageName) {
-        UTF8String moduleName = packageToModule(new UTF8String(packageName));
-
-        return moduleName != null ? moduleName.toString() : null;
-    }
-
-    public UTF8String packageToModule(UTF8String packageName) {
-        int index = find(packageName, ptmRedirectOffset, ptmRedirectLength, ptmDataWidth);
-
-        if (index != NOT_FOUND) {
-            return utf8StringAt(index + ptmDataModuleOffset);
-        }
-
-        return null;
-    }
-
-    public List<String> moduleToPackages(String moduleName) {
-        int index = find(new UTF8String(moduleName), mtpRedirectOffset,
-                mtpRedirectLength, mtpDataWidth);
-
-        if (index != NOT_FOUND) {
-            int count = get(index + mtpDataCountOffset);
-            int base = get(index + mtpDataOffsetOffset) + mtpPackagesOffset;
-            List<String> packages = new ArrayList<>(count);
-
-            for (int i = 0; i < count; i++) {
-                packages.add(stringAt(base + i));
-            }
-
-            return packages;
-        }
-
-        return null;
-    }
-
-    public List<String> allPackageNames() {
-        List<String> packages = new ArrayList<>();
-
-        for (int i = 0; i < ptmRedirectLength; i++) {
-            int offset = get(ptmDataOffset + i * ptmDataWidth + dataNameOffset);
-
-            if (offset != 0) {
-                packages.add(getString(offset));
-            }
-        }
-
-        return packages;
-    }
-
-    public Set<String> allModuleNames() {
-        Set<String> modules = new HashSet<>();
-
-        for (int i = 0; i < mtpRedirectLength; i++) {
-            int index = mtpDataOffset + i * mtpDataWidth;
-            int offset = get(index + dataNameOffset);
-
-            if (offset != 0) {
-                modules.add(getString(offset));
-            }
-        }
-
-        return modules;
-    }
-
-    public Map<String, String> packageModuleMap() {
-        Map<String, String> map = new HashMap<>();
-
-        for (int i = 0; i < mtpRedirectLength; i++) {
-            int index = mtpDataOffset + i * mtpDataWidth;
-            int offset = get(index + dataNameOffset);
-
-            if (offset != 0) {
-                String moduleName = getString(offset);
-
-                int count = get(index + mtpDataCountOffset);
-                int base = get(index + mtpDataOffsetOffset) + mtpPackagesOffset;
-
-                for (int j = 0; j < count; j++) {
-                    map.put(stringAt(base + j), moduleName);
-                }
-            }
-        }
-
-        return map;
-    }
-}
--- a/src/java.base/share/classes/jdk/internal/jimage/ImageModuleDataWriter.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,172 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.internal.jimage;
-
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-
-public class ImageModuleDataWriter {
-    final byte[] bytes;
-
-    public ImageModuleDataWriter(BasicImageWriter writer,
-            Map<String, List<String>> modulePackages) {
-        PerfectHashBuilder<String> packageToModule = new PerfectHashBuilder<>(
-                new PerfectHashBuilder.Entry<String>().getClass(),
-                new PerfectHashBuilder.Bucket<String>().getClass());
-        PerfectHashBuilder<List<String>> moduleToPackages = new PerfectHashBuilder<>(
-                new PerfectHashBuilder.Entry<List<String>>().getClass(),
-                new PerfectHashBuilder.Bucket<List<String>>().getClass());
-
-        modulePackages.entrySet().stream().forEach((entry) -> {
-            String moduleName = entry.getKey();
-            List<String> packages = entry.getValue();
-            packages.stream().forEach((packageName) -> {
-                packageToModule.put(packageName, moduleName);
-            });
-
-            moduleToPackages.put(moduleName, packages);
-        });
-
-        packageToModule.generate();
-        moduleToPackages.generate();
-
-        bytes = getBytes(writer, packageToModule, moduleToPackages);
-    }
-
-    public static ImageModuleDataWriter buildModuleData(BasicImageWriter writer,
-            Map<String, Set<String>> modulePackagesMap) {
-        Set<String> modules = modulePackagesMap.keySet();
-
-        Map<String, List<String>> modulePackages = new LinkedHashMap<>();
-        modules.stream().sorted().forEach((moduleName) -> {
-            List<String> localPackages = modulePackagesMap.get(moduleName).stream()
-                    .map(pn -> pn.replace('.', '/'))
-                    .sorted()
-                    .collect(Collectors.toList());
-            modulePackages.put(moduleName, localPackages);
-        });
-
-        return new ImageModuleDataWriter(writer, modulePackages);
-    }
-
-    public static Map<String, List<String>> toModulePackages(List<String> lines) {
-        Map<String, List<String>> modulePackages = new LinkedHashMap<>();
-
-        for (String line : lines) {
-            String[] parts = line.split(ImageModuleData.SEPARATOR);
-            String moduleName = parts[0];
-            List<String> packages = Arrays.asList(Arrays.copyOfRange(parts, 1, parts.length));
-            modulePackages.put(moduleName, packages);
-        }
-
-        return modulePackages;
-    }
-
-    public void addLocation(String name, BasicImageWriter writer) {
-        writer.addLocation(ImageModuleData.getModuleDataName(name), 0, 0, bytes.length);
-    }
-
-    private byte[] getBytes(BasicImageWriter writer,
-            PerfectHashBuilder<String> packageToModule,
-            PerfectHashBuilder<List<String>> moduleToPackages) {
-        ImageStream stream = new ImageStream(writer.getByteOrder());
-
-        // Empty jimage
-        if (packageToModule.getCount() == 0) {
-            stream.putInt(0);
-            stream.putInt(0);
-            return stream.toArray();
-        }
-
-        int[] ptmRedirect = packageToModule.getRedirect();
-        int[] mtpRedirect = moduleToPackages.getRedirect();
-        PerfectHashBuilder.Entry<String>[] ptmOrder = packageToModule.getOrder();
-        PerfectHashBuilder.Entry<List<String>>[] mtpOrder = moduleToPackages.getOrder();
-
-        stream.putInt(ptmRedirect.length);
-        stream.putInt(mtpRedirect.length);
-
-        for (int value : ptmRedirect) {
-            stream.putInt(value);
-        }
-
-        for (PerfectHashBuilder.Entry<String> entry : ptmOrder) {
-            if (entry != null) {
-                stream.putInt(writer.addString(entry.getKey()));
-                stream.putInt(writer.addString(entry.getValue()));
-            } else {
-                stream.putInt(0);
-                stream.putInt(0);
-            }
-        }
-
-        for (int value : mtpRedirect) {
-            stream.putInt(value);
-        }
-
-        int index = 0;
-
-        for (PerfectHashBuilder.Entry<List<String>> entry : mtpOrder) {
-            if (entry != null) {
-                int count = entry.getValue().size();
-                stream.putInt(writer.addString(entry.getKey()));
-                stream.putInt(count);
-                stream.putInt(index);
-                index += count;
-            } else {
-                stream.putInt(0);
-                stream.putInt(0);
-                stream.putInt(0);
-            }
-        }
-
-        for (PerfectHashBuilder.Entry<List<String>> entry : mtpOrder) {
-            if (entry != null) {
-                List<String> value = entry.getValue();
-                value.stream().forEach((packageName) -> {
-                    stream.putInt(writer.addString(packageName));
-                });
-            }
-        }
-
-        return stream.toArray();
-    }
-
-    public void writeTo(DataOutputStream out) throws IOException {
-         out.write(bytes, 0, bytes.length);
-    }
-
-    public int size() {
-        return bytes.length;
-    }
-}
--- a/src/java.base/share/classes/jdk/internal/jimage/ImageNativeSubstrate.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,219 +0,0 @@
-/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.internal.jimage;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-public final class ImageNativeSubstrate implements ImageSubstrate {
-    static {
-        java.security.AccessController.doPrivileged(
-            new java.security.PrivilegedAction<Void>() {
-                @Override
-                public Void run() {
-                    System.loadLibrary("jimage");
-                    return null;
-                }
-            });
-     }
-
-    // TODO: Reinstate when the class below, NIOACCESS, is removed.
-    //private static final JavaNioAccess NIOACCESS =
-    //        SharedSecrets.getJavaNioAccess();
-
-
-    private final long id;
-    private final long indexAddress;
-    private final long dataAddress;
-
-    static native long openImage(String imagePath, boolean bigEndian);
-    static native void closeImage(long id);
-    static native long getIndexAddress(long id);
-    static native long getDataAddress(long id);
-    static native boolean readCompressed(long id, long offset,
-            ByteBuffer compressedBuffer, long compressedSize,
-            ByteBuffer uncompressedBuffer, long uncompressedSize);
-    static native boolean read(long id, long offset,
-            ByteBuffer uncompressedBuffer, long uncompressedSize);
-    static native byte[] getStringBytes(long id, int offset);
-    static native long[] getAttributes(long id, int offset);
-    static native long[] findAttributes(long id, byte[] path);
-    static native int[] attributeOffsets(long id);
-
-    public static native long JIMAGE_Open(String path) throws IOException;
-    public static native void JIMAGE_Close(long jimageHandle);
-    public static native long JIMAGE_FindResource(long jimageHandle,
-                    String moduleName, String Version, String path,
-                    long[] size);
-    public static native long JIMAGE_GetResource(long jimageHandle,
-                    long locationHandle, byte[] buffer, long size);
-    // Get an array of names that match; return the count found upto array size
-    public static native int JIMAGE_Resources(long jimageHandle,
-                    String[] outputNames);
-    // Return the module name for the package
-    public static native String JIMAGE_PackageToModule(long imageHandle,
-                    String packageName);
-
-    static ByteBuffer newDirectByteBuffer(long address, long capacity) {
-        assert capacity < Integer.MAX_VALUE;
-        return NIOACCESS.newDirectByteBuffer(address, (int)capacity, null);
-    }
-
-    private ImageNativeSubstrate(long id) {
-        this.id = id;
-        this.indexAddress = getIndexAddress(id);
-        this.dataAddress = getDataAddress(id);
-    }
-
-    static ImageSubstrate openImage(String imagePath, ByteOrder byteOrder)
-            throws IOException {
-        long id = openImage(imagePath, byteOrder == ByteOrder.BIG_ENDIAN);
-
-        if (id == 0) {
-             throw new IOException("Image not found \"" + imagePath + "\"");
-        }
-
-        return new ImageNativeSubstrate(id);
-    }
-
-    @Override
-    public void close() {
-        closeImage(id);
-    }
-
-    @Override
-    public ByteBuffer getIndexBuffer(long offset, long size) {
-        return newDirectByteBuffer(indexAddress + offset, size);
-    }
-
-    @Override
-    public ByteBuffer getDataBuffer(long offset, long size) {
-        return dataAddress != 0 ?
-                newDirectByteBuffer(dataAddress + offset, size) : null;
-    }
-
-    @Override
-    public boolean supportsDataBuffer() {
-        return dataAddress != 0;
-    }
-
-    @Override
-    public boolean read(long offset,
-                 ByteBuffer compressedBuffer, long compressedSize,
-                 ByteBuffer uncompressedBuffer, long uncompressedSize) {
-        return readCompressed(id, offset,
-                    compressedBuffer, compressedSize,
-                    uncompressedBuffer, uncompressedSize);
-    }
-
-    @Override
-    public boolean read(long offset,
-                 ByteBuffer uncompressedBuffer, long uncompressedSize) {
-        return read(id, offset, uncompressedBuffer, uncompressedSize);
-    }
-
-    @Override
-    public byte[] getStringBytes(int offset) {
-        byte[] ret = getStringBytes(id, offset);
-        if (ret == null) {
-            throw new OutOfMemoryError("Error accessing array at offset "
-                    + offset);
-        }
-        return ret;
-    }
-
-    @Override
-    public long[] getAttributes(int offset) {
-        return getAttributes(id, offset);
-    }
-
-    @Override
-    public ImageLocation findLocation(UTF8String name, ImageStringsReader strings) {
-        long[] attributes = findAttributes(id, name.getBytes());
-
-        return attributes != null ? new ImageLocation(attributes, strings) : null;
-    }
-
-    @Override
-    public int[] attributeOffsets() {
-        return attributeOffsets(id);
-    }
-
-    // TODO: Remove when JRT-FS no longer indirectly depends on ImageNativeSubstrate
-    /**
-     * Reflective wrapper around ShareSecrets JavaNioAccess.
-     *
-     * SharedSecrets and friend interfaces moved from 'sun.misc' to 'jdk.internal.misc'
-     * in 1.9. This class provides the runtime with access to the appropriate
-     * JavaNioAccess methods whether running on 1.9, or lower.
-     */
-    static class NIOACCESS {
-
-        private static final String PKG_PREFIX = "jdk.internal.misc";
-        private static final String LEGACY_PKG_PREFIX = "sun.misc";
-
-        private static final Object javaNioAccess;
-        private static final java.lang.reflect.Method newDirectByteBufferMethod;
-
-        static {
-            try {
-                Class<?> c = getJDKClass("JavaNioAccess");
-
-                java.lang.reflect.Method m =
-                        getJDKClass("SharedSecrets").getDeclaredMethod("getJavaNioAccess");
-                javaNioAccess = m.invoke(null);
-
-                newDirectByteBufferMethod = c.getDeclaredMethod("newDirectByteBuffer",
-                                                                long.class,
-                                                                int.class,
-                                                                Object.class);
-            } catch (ReflectiveOperationException x) {
-                throw new InternalError(x);
-            }
-        }
-
-        private static Class<?> getJDKClass(String name) throws ClassNotFoundException {
-            try {
-                return Class.forName(PKG_PREFIX + "." + name);
-            } catch (ClassNotFoundException x) {
-                try {
-                    return Class.forName(LEGACY_PKG_PREFIX + "." + name);
-                } catch (ClassNotFoundException ex) {
-                    x.addSuppressed(ex);
-                    throw x;
-                }
-            }
-        }
-
-        static ByteBuffer newDirectByteBuffer(long addr, int cap, Object ob) {
-            try {
-                return (ByteBuffer) newDirectByteBufferMethod.invoke(javaNioAccess, addr, cap, ob);
-            } catch (ReflectiveOperationException x) {
-                throw new InternalError(x);
-            }
-        }
-    }
-}
--- a/src/java.base/share/classes/jdk/internal/jimage/ImageReader.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/jimage/ImageReader.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,19 +32,34 @@
 import java.nio.file.Files;
 import java.nio.file.attribute.BasicFileAttributes;
 import java.nio.file.attribute.FileTime;
-import java.nio.file.Paths;
 import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
+import java.util.Objects;
 import java.util.function.Consumer;
-import static jdk.internal.jimage.UTF8String.*;
+
+/**
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
+ */
+public class ImageReader extends BasicImageReader {
 
-public class ImageReader extends BasicImageReader {
-    // well-known strings needed for image file system.
-    static final UTF8String ROOT_STRING = UTF8String.SLASH_STRING;
+    private static final int SIZE_OF_OFFSET = 4;
+
+    // Map of files opened as LITTLE_ENDIAN
+    private static final HashMap<Path, ImageReader> OPEN_LE_FILES
+            = new HashMap<>();
+
+    // Map of files opened as BIG_ENDIAN
+    private static final HashMap<Path, ImageReader> OPEN_BE_FILES
+            = new HashMap<>();
+
+    private int openCount;
 
     // attributes of the .jimage file. jimage file does not contain
     // attributes for the individual resources (yet). We use attributes
@@ -52,78 +67,60 @@
     // Iniitalized lazily, see {@link #imageFileAttributes()}.
     private BasicFileAttributes imageFileAttributes;
 
-    private final ImageModuleData moduleData;
-
     // directory management implementation
-    private final Map<UTF8String, Node> nodes;
+    private final HashMap<String, Node> nodes;
     private volatile Directory rootDir;
 
     private Directory packagesDir;
     private Directory modulesDir;
 
-    ImageReader(String imagePath, ByteOrder byteOrder) throws IOException {
+    private ImageReader(Path imagePath, ByteOrder byteOrder) throws IOException {
         super(imagePath, byteOrder);
-        this.moduleData = new ImageModuleData(this);
-        this.nodes = Collections.synchronizedMap(new HashMap<>());
+        this.nodes = new HashMap<>();
     }
 
-    ImageReader(String imagePath) throws IOException {
-        this(imagePath, ByteOrder.nativeOrder());
+    public static ImageReader open(Path imagePath, ByteOrder byteOrder) throws IOException {
+        HashMap<Path, ImageReader> openFiles = getOpenFilesMap(byteOrder);
+        ImageReader reader;
+        synchronized (openFiles) {
+            reader = openFiles.get(imagePath);
+            if (reader == null) {
+                reader = new ImageReader(imagePath, byteOrder);
+                ImageReader existingReader = openFiles.putIfAbsent(imagePath, reader);
+                assert (existingReader == null);
+            }
+            reader.openCount++;
+        }
+        return reader;
     }
 
-    public static ImageReader open(String imagePath, ByteOrder byteOrder) throws IOException {
-        return new ImageReader(imagePath, byteOrder);
+    private static HashMap<Path, ImageReader> getOpenFilesMap(ByteOrder byteOrder) {
+        return (byteOrder == ByteOrder.BIG_ENDIAN) ? OPEN_BE_FILES : OPEN_LE_FILES;
     }
 
     /**
      * Opens the given file path as an image file, returning an {@code ImageReader}.
      */
-    public static ImageReader open(String imagePath) throws IOException {
+    public static ImageReader open(Path imagePath) throws IOException {
         return open(imagePath, ByteOrder.nativeOrder());
     }
 
-    @Override
-    public synchronized void close() throws IOException {
-        super.close();
-        clearNodes();
+    private boolean canClose() {
+        HashMap<Path, ImageReader> openFiles = getOpenFilesMap(this.getByteOrder());
+        synchronized (openFiles) {
+            if (--this.openCount == 0) {
+                return openFiles.remove(this.getName(), this);
+            }
+        }
+        return false;
     }
 
     @Override
-    public ImageLocation findLocation(UTF8String name) {
-        ImageLocation location = super.findLocation(name);
-
-        // NOTE: This should be removed when module system is up in full.
-        if (location == null) {
-            int index = name.lastIndexOf('/');
-
-            if (index != -1) {
-                UTF8String packageName = name.substring(0, index);
-                UTF8String moduleName = moduleData.packageToModule(packageName);
-
-                if (moduleName != null) {
-                    UTF8String fullName = UTF8String.SLASH_STRING.concat(moduleName,
-                            UTF8String.SLASH_STRING, name);
-                    location = super.findLocation(fullName);
-                }
-            } else {
-                // No package, try all modules.
-                for (String mod : moduleData.allModuleNames()) {
-                    location = super.findLocation("/" + mod + "/" + name);
-                    if (location != null) {
-                        break;
-                    }
-                }
-            }
-        }
-
-        return location;
-    }
-
-    /**
-     * Return the module name that contains the given package name.
-     */
-    public String getModule(String packageName) {
-        return moduleData.packageToModule(packageName);
+    public void close() throws IOException {
+        if (canClose()) {
+            super.close();
+            clearNodes();
+       }
     }
 
     // jimage file does not store directory structure. We build nodes
@@ -135,15 +132,13 @@
         private static final int MODULES_DIR = 0b0000_0000_0000_0100;
 
         private int flags;
-        private final UTF8String name;
+        private final String name;
         private final BasicFileAttributes fileAttrs;
         private boolean completed;
 
-        Node(UTF8String name, BasicFileAttributes fileAttrs) {
-            assert name != null;
-            assert fileAttrs != null;
-            this.name = name;
-            this.fileAttrs = fileAttrs;
+        Node(String name, BasicFileAttributes fileAttrs) {
+            this.name = Objects.requireNonNull(name);
+            this.fileAttrs = Objects.requireNonNull(fileAttrs);
         }
 
         /**
@@ -183,7 +178,7 @@
             return (flags & MODULES_DIR) != 0;
         }
 
-        public final UTF8String getName() {
+        public final String getName() {
             return name;
         }
 
@@ -250,7 +245,7 @@
         }
 
         public final String getNameString() {
-            return name.toString();
+            return name;
         }
 
         @Override
@@ -281,17 +276,17 @@
     static final class Directory extends Node {
         private final List<Node> children;
 
-        private Directory(Directory parent, UTF8String name, BasicFileAttributes fileAttrs) {
+        private Directory(String name, BasicFileAttributes fileAttrs) {
             super(name, fileAttrs);
             children = new ArrayList<>();
         }
 
-        static Directory create(Directory parent, UTF8String name, BasicFileAttributes fileAttrs) {
-            Directory dir = new Directory(parent, name, fileAttrs);
+        static Directory create(Directory parent, String name, BasicFileAttributes fileAttrs) {
+            Directory d = new Directory(name, fileAttrs);
             if (parent != null) {
-                parent.addChild(dir);
+                parent.addChild(d);
             }
-            return dir;
+            return d;
         }
 
         @Override
@@ -325,25 +320,15 @@
     static class Resource extends Node {
         private final ImageLocation loc;
 
-        private Resource(Directory parent, ImageLocation loc, BasicFileAttributes fileAttrs) {
-            this(parent, loc.getFullName(true), loc, fileAttrs);
+        private Resource(ImageLocation loc, BasicFileAttributes fileAttrs) {
+            super(loc.getFullName(true), fileAttrs);
+            this.loc = loc;
         }
 
-        private Resource(Directory parent, UTF8String name, ImageLocation loc, BasicFileAttributes fileAttrs) {
-            super(name, fileAttrs);
-            this.loc = loc;
-         }
-
         static Resource create(Directory parent, ImageLocation loc, BasicFileAttributes fileAttrs) {
-            Resource resource = new Resource(parent, loc, fileAttrs);
-            parent.addChild(resource);
-            return resource;
-        }
-
-        static Resource create(Directory parent, UTF8String name, ImageLocation loc, BasicFileAttributes fileAttrs) {
-            Resource resource = new Resource(parent, name, loc, fileAttrs);
-            parent.addChild(resource);
-            return resource;
+            Resource rs = new Resource(loc, fileAttrs);
+            parent.addChild(rs);
+            return rs;
         }
 
         @Override
@@ -373,7 +358,7 @@
 
         @Override
         public String extension() {
-            return loc.getExtensionString();
+            return loc.getExtension();
         }
 
         @Override
@@ -386,15 +371,15 @@
     static class LinkNode extends Node {
         private final Node link;
 
-        private LinkNode(Directory parent, UTF8String name, Node link) {
+        private LinkNode(String name, Node link) {
             super(name, link.getFileAttributes());
             this.link = link;
         }
 
-        static LinkNode create(Directory parent, UTF8String name, Node link) {
-            LinkNode linkNode = new LinkNode(parent, name, link);
-            parent.addChild(linkNode);
-            return linkNode;
+        static LinkNode create(Directory parent, String name, Node link) {
+            LinkNode ln = new LinkNode(name, link);
+            parent.addChild(ln);
+            return ln;
         }
 
         @Override
@@ -418,14 +403,6 @@
         return buildRootDirectory();
     }
 
-    public Node findNode(String name) {
-        return findNode(new UTF8String(name));
-    }
-
-    public Node findNode(byte[] name) {
-        return findNode(new UTF8String(name));
-    }
-
     /**
      * To visit sub tree resources.
      */
@@ -436,142 +413,178 @@
 
     /**
      * Lazily build a node from a name.
-     */
-    private final class NodeBuilder {
-
-        private static final int SIZE_OF_OFFSET = 4;
-
-        private final UTF8String name;
-
-        private NodeBuilder(UTF8String name) {
-            this.name = name;
-        }
+    */
+    private Node buildNode(String name) {
+        Node n;
+        boolean isPackages = name.startsWith("/packages");
+        boolean isModules = !isPackages && name.startsWith("/modules");
 
-        private Node buildNode() {
-            Node n = null;
-            boolean isPackages = false;
-            boolean isModules = false;
-            String strName = name.toString();
-            if (strName.startsWith("" + PACKAGES_STRING)) {
-                isPackages = true;
-            } else {
-                if (strName.startsWith("" + MODULES_STRING)) {
-                    isModules = true;
-                }
-            }
-            if (!isModules && !isPackages) {
-                return null;
-            }
-
-            ImageLocation loc = findLocation(name);
-
-            if (loc != null) { // A sub tree node
-                if (isPackages) {
-                    n = handlePackages(strName, loc);
-                } else { // modules sub tree
-                    n = handleModulesSubTree(strName, loc);
-                }
-            } else { // Asking for a resource? /modules/java.base/java/lang/Object.class
-                if (isModules) {
-                    n = handleResource(strName, loc);
-                }
-            }
-            return n;
+        if (!(isModules || isPackages)) {
+            return null;
         }
 
-        private void visitLocation(ImageLocation loc, LocationVisitor visitor) {
-            byte[] offsets = getResource(loc);
-            ByteBuffer buffer = ByteBuffer.wrap(offsets);
-            buffer.order(getByteOrder());
-            IntBuffer intBuffer = buffer.asIntBuffer();
-            for (int i = 0; i < offsets.length / SIZE_OF_OFFSET; i++) {
-                int offset = intBuffer.get(i);
-                ImageLocation pkgLoc = getLocation(offset);
-                visitor.visit(pkgLoc);
+        ImageLocation loc = findLocation(name);
+
+        if (loc != null) { // A sub tree node
+            if (isPackages) {
+                n = handlePackages(name, loc);
+            } else { // modules sub tree
+                n = handleModulesSubTree(name, loc);
+            }
+        } else { // Asking for a resource? /modules/java.base/java/lang/Object.class
+            if (isModules) {
+                n = handleResource(name);
+            } else {
+                // Possibly ask for /packages/java.lang/java.base
+                // although /packages/java.base not created
+                n = handleModuleLink(name);
+            }
+        }
+        return n;
+    }
+
+    private void visitLocation(ImageLocation loc, LocationVisitor visitor) {
+        byte[] offsets = getResource(loc);
+        ByteBuffer buffer = ByteBuffer.wrap(offsets);
+        buffer.order(getByteOrder());
+        IntBuffer intBuffer = buffer.asIntBuffer();
+        for (int i = 0; i < offsets.length / SIZE_OF_OFFSET; i++) {
+            int offset = intBuffer.get(i);
+            ImageLocation pkgLoc = getLocation(offset);
+            visitor.visit(pkgLoc);
+        }
+    }
+
+    private void visitPackageLocation(ImageLocation loc) {
+        // Retrieve package name
+        String pkgName = getBaseExt(loc);
+        // Content is array of offsets in Strings table
+        byte[] stringsOffsets = getResource(loc);
+        ByteBuffer buffer = ByteBuffer.wrap(stringsOffsets);
+        buffer.order(getByteOrder());
+        IntBuffer intBuffer = buffer.asIntBuffer();
+        // For each module, create a link node.
+        for (int i = 0; i < stringsOffsets.length / SIZE_OF_OFFSET; i++) {
+            // skip empty state, useless.
+            intBuffer.get(i);
+            i++;
+            int offset = intBuffer.get(i);
+            String moduleName = getString(offset);
+            Node targetNode = findNode("/modules/" + moduleName);
+            if (targetNode != null) {
+                String pkgDirName = packagesDir.getName() + "/" + pkgName;
+                Directory pkgDir = (Directory) nodes.get(pkgDirName);
+                newLinkNode(pkgDir, pkgDir.getName() + "/" + moduleName, targetNode);
             }
         }
+    }
 
-        private Node handlePackages(String name, ImageLocation loc) {
-            long size = loc.getUncompressedSize();
-            Node n = null;
-            // Only possiblities are /packages, /packages/package/module
-            if (name.equals("" + PACKAGES_STRING)) {
-                visitLocation(loc, (childloc) -> {
-                    findNode(childloc.getFullName());
-                });
-                packagesDir.setCompleted(true);
-                n = packagesDir;
-            } else {
-                if (size != 0) { // children are links to module
-                    String pkgName = getBaseExt(loc);
-                    Directory pkgDir = newDirectory(packagesDir,
-                            packagesDir.getName().concat(SLASH_STRING, new UTF8String(pkgName)));
-                    visitLocation(loc, (childloc) -> {
-                        findNode(childloc.getFullName());
-                    });
-                    pkgDir.setCompleted(true);
-                    n = pkgDir;
-                } else { // Link to module
-                    String pkgName = loc.getParentString();
-                    String modName = getBaseExt(loc);
-                    Node targetNode = findNode(MODULES_STRING + "/" + modName);
-                    if (targetNode != null) {
-                        UTF8String pkgDirName = packagesDir.getName().concat(SLASH_STRING, new UTF8String(pkgName));
-                        Directory pkgDir = (Directory) nodes.get(pkgDirName);
-                        Node linkNode = newLinkNode(pkgDir,
-                                pkgDir.getName().concat(SLASH_STRING, new UTF8String(modName)), targetNode);
-                        n = linkNode;
+    private Node handlePackages(String name, ImageLocation loc) {
+        long size = loc.getUncompressedSize();
+        Node n = null;
+        // Only possiblities are /packages, /packages/package/module
+        if (name.equals("/packages")) {
+            visitLocation(loc, (childloc) -> {
+                findNode(childloc.getFullName());
+            });
+            packagesDir.setCompleted(true);
+            n = packagesDir;
+        } else {
+            if (size != 0) { // children are offsets to module in StringsTable
+                String pkgName = getBaseExt(loc);
+                Directory pkgDir = newDirectory(packagesDir, packagesDir.getName() + "/" + pkgName);
+                visitPackageLocation(loc);
+                pkgDir.setCompleted(true);
+                n = pkgDir;
+            } else { // Link to module
+                String pkgName = loc.getParent();
+                String modName = getBaseExt(loc);
+                Node targetNode = findNode("/modules/" + modName);
+                if (targetNode != null) {
+                    String pkgDirName = packagesDir.getName() + "/" + pkgName;
+                    Directory pkgDir = (Directory) nodes.get(pkgDirName);
+                    Node linkNode = newLinkNode(pkgDir, pkgDir.getName() + "/" + modName, targetNode);
+                    n = linkNode;
+                }
+            }
+        }
+        return n;
+    }
+
+    // Asking for /packages/package/module although
+    // /packages/<pkg>/ not yet created, need to create it
+    // prior to return the link to module node.
+    private Node handleModuleLink(String name) {
+        // eg: unresolved /packages/package/module
+        // Build /packages/package node
+        Node ret = null;
+        String radical = "/packages/";
+        String path = name;
+        if (path.startsWith(radical)) {
+            int start = radical.length();
+            int pkgEnd = path.indexOf('/', start);
+            if (pkgEnd != -1) {
+                String pkg = path.substring(start, pkgEnd);
+                String pkgPath = radical + pkg;
+                Node n = findNode(pkgPath);
+                // If not found means that this is a symbolic link such as:
+                // /packages/java.util/java.base/java/util/Vector.class
+                // and will be done by a retry of the filesystem
+                for (Node child : n.getChildren()) {
+                    if (child.name.equals(name)) {
+                        ret = child;
+                        break;
                     }
                 }
             }
-            return n;
         }
-
-        private Node handleModulesSubTree(String name, ImageLocation loc) {
-            Node n;
-            Directory dir = makeDirectories(loc.getFullName());
-            visitLocation(loc, (childloc) -> {
-                String path = childloc.getFullNameString();
-                if (path.startsWith(MODULES_STRING.toString())) { // a package
-                    makeDirectories(childloc.getFullName());
-                } else { // a resource
-                    makeDirectories(childloc.buildName(true, true, false));
-                    newResource(dir, childloc);
-                }
-            });
-            dir.setCompleted(true);
-            n = dir;
-            return n;
-        }
+        return ret;
+    }
 
-        private Node handleResource(String name, ImageLocation loc) {
-            Node n = null;
-            String locationPath = name.substring((MODULES_STRING).length());
-            ImageLocation resourceLoc = findLocation(locationPath);
-            if (resourceLoc != null) {
-                Directory dir = makeDirectories(resourceLoc.buildName(true, true, false));
-                Resource res = newResource(dir, resourceLoc);
-                n = res;
+    private Node handleModulesSubTree(String name, ImageLocation loc) {
+        Node n;
+        assert (name.equals(loc.getFullName()));
+        Directory dir = makeDirectories(name);
+        visitLocation(loc, (childloc) -> {
+            String path = childloc.getFullName();
+            if (path.startsWith("/modules")) { // a package
+                makeDirectories(path);
+            } else { // a resource
+                makeDirectories(childloc.buildName(true, true, false));
+                newResource(dir, childloc);
             }
-            return n;
-        }
-
-        private String getBaseExt(ImageLocation loc) {
-            String base = loc.getBaseString();
-            String ext = loc.getExtensionString();
-            if (ext != null && !ext.isEmpty()) {
-                base = base + "." + ext;
-            }
-            return base;
-        }
+        });
+        dir.setCompleted(true);
+        n = dir;
+        return n;
     }
 
-    public synchronized Node findNode(UTF8String name) {
+    private Node handleResource(String name) {
+        Node n = null;
+        String locationPath = name.substring("/modules".length());
+        ImageLocation resourceLoc = findLocation(locationPath);
+        if (resourceLoc != null) {
+            Directory dir = makeDirectories(resourceLoc.buildName(true, true, false));
+            Resource res = newResource(dir, resourceLoc);
+            n = res;
+        }
+        return n;
+    }
+
+    private String getBaseExt(ImageLocation loc) {
+        String base = loc.getBase();
+        String ext = loc.getExtension();
+        if (ext != null && !ext.isEmpty()) {
+            base = base + "." + ext;
+        }
+        return base;
+    }
+
+    public synchronized Node findNode(String name) {
         buildRootDirectory();
         Node n = nodes.get(name);
         if (n == null || !n.isCompleted()) {
-            NodeBuilder builder = new NodeBuilder(name);
-            n = builder.buildNode();
+            n = buildNode(name);
         }
         return n;
     }
@@ -588,7 +601,7 @@
         BasicFileAttributes attrs = imageFileAttributes;
         if (attrs == null) {
             try {
-                Path file = Paths.get(imagePath());
+                Path file = getImagePath();
                 attrs = Files.readAttributes(file, BasicFileAttributes.class);
             } catch (IOException ioe) {
                 throw new UncheckedIOException(ioe);
@@ -598,30 +611,38 @@
         return attrs;
     }
 
-    private synchronized Directory buildRootDirectory() {
-        if (rootDir != null) {
-            return rootDir;
+    private Directory buildRootDirectory() {
+        Directory root = rootDir; // volatile read
+        if (root != null) {
+            return root;
         }
 
-        // FIXME no time information per resource in jimage file (yet?)
-        // we use file attributes of jimage itself.
-        // root directory
-        rootDir = newDirectory(null, ROOT_STRING);
-        rootDir.setIsRootDir();
+        synchronized (this) {
+            root = rootDir;
+            if (root != null) {
+                return root;
+            }
+
+            // FIXME no time information per resource in jimage file (yet?)
+            // we use file attributes of jimage itself.
+            // root directory
+            root = newDirectory(null, "/");
+            root.setIsRootDir();
 
-        // /packages dir
-        packagesDir = newDirectory(rootDir, PACKAGES_STRING);
-        packagesDir.setIsPackagesDir();
+            // /packages dir
+            packagesDir = newDirectory(root, "/packages");
+            packagesDir.setIsPackagesDir();
 
-        // /modules dir
-        modulesDir = newDirectory(rootDir, MODULES_STRING);
-        modulesDir.setIsModulesDir();
+            // /modules dir
+            modulesDir = newDirectory(root, "/modules");
+            modulesDir.setIsModulesDir();
 
-        rootDir.setCompleted(true);
-        return rootDir;
+            root.setCompleted(true);
+            return rootDir = root;
+        }
     }
 
-    private Directory newDirectory(Directory parent, UTF8String name) {
+    private Directory newDirectory(Directory parent, String name) {
         Directory dir = Directory.create(parent, name, imageFileAttributes());
         nodes.put(dir.getName(), dir);
         return dir;
@@ -633,39 +654,30 @@
         return res;
     }
 
-    private LinkNode newLinkNode(Directory dir, UTF8String name, Node link) {
+    private LinkNode newLinkNode(Directory dir, String name, Node link) {
         LinkNode linkNode = LinkNode.create(dir, name, link);
         nodes.put(linkNode.getName(), linkNode);
         return linkNode;
     }
 
-    private List<UTF8String> dirs(UTF8String parent) {
-        List<UTF8String> splits = new ArrayList<>();
+    private Directory makeDirectories(String parent) {
+        Directory last = rootDir;
+        for (int offset = parent.indexOf('/', 1);
+                offset != -1;
+                offset = parent.indexOf('/', offset + 1)) {
+            String dir = parent.substring(0, offset);
+            last = makeDirectory(dir, last);
+        }
+        return makeDirectory(parent, last);
 
-        for (int i = 1; i < parent.length(); i++) {
-            if (parent.byteAt(i) == '/') {
-                splits.add(parent.substring(0, i));
-            }
-        }
-
-        splits.add(parent);
-
-        return splits;
     }
 
-    private Directory makeDirectories(UTF8String parent) {
-        Directory last = rootDir;
-        List<UTF8String> dirs = dirs(parent);
-
-        for (UTF8String dir : dirs) {
-            Directory nextDir = (Directory) nodes.get(dir);
-            if (nextDir == null) {
-                nextDir = newDirectory(last, dir);
-            }
-            last = nextDir;
+    private Directory makeDirectory(String dir, Directory last) {
+        Directory nextDir = (Directory) nodes.get(dir);
+        if (nextDir == null) {
+            nextDir = newDirectory(last, dir);
         }
-
-        return last;
+        return nextDir;
     }
 
     public byte[] getResource(Node node) throws IOException {
--- a/src/java.base/share/classes/jdk/internal/jimage/ImageReaderFactory.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/jimage/ImageReaderFactory.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,13 +34,19 @@
 
 /**
  * Factory to get ImageReader
+ *
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
  */
 public class ImageReaderFactory {
     private ImageReaderFactory() {}
 
     private static final String JAVA_HOME = System.getProperty("java.home");
     private static final Path BOOT_MODULES_JIMAGE =
-        Paths.get(JAVA_HOME, "lib", "modules", "bootmodules.jimage");
+        Paths.get(JAVA_HOME, "lib", "modules");
 
     private static final Map<Path, ImageReader> readers = new ConcurrentHashMap<>();
 
@@ -52,7 +58,7 @@
         if (reader != null) {
             return reader;
         }
-        reader = ImageReader.open(jimage.toString());
+        reader = ImageReader.open(jimage);
         // potential race with other threads opening the same URL
         ImageReader r = readers.putIfAbsent(jimage, reader);
         if (r == null) {
--- a/src/java.base/share/classes/jdk/internal/jimage/ImageResourcesTree.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,341 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.internal.jimage;
-
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.TreeSet;
-
-/**
- * A class to build a sorted tree of Resource paths as a tree of ImageLocation.
- *
- */
-// XXX Public only due to the JImageTask / JImageTask code duplication
-public final class ImageResourcesTree {
-
-    private static final String MODULES = "modules";
-    private static final String PACKAGES = "packages";
-    public static final String MODULES_STRING = UTF8String.MODULES_STRING.toString();
-    public static final String PACKAGES_STRING = UTF8String.PACKAGES_STRING.toString();
-
-    public static boolean isTreeInfoResource(String path) {
-        return path.startsWith(PACKAGES_STRING) || path.startsWith(MODULES_STRING);
-    }
-
-    /**
-     * Path item tree node.
-     */
-    private static final class Node {
-
-        private final String name;
-        private final Map<String, Node> children = new TreeMap<>();
-        private final Node parent;
-        private ImageLocationWriter loc;
-        private boolean isResource;
-
-        private Node(String name, Node parent) {
-            this.name = name;
-            this.parent = parent;
-
-            if (parent != null) {
-                parent.children.put(name, this);
-            }
-        }
-
-        public String getPath() {
-            if (parent == null) {
-                return "/";
-            }
-            return buildPath(this);
-        }
-
-        public String getName() {
-            return name;
-        }
-
-        public Node getChildren(String name) {
-            Node item = children.get(name);
-            return item;
-        }
-
-        private static String buildPath(Node item) {
-            if (item == null) {
-                return null;
-            }
-            String path = buildPath(item.parent);
-            if (path == null) {
-                return item.getName();
-            } else {
-                return path + "/" + item.getName();
-            }
-        }
-    }
-
-    /**
-     * Tree of nodes.
-     */
-    private static final class Tree {
-
-        private final Map<String, Node> directAccess = new HashMap<>();
-        private final List<String> paths;
-        private final Node root;
-        private Node modules;
-        private Node packages;
-
-        private Tree(List<String> paths) {
-            this.paths = paths;
-            root = new Node("", null);
-            buildTree();
-        }
-
-        private void buildTree() {
-            modules = new Node(MODULES, root);
-            directAccess.put(modules.getPath(), modules);
-
-            Map<String, Set<String>> moduleToPackage = new TreeMap<>();
-            Map<String, Set<String>> packageToModule = new TreeMap<>();
-
-            for (String p : paths) {
-                if (!p.startsWith("/")) {
-                    continue;
-                }
-                String[] split = p.split("/");
-                Node current = modules;
-                String module = null;
-                for (int i = 0; i < split.length; i++) {
-                    String s = split[i];
-                    if (!s.isEmpty()) {
-                        if (module == null) {
-                            module = s;
-                        }
-                        Node n = current.children.get(s);
-                        if (n == null) {
-                            n = new Node(s, current);
-                            if (i == split.length - 1) { // Leaf
-                                n.isResource = true;
-                                String pkg = toPackageName(n.parent);
-                                if (pkg != null && !pkg.startsWith("META-INF")) {
-                                    Set<String> pkgs = moduleToPackage.get(module);
-                                    if (pkgs == null) {
-                                        pkgs = new TreeSet<>();
-                                        moduleToPackage.put(module, pkgs);
-                                    }
-                                    pkgs.add(pkg);
-                                }
-                            } else { // put only sub trees, no leaf
-                                directAccess.put(n.getPath(), n);
-                                String pkg = toPackageName(n);
-                                if (pkg != null && !pkg.startsWith("META-INF")) {
-                                    Set<String> mods = packageToModule.get(pkg);
-                                    if (mods == null) {
-                                        mods = new TreeSet<>();
-                                        packageToModule.put(pkg, mods);
-                                    }
-                                    mods.add(module);
-
-                                }
-                            }
-                        }
-                        current = n;
-                    }
-                }
-            }
-            packages = new Node(PACKAGES, root);
-            directAccess.put(packages.getPath(), packages);
-            for (Map.Entry<String, Set<String>> entry : moduleToPackage.entrySet()) {
-                for (String pkg : entry.getValue()) {
-                    Node pkgNode = new Node(pkg, packages);
-                    directAccess.put(pkgNode.getPath(), pkgNode);
-
-                    Node modNode = new Node(entry.getKey(), pkgNode);
-                    directAccess.put(modNode.getPath(), modNode);
-                }
-            }
-            for (Map.Entry<String, Set<String>> entry : packageToModule.entrySet()) {
-                Node pkgNode = new Node(entry.getKey(), packages);
-                directAccess.put(pkgNode.getPath(), pkgNode);
-                for (String module : entry.getValue()) {
-                    Node modNode = new Node(module, pkgNode);
-                    directAccess.put(modNode.getPath(), modNode);
-                }
-            }
-        }
-
-        public String toResourceName(Node node) {
-            if (!node.children.isEmpty()) {
-                throw new RuntimeException("Node is not a resource");
-            }
-            return removeRadical(node);
-        }
-
-        public String getModule(Node node) {
-            if (node.parent == null || node.getName().equals(MODULES) ||
-                node.getName().startsWith(PACKAGES)) {
-                return null;
-            }
-            String path = removeRadical(node);
-            // "/xxx/...";
-            path = path.substring(1);
-            int i = path.indexOf("/");
-            if (i == -1) {
-                return path;
-            } else {
-                return path.substring(0, i);
-            }
-        }
-
-        public String toPackageName(Node node) {
-            if (node.parent == null) {
-                return null;
-            }
-            String path = removeRadical(node.getPath(), "/" + MODULES + "/");
-            String module = getModule(node);
-            if (path.equals(module)) {
-                return null;
-            }
-            String pkg = removeRadical(path, module + "/");
-            return pkg.replaceAll("/", ".");
-        }
-
-        public String removeRadical(Node node) {
-            String s = node.getPath();
-            return removeRadical(node.getPath(), "/" + MODULES);
-        }
-
-        private String removeRadical(String path, String str) {
-            return path.substring(str.length());
-        }
-
-        public Node getRoot() {
-            return root;
-        }
-
-        public Map<String, Node> getMap() {
-            return directAccess;
-        }
-    }
-
-    private static final class LocationsAdder {
-
-        private long offset;
-        private final List<byte[]> content = new ArrayList<>();
-        private final BasicImageWriter writer;
-        private final Tree tree;
-
-        LocationsAdder(Tree tree, long offset, BasicImageWriter writer) {
-            this.tree = tree;
-            this.offset = offset;
-            this.writer = writer;
-            addLocations(tree.getRoot());
-        }
-
-        private int addLocations(Node current) {
-            int[] ret = new int[current.children.size()];
-            int i = 0;
-            for (java.util.Map.Entry<String, Node> entry : current.children.entrySet()) {
-                ret[i] = addLocations(entry.getValue());
-                i += 1;
-            }
-            if (current != tree.getRoot() && !current.isResource) {
-                int size = ret.length * 4;
-                writer.addLocation(current.getPath(), offset, 0, size);
-                offset += size;
-            }
-            return 0;
-        }
-
-        private List<byte[]> computeContent() {
-            // Map used to associate Tree item with locations offset.
-            Map<String, ImageLocationWriter> outLocations = new HashMap<>();
-            for (ImageLocationWriter wr : writer.getLocations()) {
-                outLocations.put(wr.getFullNameString(), wr);
-            }
-            // Attach location to node
-            for (Map.Entry<String, ImageLocationWriter> entry : outLocations.entrySet()) {
-                Node item = tree.getMap().get(entry.getKey());
-                if (item != null) {
-                    item.loc = entry.getValue();
-                }
-            }
-            computeContent(tree.getRoot(), outLocations);
-            return content;
-        }
-
-        private int computeContent(Node current, Map<String, ImageLocationWriter> outLocations) {
-            int[] ret = new int[current.children.size()];
-            int i = 0;
-            for (java.util.Map.Entry<String, Node> entry : current.children.entrySet()) {
-                ret[i] = computeContent(entry.getValue(), outLocations);
-                i += 1;
-            }
-            if (ret.length > 0) {
-                int size = ret.length * 4;
-                ByteBuffer buff = ByteBuffer.allocate(size);
-                buff.order(writer.getByteOrder());
-                for (int val : ret) {
-                    buff.putInt(val);
-                }
-                byte[] arr = buff.array();
-                content.add(arr);
-            } else {
-                if (current.isResource) {
-                    // A resource location, remove "/modules"
-                    String s = tree.toResourceName(current);
-                    current.loc = outLocations.get(s);
-                } else {
-                    // "/packages" leaf node, empty "/packages" or empty "/modules" paths
-                    current.loc = outLocations.get(current.getPath());
-                }
-            }
-            return current == tree.getRoot() ? 0 : current.loc.getLocationOffset();
-        }
-    }
-
-    private final List<String> paths;
-    private final LocationsAdder adder;
-
-    public ImageResourcesTree(long offset, BasicImageWriter writer, List<String> paths) {
-        this.paths = new ArrayList<>();
-        this.paths.addAll(paths);
-        Collections.sort(this.paths);
-        Tree tree = new Tree(this.paths);
-        adder = new LocationsAdder(tree, offset, writer);
-    }
-
-    public void addContent(DataOutputStream out) throws IOException {
-        List<byte[]> content = adder.computeContent();
-        for (byte[] c : content) {
-            out.write(c, 0, c.length);
-        }
-    }
-}
--- a/src/java.base/share/classes/jdk/internal/jimage/ImageStream.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/jimage/ImageStream.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,40 +29,47 @@
 import java.nio.ByteOrder;
 import java.util.Arrays;
 
-class ImageStream {
+/**
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
+ */
+public class ImageStream {
     private ByteBuffer buffer;
 
-    ImageStream() {
+    public ImageStream() {
         this(1024, ByteOrder.nativeOrder());
     }
 
-    ImageStream(int size) {
+    public ImageStream(int size) {
         this(size, ByteOrder.nativeOrder());
     }
 
-    ImageStream(byte[] bytes) {
+    public ImageStream(byte[] bytes) {
        this(bytes, ByteOrder.nativeOrder());
     }
 
-    ImageStream(ByteOrder byteOrder) {
+    public ImageStream(ByteOrder byteOrder) {
         this(1024, byteOrder);
     }
 
-    ImageStream(int size, ByteOrder byteOrder) {
+    public ImageStream(int size, ByteOrder byteOrder) {
         buffer = ByteBuffer.allocate(size);
         buffer.order(byteOrder);
     }
 
-    ImageStream(byte[] bytes, ByteOrder byteOrder) {
+    public ImageStream(byte[] bytes, ByteOrder byteOrder) {
         buffer = ByteBuffer.wrap(bytes);
         buffer.order(byteOrder);
     }
 
-    ImageStream(ByteBuffer buffer) {
+    public ImageStream(ByteBuffer buffer) {
         this.buffer = buffer;
     }
 
-    ImageStream align(int alignment) {
+    public ImageStream align(int alignment) {
         int padding = (getSize() - 1) & ((1 << alignment) - 1);
 
         for (int i = 0; i < padding; i++) {
@@ -72,8 +79,10 @@
         return this;
     }
 
-    void ensure(int needs) {
-        assert 0 <= needs : "Negative needs";
+    public void ensure(int needs) {
+        if (needs < 0) {
+            throw new IndexOutOfBoundsException("needs");
+        }
 
         if (needs > buffer.remaining()) {
             byte[] bytes = buffer.array();
@@ -86,109 +95,112 @@
         }
     }
 
-    boolean hasByte() {
+    public boolean hasByte() {
         return buffer.remaining() != 0;
     }
 
-    boolean hasBytes(int needs) {
+    public boolean hasBytes(int needs) {
         return needs <= buffer.remaining();
     }
 
-    void skip(int n) {
-        assert 0 <= n : "Negative offset";
+    public void skip(int n) {
+        if (n < 0) {
+            throw new IndexOutOfBoundsException("n");
+        }
+
         buffer.position(buffer.position() + n);
     }
 
-    int get() {
+    public int get() {
         return buffer.get() & 0xFF;
     }
 
-    void get(byte bytes[], int offset, int size) {
+    public void get(byte bytes[], int offset, int size) {
         buffer.get(bytes, offset, size);
     }
 
-    int getShort() {
+    public int getShort() {
         return buffer.getShort();
     }
 
-    int getInt() {
+    public int getInt() {
         return buffer.getInt();
     }
 
-    long getLong() {
+    public long getLong() {
         return buffer.getLong();
     }
 
-    ImageStream put(byte byt) {
+    public ImageStream put(byte byt) {
         ensure(1);
         buffer.put(byt);
 
         return this;
     }
 
-    ImageStream put(int byt) {
+    public ImageStream put(int byt) {
         return put((byte)byt);
     }
 
-    ImageStream put(byte bytes[], int offset, int size) {
+    public ImageStream put(byte bytes[], int offset, int size) {
         ensure(size);
         buffer.put(bytes, offset, size);
 
         return this;
     }
 
-    ImageStream put(ImageStream stream) {
+    public ImageStream put(ImageStream stream) {
         put(stream.buffer.array(), 0, stream.buffer.position());
 
         return this;
     }
 
-    ImageStream putShort(short value) {
+    public ImageStream putShort(short value) {
         ensure(2);
         buffer.putShort(value);
 
         return this;
     }
 
-    ImageStream putShort(int value) {
+    public ImageStream putShort(int value) {
         return putShort((short)value);
     }
 
-    ImageStream putInt(int value) {
+    public ImageStream putInt(int value) {
         ensure(4);
         buffer.putInt(value);
 
         return this;
     }
 
-    ImageStream putLong(long value) {
+    public ImageStream putLong(long value) {
         ensure(8);
         buffer.putLong(value);
 
         return this;
     }
 
-    ByteBuffer getBuffer() {
+    public ByteBuffer getBuffer() {
         return buffer;
     }
 
-    int getPosition() {
+    public int getPosition() {
         return buffer.position();
     }
 
-    int getSize() {
+    public int getSize() {
         return buffer.position();
     }
 
-    byte[] getBytes() {
+    public byte[] getBytes() {
         return buffer.array();
     }
 
-    void setPosition(int offset) {
+    public void setPosition(int offset) {
         buffer.position(offset);
     }
 
-    byte[] toArray() {
+    public byte[] toArray() {
         return Arrays.copyOf(buffer.array(), buffer.position());
     }
 }
--- a/src/java.base/share/classes/jdk/internal/jimage/ImageStrings.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/jimage/ImageStrings.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,8 +25,15 @@
 
 package jdk.internal.jimage;
 
-interface ImageStrings {
-    public UTF8String get(int offset);
+/**
+ * @implNote This interface needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
+ */
+public interface ImageStrings {
+    public String get(int offset);
 
-    public int add(final UTF8String string);
+    public int add(final String string);
 }
--- a/src/java.base/share/classes/jdk/internal/jimage/ImageStringsReader.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/jimage/ImageStringsReader.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,7 +25,18 @@
 
 package jdk.internal.jimage;
 
-class ImageStringsReader implements ImageStrings {
+import java.io.UTFDataFormatException;
+import java.nio.ByteBuffer;
+
+/**
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
+ */
+public class ImageStringsReader implements ImageStrings {
+    public static final int HASH_MULTIPLIER = 0x01000193;
     private final BasicImageReader reader;
 
     ImageStringsReader(BasicImageReader reader) {
@@ -33,12 +44,239 @@
     }
 
     @Override
-    public UTF8String get(int offset) {
-        return reader.getUTF8String(offset);
+    public String get(int offset) {
+        return reader.getString(offset);
     }
 
     @Override
-    public int add(final UTF8String string) {
+    public int add(final String string) {
         throw new InternalError("Can not add strings at runtime");
     }
+
+    private static int hashCode(byte[] bytes, int offset, int count, int seed) {
+        for (int i = offset, limit = offset + count; i < limit; i++) {
+            seed = (seed * HASH_MULTIPLIER) ^ (bytes[i] & 0xFF);
+        }
+
+        return seed & 0x7FFFFFFF;
+    }
+
+    public static int hashCode(byte[] bytes, int seed) {
+        return hashCode(bytes, 0, bytes.length, seed);
+    }
+
+    public static int hashCode(byte[] bytes) {
+        return hashCode(bytes, 0, bytes.length, HASH_MULTIPLIER);
+    }
+
+    public static int hashCode(String string, int seed) {
+        return hashCode(mutf8FromString(string), seed);
+    }
+
+    public static int hashCode(String string) {
+        return hashCode(mutf8FromString(string), HASH_MULTIPLIER);
+    }
+
+    static int charsFromMUTF8Length(byte[] bytes, int offset, int count) {
+        int length = 0;
+
+        for (int i = offset; i < offset + count; i++) {
+            byte ch = bytes[i];
+
+            if (ch == 0) {
+                break;
+            }
+
+            if ((ch & 0xC0) != 0x80) {
+                length++;
+            }
+        }
+
+        return length;
+    }
+
+    static void charsFromMUTF8(char[] chars, byte[] bytes, int offset, int count) throws UTFDataFormatException {
+        int j = 0;
+
+        for (int i = offset; i < offset + count; i++) {
+            byte ch = bytes[i];
+
+            if (ch == 0) {
+                break;
+            }
+
+            boolean is_unicode = (ch & 0x80) != 0;
+            int uch = ch & 0x7F;
+
+            if (is_unicode) {
+                int mask = 0x40;
+
+                while ((uch & mask) != 0) {
+                    ch = bytes[++i];
+
+                    if ((ch & 0xC0) != 0x80) {
+                        throw new UTFDataFormatException("bad continuation 0x" + Integer.toHexString(ch));
+                    }
+
+                    uch = ((uch & ~mask) << 6) | (ch & 0x3F);
+                    mask <<= 6 - 1;
+                }
+
+                if ((uch & 0xFFFF) != uch) {
+                    throw new UTFDataFormatException("character out of range \\u" + Integer.toHexString(uch));
+                }
+            }
+
+            chars[j++] = (char)uch;
+        }
+    }
+
+    public static String stringFromMUTF8(byte[] bytes, int offset, int count) {
+        int length = charsFromMUTF8Length(bytes, offset, count);
+        char[] chars = new char[length];
+
+        try {
+            charsFromMUTF8(chars, bytes, offset, count);
+        } catch (UTFDataFormatException ex) {
+            throw new InternalError("Attempt to convert non modified UTF-8 byte sequence");
+        }
+
+        return new String(chars);
+    }
+
+    public static String stringFromMUTF8(byte[] bytes) {
+        return stringFromMUTF8(bytes, 0, bytes.length);
+    }
+
+    static int charsFromByteBufferLength(ByteBuffer buffer) {
+        int length = 0;
+
+        while(buffer.hasRemaining()) {
+            byte ch = buffer.get();
+
+            if (ch == 0) {
+                return length;
+            }
+
+            if ((ch & 0xC0) != 0x80) {
+                length++;
+            }
+        }
+
+        throw new InternalError("No terminating zero byte for modified UTF-8 byte sequence");
+    }
+
+    static void charsFromByteBuffer(char chars[], ByteBuffer buffer) {
+        int j = 0;
+
+        while(buffer.hasRemaining()) {
+            byte ch = buffer.get();
+
+            if (ch == 0) {
+                return;
+            }
+
+            boolean is_unicode = (ch & 0x80) != 0;
+            int uch = ch & 0x7F;
+
+            if (is_unicode) {
+                int mask = 0x40;
+
+                while ((uch & mask) != 0) {
+                    ch = buffer.get();
+
+                    if ((ch & 0xC0) != 0x80) {
+                        throw new InternalError("Bad continuation in modified UTF-8 byte sequence");
+                    }
+
+                    uch = ((uch & ~mask) << 6) | (ch & 0x3F);
+                    mask <<= 6 - 1;
+                }
+            }
+
+            if ((uch & 0xFFFF) != uch) {
+                throw new InternalError("UTF-32 char in modified UTF-8 byte sequence");
+            }
+
+            chars[j++] = (char)uch;
+        }
+
+        throw new InternalError("No terminating zero byte for modified UTF-8 byte sequence");
+    }
+
+    public static String stringFromByteBuffer(ByteBuffer buffer) {
+        int length = charsFromByteBufferLength(buffer);
+        buffer.rewind();
+        char[] chars = new char[length];
+        charsFromByteBuffer(chars, buffer);
+
+        return new String(chars);
+    }
+
+    static int mutf8FromCharsLength(char chars[]) {
+        int length = 0;
+
+        for (char ch : chars) {
+            int uch = ch & 0xFFFF;
+
+            if ((uch & ~0x7F) != 0) {
+                int mask = ~0x3F;
+                int n = 0;
+
+                do {
+                    n++;
+                    uch >>= 6;
+                    mask >>= 1;
+                } while ((uch & mask) != 0);
+
+                length += n + 1;
+            } else if (uch == 0) {
+                length += 2;
+            } else {
+                length++;
+            }
+        }
+
+        return length;
+    }
+
+    static void mutf8FromChars(byte[] bytes, int offset, char chars[]) {
+        int j = offset;
+        byte[] buffer = new byte[8];
+
+        for (char ch : chars) {
+            int uch = ch & 0xFFFF;
+
+            if ((uch & ~0x7F) != 0) {
+                int mask = ~0x3F;
+                int n = 0;
+
+                do {
+                    buffer[n++] = (byte)(0x80 | (uch & 0x3F));
+                    uch >>= 6;
+                    mask >>= 1;
+                } while ((uch & mask) != 0);
+
+                buffer[n] = (byte)((mask << 1) | uch);
+
+                do {
+                    bytes[j++] = buffer[n--];
+                } while (0 <= n);
+            } else if (uch == 0) {
+                bytes[j++] = (byte)0xC0;
+                bytes[j++] = (byte)0x80;
+            } else {
+                bytes[j++] = (byte)uch;
+            }
+        }
+    }
+
+    public static byte[] mutf8FromString(String string) {
+        char[] chars = string.toCharArray();
+        int length = mutf8FromCharsLength(chars);
+        byte[] bytes = new byte[length];
+        mutf8FromChars(bytes, 0, chars);
+
+        return bytes;
+    }
 }
--- a/src/java.base/share/classes/jdk/internal/jimage/ImageStringsWriter.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,105 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.internal.jimage;
-
-import java.nio.ByteBuffer;
-import java.util.HashMap;
-
-class ImageStringsWriter implements ImageStrings {
-    private static final int NOT_FOUND = -1;
-    static final int EMPTY_OFFSET = 0;
-    static final UTF8String CLASS_STRING = new UTF8String("class");
-
-    private final HashMap<UTF8String, Integer> stringToOffsetMap;
-    private final ImageStream stream;
-
-    ImageStringsWriter() {
-        this.stringToOffsetMap = new HashMap<>();
-        this.stream = new ImageStream();
-
-        // Reserve 0 offset for empty string.
-        int offset = addString(UTF8String.EMPTY_STRING);
-        assert offset == 0 : "Empty string not zero offset";
-        // Reserve 1 offset for frequently used ".class".
-        addString(CLASS_STRING);
-    }
-
-    private int addString(final UTF8String string) {
-        int offset = stream.getPosition();
-        string.writeTo(stream);
-        stream.put('\0');
-        stringToOffsetMap.put(string, offset);
-
-        return offset;
-    }
-
-    @Override
-    public int add(final UTF8String string) {
-        int offset = find(string);
-
-        return offset == NOT_FOUND ? addString(string) : offset;
-    }
-
-    int find(final UTF8String string) {
-        Integer offset = stringToOffsetMap.get(string);
-
-        return offset != null ? offset : NOT_FOUND;
-    }
-
-    @Override
-    public UTF8String get(int offset) {
-        ByteBuffer buffer = stream.getBuffer();
-        assert 0 <= offset && offset < buffer.capacity() : "String buffer offset out of range";
-        int zero = NOT_FOUND;
-        for (int i = offset; i < buffer.capacity(); i++) {
-            if (buffer.get(i) == '\0') {
-                zero = i;
-                break;
-            }
-        }
-        assert zero != UTF8String.NOT_FOUND;
-        int length = zero - offset;
-        byte[] bytes = new byte[length];
-        int mark = buffer.position();
-        buffer.position(offset);
-        buffer.get(bytes);
-        buffer.position(mark);
-
-        return new UTF8String(bytes, 0, length);
-    }
-
-    ImageStream getStream() {
-        return stream;
-    }
-
-    int getSize() {
-        return stream.getSize();
-    }
-
-    int getCount() {
-        return stringToOffsetMap.size();
-    }
-}
--- a/src/java.base/share/classes/jdk/internal/jimage/ImageSubstrate.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.internal.jimage;
-
-import java.io.Closeable;
-import java.nio.ByteBuffer;
-
-interface ImageSubstrate extends Closeable {
-    @Override
-    void close();
-    boolean supportsDataBuffer();
-    ByteBuffer getIndexBuffer(long offset, long size);
-    ByteBuffer getDataBuffer(long offset, long size);
-    boolean read(long offset,
-                          ByteBuffer compressedBuffer, long compressedSize,
-                          ByteBuffer uncompressedBuffer, long uncompressedSize);
-    boolean read(long offset,
-                          ByteBuffer uncompressedBuffer, long uncompressedSize);
-    byte[] getStringBytes(int offset);
-    long[] getAttributes(int offset);
-    ImageLocation findLocation(UTF8String name, ImageStringsReader strings);
-    int[] attributeOffsets();
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/jimage/NativeImageBuffer.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.jimage;
+
+import java.nio.ByteBuffer;
+
+/**
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
+ */
+class NativeImageBuffer {
+    static {
+        java.security.AccessController.doPrivileged(
+                new java.security.PrivilegedAction<Void>() {
+                    public Void run() {
+                        System.loadLibrary("jimage");
+                        return null;
+                    }
+                });
+    }
+
+    native static ByteBuffer getNativeMap(String imagePath);
+}
--- a/src/java.base/share/classes/jdk/internal/jimage/PerfectHashBuilder.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,255 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
-*/
-
-package jdk.internal.jimage;
-
-import java.lang.reflect.Array;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-public class PerfectHashBuilder<E> {
-    private static final int RETRY_LIMIT = 1000;
-
-    private Class<?> entryComponent;
-    private Class<?> bucketComponent;
-
-    private final Map<UTF8String, Entry<E>> map = new LinkedHashMap<>();
-    private int[] redirect;
-    private Entry<E>[] order;
-    private int count = 0;
-
-    @SuppressWarnings("EqualsAndHashcode")
-    public static class Entry<E> {
-        private final UTF8String key;
-        private final E value;
-
-        Entry() {
-            this("", null);
-        }
-
-        Entry(String key, E value) {
-            this(new UTF8String(key), value);
-        }
-
-        Entry(UTF8String key, E value) {
-            this.key = key;
-            this.value = value;
-        }
-
-        UTF8String getKey() {
-            return key;
-        }
-
-        E getValue() {
-            return value;
-        }
-
-        int hashCode(int seed) {
-            return key.hashCode(seed);
-        }
-
-        @Override
-        public int hashCode() {
-            return key.hashCode();
-        }
-    }
-
-    static class Bucket<E> implements Comparable<Bucket<E>> {
-        final List<Entry<E>> list = new ArrayList<>();
-
-        void add(Entry<E> entry) {
-            list.add(entry);
-        }
-
-        int getSize() {
-            return list.size();
-        }
-
-        List<Entry<E>> getList() {
-            return list;
-        }
-
-        Entry<E> getFirst() {
-            assert !list.isEmpty() : "bucket should never be empty";
-            return list.get(0);
-        }
-
-        @Override
-        public int hashCode() {
-            return getFirst().hashCode();
-        }
-
-        @Override
-        @SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
-        public boolean equals(Object obj) {
-            return this == obj;
-        }
-
-        @Override
-        public int compareTo(Bucket<E> o) {
-            return o.getSize() - getSize();
-        }
-    }
-
-    public PerfectHashBuilder(Class<?> entryComponent, Class<?> bucketComponent) {
-        this.entryComponent = entryComponent;
-        this.bucketComponent = bucketComponent;
-    }
-
-    public int getCount() {
-        return map.size();
-    }
-
-    public int[] getRedirect() {
-        return redirect;
-    }
-
-    public Entry<E>[] getOrder() {
-        return order;
-    }
-
-    public Entry<E> put(String key, E value) {
-        return put(new UTF8String(key), value);
-    }
-
-    public Entry<E> put(UTF8String key, E value) {
-        return put(new Entry<>(key, value));
-    }
-
-    public Entry<E> put(Entry<E> entry) {
-        Entry<E> old = map.put(entry.key, entry);
-
-        if (old == null) {
-            count++;
-        }
-
-        return old;
-    }
-
-    @SuppressWarnings("unchecked")
-    public void generate() {
-        boolean redo = count != 0;
-        while (redo) {
-            redo = false;
-            redirect = new int[count];
-            order = (Entry<E>[])Array.newInstance(entryComponent, count);
-
-            Bucket<E>[] sorted = createBuckets();
-            int free = 0;
-
-            for (Bucket<E> bucket : sorted) {
-                if (bucket.getSize() != 1) {
-                    if (!collidedEntries(bucket, count)) {
-                        redo = true;
-                        break;
-                    }
-                } else {
-                    for ( ; free < count && order[free] != null; free++) {}
-
-                    if (free >= count) {
-                        redo = true;
-                        break;
-                    }
-
-                    order[free] = bucket.getFirst();
-                    redirect[bucket.hashCode() % count] = -1 - free;
-                    free++;
-                }
-            }
-
-            if (redo) {
-                count = (count + 1) | 1;
-            }
-        }
-    }
-
-    @SuppressWarnings("unchecked")
-    private Bucket<E>[] createBuckets() {
-        Bucket<E>[] buckets = (Bucket<E>[])Array.newInstance(bucketComponent, count);
-
-        map.values().stream().forEach((entry) -> {
-            int index = entry.hashCode() % count;
-            Bucket<E> bucket = buckets[index];
-
-            if (bucket == null) {
-                buckets[index] = bucket = new Bucket<>();
-            }
-
-            bucket.add(entry);
-        });
-
-        Bucket<E>[] sorted = Arrays.asList(buckets).stream()
-                .filter((bucket) -> (bucket != null))
-                .sorted()
-                .toArray((length) -> {
-                    return (Bucket<E>[])Array.newInstance(bucketComponent, length);
-                });
-
-        return sorted;
-    }
-
-    private boolean collidedEntries(Bucket<E> bucket, int count) {
-        List<Integer> undo = new ArrayList<>();
-        int seed = UTF8String.HASH_MULTIPLIER + 1;
-        int retry = 0;
-
-        redo:
-        while (true) {
-            for (Entry<E> entry : bucket.getList()) {
-                int index = entry.hashCode(seed) % count;
-                if (order[index] != null) {
-                    if (++retry > RETRY_LIMIT) {
-                        return false;
-                    }
-
-                    undo.stream().forEach((i) -> {
-                        order[i] = null;
-                    });
-
-                    undo.clear();
-                    seed++;
-
-                    if (seed == 0) {
-                        seed = 1;
-                    }
-
-                    continue redo;
-                }
-
-                order[index] = entry;
-                undo.add(index);
-            }
-
-            redirect[bucket.hashCode() % count] = seed;
-
-            break;
-        }
-
-        return true;
-    }
- }
--- a/src/java.base/share/classes/jdk/internal/jimage/ResourcePool.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,256 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.internal.jimage;
-
-import jdk.internal.jimage.decompressor.CompressedResourceHeader;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.Collection;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-
-/**
- * Pool of resources. This class contain the content of a jimage file in the
- * matter of Resource.
- */
-public interface ResourcePool {
-
-    /**
-     * Resources visitor
-     */
-    public interface Visitor {
-
-        /**
-         * Called for each visited Resource.
-         *
-         * @param resource The resource to deal with.
-         * @param order Byte order
-         * @param strings
-         * @return A resource or null if the passed resource is to be removed
-         * from the jimage.
-         * @throws Exception
-         */
-        public Resource visit(Resource resource, ByteOrder order,
-                StringTable strings) throws Exception;
-    }
-
-    /**
-     * A JImage Resource. Fully identified by its path.
-     */
-    public static class Resource {
-
-        private final String path;
-        private final ByteBuffer content;
-
-        private final String module;
-
-        public Resource(String path, ByteBuffer content) {
-            Objects.requireNonNull(path);
-            Objects.requireNonNull(content);
-            this.path = path;
-            this.content = content.asReadOnlyBuffer();
-            String[] split = ImageFileCreator.splitPath(path);
-            module = split[0];
-        }
-
-        public String getPath() {
-            return path;
-        }
-
-        public String getModule() {
-            return module;
-        }
-
-        /**
-         * The resource content.
-         *
-         * @return A read only buffer.
-         */
-        public ByteBuffer getContent() {
-            return content;
-        }
-
-        public int getLength() {
-            return content.limit();
-        }
-
-        public byte[] getByteArray() {
-            content.rewind();
-            byte[] array = new byte[content.remaining()];
-            content.get(array);
-            return array;
-        }
-
-        @Override
-        public String toString() {
-            return getPath();
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (!(obj instanceof Resource)) {
-                return false;
-            }
-            Resource res = (Resource) obj;
-            return res.path.equals(path);
-        }
-
-        @Override
-        public int hashCode() {
-            int hash = 7;
-            hash = 53 * hash + Objects.hashCode(this.path);
-            return hash;
-        }
-    }
-
-    /**
-     * A resource that has been compressed.
-     */
-    public static final class CompressedResource extends Resource {
-
-        private final long uncompressed_size;
-
-        private CompressedResource(String path, ByteBuffer content,
-                long uncompressed_size) {
-            super(path, content);
-            this.uncompressed_size = uncompressed_size;
-        }
-
-        public long getUncompressedSize() {
-            return uncompressed_size;
-        }
-
-        public static CompressedResource newCompressedResource(Resource original,
-                ByteBuffer compressed,
-                String plugin, String pluginConfig, StringTable strings,
-                ByteOrder order) throws Exception {
-            Objects.requireNonNull(original);
-            Objects.requireNonNull(compressed);
-            Objects.requireNonNull(plugin);
-
-            boolean isTerminal = !(original instanceof CompressedResource);
-            long uncompressed_size = original.getLength();
-            if (original instanceof CompressedResource) {
-                CompressedResource comp = (CompressedResource) original;
-                uncompressed_size = comp.getUncompressedSize();
-            }
-            int nameOffset = strings.addString(plugin);
-            int configOffset = -1;
-            if (pluginConfig != null) {
-                configOffset = strings.addString(plugin);
-            }
-            CompressedResourceHeader rh =
-                    new CompressedResourceHeader(compressed.limit(), original.getLength(),
-                    nameOffset, configOffset, isTerminal);
-            // Merge header with content;
-            byte[] h = rh.getBytes(order);
-            ByteBuffer bb = ByteBuffer.allocate(compressed.limit() + h.length);
-            bb.order(order);
-            bb.put(h);
-            bb.put(compressed);
-            ByteBuffer contentWithHeader = ByteBuffer.wrap(bb.array());
-
-            CompressedResource compressedResource =
-                    new CompressedResource(original.getPath(),
-                    contentWithHeader, uncompressed_size);
-            return compressedResource;
-        }
-    }
-
-    /**
-     * Read only state.
-     *
-     * @return true if readonly false otherwise.
-     */
-    public boolean isReadOnly();
-
-    /**
-     * The byte order
-     *
-     * @return
-     */
-    public ByteOrder getByteOrder();
-
-    /**
-     * Add a resource.
-     *
-     * @param resource The Resource to add.
-     * @throws java.lang.Exception If the pool is read only.
-     */
-    public void addResource(Resource resource) throws Exception;
-
-    /**
-     * Check if a resource is contained in the pool.
-     *
-     * @param res The resource to check.
-     * @return true if res is contained, false otherwise.
-     */
-    public boolean contains(Resource res);
-
-    /**
-     * Get all resources contained in this pool instance.
-     *
-     * @return The collection of resources;
-     */
-    public Collection<Resource> getResources();
-
-    /**
-     * Get the resource for the passed path.
-     *
-     * @param path A resource path
-     * @return A Resource instance or null if the resource is not found
-     */
-    public Resource getResource(String path);
-
-    /**
-     * The Image modules. It is computed based on the resources contained by
-     * this ResourcePool instance.
-     *
-     * @return The Image Modules.
-     */
-    public Map<String, Set<String>> getModulePackages();
-
-    /**
-     * Check if this pool contains some resources.
-     *
-     * @return True if contains some resources.
-     */
-    public boolean isEmpty();
-
-    /**
-     * Visit the resources contained in this ResourcePool.
-     *
-     * @param visitor The visitor
-     * @param output The pool to store resources.
-     * @param strings
-     * @throws Exception
-     */
-    public void visit(Visitor visitor, ResourcePool output, StringTable strings)
-            throws Exception;
-
-    public void addTransformedResource(Resource original, ByteBuffer transformed)
-            throws Exception;
-}
--- a/src/java.base/share/classes/jdk/internal/jimage/ResourcePoolImpl.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,211 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.internal.jimage;
-
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-
-/**
- * Pool of resources. This class contain the content of a jimage file in the
- * matter of Resource.
- */
-public class ResourcePoolImpl implements ResourcePool {
-
-    private final Map<String, Resource> resources = new LinkedHashMap<>();
-
-    private final ByteOrder order;
-    private boolean isReadOnly;
-
-    public ResourcePoolImpl(ByteOrder order) {
-        Objects.requireNonNull(order);
-        this.order = order;
-    }
-
-    /**
-     * Make this Resources instance read-only. No resource can be added.
-     */
-    public void setReadOnly() {
-        isReadOnly = true;
-    }
-
-    /**
-     * Read only state.
-     *
-     * @return true if readonly false otherwise.
-     */
-    @Override
-    public boolean isReadOnly() {
-        return isReadOnly;
-    }
-
-    /**
-     * The byte order
-     *
-     * @return
-     */
-    @Override
-    public ByteOrder getByteOrder() {
-        return order;
-    }
-
-    /**
-     * Add a resource.
-     *
-     * @param resource The Resource to add.
-     * @throws java.lang.Exception If the pool is read only.
-     */
-    @Override
-    public void addResource(Resource resource) throws Exception {
-        if (isReadOnly()) {
-            throw new Exception("pool is readonly");
-        }
-        Objects.requireNonNull(resource);
-        if (resources.get(resource.getPath()) != null) {
-            throw new Exception("Resource" + resource.getPath() +
-                    " already present");
-        }
-        resources.put(resource.getPath(), resource);
-    }
-
-    /**
-     * Check if a resource is contained in the pool.
-     *
-     * @param res The resource to check.
-     * @return true if res is contained, false otherwise.
-     */
-    @Override
-    public boolean contains(Resource res) {
-        Objects.requireNonNull(res);
-        try {
-            getResource(res.getPath());
-            return true;
-        } catch (Exception ex) {
-            return false;
-        }
-    }
-
-    /**
-     * Get all resources contained in this pool instance.
-     *
-     * @return The collection of resources;
-     */
-    @Override
-    public Collection<Resource> getResources() {
-        return Collections.unmodifiableCollection(resources.values());
-    }
-
-/**
-     * Get the resource for the passed path.
-     *
-     * @param path A resource path
-     * @return A Resource instance or null if the resource is not found
-     */
-    @Override
-    public Resource getResource(String path) {
-        Objects.requireNonNull(path);
-        return resources.get(path);
-    }
-
-    /**
-     * The Image modules. It is computed based on the resources contained by
-     * this ResourcePool instance.
-     *
-     * @return The Image Modules.
-     */
-    @Override
-    public Map<String, Set<String>> getModulePackages() {
-        Map<String, Set<String>> moduleToPackage = new LinkedHashMap<>();
-        retrieveModulesPackages(moduleToPackage);
-        return moduleToPackage;
-    }
-
-    /**
-     * Check if this pool contains some resources.
-     *
-     * @return True if contains some resources.
-     */
-    @Override
-    public boolean isEmpty() {
-        return resources.isEmpty();
-    }
-
-    /**
-     * Visit the resources contained in this ResourcePool.
-     *
-     * @param visitor The visitor
-     * @param strings
-     * @throws Exception
-     */
-    @Override
-    public void visit(Visitor visitor, ResourcePool output, StringTable strings)
-            throws Exception {
-        for (Resource resource : getResources()) {
-            Resource res = visitor.visit(resource, order, strings);
-            if (res != null) {
-                output.addResource(res);
-            }
-        }
-    }
-
-    @Override
-    public void addTransformedResource(Resource original, ByteBuffer transformed)
-            throws Exception {
-        if (isReadOnly()) {
-            throw new Exception("Pool is readonly");
-        }
-        Objects.requireNonNull(original);
-        Objects.requireNonNull(transformed);
-        if (resources.get(original.getPath()) != null) {
-            throw new Exception("Resource already present");
-        }
-        Resource res = new Resource(original.getPath(), transformed);
-        addResource(res);
-    }
-
-    private void retrieveModulesPackages(Map<String, Set<String>> moduleToPackage) {
-        for (Resource res : resources.values()) {
-            Set<String> pkgs = moduleToPackage.get(res.getModule());
-            if (pkgs == null) {
-                pkgs = new HashSet<>();
-                moduleToPackage.put(res.getModule(), pkgs);
-            }
-            // Module metadata only contains packages with resource files
-            if (ImageFileCreator.isResourcePackage(res.getPath())) {
-                String[] split = ImageFileCreator.splitPath(res.getPath());
-                String pkg = split[1];
-                if (pkg != null && !pkg.isEmpty()) {
-                    pkgs.add(pkg);
-                }
-            }
-        }
-    }
-}
--- a/src/java.base/share/classes/jdk/internal/jimage/StringTable.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.internal.jimage;
-
-/**
-* Added strings are stored in the jimage strings table.
-*/
-public interface StringTable {
-    /**
-     * Add a string to the jimage strings table.
-     * @param str The string to add.
-     * @return a String identifier.
-     */
-    public int addString(String str);
-
-    /**
-     * Retrieve a string from the passed id.
-     * @param id The string id.
-     * @return The string referenced by the passed id.
-     */
-    public String getString(int id);
-}
--- a/src/java.base/share/classes/jdk/internal/jimage/UTF8String.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,250 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.internal.jimage;
-
-import java.nio.charset.Charset;
-import java.util.Arrays;
-
-public final class UTF8String implements CharSequence {
-    // Same as StandardCharsets.UTF_8 without loading all of the standard charsets
-    static final Charset UTF_8 = Charset.forName("UTF-8");
-
-    static final int NOT_FOUND = -1;
-    static final int HASH_MULTIPLIER = 0x01000193;
-    static final UTF8String EMPTY_STRING = new UTF8String("");
-    static final UTF8String SLASH_STRING = new UTF8String("/");
-    static final UTF8String DOT_STRING = new UTF8String(".");
-
-    // TODO This strings are implementation specific and should be defined elsewhere.
-    static final UTF8String MODULES_STRING = new UTF8String("/modules");
-    static final UTF8String PACKAGES_STRING = new UTF8String("/packages");
-
-    final byte[] bytes;
-    final int offset;
-    final int count;
-    int hashcode;
-
-    public UTF8String(byte[] bytes, int offset, int count) {
-        if (offset < 0 || count < 0 || (offset + count) > bytes.length) {
-            throw new IndexOutOfBoundsException("offset/count out of range");
-        }
-        this.bytes = bytes;
-        this.offset = offset;
-        this.count = count;
-        this.hashcode = -1;
-    }
-
-    public UTF8String(byte[] bytes, int offset) {
-        this(bytes, offset, bytes.length - offset);
-    }
-
-    public UTF8String(byte[] bytes) {
-        this(bytes, 0, bytes.length);
-    }
-
-    public UTF8String(String string) {
-        this(stringToBytes(string));
-    }
-
-    @Override
-    public int length() {
-        return count;
-    }
-
-    public boolean isEmpty() {
-        return count == 0;
-    }
-
-    public int byteAt(int index) {
-        return bytes[offset + index] & 0xFF;
-    }
-
-    public UTF8String concat(UTF8String s) {
-        int total = count + s.count;
-        byte[] combined = new byte[total];
-        System.arraycopy(bytes, offset, combined, 0, count);
-        System.arraycopy(s.bytes, s.offset, combined, count, s.count);
-
-        return new UTF8String(combined, 0, total);
-    }
-
-    public UTF8String concat(UTF8String... s) {
-        int total = count;
-
-        for (UTF8String i : s) {
-            total += i.count;
-        }
-
-        byte[] combined = new byte[total];
-        System.arraycopy(bytes, offset, combined, 0, count);
-        int next = count;
-
-        for (UTF8String i : s) {
-            System.arraycopy(i.bytes, i.offset, combined, next, i.count);
-            next += i.count;
-        }
-
-        return new UTF8String(combined, 0, total);
-    }
-
-    public UTF8String substring(int offset) {
-        return substring(offset, this.count - offset);
-    }
-
-    public UTF8String substring(int offset, int count) {
-        int newOffset = this.offset + offset;
-        return new UTF8String(bytes, newOffset, count);
-    }
-
-    public UTF8String trimToSize() {
-        return offset == 0 && bytes.length == count ? this :
-               new UTF8String(Arrays.copyOfRange(bytes, offset, offset + count));
-    }
-
-    public int indexOf(int ch) {
-        return indexOf(ch, 0);
-    }
-
-    public int indexOf(int ch, int start) {
-        for (int i = Math.max(start, 0); i < count; i++) {
-            if (byteAt(i) == ch) {
-                return i;
-            }
-        }
-
-        return NOT_FOUND;
-    }
-
-    public int lastIndexOf(int ch) {
-        return lastIndexOf(ch, count - 1);
-    }
-
-    public int lastIndexOf(int ch, int start) {
-        for (int i = Math.min(start, count); i > 0; i--) {
-            if (byteAt(i) == ch) {
-                return i;
-            }
-        }
-
-        return NOT_FOUND;
-    }
-
-    void writeTo(ImageStream buffer) {
-        buffer.put(bytes, offset, count);
-    }
-
-    static int hashCode(int seed, byte[] bytes, int offset, int count) {
-        for (int i = offset, limit = offset + count; i < limit; i++) {
-            seed = (seed * HASH_MULTIPLIER) ^ (bytes[i] & 0xFF);
-        }
-
-        return seed & 0x7FFFFFFF;
-    }
-
-    int hashCode(int seed) {
-        return hashCode(seed, bytes, offset, count);
-    }
-
-    @Override
-    public int hashCode() {
-        if (hashcode < 0) {
-            hashcode = hashCode(HASH_MULTIPLIER, bytes, offset, count);
-        }
-
-        return hashcode;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (obj == null) {
-            return false;
-        }
-
-        if (getClass() != obj.getClass()) {
-            return false;
-        }
-
-        return equals(this, (UTF8String)obj);
-    }
-
-    public static boolean equals(UTF8String a, UTF8String b) {
-        if (a == b) {
-            return true;
-        }
-
-        int count = a.count;
-
-        if (count != b.count) {
-            return false;
-        }
-
-        byte[] aBytes = a.bytes;
-        byte[] bBytes = b.bytes;
-        int aOffset = a.offset;
-        int bOffset = b.offset;
-
-        for (int i = 0; i < count; i++) {
-            if (aBytes[aOffset + i] != bBytes[bOffset + i]) {
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-    public byte[] getBytesCopy() {
-        return Arrays.copyOfRange(bytes, offset, offset + count);
-    }
-
-    byte[] getBytes() {
-        if (offset != 0 || bytes.length != count) {
-            return Arrays.copyOfRange(bytes, offset, offset + count);
-        }
-
-        return bytes;
-    }
-
-    private static byte[] stringToBytes(String string) {
-        return string.getBytes(UTF_8);
-    }
-
-    @Override
-    public String toString() {
-        return new String(bytes, offset, count, UTF_8);
-    }
-
-    @Override
-    public char charAt(int index) {
-        int ch = byteAt(index);
-
-        return (ch & 0x80) == 0 ? (char)ch : '\0';
-    }
-
-    @Override
-    public CharSequence subSequence(int start, int end) {
-        return (CharSequence)substring(start, end - start);
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/jimage/decompressor/CompressIndexes.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.jimage.decompressor;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ * Index compressor. Use the minimal amount of bytes required to store
+ * an integer.
+ *
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
+ */
+public class CompressIndexes {
+    private static final int INTEGER_SIZE = 4;
+
+    public static List<Integer> decompressFlow(byte[] values) {
+        List<Integer> lst = new ArrayList<>();
+        for (int i = 0; i < values.length;) {
+            byte b = values[i];
+            int length = isCompressed(b) ? getLength(b) : INTEGER_SIZE;
+            int decompressed = decompress(values, i);
+            lst.add(decompressed);
+            i += length;
+        }
+        return lst;
+    }
+
+    public static int readInt(DataInputStream cr) throws IOException {
+        byte[] b = new byte[1];
+        cr.readFully(b);
+        byte firstByte = b[0];
+        boolean compressed = CompressIndexes.isCompressed(firstByte);
+        int toRead = 4;
+        if(compressed) {
+            toRead = CompressIndexes.getLength(firstByte);
+        }
+        byte[] content = new byte[toRead-1];
+        cr.readFully(content);
+        ByteBuffer bb = ByteBuffer.allocate(content.length+1);
+        bb.put(firstByte);
+        bb.put(content);
+        int index = CompressIndexes.decompress(bb.array(), 0);
+        return index;
+    }
+
+    public static int getLength(byte b) {
+        return ((byte) (b & 0x60) >> 5);
+    }
+
+    public static boolean isCompressed(byte b) {
+        return b < 0;
+    }
+
+    public static int decompress(byte[] value, int offset) {
+        byte b1 = value[offset];
+        ByteBuffer buffer = ByteBuffer.allocate(INTEGER_SIZE);
+        if (isCompressed(b1)) { // compressed
+            int length = getLength(b1);
+            byte clearedValue = (byte) (b1 & 0x1F);
+
+            int start = INTEGER_SIZE - length;
+            buffer.put(start, clearedValue);
+            for (int i = offset + 1; i < offset + length; i++) {
+                buffer.put(++start, value[i]);
+            }
+        } else {
+            buffer.put(value, offset, INTEGER_SIZE);
+        }
+        return buffer.getInt(0);
+    }
+
+    public static byte[] compress(int val) {
+        ByteBuffer result = ByteBuffer.allocate(4).putInt(val);
+        byte[] array = result.array();
+
+        if ((val & 0xFF000000) == 0) { // nothing on 4th
+            if ((val & 0x00FF0000) == 0) { // nothing on 3rd
+                if ((val & 0x0000FF00) == 0) { // nothing on 2nd
+                    if ((val & 0x000000E0) == 0) { // only in 1st, encode length in the byte.
+                        //sign bit and size 1 ==> 101X
+                        result = ByteBuffer.allocate(1);
+                        result.put((byte) (0xA0 | array[3]));
+                    } else { // add a byte for size
+                        //sign bit and size 2 ==> 110X
+                        result = ByteBuffer.allocate(2);
+                        result.put((byte) 0xC0);
+                        result.put(array[3]);
+                    }
+                } else { // content in 2nd
+                    if ((val & 0x0000E000) == 0) {// encode length in the byte.
+                        //sign bit and size 2 ==> 110X
+                        result = ByteBuffer.allocate(2);
+                        result.put((byte) (0xC0 | array[2]));
+                        result.put(array[3]);
+                    } else { // add a byte for size
+                        //sign bit and size 3 ==> 111X
+                        result = ByteBuffer.allocate(3);
+                        result.put((byte) 0xE0);
+                        result.put(array[2]);
+                        result.put(array[3]);
+                    }
+                }
+            } else {// content in 3rd
+                if ((val & 0x00E00000) == 0) {// encode length in the byte.
+                    //sign bit and size 3 ==> 111X
+                    result = ByteBuffer.allocate(3);
+                    result.put((byte) (0xE0 | array[1]));
+                    result.put(array[2]);
+                    result.put(array[3]);
+                } else { // add a byte, useless
+                    //
+                }
+            }
+        }
+        return result.array();
+    }
+}
--- a/src/java.base/share/classes/jdk/internal/jimage/decompressor/CompressedResourceHeader.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/jimage/decompressor/CompressedResourceHeader.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,19 +34,25 @@
  * A resource header for compressed resource. This class is handled internally,
  * you don't have to add header to the resource, headers are added automatically
  * for compressed resources.
+ *
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
  */
 public final class CompressedResourceHeader {
 
-    private static final int SIZE = 21;
+    private static final int SIZE = 29;
     public static final int MAGIC = 0xCAFEFAFA;
-    private final int uncompressedSize;
-    private final int compressedSize;
+    private final long uncompressedSize;
+    private final long compressedSize;
     private final int decompressorNameOffset;
     private final int contentOffset;
     private final boolean isTerminal;
 
-    public CompressedResourceHeader(int compressedSize,
-            int uncompressedSize, int decompressorNameOffset, int contentOffset,
+    public CompressedResourceHeader(long compressedSize,
+            long uncompressedSize, int decompressorNameOffset, int contentOffset,
             boolean isTerminal) {
         this.compressedSize = compressedSize;
         this.uncompressedSize = uncompressedSize;
@@ -68,18 +74,18 @@
     }
 
     public String getStoredContent(StringsProvider provider) {
-        Objects.nonNull(provider);
+        Objects.requireNonNull(provider);
         if(contentOffset == -1) {
             return null;
         }
         return provider.getString(contentOffset);
     }
 
-    public int getUncompressedSize() {
+    public long getUncompressedSize() {
         return uncompressedSize;
     }
 
-    public int getResourceSize() {
+    public long getResourceSize() {
         return compressedSize;
     }
 
@@ -88,8 +94,8 @@
         ByteBuffer buffer = ByteBuffer.allocate(SIZE);
         buffer.order(order);
         buffer.putInt(MAGIC);
-        buffer.putInt(compressedSize);
-        buffer.putInt(uncompressedSize);
+        buffer.putLong(compressedSize);
+        buffer.putLong(uncompressedSize);
         buffer.putInt(decompressorNameOffset);
         buffer.putInt(contentOffset);
         buffer.put(isTerminal ? (byte)1 : (byte)0);
@@ -113,8 +119,8 @@
         if(magic != MAGIC) {
             return null;
         }
-        int size = buffer.getInt();
-        int uncompressedSize = buffer.getInt();
+        long size = buffer.getLong();
+        long uncompressedSize = buffer.getLong();
         int decompressorNameOffset = buffer.getInt();
         int contentIndex = buffer.getInt();
         byte isTerminal = buffer.get();
--- a/src/java.base/share/classes/jdk/internal/jimage/decompressor/Decompressor.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/jimage/decompressor/Decompressor.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,7 @@
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.nio.ByteOrder;
+import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
@@ -35,6 +36,12 @@
 
 /**
  * Entry point to decompress resources.
+ *
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
  */
 public final class Decompressor {
 
@@ -71,8 +78,9 @@
                     String storedContent = header.getStoredContent(provider);
                     Properties props = new Properties();
                     if (storedContent != null) {
-                        try (ByteArrayInputStream stream =
-                                new ByteArrayInputStream(storedContent.getBytes());) {
+                        try (ByteArrayInputStream stream
+                                = new ByteArrayInputStream(storedContent.
+                                        getBytes(StandardCharsets.UTF_8));) {
                             props.loadFromXML(stream);
                         }
                     }
--- a/src/java.base/share/classes/jdk/internal/jimage/decompressor/ResourceDecompressor.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/jimage/decompressor/ResourceDecompressor.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,7 +26,13 @@
 
 /**
  *
- * JImage Decompressor.
+ * JLink Image Decompressor.
+ *
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
  */
 public interface ResourceDecompressor {
 
@@ -49,5 +55,5 @@
      * @throws Exception
      */
     public byte[] decompress(StringsProvider strings, byte[] content, int offset,
-            int originalSize) throws Exception;
+            long originalSize) throws Exception;
 }
--- a/src/java.base/share/classes/jdk/internal/jimage/decompressor/ResourceDecompressorFactory.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/jimage/decompressor/ResourceDecompressorFactory.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,18 +29,19 @@
 
 /**
  *
- * JImage Resource Decompressor factory
+ * JLink Resource Decompressor factory
+ *
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
  */
 public abstract class ResourceDecompressorFactory {
     private final String name;
-    private final String description;
-    private final String arguments;
 
-    protected ResourceDecompressorFactory(String name, String description,
-            String arguments) {
+    protected ResourceDecompressorFactory(String name) {
         this.name = name;
-        this.description = description;
-        this.arguments = arguments;
     }
 
     /**
@@ -52,22 +53,6 @@
     }
 
     /**
-     * The Factory description.
-     * @return The description.
-     */
-    public String getDescription() {
-        return description;
-    }
-
-    /**
-     * The Factory arguments description.
-     * @return The arguments description.
-     */
-    public String getArgumentsDescription() {
-        return arguments;
-    }
-
-    /**
      * To build a new decompressor.
      * @param properties Contains configuration.
      * @return A new decompressor.
--- a/src/java.base/share/classes/jdk/internal/jimage/decompressor/ResourceDecompressorRepository.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/jimage/decompressor/ResourceDecompressorRepository.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,8 +31,14 @@
 
 /**
  *
- * JImage Decompressors. All decompressors must be registered in the static
+ * JLink Decompressors. All decompressors must be registered in the static
  * initializer of this class.
+ *
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
  */
 public final class ResourceDecompressorRepository {
 
@@ -43,6 +49,7 @@
 
     static {
         registerReaderProvider(new ZipDecompressorFactory());
+        registerReaderProvider(new StringSharingDecompressorFactory());
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/jimage/decompressor/SignatureParser.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.jimage.decompressor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ * A descriptor parser used to extract java type strings from
+ * UTF_8 descriptors.
+ *
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
+ */
+public class SignatureParser {
+
+   public static class ParseResult {
+
+        public final List<String> types = new ArrayList<>();
+        public String formatted;
+        private ParseResult() {}
+    }
+
+    private SignatureParser() {}
+
+    public static String reconstruct(String formatted, List<String> arguments) {
+        int arg_index = 0;
+        char[] chars = formatted.toCharArray();
+        StringBuilder out = new StringBuilder();
+
+        for (int i = 0; i < chars.length; i++) {
+            char c = chars[i];
+            out.append(c);
+            switch (c) {
+                case 'L': {
+                    String pkg = arguments.get(arg_index);
+                    if(pkg.length() > 0) {
+                        out.append(pkg).append("/");
+                    }
+                    arg_index+=1;
+                    out.append(arguments.get(arg_index));
+                    arg_index+=1;
+                    break;
+                }
+                default: {
+                    break;
+                }
+            }
+        }
+        return out.toString();
+    }
+
+    public static ParseResult parseSignatureDescriptor(String str) {
+        ParseResult res = new ParseResult();
+        char[] chars = str.toCharArray();
+        StringBuilder type = null;
+        StringBuilder formatted = new StringBuilder();
+        for (int i = 0; i < chars.length; i++) {
+            char c = chars[i];
+            switch (c) {
+                case ';':
+                case ':':
+                case '<': {
+                    if(type != null) {
+                        String fullName = type.toString();
+                        int endIndex = fullName.lastIndexOf("/");
+                        String clazz = fullName;
+                        String pkg = "";
+                        if(endIndex != -1) {
+                            pkg = fullName.substring(0, endIndex);
+                            clazz = fullName.substring(endIndex+1);
+                        }
+                        res.types.add(pkg);
+                        res.types.add(clazz);
+                    }
+                    formatted.append(c);
+
+                    type = null;
+                    break;
+                }
+                case 'L': {
+                    if(type == null) {
+                        type = new StringBuilder();
+                        formatted.append(c);
+                    } else {
+                        type.append(c);
+                    }
+                    break;
+                }
+                default: {
+                    if(type == null) {
+                        formatted.append(c);
+                    } else {
+                        type.append(c);
+                    }
+                    break;
+                }
+            }
+        }
+        res.formatted = formatted.toString();
+        return res;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/jimage/decompressor/StringSharingDecompressor.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.jimage.decompressor;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ *
+ * A Decompressor that reconstructs the constant pool of classes.
+ *
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
+ */
+public class StringSharingDecompressor implements ResourceDecompressor {
+
+    public static final int EXTERNALIZED_STRING = 23;
+    public static final int EXTERNALIZED_STRING_DESCRIPTOR = 25;
+
+    private static final int CONSTANT_Utf8 = 1;
+    private static final int CONSTANT_Integer = 3;
+    private static final int CONSTANT_Float = 4;
+    private static final int CONSTANT_Long = 5;
+    private static final int CONSTANT_Double = 6;
+    private static final int CONSTANT_Class = 7;
+    private static final int CONSTANT_String = 8;
+    private static final int CONSTANT_Fieldref = 9;
+    private static final int CONSTANT_Methodref = 10;
+    private static final int CONSTANT_InterfaceMethodref = 11;
+    private static final int CONSTANT_NameAndType = 12;
+    private static final int CONSTANT_MethodHandle = 15;
+    private static final int CONSTANT_MethodType = 16;
+    private static final int CONSTANT_InvokeDynamic = 18;
+
+    private static final int[] SIZES = new int[20];
+
+    static {
+
+        //SIZES[CONSTANT_Utf8] = XXX;
+        SIZES[CONSTANT_Integer] = 4;
+        SIZES[CONSTANT_Float] = 4;
+        SIZES[CONSTANT_Long] = 8;
+        SIZES[CONSTANT_Double] = 8;
+        SIZES[CONSTANT_Class] = 2;
+        SIZES[CONSTANT_String] = 2;
+        SIZES[CONSTANT_Fieldref] = 4;
+        SIZES[CONSTANT_Methodref] = 4;
+        SIZES[CONSTANT_InterfaceMethodref] = 4;
+        SIZES[CONSTANT_NameAndType] = 4;
+        SIZES[CONSTANT_MethodHandle] = 3;
+        SIZES[CONSTANT_MethodType] = 2;
+        SIZES[CONSTANT_InvokeDynamic] = 4;
+    }
+
+    public static int[] getSizes() {
+        return SIZES.clone();
+    }
+
+    @SuppressWarnings("fallthrough")
+    public static byte[] normalize(StringsProvider provider, byte[] transformed,
+            int offset) throws IOException {
+        DataInputStream stream = new DataInputStream(new ByteArrayInputStream(transformed,
+                offset, transformed.length - offset));
+        ByteArrayOutputStream outStream = new ByteArrayOutputStream(transformed.length);
+        DataOutputStream out = new DataOutputStream(outStream);
+        byte[] header = new byte[8]; //maginc/4, minor/2, major/2
+        stream.readFully(header);
+        out.write(header);
+        int count = stream.readUnsignedShort();
+        out.writeShort(count);
+        for (int i = 1; i < count; i++) {
+            int tag = stream.readUnsignedByte();
+            byte[] arr;
+            switch (tag) {
+                case CONSTANT_Utf8: {
+                    out.write(tag);
+                    String utf = stream.readUTF();
+                    out.writeUTF(utf);
+                    break;
+                }
+
+                case EXTERNALIZED_STRING: {
+                    int index = CompressIndexes.readInt(stream);
+                    String orig = provider.getString(index);
+                    out.write(CONSTANT_Utf8);
+                    out.writeUTF(orig);
+                    break;
+                }
+
+                case EXTERNALIZED_STRING_DESCRIPTOR: {
+                    String orig = reconstruct(provider, stream);
+                    out.write(CONSTANT_Utf8);
+                    out.writeUTF(orig);
+                    break;
+                }
+                case CONSTANT_Long:
+                case CONSTANT_Double: {
+                    i++;
+                }
+                default: {
+                    out.write(tag);
+                    int size = SIZES[tag];
+                    arr = new byte[size];
+                    stream.readFully(arr);
+                    out.write(arr);
+                }
+            }
+        }
+        out.write(transformed, transformed.length - stream.available(),
+                stream.available());
+        out.flush();
+
+        return outStream.toByteArray();
+    }
+
+    private static String reconstruct(StringsProvider reader, DataInputStream cr)
+            throws IOException {
+        int descIndex = CompressIndexes.readInt(cr);
+        String desc = reader.getString(descIndex);
+        byte[] encodedDesc = getEncoded(desc);
+        int indexes_length = CompressIndexes.readInt(cr);
+        byte[] bytes = new byte[indexes_length];
+        cr.readFully(bytes);
+        List<Integer> indices = CompressIndexes.decompressFlow(bytes);
+        ByteBuffer buffer = ByteBuffer.allocate(encodedDesc.length * 2);
+        buffer.order(ByteOrder.BIG_ENDIAN);
+        int argIndex = 0;
+        for (byte c : encodedDesc) {
+            if (c == 'L') {
+                buffer = safeAdd(buffer, c);
+                int index = indices.get(argIndex);
+                argIndex += 1;
+                String pkg = reader.getString(index);
+                if (pkg.length() > 0) {
+                    pkg = pkg + "/";
+                    byte[] encoded = getEncoded(pkg);
+                    buffer = safeAdd(buffer, encoded);
+                }
+                int classIndex = indices.get(argIndex);
+                argIndex += 1;
+                String clazz = reader.getString(classIndex);
+                byte[] encoded = getEncoded(clazz);
+                buffer = safeAdd(buffer, encoded);
+            } else {
+                buffer = safeAdd(buffer, c);
+            }
+        }
+
+        byte[] encoded = buffer.array();
+        ByteBuffer result = ByteBuffer.allocate(encoded.length + 2);
+        result.order(ByteOrder.BIG_ENDIAN);
+        result.putShort((short) buffer.position());
+        result.put(encoded, 0, buffer.position());
+        ByteArrayInputStream stream = new ByteArrayInputStream(result.array());
+        DataInputStream inStream = new DataInputStream(stream);
+        String str = inStream.readUTF();
+        return str;
+    }
+
+    public static byte[] getEncoded(String pre) throws IOException {
+        ByteArrayOutputStream resultStream = new ByteArrayOutputStream();
+        DataOutputStream resultOut = new DataOutputStream(resultStream);
+        resultOut.writeUTF(pre);
+        byte[] content = resultStream.toByteArray();
+        // first 2 items are length;
+        if (content.length <= 2) {
+            return new byte[0];
+        }
+        return Arrays.copyOfRange(content, 2, content.length);
+    }
+
+    private static ByteBuffer safeAdd(ByteBuffer current, byte b) {
+        byte[] bytes = {b};
+        return safeAdd(current, bytes);
+    }
+
+    private static ByteBuffer safeAdd(ByteBuffer current, byte[] bytes) {
+        if (current.remaining() < bytes.length) {
+            ByteBuffer newBuffer = ByteBuffer.allocate((current.capacity()
+                    + bytes.length) * 2);
+            newBuffer.order(ByteOrder.BIG_ENDIAN);
+            newBuffer.put(current.array(), 0, current.position());
+            current = newBuffer;
+        }
+        current.put(bytes);
+        return current;
+    }
+
+    @Override
+    public String getName() {
+        return StringSharingDecompressorFactory.NAME;
+    }
+
+    public StringSharingDecompressor(Properties properties) {
+
+    }
+
+    @Override
+    public byte[] decompress(StringsProvider reader, byte[] content,
+            int offset, long originalSize) throws Exception {
+        return normalize(reader, content, offset);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/jimage/decompressor/StringSharingDecompressorFactory.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.jimage.decompressor;
+
+import java.io.IOException;
+import java.util.Properties;
+
+/**
+ *
+ * Constant Pool strings sharing Decompressor factory.
+ *
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
+ */
+public class StringSharingDecompressorFactory extends ResourceDecompressorFactory {
+
+    public static final String NAME = "compact-cp";
+    public StringSharingDecompressorFactory() {
+        super(NAME);
+    }
+
+    @Override
+    public ResourceDecompressor newDecompressor(Properties properties)
+            throws IOException {
+        return new StringSharingDecompressor(properties);
+    }
+}
--- a/src/java.base/share/classes/jdk/internal/jimage/decompressor/ZipDecompressor.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/jimage/decompressor/ZipDecompressor.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,13 +25,17 @@
 package jdk.internal.jimage.decompressor;
 
 import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.util.zip.DataFormatException;
 import java.util.zip.Inflater;
 
 /**
  *
  * ZIP Decompressor
+ *
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
  */
 final class ZipDecompressor implements ResourceDecompressor {
 
@@ -40,29 +44,18 @@
         return ZipDecompressorFactory.NAME;
     }
 
-    static byte[] decompress(byte[] bytesIn, int offset) {
+    static byte[] decompress(byte[] bytesIn, int offset) throws Exception {
         Inflater inflater = new Inflater();
         inflater.setInput(bytesIn, offset, bytesIn.length - offset);
         ByteArrayOutputStream stream = new ByteArrayOutputStream(bytesIn.length - offset);
         byte[] buffer = new byte[1024];
 
         while (!inflater.finished()) {
-            int count;
-
-            try {
-                count = inflater.inflate(buffer);
-            } catch (DataFormatException ex) {
-                return null;
-            }
-
+            int count = inflater.inflate(buffer);
             stream.write(buffer, 0, count);
         }
 
-        try {
-            stream.close();
-        } catch (IOException ex) {
-            return null;
-        }
+        stream.close();
 
         byte[] bytesOut = stream.toByteArray();
         inflater.end();
@@ -72,7 +65,7 @@
 
     @Override
     public byte[] decompress(StringsProvider reader, byte[] content, int offset,
-            int originalSize) throws Exception {
+            long originalSize) throws Exception {
         byte[] decompressed = decompress(content, offset);
         return decompressed;
     }
--- a/src/java.base/share/classes/jdk/internal/jimage/decompressor/ZipDecompressorFactory.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/jimage/decompressor/ZipDecompressorFactory.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,11 +30,17 @@
 /**
  *
  * ZIP decompressor factory
+ *
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
  */
 public final class ZipDecompressorFactory extends ResourceDecompressorFactory {
     public static final String NAME = "zip";
     public ZipDecompressorFactory() {
-        super(NAME, "ZIP Decompression", null);
+        super(NAME);
     }
 
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/jrtfs/AbstractJrtFileAttributes.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.jrtfs;
+
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.Formatter;
+
+/**
+ * Base class for file attributes supported by jrt file systems.
+ *
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
+ */
+public abstract class AbstractJrtFileAttributes implements BasicFileAttributes {
+
+    // jrt fs specific attributes
+    /**
+     * Compressed resource file. If not available or not applicable, 0L is
+     * returned.
+     *
+     * @return the compressed resource size for compressed resources.
+     */
+    public abstract long compressedSize();
+
+    /**
+     * "file" extension of a file resource.
+     *
+     * @return extension string for the file resource
+     */
+    public abstract String extension();
+
+    @Override
+    public final String toString() {
+        StringBuilder sb = new StringBuilder(1024);
+        try (Formatter fm = new Formatter(sb)) {
+            if (creationTime() != null) {
+                fm.format("    creationTime    : %tc%n", creationTime().toMillis());
+            } else {
+                fm.format("    creationTime    : null%n");
+            }
+
+            if (lastAccessTime() != null) {
+                fm.format("    lastAccessTime  : %tc%n", lastAccessTime().toMillis());
+            } else {
+                fm.format("    lastAccessTime  : null%n");
+            }
+            fm.format("    lastModifiedTime: %tc%n", lastModifiedTime().toMillis());
+            fm.format("    isRegularFile   : %b%n", isRegularFile());
+            fm.format("    isDirectory     : %b%n", isDirectory());
+            fm.format("    isSymbolicLink  : %b%n", isSymbolicLink());
+            fm.format("    isOther         : %b%n", isOther());
+            fm.format("    fileKey         : %s%n", fileKey());
+            fm.format("    size            : %d%n", size());
+            fm.format("    compressedSize  : %d%n", compressedSize());
+            fm.format("    extension       : %s%n", extension());
+        }
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/jrtfs/AbstractJrtFileSystem.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,372 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.jrtfs;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.Channels;
+import java.nio.channels.FileChannel;
+import java.nio.channels.NonWritableChannelException;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.SeekableByteChannel;
+import java.nio.charset.Charset;
+import java.nio.file.ClosedFileSystemException;
+import java.nio.file.CopyOption;
+import java.nio.file.FileStore;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystemNotFoundException;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.OpenOption;
+import java.nio.file.Path;
+import java.nio.file.PathMatcher;
+import java.nio.file.ReadOnlyFileSystemException;
+import java.nio.file.StandardOpenOption;
+import java.nio.file.WatchService;
+import java.nio.file.attribute.FileAttribute;
+import java.nio.file.attribute.FileTime;
+import java.nio.file.attribute.UserPrincipalLookupService;
+import java.nio.file.spi.FileSystemProvider;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+/**
+ * Base class for jrt file systems. jrt filesystem implementations are currently
+ * available on top of .jimage file and on top "exploded" build directories.
+ *
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
+ */
+abstract class AbstractJrtFileSystem extends FileSystem {
+
+    private final JrtFileSystemProvider provider;
+
+    AbstractJrtFileSystem(JrtFileSystemProvider provider, Map<String, ?> options) {
+        this.provider = provider;
+    }
+
+    private static final Charset UTF_8 = Charset.forName("UTF-8");
+
+    // static utility methods
+    static ReadOnlyFileSystemException readOnly() {
+        return new ReadOnlyFileSystemException();
+    }
+
+    // if a Path does not exist, throw exception
+    static void checkExists(Path path) {
+        if (Files.notExists(path)) {
+            throw new FileSystemNotFoundException(path.toString());
+        }
+    }
+
+    static byte[] getBytes(String name) {
+        return name.getBytes(UTF_8);
+    }
+
+    static String getString(byte[] name) {
+        return new String(name, UTF_8);
+    }
+
+    // do the supplied options imply that we have to chase symlinks?
+    static boolean followLinks(LinkOption... options) {
+        if (options != null) {
+            for (LinkOption lo : options) {
+                if (lo == LinkOption.NOFOLLOW_LINKS) {
+                    return false;
+                } else if (lo == null) {
+                    throw new NullPointerException();
+                } else {
+                    throw new AssertionError("should not reach here");
+                }
+            }
+        }
+        return true;
+    }
+
+    // check that the options passed are supported by (read-only) jrt file system
+    static void checkOptions(Set<? extends OpenOption> options) {
+        // check for options of null type and option is an intance of StandardOpenOption
+        for (OpenOption option : options) {
+            if (option == null) {
+                throw new NullPointerException();
+            }
+            if (!(option instanceof StandardOpenOption)) {
+                throw new IllegalArgumentException();
+            }
+        }
+
+        if (options.contains(StandardOpenOption.WRITE)
+                || options.contains(StandardOpenOption.APPEND)) {
+            throw readOnly();
+        }
+    }
+
+    // FileSystem method implementations
+    @Override
+    public FileSystemProvider provider() {
+        return provider;
+    }
+
+    @Override
+    public Iterable<Path> getRootDirectories() {
+        ArrayList<Path> pathArr = new ArrayList<>();
+        pathArr.add(getRootPath());
+        return pathArr;
+    }
+
+    @Override
+    public AbstractJrtPath getPath(String first, String... more) {
+        String path;
+        if (more.length == 0) {
+            path = first;
+        } else {
+            StringBuilder sb = new StringBuilder();
+            sb.append(first);
+            for (String segment : more) {
+                if (segment.length() > 0) {
+                    if (sb.length() > 0) {
+                        sb.append('/');
+                    }
+                    sb.append(segment);
+                }
+            }
+            path = sb.toString();
+        }
+        return getRootPath().newJrtPath(getBytes(path));
+    }
+
+    @Override
+    public final boolean isReadOnly() {
+        return true;
+    }
+
+    @Override
+    public final UserPrincipalLookupService getUserPrincipalLookupService() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public final WatchService newWatchService() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public final Iterable<FileStore> getFileStores() {
+        ArrayList<FileStore> list = new ArrayList<>(1);
+        list.add(getFileStore(getRootPath()));
+        return list;
+    }
+
+    private static final Set<String> supportedFileAttributeViews
+            = Collections.unmodifiableSet(
+                    new HashSet<String>(Arrays.asList("basic", "jrt")));
+
+    @Override
+    public final Set<String> supportedFileAttributeViews() {
+        return supportedFileAttributeViews;
+    }
+
+    @Override
+    public final String toString() {
+        return "jrt:/";
+    }
+
+    @Override
+    public final String getSeparator() {
+        return "/";
+    }
+
+    private static final String GLOB_SYNTAX = "glob";
+    private static final String REGEX_SYNTAX = "regex";
+
+    @Override
+    public PathMatcher getPathMatcher(String syntaxAndInput) {
+        int pos = syntaxAndInput.indexOf(':');
+        if (pos <= 0 || pos == syntaxAndInput.length()) {
+            throw new IllegalArgumentException();
+        }
+        String syntax = syntaxAndInput.substring(0, pos);
+        String input = syntaxAndInput.substring(pos + 1);
+        String expr;
+        if (syntax.equalsIgnoreCase(GLOB_SYNTAX)) {
+            expr = JrtUtils.toRegexPattern(input);
+        } else {
+            if (syntax.equalsIgnoreCase(REGEX_SYNTAX)) {
+                expr = input;
+            } else {
+                throw new UnsupportedOperationException("Syntax '" + syntax
+                        + "' not recognized");
+            }
+        }
+        // return matcher
+        final Pattern pattern = Pattern.compile(expr);
+        return (Path path) -> pattern.matcher(path.toString()).matches();
+    }
+
+    // These methods throw read only file system exception
+    final void setTimes(AbstractJrtPath jrtPath, FileTime mtime, FileTime atime, FileTime ctime)
+            throws IOException {
+        throw readOnly();
+    }
+
+    final void createDirectory(AbstractJrtPath jrtPath, FileAttribute<?>... attrs) throws IOException {
+        throw readOnly();
+    }
+
+    final void deleteFile(AbstractJrtPath jrtPath, boolean failIfNotExists)
+            throws IOException {
+        throw readOnly();
+    }
+
+    final OutputStream newOutputStream(AbstractJrtPath jrtPath, OpenOption... options)
+            throws IOException {
+        throw readOnly();
+    }
+
+    final void copyFile(boolean deletesrc, AbstractJrtPath srcPath, AbstractJrtPath dstPath, CopyOption... options)
+            throws IOException {
+        throw readOnly();
+    }
+
+    final FileChannel newFileChannel(AbstractJrtPath jrtPath,
+            Set<? extends OpenOption> options,
+            FileAttribute<?>... attrs)
+            throws IOException {
+        throw new UnsupportedOperationException("newFileChannel");
+    }
+
+    final InputStream newInputStream(AbstractJrtPath jrtPath) throws IOException {
+        return new ByteArrayInputStream(getFileContent(jrtPath));
+    }
+
+    final SeekableByteChannel newByteChannel(AbstractJrtPath jrtPath,
+            Set<? extends OpenOption> options,
+            FileAttribute<?>... attrs)
+            throws IOException {
+        checkOptions(options);
+
+        byte[] buf = getFileContent(jrtPath);
+        final ReadableByteChannel rbc
+                = Channels.newChannel(new ByteArrayInputStream(buf));
+        final long size = buf.length;
+        return new SeekableByteChannel() {
+            long read = 0;
+
+            @Override
+            public boolean isOpen() {
+                return rbc.isOpen();
+            }
+
+            @Override
+            public long position() throws IOException {
+                return read;
+            }
+
+            @Override
+            public SeekableByteChannel position(long pos)
+                    throws IOException {
+                throw new UnsupportedOperationException();
+            }
+
+            @Override
+            public int read(ByteBuffer dst) throws IOException {
+                int n = rbc.read(dst);
+                if (n > 0) {
+                    read += n;
+                }
+                return n;
+            }
+
+            @Override
+            public SeekableByteChannel truncate(long size)
+                    throws IOException {
+                throw new NonWritableChannelException();
+            }
+
+            @Override
+            public int write(ByteBuffer src) throws IOException {
+                throw new NonWritableChannelException();
+            }
+
+            @Override
+            public long size() throws IOException {
+                return size;
+            }
+
+            @Override
+            public void close() throws IOException {
+                rbc.close();
+            }
+        };
+    }
+
+    final JrtFileStore getFileStore(AbstractJrtPath jrtPath) {
+        return new JrtFileStore(jrtPath);
+    }
+
+    final void ensureOpen() throws IOException {
+        if (!isOpen()) {
+            throw new ClosedFileSystemException();
+        }
+    }
+
+    // abstract methods to be implemented by a particular jrt file system
+    abstract AbstractJrtPath getRootPath();
+
+    abstract boolean isSameFile(AbstractJrtPath jrtPath1, AbstractJrtPath jrtPath2) throws IOException;
+
+    abstract boolean isLink(AbstractJrtPath jrtPath) throws IOException;
+
+    abstract AbstractJrtPath resolveLink(AbstractJrtPath jrtPath) throws IOException;
+
+    abstract AbstractJrtFileAttributes getFileAttributes(AbstractJrtPath jrtPath, LinkOption... options) throws IOException;
+
+    abstract boolean exists(AbstractJrtPath jrtPath) throws IOException;
+
+    abstract boolean isDirectory(AbstractJrtPath jrtPath, boolean resolveLinks) throws IOException;
+
+    /**
+     * returns the list of child paths of the given directory "path"
+     *
+     * @param path name of the directory whose content is listed
+     * @return iterator for child paths of the given directory path
+     */
+    abstract Iterator<Path> iteratorOf(AbstractJrtPath jrtPath) throws IOException;
+
+    // returns the content of the file resource specified by the path
+    abstract byte[] getFileContent(AbstractJrtPath jrtPath) throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/jrtfs/AbstractJrtPath.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,935 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.jrtfs;
+
+import java.io.*;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.channels.*;
+import java.nio.file.*;
+import java.nio.file.DirectoryStream.Filter;
+import java.nio.file.attribute.*;
+import java.util.*;
+import static java.nio.file.StandardOpenOption.*;
+import static java.nio.file.StandardCopyOption.*;
+
+/**
+ * Base class for Path implementation of jrt file systems.
+ *
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
+ */
+abstract class AbstractJrtPath implements Path {
+
+    protected final AbstractJrtFileSystem jrtfs;
+    private final byte[] path;
+    private volatile int[] offsets;
+    private int hashcode = 0;  // cached hashcode (created lazily)
+
+    AbstractJrtPath(AbstractJrtFileSystem jrtfs, byte[] path) {
+        this(jrtfs, path, false);
+        this.resolved = null;
+    }
+
+    AbstractJrtPath(AbstractJrtFileSystem jrtfs, byte[] path, boolean normalized) {
+        this.resolved = null;
+        this.jrtfs = jrtfs;
+        if (normalized) {
+            this.path = path;
+        } else {
+            this.path = normalize(path);
+        }
+    }
+
+    // factory methods to create subtypes of AbstractJrtPath
+    protected abstract AbstractJrtPath newJrtPath(byte[] path);
+
+    protected abstract AbstractJrtPath newJrtPath(byte[] path, boolean normalized);
+
+    final byte[] getName() {
+        return path;
+    }
+
+    @Override
+    public final AbstractJrtPath getRoot() {
+        if (this.isAbsolute()) {
+            return jrtfs.getRootPath();
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public final AbstractJrtPath getFileName() {
+        initOffsets();
+        int count = offsets.length;
+        if (count == 0) {
+            return null;  // no elements so no name
+        }
+        if (count == 1 && path[0] != '/') {
+            return this;
+        }
+        int lastOffset = offsets[count - 1];
+        int len = path.length - lastOffset;
+        byte[] result = new byte[len];
+        System.arraycopy(path, lastOffset, result, 0, len);
+        return newJrtPath(result);
+    }
+
+    @Override
+    public final AbstractJrtPath getParent() {
+        initOffsets();
+        int count = offsets.length;
+        if (count == 0) // no elements so no parent
+        {
+            return null;
+        }
+        int len = offsets[count - 1] - 1;
+        if (len <= 0) // parent is root only (may be null)
+        {
+            return getRoot();
+        }
+        byte[] result = new byte[len];
+        System.arraycopy(path, 0, result, 0, len);
+        return newJrtPath(result);
+    }
+
+    @Override
+    public final int getNameCount() {
+        initOffsets();
+        return offsets.length;
+    }
+
+    @Override
+    public final AbstractJrtPath getName(int index) {
+        initOffsets();
+        if (index < 0 || index >= offsets.length) {
+            throw new IllegalArgumentException();
+        }
+        int begin = offsets[index];
+        int len;
+        if (index == (offsets.length - 1)) {
+            len = path.length - begin;
+        } else {
+            len = offsets[index + 1] - begin - 1;
+        }
+        // construct result
+        byte[] result = new byte[len];
+        System.arraycopy(path, begin, result, 0, len);
+        return newJrtPath(result);
+    }
+
+    @Override
+    public final AbstractJrtPath subpath(int beginIndex, int endIndex) {
+        initOffsets();
+        if (beginIndex < 0
+                || beginIndex >= offsets.length
+                || endIndex > offsets.length
+                || beginIndex >= endIndex) {
+            throw new IllegalArgumentException();
+        }
+
+        // starting offset and length
+        int begin = offsets[beginIndex];
+        int len;
+        if (endIndex == offsets.length) {
+            len = path.length - begin;
+        } else {
+            len = offsets[endIndex] - begin - 1;
+        }
+        // construct result
+        byte[] result = new byte[len];
+        System.arraycopy(path, begin, result, 0, len);
+        return newJrtPath(result);
+    }
+
+    @Override
+    public final AbstractJrtPath toRealPath(LinkOption... options) throws IOException {
+        AbstractJrtPath realPath = newJrtPath(getResolvedPath()).toAbsolutePath();
+        realPath = JrtFileSystem.followLinks(options) ? jrtfs.resolveLink(this) : realPath;
+        realPath.checkAccess();
+        return realPath;
+    }
+
+    final AbstractJrtPath readSymbolicLink() throws IOException {
+        if (!jrtfs.isLink(this)) {
+            throw new IOException("not a symbolic link");
+        }
+
+        return jrtfs.resolveLink(this);
+    }
+
+    final boolean isHidden() {
+        return false;
+    }
+
+    @Override
+    public final AbstractJrtPath toAbsolutePath() {
+        if (isAbsolute()) {
+            return this;
+        } else {
+            //add / bofore the existing path
+            byte[] tmp = new byte[path.length + 1];
+            tmp[0] = '/';
+            System.arraycopy(path, 0, tmp, 1, path.length);
+            return newJrtPath(tmp).normalize();
+        }
+    }
+
+    @Override
+    public final URI toUri() {
+        try {
+            return new URI("jrt",
+                    JrtFileSystem.getString(toAbsolutePath().path),
+                    null);
+        } catch (URISyntaxException ex) {
+            throw new AssertionError(ex);
+        }
+    }
+
+    private boolean equalsNameAt(AbstractJrtPath other, int index) {
+        int mbegin = offsets[index];
+        int mlen;
+        if (index == (offsets.length - 1)) {
+            mlen = path.length - mbegin;
+        } else {
+            mlen = offsets[index + 1] - mbegin - 1;
+        }
+        int obegin = other.offsets[index];
+        int olen;
+        if (index == (other.offsets.length - 1)) {
+            olen = other.path.length - obegin;
+        } else {
+            olen = other.offsets[index + 1] - obegin - 1;
+        }
+        if (mlen != olen) {
+            return false;
+        }
+        int n = 0;
+        while (n < mlen) {
+            if (path[mbegin + n] != other.path[obegin + n]) {
+                return false;
+            }
+            n++;
+        }
+        return true;
+    }
+
+    @Override
+    public final AbstractJrtPath relativize(Path other) {
+        final AbstractJrtPath o = checkPath(other);
+        if (o.equals(this)) {
+            return newJrtPath(new byte[0], true);
+        }
+        if (/* this.getFileSystem() != o.getFileSystem() || */this.isAbsolute() != o.isAbsolute()) {
+            throw new IllegalArgumentException();
+        }
+        int mc = this.getNameCount();
+        int oc = o.getNameCount();
+        int n = Math.min(mc, oc);
+        int i = 0;
+        while (i < n) {
+            if (!equalsNameAt(o, i)) {
+                break;
+            }
+            i++;
+        }
+        int dotdots = mc - i;
+        int len = dotdots * 3 - 1;
+        if (i < oc) {
+            len += (o.path.length - o.offsets[i] + 1);
+        }
+        byte[] result = new byte[len];
+
+        int pos = 0;
+        while (dotdots > 0) {
+            result[pos++] = (byte) '.';
+            result[pos++] = (byte) '.';
+            if (pos < len) // no tailing slash at the end
+            {
+                result[pos++] = (byte) '/';
+            }
+            dotdots--;
+        }
+        if (i < oc) {
+            System.arraycopy(o.path, o.offsets[i],
+                    result, pos,
+                    o.path.length - o.offsets[i]);
+        }
+        return newJrtPath(result);
+    }
+
+    @Override
+    public AbstractJrtFileSystem getFileSystem() {
+        return jrtfs;
+    }
+
+    @Override
+    public final boolean isAbsolute() {
+        return (this.path.length > 0 && path[0] == '/');
+    }
+
+    @Override
+    public final AbstractJrtPath resolve(Path other) {
+        final AbstractJrtPath o = checkPath(other);
+        if (o.isAbsolute()) {
+            return o;
+        }
+        byte[] res;
+        if (this.path[path.length - 1] == '/') {
+            res = new byte[path.length + o.path.length];
+            System.arraycopy(path, 0, res, 0, path.length);
+            System.arraycopy(o.path, 0, res, path.length, o.path.length);
+        } else {
+            res = new byte[path.length + 1 + o.path.length];
+            System.arraycopy(path, 0, res, 0, path.length);
+            res[path.length] = '/';
+            System.arraycopy(o.path, 0, res, path.length + 1, o.path.length);
+        }
+        return newJrtPath(res);
+    }
+
+    @Override
+    public final Path resolveSibling(Path other) {
+        if (other == null) {
+            throw new NullPointerException();
+        }
+        Path parent = getParent();
+        return (parent == null) ? other : parent.resolve(other);
+    }
+
+    @Override
+    public final boolean startsWith(Path other) {
+        final AbstractJrtPath o = checkPath(other);
+        if (o.isAbsolute() != this.isAbsolute()
+                || o.path.length > this.path.length) {
+            return false;
+        }
+        int olast = o.path.length;
+        for (int i = 0; i < olast; i++) {
+            if (o.path[i] != this.path[i]) {
+                return false;
+            }
+        }
+        olast--;
+        return o.path.length == this.path.length
+                || o.path[olast] == '/'
+                || this.path[olast + 1] == '/';
+    }
+
+    @Override
+    public final boolean endsWith(Path other) {
+        final AbstractJrtPath o = checkPath(other);
+        int olast = o.path.length - 1;
+        if (olast > 0 && o.path[olast] == '/') {
+            olast--;
+        }
+        int last = this.path.length - 1;
+        if (last > 0 && this.path[last] == '/') {
+            last--;
+        }
+        if (olast == -1) // o.path.length == 0
+        {
+            return last == -1;
+        }
+        if ((o.isAbsolute() && (!this.isAbsolute() || olast != last))
+                || (last < olast)) {
+            return false;
+        }
+        for (; olast >= 0; olast--, last--) {
+            if (o.path[olast] != this.path[last]) {
+                return false;
+            }
+        }
+        return o.path[olast + 1] == '/'
+                || last == -1 || this.path[last] == '/';
+    }
+
+    @Override
+    public final AbstractJrtPath resolve(String other) {
+        return resolve(getFileSystem().getPath(other));
+    }
+
+    @Override
+    public final Path resolveSibling(String other) {
+        return resolveSibling(getFileSystem().getPath(other));
+    }
+
+    @Override
+    public final boolean startsWith(String other) {
+        return startsWith(getFileSystem().getPath(other));
+    }
+
+    @Override
+    public final boolean endsWith(String other) {
+        return endsWith(getFileSystem().getPath(other));
+    }
+
+    @Override
+    public final AbstractJrtPath normalize() {
+        byte[] res = getResolved();
+        if (res == path) // no change
+        {
+            return this;
+        }
+        return newJrtPath(res, true);
+    }
+
+    private AbstractJrtPath checkPath(Path path) {
+        if (path == null) {
+            throw new NullPointerException();
+        }
+        if (!(path instanceof AbstractJrtPath)) {
+            throw new ProviderMismatchException();
+        }
+        return (AbstractJrtPath) path;
+    }
+
+    // create offset list if not already created
+    private void initOffsets() {
+        if (offsets == null) {
+            int count, index;
+            // count names
+            count = 0;
+            index = 0;
+            while (index < path.length) {
+                byte c = path[index++];
+                if (c != '/') {
+                    count++;
+                    while (index < path.length && path[index] != '/') {
+                        index++;
+                    }
+                }
+            }
+            // populate offsets
+            int[] result = new int[count];
+            count = 0;
+            index = 0;
+            while (index < path.length) {
+                byte c = path[index];
+                if (c == '/') {
+                    index++;
+                } else {
+                    result[count++] = index++;
+                    while (index < path.length && path[index] != '/') {
+                        index++;
+                    }
+                }
+            }
+            synchronized (this) {
+                if (offsets == null) {
+                    offsets = result;
+                }
+            }
+        }
+    }
+
+    private volatile byte[] resolved;
+
+    final byte[] getResolvedPath() {
+        byte[] r = resolved;
+        if (r == null) {
+            if (isAbsolute()) {
+                r = getResolved();
+            } else {
+                r = toAbsolutePath().getResolvedPath();
+            }
+            resolved = r;
+        }
+        return resolved;
+    }
+
+    // removes redundant slashs, replace "\" to separator "/"
+    // and check for invalid characters
+    private static byte[] normalize(byte[] path) {
+        if (path.length == 0) {
+            return path;
+        }
+        byte prevC = 0;
+        for (int i = 0; i < path.length; i++) {
+            byte c = path[i];
+            if (c == '\\') {
+                return normalize(path, i);
+            }
+            if (c == (byte) '/' && prevC == '/') {
+                return normalize(path, i - 1);
+            }
+            if (c == '\u0000') {
+                throw new InvalidPathException(JrtFileSystem.getString(path),
+                        "Path: nul character not allowed");
+            }
+            prevC = c;
+        }
+
+        if (path.length > 1 && path[path.length - 1] == '/') {
+            return Arrays.copyOf(path, path.length - 1);
+        }
+
+        return path;
+    }
+
+    private static byte[] normalize(byte[] path, int off) {
+        byte[] to = new byte[path.length];
+        int n = 0;
+        while (n < off) {
+            to[n] = path[n];
+            n++;
+        }
+        int m = n;
+        byte prevC = 0;
+        while (n < path.length) {
+            byte c = path[n++];
+            if (c == (byte) '\\') {
+                c = (byte) '/';
+            }
+            if (c == (byte) '/' && prevC == (byte) '/') {
+                continue;
+            }
+            if (c == '\u0000') {
+                throw new InvalidPathException(JrtFileSystem.getString(path),
+                        "Path: nul character not allowed");
+            }
+            to[m++] = c;
+            prevC = c;
+        }
+        if (m > 1 && to[m - 1] == '/') {
+            m--;
+        }
+        return (m == to.length) ? to : Arrays.copyOf(to, m);
+    }
+
+    // Remove DotSlash(./) and resolve DotDot (..) components
+    private byte[] getResolved() {
+        if (path.length == 0) {
+            return path;
+        }
+        for (int i = 0; i < path.length; i++) {
+            byte c = path[i];
+            if (c == (byte) '.') {
+                return resolve0();
+            }
+        }
+
+        return path;
+    }
+
+    // TBD: performance, avoid initOffsets
+    private byte[] resolve0() {
+        byte[] to = new byte[path.length];
+        int nc = getNameCount();
+        int[] lastM = new int[nc];
+        int lastMOff = -1;
+        int m = 0;
+        for (int i = 0; i < nc; i++) {
+            int n = offsets[i];
+            int len = (i == offsets.length - 1)
+                    ? (path.length - n) : (offsets[i + 1] - n - 1);
+            if (len == 1 && path[n] == (byte) '.') {
+                if (m == 0 && path[0] == '/') // absolute path
+                {
+                    to[m++] = '/';
+                }
+                continue;
+            }
+            if (len == 2 && path[n] == '.' && path[n + 1] == '.') {
+                if (lastMOff >= 0) {
+                    m = lastM[lastMOff--];  // retreat
+                    continue;
+                }
+                if (path[0] == '/') {  // "/../xyz" skip
+                    if (m == 0) {
+                        to[m++] = '/';
+                    }
+                } else {               // "../xyz" -> "../xyz"
+                    if (m != 0 && to[m - 1] != '/') {
+                        to[m++] = '/';
+                    }
+                    while (len-- > 0) {
+                        to[m++] = path[n++];
+                    }
+                }
+                continue;
+            }
+            if (m == 0 && path[0] == '/' || // absolute path
+                    m != 0 && to[m - 1] != '/') {   // not the first name
+                to[m++] = '/';
+            }
+            lastM[++lastMOff] = m;
+            while (len-- > 0) {
+                to[m++] = path[n++];
+            }
+        }
+        if (m > 1 && to[m - 1] == '/') {
+            m--;
+        }
+        return (m == to.length) ? to : Arrays.copyOf(to, m);
+    }
+
+    @Override
+    public final String toString() {
+        return JrtFileSystem.getString(path);
+    }
+
+    @Override
+    public final int hashCode() {
+        int h = hashcode;
+        if (h == 0) {
+            hashcode = h = Arrays.hashCode(path);
+        }
+        return h;
+    }
+
+    @Override
+    public final boolean equals(Object obj) {
+        return obj != null
+                && obj instanceof AbstractJrtPath
+                && this.jrtfs == ((AbstractJrtPath) obj).jrtfs
+                && compareTo((Path) obj) == 0;
+    }
+
+    @Override
+    public final int compareTo(Path other) {
+        final AbstractJrtPath o = checkPath(other);
+        int len1 = this.path.length;
+        int len2 = o.path.length;
+
+        int n = Math.min(len1, len2);
+        byte v1[] = this.path;
+        byte v2[] = o.path;
+
+        int k = 0;
+        while (k < n) {
+            int c1 = v1[k] & 0xff;
+            int c2 = v2[k] & 0xff;
+            if (c1 != c2) {
+                return c1 - c2;
+            }
+            k++;
+        }
+        return len1 - len2;
+    }
+
+    @Override
+    public final WatchKey register(
+            WatchService watcher,
+            WatchEvent.Kind<?>[] events,
+            WatchEvent.Modifier... modifiers) {
+        if (watcher == null || events == null || modifiers == null) {
+            throw new NullPointerException();
+        }
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public final WatchKey register(WatchService watcher, WatchEvent.Kind<?>... events) {
+        return register(watcher, events, new WatchEvent.Modifier[0]);
+    }
+
+    @Override
+    public final File toFile() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public final Iterator<Path> iterator() {
+        return new Iterator<Path>() {
+            private int i = 0;
+
+            @Override
+            public boolean hasNext() {
+                return (i < getNameCount());
+            }
+
+            @Override
+            public Path next() {
+                if (i < getNameCount()) {
+                    Path result = getName(i);
+                    i++;
+                    return result;
+                } else {
+                    throw new NoSuchElementException();
+                }
+            }
+
+            @Override
+            public void remove() {
+                throw new ReadOnlyFileSystemException();
+            }
+        };
+    }
+
+    /////////////////////////////////////////////////////////////////////
+    // Helpers for JrtFileSystemProvider and JrtFileSystem
+    final int getPathLength() {
+        return path.length;
+    }
+
+    final void createDirectory(FileAttribute<?>... attrs)
+            throws IOException {
+        jrtfs.createDirectory(this, attrs);
+    }
+
+    final InputStream newInputStream(OpenOption... options) throws IOException {
+        if (options.length > 0) {
+            for (OpenOption opt : options) {
+                if (opt != READ) {
+                    throw new UnsupportedOperationException("'" + opt + "' not allowed");
+                }
+            }
+        }
+        return jrtfs.newInputStream(this);
+    }
+
+    final DirectoryStream<Path> newDirectoryStream(Filter<? super Path> filter)
+            throws IOException {
+        return new JrtDirectoryStream(this, filter);
+    }
+
+    final void delete() throws IOException {
+        jrtfs.deleteFile(this, true);
+    }
+
+    final void deleteIfExists() throws IOException {
+        jrtfs.deleteFile(this, false);
+    }
+
+    final AbstractJrtFileAttributes getAttributes(LinkOption... options) throws IOException {
+        AbstractJrtFileAttributes zfas = jrtfs.getFileAttributes(this, options);
+        if (zfas == null) {
+            throw new NoSuchFileException(toString());
+        }
+        return zfas;
+    }
+
+    final void setAttribute(String attribute, Object value, LinkOption... options)
+            throws IOException {
+        String type;
+        String attr;
+        int colonPos = attribute.indexOf(':');
+        if (colonPos == -1) {
+            type = "basic";
+            attr = attribute;
+        } else {
+            type = attribute.substring(0, colonPos++);
+            attr = attribute.substring(colonPos);
+        }
+        JrtFileAttributeView view = JrtFileAttributeView.get(this, type, options);
+        if (view == null) {
+            throw new UnsupportedOperationException("view <" + view + "> is not supported");
+        }
+        view.setAttribute(attr, value);
+    }
+
+    final void setTimes(FileTime mtime, FileTime atime, FileTime ctime)
+            throws IOException {
+        jrtfs.setTimes(this, mtime, atime, ctime);
+    }
+
+    final Map<String, Object> readAttributes(String attributes, LinkOption... options)
+            throws IOException {
+        String view;
+        String attrs;
+        int colonPos = attributes.indexOf(':');
+        if (colonPos == -1) {
+            view = "basic";
+            attrs = attributes;
+        } else {
+            view = attributes.substring(0, colonPos++);
+            attrs = attributes.substring(colonPos);
+        }
+        JrtFileAttributeView jrtfv = JrtFileAttributeView.get(this, view, options);
+        if (jrtfv == null) {
+            throw new UnsupportedOperationException("view not supported");
+        }
+        return jrtfv.readAttributes(attrs);
+    }
+
+    final FileStore getFileStore() throws IOException {
+        // each JrtFileSystem only has one root (as requested for now)
+        if (exists()) {
+            return jrtfs.getFileStore(this);
+        }
+        throw new NoSuchFileException(JrtFileSystem.getString(path));
+    }
+
+    final boolean isSameFile(Path other) throws IOException {
+        if (this.equals(other)) {
+            return true;
+        }
+        if (other == null
+                || this.getFileSystem() != other.getFileSystem()) {
+            return false;
+        }
+        this.checkAccess();
+        AbstractJrtPath target = (AbstractJrtPath) other;
+        target.checkAccess();
+        return Arrays.equals(this.getResolvedPath(), target.getResolvedPath())
+                || jrtfs.isSameFile(this, target);
+    }
+
+    final SeekableByteChannel newByteChannel(Set<? extends OpenOption> options,
+            FileAttribute<?>... attrs)
+            throws IOException {
+        return jrtfs.newByteChannel(this, options, attrs);
+    }
+
+    final FileChannel newFileChannel(Set<? extends OpenOption> options,
+            FileAttribute<?>... attrs)
+            throws IOException {
+        return jrtfs.newFileChannel(this, options, attrs);
+    }
+
+    final void checkAccess(AccessMode... modes) throws IOException {
+        boolean w = false;
+        boolean x = false;
+        for (AccessMode mode : modes) {
+            switch (mode) {
+                case READ:
+                    break;
+                case WRITE:
+                    w = true;
+                    break;
+                case EXECUTE:
+                    x = true;
+                    break;
+                default:
+                    throw new UnsupportedOperationException();
+            }
+        }
+
+        BasicFileAttributes attrs = jrtfs.getFileAttributes(this);
+        if (attrs == null && (path.length != 1 || path[0] != '/')) {
+            throw new NoSuchFileException(toString());
+        }
+        if (w) {
+//            if (jrtfs.isReadOnly())
+            throw new AccessDeniedException(toString());
+        }
+        if (x) {
+            throw new AccessDeniedException(toString());
+        }
+    }
+
+    final boolean exists() {
+        try {
+            return jrtfs.exists(this);
+        } catch (IOException x) {
+        }
+        return false;
+    }
+
+    final OutputStream newOutputStream(OpenOption... options) throws IOException {
+        if (options.length == 0) {
+            return jrtfs.newOutputStream(this,
+                    CREATE_NEW, WRITE);
+        }
+        return jrtfs.newOutputStream(this, options);
+    }
+
+    final void move(AbstractJrtPath target, CopyOption... options)
+            throws IOException {
+        if (this.jrtfs == target.jrtfs) {
+            jrtfs.copyFile(true,
+                    this, target,
+                    options);
+        } else {
+            copyToTarget(target, options);
+            delete();
+        }
+    }
+
+    final void copy(AbstractJrtPath target, CopyOption... options)
+            throws IOException {
+        if (this.jrtfs == target.jrtfs) {
+            jrtfs.copyFile(false,
+                    this, target,
+                    options);
+        } else {
+            copyToTarget(target, options);
+        }
+    }
+
+    private void copyToTarget(AbstractJrtPath target, CopyOption... options)
+            throws IOException {
+        boolean replaceExisting = false;
+        boolean copyAttrs = false;
+        for (CopyOption opt : options) {
+            if (opt == REPLACE_EXISTING) {
+                replaceExisting = true;
+            } else if (opt == COPY_ATTRIBUTES) {
+                copyAttrs = true;
+            }
+        }
+        // attributes of source file
+        BasicFileAttributes jrtfas = getAttributes();
+        // check if target exists
+        boolean exists;
+        if (replaceExisting) {
+            try {
+                target.deleteIfExists();
+                exists = false;
+            } catch (DirectoryNotEmptyException x) {
+                exists = true;
+            }
+        } else {
+            exists = target.exists();
+        }
+        if (exists) {
+            throw new FileAlreadyExistsException(target.toString());
+        }
+
+        if (jrtfas.isDirectory()) {
+            // create directory or file
+            target.createDirectory();
+        } else {
+            try (InputStream is = jrtfs.newInputStream(this); OutputStream os = target.newOutputStream()) {
+                byte[] buf = new byte[8192];
+                int n;
+                while ((n = is.read(buf)) != -1) {
+                    os.write(buf, 0, n);
+                }
+            }
+        }
+        if (copyAttrs) {
+            BasicFileAttributeView view
+                    = JrtFileAttributeView.get(target, BasicFileAttributeView.class);
+            try {
+                view.setTimes(jrtfas.lastModifiedTime(),
+                        jrtfas.lastAccessTime(),
+                        jrtfas.creationTime());
+            } catch (IOException x) {
+                // rollback?
+                try {
+                    target.delete();
+                } catch (IOException ignore) {
+                }
+                throw x;
+            }
+        }
+    }
+}
--- a/src/java.base/share/classes/jdk/internal/jrtfs/JrtDirectoryStream.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/jrtfs/JrtDirectoryStream.java	Thu Mar 17 19:04:16 2016 +0000
@@ -22,7 +22,6 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-
 package jdk.internal.jrtfs;
 
 import java.nio.file.DirectoryStream;
@@ -34,48 +33,47 @@
 import java.util.NoSuchElementException;
 import java.io.IOException;
 
+/**
+ * DirectoryStream implementation for jrt file system implementations.
+ *
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
+ */
 final class JrtDirectoryStream implements DirectoryStream<Path> {
-    private final JrtFileSystem jrtfs;
-    private final byte[] path;
-    // prefix to be used for children of this directory
-    // so that child path are reported relatively (if needed)
-    private final String childPrefix;
+
+    private final AbstractJrtFileSystem jrtfs;
+    private final AbstractJrtPath dir;
     private final DirectoryStream.Filter<? super Path> filter;
     private volatile boolean isClosed;
     private volatile Iterator<Path> itr;
 
-    JrtDirectoryStream(JrtPath jrtPath,
-                       DirectoryStream.Filter<? super java.nio.file.Path> filter)
-        throws IOException
-    {
+    JrtDirectoryStream(AbstractJrtPath jrtPath,
+            DirectoryStream.Filter<? super java.nio.file.Path> filter)
+            throws IOException {
         this.jrtfs = jrtPath.getFileSystem();
-        this.path = jrtPath.getResolvedPath();
+        this.dir = jrtPath;
         // sanity check
-        if (!jrtfs.isDirectory(path, true))
+        if (!jrtfs.isDirectory(dir, true)) {
             throw new NotDirectoryException(jrtPath.toString());
+        }
 
-        // absolute path and does not have funky chars in front like /./java.base
-        if (jrtPath.isAbsolute() && (path.length == jrtPath.getPathLength())) {
-            childPrefix = null;
-        } else {
-            // cases where directory content needs to modified with prefix
-            // like ./java.base, /./java.base, java.base and so on.
-            String dirName = jrtPath.toString();
-            int idx = dirName.indexOf(JrtFileSystem.getString(path).substring(1));
-            childPrefix = dirName.substring(0, idx);
-        }
         this.filter = filter;
     }
 
     @Override
     public synchronized Iterator<Path> iterator() {
-        if (isClosed)
+        if (isClosed) {
             throw new ClosedDirectoryStreamException();
-        if (itr != null)
+        }
+        if (itr != null) {
             throw new IllegalStateException("Iterator has already been returned");
+        }
 
         try {
-            itr = jrtfs.iteratorOf(path, childPrefix);
+            itr = jrtfs.iteratorOf(dir);
         } catch (IOException e) {
             throw new IllegalStateException(e);
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/jrtfs/JrtExplodedFileAttributes.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.jrtfs;
+
+import java.io.IOException;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.nio.file.attribute.FileTime;
+import jdk.internal.jrtfs.JrtExplodedFileSystem.Node;
+
+/**
+ * jrt file system attributes implementation on top of 'exploded file system'
+ * Node.
+ *
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
+ */
+final class JrtExplodedFileAttributes extends AbstractJrtFileAttributes {
+
+    private final Node node;
+    private final BasicFileAttributes attrs;
+
+    JrtExplodedFileAttributes(Node node) throws IOException {
+        this.node = node;
+        this.attrs = node.getBasicAttrs();
+    }
+
+    @Override
+    public FileTime creationTime() {
+        return attrs.creationTime();
+    }
+
+    @Override
+    public boolean isDirectory() {
+        return node.isDirectory();
+    }
+
+    @Override
+    public boolean isOther() {
+        return false;
+    }
+
+    @Override
+    public boolean isRegularFile() {
+        return node.isFile();
+    }
+
+    @Override
+    public FileTime lastAccessTime() {
+        return attrs.lastAccessTime();
+    }
+
+    @Override
+    public FileTime lastModifiedTime() {
+        return attrs.lastModifiedTime();
+    }
+
+    @Override
+    public long size() {
+        return isRegularFile() ? attrs.size() : 0L;
+    }
+
+    @Override
+    public boolean isSymbolicLink() {
+        return node.isLink();
+    }
+
+    @Override
+    public Object fileKey() {
+        return node.resolveLink(true);
+    }
+
+    @Override
+    public long compressedSize() {
+        return 0L;
+    }
+
+    @Override
+    public String extension() {
+        return node.getExtension();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/jrtfs/JrtExplodedFileSystem.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,528 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.jrtfs;
+
+import java.io.IOException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystemException;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.NotDirectoryException;
+import java.nio.file.Path;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import static java.util.stream.Collectors.toList;
+import static jdk.internal.jrtfs.AbstractJrtFileSystem.getString;
+
+/**
+ * A jrt file system built on $JAVA_HOME/modules directory ('exploded modules
+ * build')
+ *
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
+ */
+class JrtExplodedFileSystem extends AbstractJrtFileSystem {
+
+    private static final String MODULES = "/modules/";
+    private static final String PACKAGES = "/packages/";
+    private static final int PACKAGES_LEN = PACKAGES.length();
+
+    // root path
+    private final JrtExplodedPath rootPath;
+    private volatile boolean isOpen;
+    private final FileSystem defaultFS;
+    private final String separator;
+    private final Map<String, Node> nodes = Collections.synchronizedMap(new HashMap<>());
+    private final BasicFileAttributes modulesDirAttrs;
+
+    JrtExplodedFileSystem(JrtFileSystemProvider provider,
+            Map<String, ?> env)
+            throws IOException {
+
+        super(provider, env);
+        checkExists(SystemImages.explodedModulesDir());
+        byte[] root = new byte[]{'/'};
+        rootPath = new JrtExplodedPath(this, root);
+        isOpen = true;
+        defaultFS = FileSystems.getDefault();
+        String str = defaultFS.getSeparator();
+        separator = str.equals(getSeparator()) ? null : str;
+        modulesDirAttrs = Files.readAttributes(SystemImages.explodedModulesDir(), BasicFileAttributes.class);
+        initNodes();
+    }
+
+    @Override
+    public void close() throws IOException {
+        cleanup();
+    }
+
+    @Override
+    public boolean isOpen() {
+        return isOpen;
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        cleanup();
+        super.finalize();
+    }
+
+    private synchronized void cleanup() {
+        isOpen = false;
+        nodes.clear();
+    }
+
+    @Override
+    JrtExplodedPath getRootPath() {
+        return rootPath;
+    }
+
+    // Base class for Nodes of this file system
+    abstract class Node {
+
+        private final String name;
+
+        Node(String name) {
+            this.name = name;
+        }
+
+        final String getName() {
+            return name;
+        }
+
+        final String getExtension() {
+            if (isFile()) {
+                final int index = name.lastIndexOf(".");
+                if (index != -1) {
+                    return name.substring(index + 1);
+                }
+            }
+
+            return null;
+        }
+
+        BasicFileAttributes getBasicAttrs() throws IOException {
+            return modulesDirAttrs;
+        }
+
+        boolean isLink() {
+            return false;
+        }
+
+        boolean isDirectory() {
+            return false;
+        }
+
+        boolean isFile() {
+            return false;
+        }
+
+        byte[] getContent() throws IOException {
+            if (!isFile()) {
+                throw new FileSystemException(name + " is not file");
+            }
+
+            throw new AssertionError("ShouldNotReachHere");
+        }
+
+        List<Node> getChildren() throws IOException {
+            if (!isDirectory()) {
+                throw new NotDirectoryException(name);
+            }
+
+            throw new AssertionError("ShouldNotReachHere");
+        }
+
+        final Node resolveLink() {
+            return resolveLink(false);
+        }
+
+        Node resolveLink(boolean recursive) {
+            return this;
+        }
+    }
+
+    // A Node that is backed by actual default file system Path
+    private final class PathNode extends Node {
+
+        // Path in underlying default file system
+        private final Path path;
+        private final boolean file;
+        // lazily initialized, don't read attributes unless required!
+        private BasicFileAttributes attrs;
+
+        PathNode(String name, Path path) {
+            super(name);
+            this.path = path;
+            this.file = Files.isRegularFile(path);
+        }
+
+        @Override
+        synchronized BasicFileAttributes getBasicAttrs() throws IOException {
+            if (attrs == null) {
+                attrs = Files.readAttributes(path, BasicFileAttributes.class);
+            }
+            return attrs;
+        }
+
+        @Override
+        boolean isDirectory() {
+            return !file;
+        }
+
+        @Override
+        boolean isFile() {
+            return file;
+        }
+
+        @Override
+        byte[] getContent() throws IOException {
+            if (!isFile()) {
+                throw new FileSystemException(getName() + " is not file");
+            }
+
+            return Files.readAllBytes(path);
+        }
+
+        @Override
+        List<Node> getChildren() throws IOException {
+            if (!isDirectory()) {
+                throw new NotDirectoryException(getName());
+            }
+
+            List<Node> children = new ArrayList<>();
+            try (DirectoryStream<Path> stream = Files.newDirectoryStream(path)) {
+                for (Path cp : stream) {
+                    cp = SystemImages.explodedModulesDir().relativize(cp);
+                    String cpName = MODULES + nativeSlashToFrontSlash(cp.toString());
+                    try {
+                        children.add(findNode(cpName));
+                    } catch (NoSuchFileException nsfe) {
+                        // findNode may choose to hide certain files!
+                    }
+                }
+            }
+
+            return children;
+        }
+    }
+
+    // A Node that links to another Node
+    private final class LinkNode extends Node {
+
+        // underlying linked Node
+        private final Node link;
+
+        LinkNode(String name, Node link) {
+            super(name);
+            this.link = link;
+        }
+
+        @Override
+        BasicFileAttributes getBasicAttrs() throws IOException {
+            return link.getBasicAttrs();
+        }
+
+        @Override
+        public boolean isLink() {
+            return true;
+        }
+
+        @Override
+        Node resolveLink(boolean recursive) {
+            return recursive && (link instanceof LinkNode) ? ((LinkNode) link).resolveLink(true) : link;
+        }
+    }
+
+    // A directory Node with it's children Nodes
+    private final class DirNode extends Node {
+
+        // children Nodes of this Node.
+        private final List<Node> children;
+
+        DirNode(String name, List<Node> children) {
+            super(name);
+            this.children = children;
+        }
+
+        @Override
+        boolean isDirectory() {
+            return true;
+        }
+
+        @Override
+        List<Node> getChildren() throws IOException {
+            return children;
+        }
+    }
+
+    private JrtExplodedPath toJrtExplodedPath(String path) {
+        return toJrtExplodedPath(getBytes(path));
+    }
+
+    private JrtExplodedPath toJrtExplodedPath(byte[] path) {
+        return new JrtExplodedPath(this, path);
+    }
+
+    @Override
+    boolean isSameFile(AbstractJrtPath jrtPath1, AbstractJrtPath jrtPath2) throws IOException {
+        Node n1 = checkNode(jrtPath1);
+        Node n2 = checkNode(jrtPath2);
+        return n1 == n2;
+    }
+
+    @Override
+    boolean isLink(AbstractJrtPath jrtPath) throws IOException {
+        return checkNode(jrtPath).isLink();
+    }
+
+    @Override
+    AbstractJrtPath resolveLink(AbstractJrtPath jrtPath) throws IOException {
+        String name = checkNode(jrtPath).resolveLink().getName();
+        return toJrtExplodedPath(name);
+    }
+
+    @Override
+    AbstractJrtFileAttributes getFileAttributes(AbstractJrtPath jrtPath, LinkOption... options) throws IOException {
+        Node node = checkNode(jrtPath);
+        if (node.isLink() && followLinks(options)) {
+            node = node.resolveLink(true);
+        }
+        return new JrtExplodedFileAttributes(node);
+    }
+
+    @Override
+    boolean exists(AbstractJrtPath jrtPath) throws IOException {
+        try {
+            checkNode(jrtPath);
+            return true;
+        } catch (NoSuchFileException nsfe) {
+            return false;
+        }
+    }
+
+    @Override
+    boolean isDirectory(AbstractJrtPath jrtPath, boolean resolveLinks) throws IOException {
+        Node node = checkNode(jrtPath);
+        return resolveLinks && node.isLink()
+                ? node.resolveLink(true).isDirectory()
+                : node.isDirectory();
+    }
+
+    @Override
+    Iterator<Path> iteratorOf(AbstractJrtPath dir) throws IOException {
+        Node node = checkNode(dir).resolveLink(true);
+        if (!node.isDirectory()) {
+            throw new NotDirectoryException(getString(dir.getName()));
+        }
+
+        Function<Node, Path> nodeToPath =
+            child -> dir.resolve(
+                toJrtExplodedPath(child.getName()).
+                getFileName());
+
+        return node.getChildren().stream().
+                   map(nodeToPath).collect(toList()).
+                   iterator();
+    }
+
+    @Override
+    byte[] getFileContent(AbstractJrtPath jrtPath) throws IOException {
+        return checkNode(jrtPath).getContent();
+    }
+
+    private Node checkNode(AbstractJrtPath jrtPath) throws IOException {
+        return checkNode(jrtPath.getResolvedPath());
+    }
+
+    private Node checkNode(byte[] path) throws IOException {
+        ensureOpen();
+        return findNode(path);
+    }
+
+    synchronized Node findNode(byte[] path) throws IOException {
+        return findNode(getString(path));
+    }
+
+    // find Node for the given Path
+    synchronized Node findNode(String str) throws IOException {
+        Node node = findModulesNode(str);
+        if (node != null) {
+            return node;
+        }
+
+        // lazily created for paths like /packages/<package>/<module>/xyz
+        // For example /packages/java.lang/java.base/java/lang/
+        if (str.startsWith(PACKAGES)) {
+            // pkgEndIdx marks end of <package> part
+            int pkgEndIdx = str.indexOf('/', PACKAGES_LEN);
+            if (pkgEndIdx != -1) {
+                // modEndIdx marks end of <module> part
+                int modEndIdx = str.indexOf('/', pkgEndIdx + 1);
+                if (modEndIdx != -1) {
+                    // make sure we have such module link!
+                    // ie., /packages/<package>/<module> is valid
+                    Node linkNode = nodes.get(str.substring(0, modEndIdx));
+                    if (linkNode == null || !linkNode.isLink()) {
+                        throw new NoSuchFileException(str);
+                    }
+
+                    // map to "/modules/zyz" path and return that node
+                    // For example, "/modules/java.base/java/lang" for
+                    // "/packages/java.lang/java.base/java/lang".
+                    String mod = MODULES + str.substring(pkgEndIdx + 1);
+                    return findNode(mod);
+                }
+            }
+        }
+
+        throw new NoSuchFileException(str);
+    }
+
+    // find a Node for a path that starts like "/modules/..."
+    synchronized Node findModulesNode(String str) throws IOException {
+        Node node = nodes.get(str);
+        if (node != null) {
+            return node;
+        }
+
+        // lazily created "/modules/xyz/abc/" Node
+        // This is mapped to default file system path "<JDK_MODULES_DIR>/xyz/abc"
+        Path p = underlyingPath(str);
+        if (p != null) {
+            if (Files.isRegularFile(p)) {
+                Path file = p.getFileName();
+                if (file.toString().startsWith("_the.")) {
+                    return null;
+                }
+            }
+            node = new PathNode(str, p);
+            nodes.put(str, node);
+            return node;
+        }
+
+        return null;
+    }
+
+    Path underlyingPath(String str) {
+        if (str.startsWith(MODULES)) {
+            str = frontSlashToNativeSlash(str.substring("/modules".length()));
+            return defaultFS.getPath(SystemImages.explodedModulesDir().toString(), str);
+        }
+        return null;
+    }
+
+    // convert "/" to platform path separator
+    private String frontSlashToNativeSlash(String str) {
+        return separator == null ? str : str.replace("/", separator);
+    }
+
+    // convert platform path separator to "/"
+    private String nativeSlashToFrontSlash(String str) {
+        return separator == null ? str : str.replace(separator, "/");
+    }
+
+    // convert "/"s to "."s
+    private String slashesToDots(String str) {
+        return str.replace(separator != null ? separator : "/", ".");
+    }
+
+    // initialize file system Nodes
+    private void initNodes() throws IOException {
+        // same package prefix may exist in mutliple modules. This Map
+        // is filled by walking "jdk modules" directory recursively!
+        Map<String, List<String>> packageToModules = new HashMap<>();
+
+        try (DirectoryStream<Path> stream = Files.newDirectoryStream(SystemImages.explodedModulesDir())) {
+            for (Path module : stream) {
+                if (Files.isDirectory(module)) {
+                    String moduleName = module.getFileName().toString();
+                    // make sure "/modules/<moduleName>" is created
+                    findModulesNode(MODULES + moduleName);
+
+                    Files.walk(module).filter(Files::isDirectory).forEach((p) -> {
+                        p = module.relativize(p);
+                        String pkgName = slashesToDots(p.toString());
+                        // skip META-INFO and empty strings
+                        if (!pkgName.isEmpty() && !pkgName.startsWith("META-INF")) {
+                            List<String> moduleNames = packageToModules.get(pkgName);
+                            if (moduleNames == null) {
+                                moduleNames = new ArrayList<>();
+                                packageToModules.put(pkgName, moduleNames);
+                            }
+                            moduleNames.add(moduleName);
+                        }
+                    });
+                }
+            }
+        }
+
+        // create "/modules" directory
+        // "nodes" map contains only /modules/<foo> nodes only so far and so add all as children of /modules
+        DirNode modulesDir = new DirNode("/modules", new ArrayList<>(nodes.values()));
+        nodes.put(modulesDir.getName(), modulesDir);
+
+        // create children under "/packages"
+        List<Node> packagesChildren = new ArrayList<>(packageToModules.size());
+        for (Map.Entry<String, List<String>> entry : packageToModules.entrySet()) {
+            String pkgName = entry.getKey();
+            List<String> moduleNameList = entry.getValue();
+            List<Node> moduleLinkNodes = new ArrayList<>(moduleNameList.size());
+            for (String moduleName : moduleNameList) {
+                Node moduleNode = findModulesNode(MODULES + moduleName);
+                LinkNode linkNode = new LinkNode(PACKAGES + pkgName + "/" + moduleName, moduleNode);
+                nodes.put(linkNode.getName(), linkNode);
+                moduleLinkNodes.add(linkNode);
+            }
+
+            DirNode pkgDir = new DirNode(PACKAGES + pkgName, moduleLinkNodes);
+            nodes.put(pkgDir.getName(), pkgDir);
+            packagesChildren.add(pkgDir);
+        }
+
+        // "/packages" dir
+        DirNode packagesDir = new DirNode("/packages", packagesChildren);
+        nodes.put(packagesDir.getName(), packagesDir);
+
+        // finally "/" dir!
+        List<Node> rootChildren = new ArrayList<>();
+        rootChildren.add(modulesDir);
+        rootChildren.add(packagesDir);
+        DirNode root = new DirNode("/", rootChildren);
+        nodes.put(root.getName(), root);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/jrtfs/JrtExplodedPath.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.jrtfs;
+
+/**
+ * Path implementation for jrt file system on JDK exploded modules build.
+ *
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
+ */
+final class JrtExplodedPath extends AbstractJrtPath {
+
+    JrtExplodedPath(AbstractJrtFileSystem jrtfs, byte[] path) {
+        super(jrtfs, path);
+    }
+
+    JrtExplodedPath(AbstractJrtFileSystem jrtfs, byte[] path, boolean normalized) {
+        super(jrtfs, path, normalized);
+    }
+
+    @Override
+    protected AbstractJrtPath newJrtPath(byte[] path) {
+        return new JrtExplodedPath(jrtfs, path);
+    }
+
+    @Override
+    protected AbstractJrtPath newJrtPath(byte[] path, boolean normalized) {
+        return new JrtExplodedPath(jrtfs, path, normalized);
+    }
+
+    @Override
+    public JrtExplodedFileSystem getFileSystem() {
+        return (JrtExplodedFileSystem) jrtfs;
+    }
+}
--- a/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileAttributeView.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileAttributeView.java	Thu Mar 17 19:04:16 2016 +0000
@@ -22,7 +22,6 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-
 package jdk.internal.jrtfs;
 
 import java.nio.file.LinkOption;
@@ -31,9 +30,19 @@
 import java.util.LinkedHashMap;
 import java.util.Map;
 
-final class JrtFileAttributeView implements BasicFileAttributeView
-{
+/**
+ * File attribute view for jrt file system.
+ *
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
+ */
+final class JrtFileAttributeView implements BasicFileAttributeView {
+
     private static enum AttrID {
+
         size,
         creationTime,
         lastAccessTime,
@@ -47,124 +56,133 @@
         extension
     };
 
-    private final JrtPath path;
+    private final AbstractJrtPath path;
     private final boolean isJrtView;
     private final LinkOption[] options;
 
-    private JrtFileAttributeView(JrtPath path, boolean isJrtView, LinkOption... options) {
+    private JrtFileAttributeView(AbstractJrtPath path, boolean isJrtView, LinkOption... options) {
         this.path = path;
         this.isJrtView = isJrtView;
         this.options = options;
     }
 
     @SuppressWarnings("unchecked") // Cast to V
-    static <V extends FileAttributeView> V get(JrtPath path, Class<V> type, LinkOption... options) {
-        if (type == null)
+    static <V extends FileAttributeView> V get(AbstractJrtPath path, Class<V> type, LinkOption... options) {
+        if (type == null) {
             throw new NullPointerException();
-        if (type == BasicFileAttributeView.class)
-            return (V)new JrtFileAttributeView(path, false, options);
-        if (type == JrtFileAttributeView.class)
-            return (V)new JrtFileAttributeView(path, true, options);
+        }
+        if (type == BasicFileAttributeView.class) {
+            return (V) new JrtFileAttributeView(path, false, options);
+        }
+        if (type == JrtFileAttributeView.class) {
+            return (V) new JrtFileAttributeView(path, true, options);
+        }
         return null;
     }
 
-    static JrtFileAttributeView get(JrtPath path, String type, LinkOption... options) {
-        if (type == null)
+    static JrtFileAttributeView get(AbstractJrtPath path, String type, LinkOption... options) {
+        if (type == null) {
             throw new NullPointerException();
-        if (type.equals("basic"))
+        }
+        if (type.equals("basic")) {
             return new JrtFileAttributeView(path, false, options);
-        if (type.equals("jjrt"))
+        }
+        if (type.equals("jrt")) {
             return new JrtFileAttributeView(path, true, options);
+        }
         return null;
     }
 
     @Override
     public String name() {
-        return isJrtView ? "jjrt" : "basic";
+        return isJrtView ? "jrt" : "basic";
     }
 
     @Override
-    public JrtFileAttributes readAttributes() throws IOException
-    {
+    public AbstractJrtFileAttributes readAttributes() throws IOException {
         return path.getAttributes(options);
     }
 
     @Override
     public void setTimes(FileTime lastModifiedTime,
-                         FileTime lastAccessTime,
-                         FileTime createTime)
-        throws IOException
-    {
+            FileTime lastAccessTime,
+            FileTime createTime)
+            throws IOException {
         path.setTimes(lastModifiedTime, lastAccessTime, createTime);
     }
 
     void setAttribute(String attribute, Object value)
-        throws IOException
-    {
+            throws IOException {
         try {
-            if (AttrID.valueOf(attribute) == AttrID.lastModifiedTime)
-                setTimes ((FileTime)value, null, null);
-            if (AttrID.valueOf(attribute) == AttrID.lastAccessTime)
-                setTimes (null, (FileTime)value, null);
-            if (AttrID.valueOf(attribute) == AttrID.creationTime)
-                setTimes (null, null, (FileTime)value);
+            if (AttrID.valueOf(attribute) == AttrID.lastModifiedTime) {
+                setTimes((FileTime) value, null, null);
+            }
+            if (AttrID.valueOf(attribute) == AttrID.lastAccessTime) {
+                setTimes(null, (FileTime) value, null);
+            }
+            if (AttrID.valueOf(attribute) == AttrID.creationTime) {
+                setTimes(null, null, (FileTime) value);
+            }
             return;
-        } catch (IllegalArgumentException x) {}
-        throw new UnsupportedOperationException("'" + attribute +
-            "' is unknown or read-only attribute");
+        } catch (IllegalArgumentException x) {
+        }
+        throw new UnsupportedOperationException("'" + attribute
+                + "' is unknown or read-only attribute");
     }
 
     Map<String, Object> readAttributes(String attributes)
-        throws IOException
-    {
-        JrtFileAttributes jrtfas = readAttributes();
+            throws IOException {
+        AbstractJrtFileAttributes jrtfas = readAttributes();
         LinkedHashMap<String, Object> map = new LinkedHashMap<>();
         if ("*".equals(attributes)) {
             for (AttrID id : AttrID.values()) {
                 try {
                     map.put(id.name(), attribute(id, jrtfas));
-                } catch (IllegalArgumentException x) {}
+                } catch (IllegalArgumentException x) {
+                }
             }
         } else {
             String[] as = attributes.split(",");
             for (String a : as) {
                 try {
                     map.put(a, attribute(AttrID.valueOf(a), jrtfas));
-                } catch (IllegalArgumentException x) {}
+                } catch (IllegalArgumentException x) {
+                }
             }
         }
         return map;
     }
 
-    Object attribute(AttrID id, JrtFileAttributes jrtfas) {
+    Object attribute(AttrID id, AbstractJrtFileAttributes jrtfas) {
         switch (id) {
-        case size:
-            return jrtfas.size();
-        case creationTime:
-            return jrtfas.creationTime();
-        case lastAccessTime:
-            return jrtfas.lastAccessTime();
-        case lastModifiedTime:
-            return jrtfas.lastModifiedTime();
-        case isDirectory:
-            return jrtfas.isDirectory();
-        case isRegularFile:
-            return jrtfas.isRegularFile();
-        case isSymbolicLink:
-            return jrtfas.isSymbolicLink();
-        case isOther:
-            return jrtfas.isOther();
-        case fileKey:
-            return jrtfas.fileKey();
-        case compressedSize:
-            if (isJrtView)
-                return jrtfas.compressedSize();
-            break;
-        case extension:
-            if (isJrtView) {
-                return jrtfas.extension();
-            }
-            break;
+            case size:
+                return jrtfas.size();
+            case creationTime:
+                return jrtfas.creationTime();
+            case lastAccessTime:
+                return jrtfas.lastAccessTime();
+            case lastModifiedTime:
+                return jrtfas.lastModifiedTime();
+            case isDirectory:
+                return jrtfas.isDirectory();
+            case isRegularFile:
+                return jrtfas.isRegularFile();
+            case isSymbolicLink:
+                return jrtfas.isSymbolicLink();
+            case isOther:
+                return jrtfas.isOther();
+            case fileKey:
+                return jrtfas.fileKey();
+            case compressedSize:
+                if (isJrtView) {
+                    return jrtfas.compressedSize();
+                }
+                break;
+            case extension:
+                if (isJrtView) {
+                    return jrtfas.extension();
+                }
+                break;
         }
         return null;
     }
--- a/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileAttributes.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileAttributes.java	Thu Mar 17 19:04:16 2016 +0000
@@ -22,16 +22,22 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-
 package jdk.internal.jrtfs;
 
-import java.nio.file.attribute.BasicFileAttributes;
 import java.nio.file.attribute.FileTime;
-import java.util.Formatter;
 import jdk.internal.jimage.ImageReader.Node;
 
-final class JrtFileAttributes implements BasicFileAttributes
-{
+/**
+ * File attributes implementation for jrt image file system.
+ *
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
+ */
+final class JrtFileAttributes extends AbstractJrtFileAttributes {
+
     private final Node node;
 
     JrtFileAttributes(Node node) {
@@ -85,37 +91,13 @@
     }
 
     ///////// jrt entry attributes ///////////
+    @Override
     public long compressedSize() {
         return node.compressedSize();
     }
 
+    @Override
     public String extension() {
         return node.extension();
     }
-
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder(1024);
-        try (Formatter fm = new Formatter(sb)) {
-            if (creationTime() != null)
-                fm.format("    creationTime    : %tc%n", creationTime().toMillis());
-            else
-                fm.format("    creationTime    : null%n");
-
-            if (lastAccessTime() != null)
-                fm.format("    lastAccessTime  : %tc%n", lastAccessTime().toMillis());
-            else
-                fm.format("    lastAccessTime  : null%n");
-            fm.format("    lastModifiedTime: %tc%n", lastModifiedTime().toMillis());
-            fm.format("    isRegularFile   : %b%n", isRegularFile());
-            fm.format("    isDirectory     : %b%n", isDirectory());
-            fm.format("    isSymbolicLink  : %b%n", isSymbolicLink());
-            fm.format("    isOther         : %b%n", isOther());
-            fm.format("    fileKey         : %s%n", fileKey());
-            fm.format("    size            : %d%n", size());
-            fm.format("    compressedSize  : %d%n", compressedSize());
-            fm.format("    extension       : %s%n", extension());
-        }
-        return sb.toString();
-    }
 }
--- a/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileStore.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileStore.java	Thu Mar 17 19:04:16 2016 +0000
@@ -22,23 +22,29 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-
 package jdk.internal.jrtfs;
 
 import java.io.IOException;
-import java.nio.file.Files;
 import java.nio.file.FileStore;
-import java.nio.file.FileSystems;
-import java.nio.file.Path;
+import java.nio.file.FileSystem;
 import java.nio.file.attribute.FileAttributeView;
+import java.nio.file.attribute.BasicFileAttributeView;
 import java.nio.file.attribute.FileStoreAttributeView;
-import java.nio.file.attribute.BasicFileAttributeView;
 
+/**
+ * File store implementation for jrt file systems.
+ *
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
+ */
 final class JrtFileStore extends FileStore {
 
-    private final JrtFileSystem jrtfs;
+    protected final FileSystem jrtfs;
 
-    JrtFileStore(JrtPath jrtPath) {
+    JrtFileStore(AbstractJrtPath jrtPath) {
         this.jrtfs = jrtPath.getFileSystem();
     }
 
@@ -58,12 +64,6 @@
     }
 
     @Override
-    public boolean supportsFileAttributeView(Class<? extends FileAttributeView> type) {
-        return (type == BasicFileAttributeView.class ||
-                type == JrtFileAttributeView.class);
-    }
-
-    @Override
     public boolean supportsFileAttributeView(String name) {
         return name.equals("basic") || name.equals("jrt");
     }
@@ -71,28 +71,35 @@
     @Override
     @SuppressWarnings("unchecked")
     public <V extends FileStoreAttributeView> V getFileStoreAttributeView(Class<V> type) {
-        if (type == null)
+        if (type == null) {
             throw new NullPointerException();
-        return (V)null;
+        }
+        return (V) null;
     }
 
     @Override
     public long getTotalSpace() throws IOException {
-         throw new UnsupportedOperationException("getTotalSpace");
+        throw new UnsupportedOperationException("getTotalSpace");
     }
 
     @Override
     public long getUsableSpace() throws IOException {
-         throw new UnsupportedOperationException("getUsableSpace");
+        throw new UnsupportedOperationException("getUsableSpace");
     }
 
     @Override
     public long getUnallocatedSpace() throws IOException {
-         throw new UnsupportedOperationException("getUnallocatedSpace");
+        throw new UnsupportedOperationException("getUnallocatedSpace");
     }
 
     @Override
     public Object getAttribute(String attribute) throws IOException {
-         throw new UnsupportedOperationException("does not support " + attribute);
+        throw new UnsupportedOperationException("does not support " + attribute);
+    }
+
+    @Override
+    public boolean supportsFileAttributeView(Class<? extends FileAttributeView> type) {
+        return (type == BasicFileAttributeView.class
+                || type == JrtFileAttributeView.class);
     }
 }
--- a/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystem.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystem.java	Thu Mar 17 19:04:16 2016 +0000
@@ -24,73 +24,44 @@
  */
 package jdk.internal.jrtfs;
 
-import java.io.ByteArrayInputStream;
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.ByteBuffer;
-import java.nio.channels.*;
-import java.nio.charset.Charset;
-import java.nio.file.ClosedFileSystemException;
-import java.nio.file.CopyOption;
 import java.nio.file.LinkOption;
-import java.nio.file.FileStore;
-import java.nio.file.FileSystem;
 import java.nio.file.FileSystemException;
-import java.nio.file.FileSystemNotFoundException;
-import java.nio.file.Files;
+import java.nio.file.InvalidPathException;
 import java.nio.file.NoSuchFileException;
 import java.nio.file.NotDirectoryException;
-import java.nio.file.OpenOption;
 import java.nio.file.Path;
-import java.nio.file.PathMatcher;
-import java.nio.file.ReadOnlyFileSystemException;
-import java.nio.file.StandardOpenOption;
-import java.nio.file.WatchService;
-import java.nio.file.attribute.FileAttribute;
-import java.nio.file.attribute.FileTime;
-import java.nio.file.attribute.UserPrincipalLookupService;
-import java.nio.file.spi.FileSystemProvider;
-import java.util.concurrent.ConcurrentHashMap;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 import java.util.function.Function;
-import java.util.regex.Pattern;
 import static java.util.stream.Collectors.toList;
 import jdk.internal.jimage.ImageReader;
 import jdk.internal.jimage.ImageReader.Node;
-import jdk.internal.jimage.UTF8String;
+
 
 /**
- * A FileSystem built on System jimage files.
+ * jrt file system implementation built on System jimage files.
+ *
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
  */
-class JrtFileSystem extends FileSystem {
-    private static final Charset UTF_8 = Charset.forName("UTF-8");
+class JrtFileSystem extends AbstractJrtFileSystem {
 
-    private final JrtFileSystemProvider provider;
-    // System image readers
+    // System image reader
     private ImageReader bootImage;
-    private ImageReader extImage;
-    private ImageReader appImage;
     // root path
     private final JrtPath rootPath;
     private volatile boolean isOpen;
 
-    private static void checkExists(Path path) {
-        if (Files.notExists(path)) {
-            throw new FileSystemNotFoundException(path.toString());
-        }
-    }
-
     // open a .jimage and build directory structure
     private static ImageReader openImage(Path path) throws IOException {
-        ImageReader image = ImageReader.open(path.toString());
+        ImageReader image = ImageReader.open(path);
         image.getRootDirectory();
         return image;
     }
@@ -98,31 +69,18 @@
     JrtFileSystem(JrtFileSystemProvider provider,
             Map<String, ?> env)
             throws IOException {
-        this.provider = provider;
-        checkExists(SystemImages.bootImagePath);
-        checkExists(SystemImages.extImagePath);
-        checkExists(SystemImages.appImagePath);
+        super(provider, env);
+        checkExists(SystemImages.moduleImageFile());
 
-        // open image files
-        this.bootImage = openImage(SystemImages.bootImagePath);
-        this.extImage = openImage(SystemImages.extImagePath);
-        this.appImage = openImage(SystemImages.appImagePath);
+        // open image file
+        this.bootImage = openImage(SystemImages.moduleImageFile());
 
-        byte[] root = new byte[] { '/' };
+        byte[] root = new byte[]{'/'};
         rootPath = new JrtPath(this, root);
         isOpen = true;
     }
 
-    @Override
-    public FileSystemProvider provider() {
-        return provider;
-    }
-
-    @Override
-    public String getSeparator() {
-        return "/";
-    }
-
+    // FileSystem method implementations
     @Override
     public boolean isOpen() {
         return isOpen;
@@ -134,191 +92,139 @@
     }
 
     @Override
-    protected void finalize() {
+    protected void finalize() throws Throwable {
         try {
             cleanup();
-        } catch (IOException ignored) {}
+        } catch (IOException ignored) {
+        }
+        super.finalize();
+    }
+
+    // AbstractJrtFileSystem method implementations
+    @Override
+    JrtPath getRootPath() {
+        return rootPath;
+    }
+
+    @Override
+    boolean isSameFile(AbstractJrtPath p1, AbstractJrtPath p2) throws IOException {
+        ensureOpen();
+        Node node1 = findNode(p1);
+        Node node2 = findNode(p2);
+        return node1.equals(node2);
+    }
+
+    @Override
+    boolean isLink(AbstractJrtPath jrtPath) throws IOException {
+        return checkNode(jrtPath).isLink();
+    }
+
+    @Override
+    AbstractJrtPath resolveLink(AbstractJrtPath jrtPath) throws IOException {
+        Node node = checkNode(jrtPath);
+        if (node.isLink()) {
+            node = node.resolveLink();
+            return toJrtPath(getBytes(node.getName()));
+        }
+
+        return jrtPath;
+    }
+
+    @Override
+    JrtFileAttributes getFileAttributes(AbstractJrtPath jrtPath, LinkOption... options)
+            throws IOException {
+        Node node = checkNode(jrtPath);
+        if (node.isLink() && followLinks(options)) {
+            return new JrtFileAttributes(node.resolveLink(true));
+        }
+        return new JrtFileAttributes(node);
     }
 
+    @Override
+    boolean exists(AbstractJrtPath jrtPath) throws IOException {
+        try {
+            checkNode(jrtPath);
+        } catch (NoSuchFileException exp) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    boolean isDirectory(AbstractJrtPath jrtPath, boolean resolveLinks)
+            throws IOException {
+        Node node = checkNode(jrtPath);
+        return resolveLinks && node.isLink()
+                ? node.resolveLink(true).isDirectory()
+                : node.isDirectory();
+    }
+
+    @Override
+    Iterator<Path> iteratorOf(AbstractJrtPath jrtPath) throws IOException {
+        Node node = checkNode(jrtPath).resolveLink(true);
+        if (!node.isDirectory()) {
+            throw new NotDirectoryException(getString(jrtPath.getName()));
+        }
+
+        if (node.isRootDir()) {
+            return rootDirIterator(jrtPath);
+        } else if (node.isModulesDir()) {
+            return modulesDirIterator(jrtPath);
+        } else if (node.isPackagesDir()) {
+            return packagesDirIterator(jrtPath);
+        }
+
+        return nodesToIterator(jrtPath, node.getChildren());
+    }
+
+    @Override
+    byte[] getFileContent(AbstractJrtPath jrtPath) throws IOException {
+        final Node node = checkResource(jrtPath);
+        return bootImage.getResource(node);
+    }
+
+    // Implementation details below this point
     // clean up this file system - called from finalize and close
     private void cleanup() throws IOException {
         if (!isOpen) {
             return;
         }
 
-        synchronized(this) {
+        synchronized (this) {
             isOpen = false;
 
             // close all image reader and null out
             bootImage.close();
             bootImage = null;
-            extImage.close();
-            extImage = null;
-            appImage.close();
-            appImage = null;
-        }
-    }
-
-    private void ensureOpen() throws IOException {
-        if (!isOpen) {
-            throw new ClosedFileSystemException();
         }
     }
 
-    @Override
-    public boolean isReadOnly() {
-        return true;
-    }
-
-    private ReadOnlyFileSystemException readOnly() {
-        return new ReadOnlyFileSystemException();
-    }
-
-    @Override
-    public Iterable<Path> getRootDirectories() {
-        ArrayList<Path> pathArr = new ArrayList<>();
-        pathArr.add(rootPath);
-        return pathArr;
-    }
-
-    JrtPath getRootPath() {
-        return rootPath;
-    }
-
-    @Override
-    public JrtPath getPath(String first, String... more) {
-        String path;
-        if (more.length == 0) {
-            path = first;
-        } else {
-            StringBuilder sb = new StringBuilder();
-            sb.append(first);
-            for (String segment : more) {
-                if (segment.length() > 0) {
-                    if (sb.length() > 0) {
-                        sb.append('/');
-                    }
-                    sb.append(segment);
-                }
-            }
-            path = sb.toString();
+    private Node lookup(byte[] path) {
+        Node node = null;
+        try {
+            node = bootImage.findNode(getString(path));
+        } catch (RuntimeException re) {
+            throw new InvalidPathException(getString(path), re.toString());
         }
-        return new JrtPath(this, getBytes(path));
-    }
-
-    @Override
-    public UserPrincipalLookupService getUserPrincipalLookupService() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public WatchService newWatchService() {
-        throw new UnsupportedOperationException();
-    }
-
-    FileStore getFileStore(JrtPath path) {
-        return new JrtFileStore(path);
-    }
-
-    @Override
-    public Iterable<FileStore> getFileStores() {
-        ArrayList<FileStore> list = new ArrayList<>(1);
-        list.add(new JrtFileStore(new JrtPath(this, new byte[]{'/'})));
-        return list;
-    }
-
-    private static final Set<String> supportedFileAttributeViews
-            = Collections.unmodifiableSet(
-                    new HashSet<String>(Arrays.asList("basic", "jrt")));
-
-    @Override
-    public Set<String> supportedFileAttributeViews() {
-        return supportedFileAttributeViews;
+        return node;
     }
 
-    @Override
-    public String toString() {
-        return "jrt:/";
-    }
-
-    private static final String GLOB_SYNTAX = "glob";
-    private static final String REGEX_SYNTAX = "regex";
-
-    @Override
-    public PathMatcher getPathMatcher(String syntaxAndInput) {
-        int pos = syntaxAndInput.indexOf(':');
-        if (pos <= 0 || pos == syntaxAndInput.length()) {
-            throw new IllegalArgumentException();
-        }
-        String syntax = syntaxAndInput.substring(0, pos);
-        String input = syntaxAndInput.substring(pos + 1);
-        String expr;
-        if (syntax.equalsIgnoreCase(GLOB_SYNTAX)) {
-            expr = JrtUtils.toRegexPattern(input);
-        } else {
-            if (syntax.equalsIgnoreCase(REGEX_SYNTAX)) {
-                expr = input;
-            } else {
-                throw new UnsupportedOperationException("Syntax '" + syntax
-                        + "' not recognized");
-            }
-        }
-        // return matcher
-        final Pattern pattern = Pattern.compile(expr);
-        return (Path path) -> pattern.matcher(path.toString()).matches();
-    }
-
-    static byte[] getBytes(String name) {
-        return name.getBytes(UTF_8);
-    }
-
-    static String getString(byte[] name) {
-        return new String(name, UTF_8);
-    }
-
-    private static class NodeAndImage {
-        final Node node;
-        final ImageReader image;
-
-        NodeAndImage(Node node, ImageReader image) {
-            this.node = node; this.image = image;
-        }
-
-        byte[] getResource() throws IOException {
-            return image.getResource(node);
-        }
-    }
-
-    private NodeAndImage lookup(byte[] path) {
-        Node node = bootImage.findNode(path);
-        ImageReader image = bootImage;
-        if (node == null) {
-            node = extImage.findNode(path);
-            image = extImage;
-        }
-        if (node == null) {
-            node = appImage.findNode(path);
-            image = appImage;
-        }
-        return node != null? new NodeAndImage(node, image) : null;
-    }
-
-    private NodeAndImage lookupSymbolic(byte[] path) {
+    private Node lookupSymbolic(byte[] path) {
         for (int i = 1; i < path.length; i++) {
-            if (path[i] == (byte)'/') {
+            if (path[i] == (byte) '/') {
                 byte[] prefix = Arrays.copyOfRange(path, 0, i);
-                NodeAndImage ni = lookup(prefix);
-                if (ni == null) {
+                Node node = lookup(prefix);
+                if (node == null) {
                     break;
                 }
 
-                if (ni.node.isLink()) {
-                    Node link = ni.node.resolveLink(true);
+                if (node.isLink()) {
+                    Node link = node.resolveLink(true);
                     // resolved symbolic path concatenated to the rest of the path
-                    UTF8String resPath = link.getName().concat(new UTF8String(path, i));
-                    byte[] resPathBytes = resPath.getBytesCopy();
-                    ni = lookup(resPathBytes);
-                    return ni != null? ni : lookupSymbolic(resPathBytes);
+                    String resPath = link.getName() + getString(path).substring(i);
+                    byte[] resPathBytes = getBytes(resPath);
+                    node = lookup(resPathBytes);
+                    return node != null ? node : lookupSymbolic(resPathBytes);
                 }
             }
         }
@@ -326,336 +232,100 @@
         return null;
     }
 
-    private NodeAndImage findNode(byte[] path) throws IOException {
-        NodeAndImage ni = lookup(path);
-        if (ni == null) {
-            ni = lookupSymbolic(path);
-            if (ni == null) {
+    private Node findNode(AbstractJrtPath jrtPath) throws IOException {
+        return findNode(jrtPath.getResolvedPath());
+    }
+
+    private Node findNode(byte[] path) throws IOException {
+        Node node = lookup(path);
+        if (node == null) {
+            node = lookupSymbolic(path);
+            if (node == null) {
                 throw new NoSuchFileException(getString(path));
             }
         }
-        return ni;
+        return node;
     }
 
-    private NodeAndImage checkNode(byte[] path) throws IOException {
+    private Node checkNode(AbstractJrtPath jrtPath) throws IOException {
+        return checkNode(jrtPath.getResolvedPath());
+    }
+
+    private Node checkNode(byte[] path) throws IOException {
         ensureOpen();
         return findNode(path);
     }
 
-    private NodeAndImage checkResource(byte[] path) throws IOException {
-        NodeAndImage ni = checkNode(path);
-        if (ni.node.isDirectory()) {
+    private Node checkResource(AbstractJrtPath jrtPath) throws IOException {
+        return checkResource(jrtPath.getResolvedPath());
+    }
+
+    private Node checkResource(byte[] path) throws IOException {
+        Node node = checkNode(path);
+        if (node.isDirectory()) {
             throw new FileSystemException(getString(path) + " is a directory");
         }
 
-        assert ni.node.isResource() : "resource node expected here";
-        return ni;
-    }
-
-    static boolean followLinks(LinkOption... options) {
-        if (options != null) {
-            for (LinkOption lo : options) {
-                if (lo == LinkOption.NOFOLLOW_LINKS) {
-                    return false;
-                } else if (lo == null) {
-                    throw new NullPointerException();
-                } else {
-                    throw new AssertionError("should not reach here");
-                }
-            }
-        }
-        return true;
+        assert node.isResource() : "resource node expected here";
+        return node;
     }
 
-    // package private helpers
-    JrtFileAttributes getFileAttributes(byte[] path, LinkOption... options)
-            throws IOException {
-        NodeAndImage ni = checkNode(path);
-        if (ni.node.isLink() && followLinks(options)) {
-            return new JrtFileAttributes(ni.node.resolveLink(true));
-        }
-        return new JrtFileAttributes(ni.node);
-    }
-
-    void setTimes(byte[] path, FileTime mtime, FileTime atime, FileTime ctime)
-            throws IOException {
-        throw readOnly();
-    }
-
-    boolean exists(byte[] path) throws IOException {
-        ensureOpen();
-        try {
-            findNode(path);
-        } catch (NoSuchFileException exp) {
-            return false;
-        }
-        return true;
-    }
-
-    boolean isDirectory(byte[] path, boolean resolveLinks)
-            throws IOException {
-        ensureOpen();
-        NodeAndImage ni = checkNode(path);
-        return resolveLinks && ni.node.isLink()?
-            ni.node.resolveLink(true).isDirectory() :
-            ni.node.isDirectory();
-    }
-
-    JrtPath toJrtPath(String path) {
+    private JrtPath toJrtPath(String path) {
         return toJrtPath(getBytes(path));
     }
 
-    JrtPath toJrtPath(byte[] path) {
+    private JrtPath toJrtPath(byte[] path) {
         return new JrtPath(this, path);
     }
 
-    boolean isSameFile(JrtPath p1, JrtPath p2) throws IOException {
-        NodeAndImage n1 = findNode(p1.getName());
-        NodeAndImage n2 = findNode(p2.getName());
-        return n1.node.equals(n2.node);
-    }
-
-    boolean isLink(JrtPath jrtPath) throws IOException {
-        return findNode(jrtPath.getName()).node.isLink();
-    }
-
-    JrtPath resolveLink(JrtPath jrtPath) throws IOException {
-        NodeAndImage ni = findNode(jrtPath.getName());
-        if (ni.node.isLink()) {
-            Node node = ni.node.resolveLink();
-            return toJrtPath(node.getName().getBytesCopy());
-        }
-
-        return jrtPath;
+    private Iterator<Path> nodesToIterator(AbstractJrtPath dir, List<Node> childNodes) {
+        Function<Node, Path> nodeToPath =
+            child -> dir.resolve(
+                toJrtPath(child.getNameString()).getFileName());
+        return childNodes.stream().
+                map(nodeToPath).collect(toList()).
+                iterator();
     }
 
-    private Map<UTF8String, List<Node>> packagesTreeChildren = new ConcurrentHashMap<>();
-
-    /**
-     * returns the list of child paths of the given directory "path"
-     *
-     * @param path name of the directory whose content is listed
-     * @param childPrefix prefix added to returned children names - may be null
-              in which case absolute child paths are returned
-     * @return iterator for child paths of the given directory path
-     */
-    Iterator<Path> iteratorOf(byte[] path, String childPrefix)
-            throws IOException {
-        NodeAndImage ni = checkNode(path);
-        Node node = ni.node.resolveLink(true);
-
-        if (!node.isDirectory()) {
-            throw new NotDirectoryException(getString(path));
-        }
-
-        if (node.isRootDir()) {
-            return rootDirIterator(path, childPrefix);
-        } else if (node.isModulesDir()) {
-            return modulesDirIterator(path, childPrefix);
-        } else if (node.isPackagesDir()) {
-            return packagesDirIterator(path, childPrefix);
-        } else if (node.getNameString().startsWith("/packages/")) {
-            if (ni.image != appImage) {
-                UTF8String name = node.getName();
-                List<Node> children = packagesTreeChildren.get(name);
-                if (children != null) {
-                    return nodesToIterator(toJrtPath(path), childPrefix, children);
-                }
+    private List<Node> rootChildren;
 
-                children = new ArrayList<>();
-                children.addAll(node.getChildren());
-                Node tmpNode = null;
-                // found in boot
-                if (ni.image == bootImage) {
-                    tmpNode = extImage.findNode(name);
-                    if (tmpNode != null) {
-                        children.addAll(tmpNode.getChildren());
-                    }
-                }
-
-                // found in ext
-                tmpNode = appImage.findNode(name);
-                if (tmpNode != null) {
-                    children.addAll(tmpNode.getChildren());
-                }
-
-                packagesTreeChildren.put(name, children);
-                return nodesToIterator(toJrtPath(path), childPrefix, children);
-            }
-        }
-
-        return nodesToIterator(toJrtPath(path), childPrefix, node.getChildren());
-    }
-
-    private Iterator<Path> nodesToIterator(Path path, String childPrefix, List<Node> childNodes) {
-        Function<Node, Path> f = childPrefix == null
-                ? child -> toJrtPath(child.getNameString())
-                : child -> toJrtPath(childPrefix + child.getNameString().substring(1));
-         return childNodes.stream().map(f).collect(toList()).iterator();
-    }
-
-    private void addRootDirContent(List<Node> children) {
-        for (Node child : children) {
-            if (!(child.isModulesDir() || child.isPackagesDir())) {
-                rootChildren.add(child);
-            }
+    private synchronized void initRootChildren(AbstractJrtPath jrtPath) throws IOException {
+        if (rootChildren == null) {
+            rootChildren = new ArrayList<>();
+            rootChildren.addAll(findNode(jrtPath).getChildren());
         }
     }
 
-    private List<Node> rootChildren;
-    private synchronized void initRootChildren(byte[] path) {
-        if (rootChildren == null) {
-            rootChildren = new ArrayList<>();
-            rootChildren.addAll(bootImage.findNode(path).getChildren());
-            addRootDirContent(extImage.findNode(path).getChildren());
-            addRootDirContent(appImage.findNode(path).getChildren());
+    private Iterator<Path> rootDirIterator(AbstractJrtPath jrtPath) throws IOException {
+        initRootChildren(jrtPath);
+        return nodesToIterator(jrtPath, rootChildren);
+    }
+
+    private List<Node> modulesChildren;
+
+    private synchronized void initModulesChildren(AbstractJrtPath jrtPath) throws IOException {
+        if (modulesChildren == null) {
+            modulesChildren = new ArrayList<>();
+            modulesChildren.addAll(findNode(jrtPath).getChildren());
         }
     }
 
-    private Iterator<Path> rootDirIterator(byte[] path, String childPrefix) throws IOException {
-        initRootChildren(path);
-        return nodesToIterator(rootPath, childPrefix, rootChildren);
-    }
-
-    private List<Node> modulesChildren;
-    private synchronized void initModulesChildren(byte[] path) {
-        if (modulesChildren == null) {
-            modulesChildren = new ArrayList<>();
-            modulesChildren.addAll(bootImage.findNode(path).getChildren());
-            modulesChildren.addAll(appImage.findNode(path).getChildren());
-            modulesChildren.addAll(extImage.findNode(path).getChildren());
-        }
-    }
-
-    private Iterator<Path> modulesDirIterator(byte[] path, String childPrefix) throws IOException {
-        initModulesChildren(path);
-        return nodesToIterator(new JrtPath(this, path), childPrefix, modulesChildren);
+    private Iterator<Path> modulesDirIterator(AbstractJrtPath jrtPath) throws IOException {
+        initModulesChildren(jrtPath);
+        return nodesToIterator(jrtPath, modulesChildren);
     }
 
     private List<Node> packagesChildren;
-    private synchronized void initPackagesChildren(byte[] path) {
+
+    private synchronized void initPackagesChildren(AbstractJrtPath jrtPath) throws IOException {
         if (packagesChildren == null) {
             packagesChildren = new ArrayList<>();
-            packagesChildren.addAll(bootImage.findNode(path).getChildren());
-            packagesChildren.addAll(extImage.findNode(path).getChildren());
-            packagesChildren.addAll(appImage.findNode(path).getChildren());
-        }
-    }
-    private Iterator<Path> packagesDirIterator(byte[] path, String childPrefix) throws IOException {
-        initPackagesChildren(path);
-        return nodesToIterator(new JrtPath(this, path), childPrefix, packagesChildren);
-    }
-
-    void createDirectory(byte[] dir, FileAttribute<?>... attrs)
-            throws IOException {
-        throw readOnly();
-    }
-
-    void copyFile(boolean deletesrc, byte[] src, byte[] dst, CopyOption... options)
-            throws IOException {
-        throw readOnly();
-    }
-
-    public void deleteFile(byte[] path, boolean failIfNotExists)
-            throws IOException {
-        throw readOnly();
-    }
-
-    OutputStream newOutputStream(byte[] path, OpenOption... options)
-            throws IOException {
-        throw readOnly();
-    }
-
-    private void checkOptions(Set<? extends OpenOption> options) {
-        // check for options of null type and option is an intance of StandardOpenOption
-        for (OpenOption option : options) {
-            if (option == null) {
-                throw new NullPointerException();
-            }
-            if (!(option instanceof StandardOpenOption)) {
-                throw new IllegalArgumentException();
-            }
+            packagesChildren.addAll(findNode(jrtPath).getChildren());
         }
     }
 
-    // Returns an input stream for reading the contents of the specified
-    // file entry.
-    InputStream newInputStream(byte[] path) throws IOException {
-        final NodeAndImage ni = checkResource(path);
-        return new ByteArrayInputStream(ni.getResource());
-    }
-
-    SeekableByteChannel newByteChannel(byte[] path,
-            Set<? extends OpenOption> options,
-            FileAttribute<?>... attrs)
-            throws IOException {
-        checkOptions(options);
-        if (options.contains(StandardOpenOption.WRITE)
-                || options.contains(StandardOpenOption.APPEND)) {
-            throw readOnly();
-        }
-
-        NodeAndImage ni = checkResource(path);
-        byte[] buf = ni.getResource();
-        final ReadableByteChannel rbc
-                = Channels.newChannel(new ByteArrayInputStream(buf));
-        final long size = buf.length;
-        return new SeekableByteChannel() {
-            long read = 0;
-
-            @Override
-            public boolean isOpen() {
-                return rbc.isOpen();
-            }
-
-            @Override
-            public long position() throws IOException {
-                return read;
-            }
-
-            @Override
-            public SeekableByteChannel position(long pos)
-                    throws IOException {
-                throw new UnsupportedOperationException();
-            }
-
-            @Override
-            public int read(ByteBuffer dst) throws IOException {
-                int n = rbc.read(dst);
-                if (n > 0) {
-                    read += n;
-                }
-                return n;
-            }
-
-            @Override
-            public SeekableByteChannel truncate(long size)
-                    throws IOException {
-                throw new NonWritableChannelException();
-            }
-
-            @Override
-            public int write(ByteBuffer src) throws IOException {
-                throw new NonWritableChannelException();
-            }
-
-            @Override
-            public long size() throws IOException {
-                return size;
-            }
-
-            @Override
-            public void close() throws IOException {
-                rbc.close();
-            }
-        };
-    }
-
-    // Returns a FileChannel of the specified path.
-    FileChannel newFileChannel(byte[] path,
-            Set<? extends OpenOption> options,
-            FileAttribute<?>... attrs)
-            throws IOException {
-        throw new UnsupportedOperationException("newFileChannel");
+    private Iterator<Path> packagesDirIterator(AbstractJrtPath jrtPath) throws IOException {
+        initPackagesChildren(jrtPath);
+        return nodesToIterator(jrtPath, packagesChildren);
     }
 }
--- a/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java	Thu Mar 17 19:04:16 2016 +0000
@@ -22,26 +22,42 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-
 package jdk.internal.jrtfs;
 
 import java.io.*;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
 import java.nio.channels.*;
 import java.nio.file.*;
 import java.nio.file.DirectoryStream.Filter;
 import java.nio.file.attribute.*;
 import java.nio.file.spi.FileSystemProvider;
 import java.net.URI;
-import java.net.URISyntaxException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.ExecutorService;
 
+/**
+ * File system provider for jrt file systems. Conditionally creates jrt fs on
+ * .jimage file or exploded modules directory of underlying JDK.
+ *
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
+ */
 public final class JrtFileSystemProvider extends FileSystemProvider {
+
     private volatile FileSystem theFileSystem;
 
-    public JrtFileSystemProvider() { }
+    public JrtFileSystemProvider() {
+    }
 
     @Override
     public String getScheme() {
@@ -55,50 +71,132 @@
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
             String home = SystemImages.RUNTIME_HOME;
-            FilePermission perm =
-                new FilePermission(home + File.separator + "-", "read");
+            FilePermission perm
+                    = new FilePermission(home + File.separator + "-", "read");
             sm.checkPermission(perm);
         }
     }
 
     private void checkUri(URI uri) {
-        if (!uri.getScheme().equalsIgnoreCase(getScheme()))
+        if (!uri.getScheme().equalsIgnoreCase(getScheme())) {
             throw new IllegalArgumentException("URI does not match this provider");
-        if (uri.getAuthority() != null)
+        }
+        if (uri.getAuthority() != null) {
             throw new IllegalArgumentException("Authority component present");
-        if (uri.getPath() == null)
+        }
+        if (uri.getPath() == null) {
             throw new IllegalArgumentException("Path component is undefined");
-        if (!uri.getPath().equals("/"))
+        }
+        if (!uri.getPath().equals("/")) {
             throw new IllegalArgumentException("Path component should be '/'");
-        if (uri.getQuery() != null)
+        }
+        if (uri.getQuery() != null) {
             throw new IllegalArgumentException("Query component present");
-        if (uri.getFragment() != null)
+        }
+        if (uri.getFragment() != null) {
             throw new IllegalArgumentException("Fragment component present");
+        }
     }
 
     @Override
     public FileSystem newFileSystem(URI uri, Map<String, ?> env)
-        throws IOException
-    {
+            throws IOException {
         checkPermission();
         checkUri(uri);
-        return new JrtFileSystem(this, env);
+
+        if (env != null && env.containsKey("java.home")) {
+            return newFileSystem((String)env.get("java.home"), uri, env);
+        } else {
+            return SystemImages.hasModulesImage()
+                    ? new JrtFileSystem(this, env)
+                    : new JrtExplodedFileSystem(this, env);
+        }
+    }
+
+    private static final String JRT_FS_JAR = "jrt-fs.jar";
+    private FileSystem newFileSystem(String targetHome, URI uri, Map<String, ?> env)
+            throws IOException {
+        Objects.requireNonNull(targetHome);
+        Path jrtfs = FileSystems.getDefault().getPath(targetHome, JRT_FS_JAR);
+        if (Files.notExists(jrtfs)) {
+            throw new IOException(jrtfs.toString() + " not exist");
+        }
+
+        Map<String,?> newEnv = new HashMap<>(env);
+        newEnv.remove("java.home");
+        ClassLoader cl = newJrtFsLoader(jrtfs);
+        try {
+            Class<?> c = Class.forName(JrtFileSystemProvider.class.getName(), false, cl);
+            return ((FileSystemProvider)c.newInstance()).newFileSystem(uri, newEnv);
+        } catch (ClassNotFoundException |
+                 IllegalAccessException |
+                 InstantiationException e) {
+            throw new IOException(e);
+        }
+    }
+
+    private static class JrtFsLoader extends URLClassLoader {
+        JrtFsLoader(URL[] urls) {
+            super(urls);
+        }
+
+        @Override
+        protected Class<?> loadClass(String cn, boolean resolve)
+                throws ClassNotFoundException
+        {
+            Class<?> c = findLoadedClass(cn);
+            if (c == null) {
+                URL u = findResource(cn.replace('.', '/') + ".class");
+                if (u != null) {
+                    c = findClass(cn);
+                } else {
+                    return super.loadClass(cn, resolve);
+                }
+            }
+            if (resolve)
+                resolveClass(c);
+            return c;
+        }
+    }
+
+    private static URLClassLoader newJrtFsLoader(Path jrtfs) {
+        final URL url;
+        try {
+            url = jrtfs.toUri().toURL();
+        } catch (MalformedURLException mue) {
+            throw new IllegalArgumentException(mue);
+        }
+
+        final URL[] urls = new URL[] { url };
+        return AccessController.doPrivileged(
+                new PrivilegedAction<URLClassLoader>() {
+                    @Override
+                    public URLClassLoader run() {
+                        return new JrtFsLoader(urls);
+                    }
+                }
+        );
     }
 
     @Override
     public Path getPath(URI uri) {
         checkPermission();
-        if (!uri.getScheme().equalsIgnoreCase(getScheme()))
+        if (!uri.getScheme().equalsIgnoreCase(getScheme())) {
             throw new IllegalArgumentException("URI does not match this provider");
-        if (uri.getAuthority() != null)
+        }
+        if (uri.getAuthority() != null) {
             throw new IllegalArgumentException("Authority component present");
-        if (uri.getQuery() != null)
+        }
+        if (uri.getQuery() != null) {
             throw new IllegalArgumentException("Query component present");
-        if (uri.getFragment() != null)
+        }
+        if (uri.getFragment() != null) {
             throw new IllegalArgumentException("Fragment component present");
+        }
         String path = uri.getPath();
-        if (path == null || path.charAt(0) != '/')
+        if (path == null || path.charAt(0) != '/') {
             throw new IllegalArgumentException("Invalid path component");
+        }
         return getTheFileSystem().getPath(path);
     }
 
@@ -110,11 +208,21 @@
                 fs = this.theFileSystem;
                 if (fs == null) {
                     try {
-                        this.theFileSystem = fs = new JrtFileSystem(this, null) {
-                            @Override public void close() {
-                                throw new UnsupportedOperationException();
-                            }
-                        };
+                        if (SystemImages.hasModulesImage()) {
+                            this.theFileSystem = fs = new JrtFileSystem(this, null) {
+                                @Override
+                                public void close() {
+                                    throw new UnsupportedOperationException();
+                                }
+                            };
+                        } else {
+                            this.theFileSystem = fs = new JrtExplodedFileSystem(this, null) {
+                                @Override
+                                public void close() {
+                                    throw new UnsupportedOperationException();
+                                }
+                            };
+                        }
                     } catch (IOException ioe) {
                         throw new InternalError(ioe);
                     }
@@ -132,71 +240,69 @@
     }
 
     // Checks that the given file is a JrtPath
-    static final JrtPath toJrtPath(Path path) {
-        if (path == null)
+    static final AbstractJrtPath toAbstractJrtPath(Path path) {
+        if (path == null) {
             throw new NullPointerException();
-        if (!(path instanceof JrtPath))
+        }
+        if (!(path instanceof AbstractJrtPath)) {
             throw new ProviderMismatchException();
-        return (JrtPath)path;
+        }
+        return (AbstractJrtPath) path;
     }
 
     @Override
     public void checkAccess(Path path, AccessMode... modes) throws IOException {
-        toJrtPath(path).checkAccess(modes);
+        toAbstractJrtPath(path).checkAccess(modes);
     }
 
     @Override
     public Path readSymbolicLink(Path link) throws IOException {
-        return toJrtPath(link).readSymbolicLink();
+        return toAbstractJrtPath(link).readSymbolicLink();
     }
 
     @Override
     public void copy(Path src, Path target, CopyOption... options)
-        throws IOException
-    {
-        toJrtPath(src).copy(toJrtPath(target), options);
+            throws IOException {
+        toAbstractJrtPath(src).copy(toAbstractJrtPath(target), options);
     }
 
     @Override
     public void createDirectory(Path path, FileAttribute<?>... attrs)
-        throws IOException
-    {
-        toJrtPath(path).createDirectory(attrs);
+            throws IOException {
+        toAbstractJrtPath(path).createDirectory(attrs);
     }
 
     @Override
     public final void delete(Path path) throws IOException {
-        toJrtPath(path).delete();
+        toAbstractJrtPath(path).delete();
     }
 
     @Override
     @SuppressWarnings("unchecked")
     public <V extends FileAttributeView> V
-        getFileAttributeView(Path path, Class<V> type, LinkOption... options)
-    {
-        return JrtFileAttributeView.get(toJrtPath(path), type, options);
+            getFileAttributeView(Path path, Class<V> type, LinkOption... options) {
+        return JrtFileAttributeView.get(toAbstractJrtPath(path), type, options);
     }
 
     @Override
     public FileStore getFileStore(Path path) throws IOException {
-        return toJrtPath(path).getFileStore();
+        return toAbstractJrtPath(path).getFileStore();
     }
 
     @Override
     public boolean isHidden(Path path) {
-        return toJrtPath(path).isHidden();
+        return toAbstractJrtPath(path).isHidden();
     }
 
     @Override
     public boolean isSameFile(Path path, Path other) throws IOException {
-        return toJrtPath(path).isSameFile(other);
+        return toAbstractJrtPath(path).isSameFile(other);
     }
 
     @Override
     public void move(Path src, Path target, CopyOption... options)
-        throws IOException
-    {
-        toJrtPath(src).move(toJrtPath(target), options);
+            throws IOException {
+        toAbstractJrtPath(src).move(toAbstractJrtPath(target), options);
     }
 
     @Override
@@ -204,74 +310,66 @@
             Set<? extends OpenOption> options,
             ExecutorService exec,
             FileAttribute<?>... attrs)
-            throws IOException
-    {
+            throws IOException {
         throw new UnsupportedOperationException();
     }
 
     @Override
     public SeekableByteChannel newByteChannel(Path path,
-                                              Set<? extends OpenOption> options,
-                                              FileAttribute<?>... attrs)
-        throws IOException
-    {
-        return toJrtPath(path).newByteChannel(options, attrs);
+            Set<? extends OpenOption> options,
+            FileAttribute<?>... attrs)
+            throws IOException {
+        return toAbstractJrtPath(path).newByteChannel(options, attrs);
     }
 
     @Override
     public DirectoryStream<Path> newDirectoryStream(
-        Path path, Filter<? super Path> filter) throws IOException
-    {
-        return toJrtPath(path).newDirectoryStream(filter);
+            Path path, Filter<? super Path> filter) throws IOException {
+        return toAbstractJrtPath(path).newDirectoryStream(filter);
     }
 
     @Override
     public FileChannel newFileChannel(Path path,
-                                      Set<? extends OpenOption> options,
-                                      FileAttribute<?>... attrs)
-        throws IOException
-    {
-        return toJrtPath(path).newFileChannel(options, attrs);
+            Set<? extends OpenOption> options,
+            FileAttribute<?>... attrs)
+            throws IOException {
+        return toAbstractJrtPath(path).newFileChannel(options, attrs);
     }
 
     @Override
     public InputStream newInputStream(Path path, OpenOption... options)
-        throws IOException
-    {
-        return toJrtPath(path).newInputStream(options);
+            throws IOException {
+        return toAbstractJrtPath(path).newInputStream(options);
     }
 
     @Override
     public OutputStream newOutputStream(Path path, OpenOption... options)
-        throws IOException
-    {
-        return toJrtPath(path).newOutputStream(options);
+            throws IOException {
+        return toAbstractJrtPath(path).newOutputStream(options);
     }
 
     @Override
     @SuppressWarnings("unchecked") // Cast to A
     public <A extends BasicFileAttributes> A
-        readAttributes(Path path, Class<A> type, LinkOption... options)
-        throws IOException
-    {
-        if (type == BasicFileAttributes.class || type == JrtFileAttributes.class)
-            return (A)toJrtPath(path).getAttributes(options);
+            readAttributes(Path path, Class<A> type, LinkOption... options)
+            throws IOException {
+        if (type == BasicFileAttributes.class || type == JrtFileAttributes.class) {
+            return (A) toAbstractJrtPath(path).getAttributes(options);
+        }
         return null;
     }
 
     @Override
     public Map<String, Object>
-        readAttributes(Path path, String attribute, LinkOption... options)
-        throws IOException
-    {
-        return toJrtPath(path).readAttributes(attribute, options);
+            readAttributes(Path path, String attribute, LinkOption... options)
+            throws IOException {
+        return toAbstractJrtPath(path).readAttributes(attribute, options);
     }
 
     @Override
     public void setAttribute(Path path, String attribute,
-                             Object value, LinkOption... options)
-        throws IOException
-    {
-        toJrtPath(path).setAttribute(attribute, value, options);
+            Object value, LinkOption... options)
+            throws IOException {
+        toAbstractJrtPath(path).setAttribute(attribute, value, options);
     }
 }
--- a/src/java.base/share/classes/jdk/internal/jrtfs/JrtPath.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/jrtfs/JrtPath.java	Thu Mar 17 19:04:16 2016 +0000
@@ -22,848 +22,34 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-
 package jdk.internal.jrtfs;
 
-import java.io.*;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.nio.channels.*;
-import java.nio.file.*;
-import java.nio.file.DirectoryStream.Filter;
-import java.nio.file.attribute.*;
-import java.util.*;
-import static java.nio.file.StandardOpenOption.*;
-import static java.nio.file.StandardCopyOption.*;
+/**
+ * jrt Path implementation for jrt on .jimage files.
+ *
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
+ */
+final class JrtPath extends AbstractJrtPath {
 
-final class JrtPath implements Path {
-
-    private final JrtFileSystem jrtfs;
-    private final byte[] path;
-    private volatile int[] offsets;
-    private int hashcode = 0;  // cached hashcode (created lazily)
-
-    JrtPath(JrtFileSystem jrtfs, byte[] path) {
+    JrtPath(AbstractJrtFileSystem jrtfs, byte[] path) {
         this(jrtfs, path, false);
     }
 
-    JrtPath(JrtFileSystem jrtfs, byte[] path, boolean normalized) {
-        this.jrtfs = jrtfs;
-        if (normalized)
-            this.path = path;
-        else
-            this.path = normalize(path);
-    }
-
-    byte[] getName() {
-        return path;
-    }
-
-    @Override
-    public JrtPath getRoot() {
-        if (this.isAbsolute())
-            return jrtfs.getRootPath();
-        else
-            return null;
-    }
-
-    @Override
-    public Path getFileName() {
-        initOffsets();
-        int count = offsets.length;
-        if (count == 0)
-            return null;  // no elements so no name
-        if (count == 1 && path[0] != '/')
-            return this;
-        int lastOffset = offsets[count-1];
-        int len = path.length - lastOffset;
-        byte[] result = new byte[len];
-        System.arraycopy(path, lastOffset, result, 0, len);
-        return new JrtPath(jrtfs, result);
-    }
-
-    @Override
-    public JrtPath getParent() {
-        initOffsets();
-        int count = offsets.length;
-        if (count == 0)    // no elements so no parent
-            return null;
-        int len = offsets[count-1] - 1;
-        if (len <= 0)      // parent is root only (may be null)
-            return getRoot();
-        byte[] result = new byte[len];
-        System.arraycopy(path, 0, result, 0, len);
-        return new JrtPath(jrtfs, result);
-    }
-
-    @Override
-    public int getNameCount() {
-        initOffsets();
-        return offsets.length;
-    }
-
-    @Override
-    public JrtPath getName(int index) {
-        initOffsets();
-        if (index < 0 || index >= offsets.length)
-            throw new IllegalArgumentException();
-        int begin = offsets[index];
-        int len;
-        if (index == (offsets.length-1))
-            len = path.length - begin;
-        else
-            len = offsets[index+1] - begin - 1;
-        // construct result
-        byte[] result = new byte[len];
-        System.arraycopy(path, begin, result, 0, len);
-        return new JrtPath(jrtfs, result);
-    }
-
-    @Override
-    public JrtPath subpath(int beginIndex, int endIndex) {
-        initOffsets();
-        if (beginIndex < 0 ||
-            beginIndex >=  offsets.length ||
-            endIndex > offsets.length ||
-            beginIndex >= endIndex)
-            throw new IllegalArgumentException();
-
-        // starting offset and length
-        int begin = offsets[beginIndex];
-        int len;
-        if (endIndex == offsets.length)
-            len = path.length - begin;
-        else
-            len = offsets[endIndex] - begin - 1;
-        // construct result
-        byte[] result = new byte[len];
-        System.arraycopy(path, begin, result, 0, len);
-        return new JrtPath(jrtfs, result);
-    }
-
-    @Override
-    public JrtPath toRealPath(LinkOption... options) throws IOException {
-        JrtPath realPath = new JrtPath(jrtfs, getResolvedPath()).toAbsolutePath();
-        realPath = JrtFileSystem.followLinks(options)? jrtfs.resolveLink(this) : realPath;
-        realPath.checkAccess();
-        return realPath;
-    }
-
-    JrtPath readSymbolicLink() throws IOException {
-        if (! jrtfs.isLink(this)) {
-           throw new IOException("not a symbolic link");
-        }
-
-        return jrtfs.resolveLink(this);
-    }
-
-    boolean isHidden() {
-        return false;
-    }
-
-    @Override
-    public JrtPath toAbsolutePath() {
-        if (isAbsolute()) {
-            return this;
-        } else {
-            //add / bofore the existing path
-            byte[] tmp = new byte[path.length + 1];
-            tmp[0] = '/';
-            System.arraycopy(path, 0, tmp, 1, path.length);
-            return (JrtPath) new JrtPath(jrtfs, tmp).normalize();
-        }
-    }
-
-    @Override
-    public URI toUri() {
-        try {
-            return new URI("jrt",
-                           JrtFileSystem.getString(toAbsolutePath().path),
-                           null);
-        } catch (URISyntaxException ex) {
-            throw new AssertionError(ex);
-        }
-    }
-
-    private boolean equalsNameAt(JrtPath other, int index) {
-        int mbegin = offsets[index];
-        int mlen;
-        if (index == (offsets.length-1))
-            mlen = path.length - mbegin;
-        else
-            mlen = offsets[index + 1] - mbegin - 1;
-        int obegin = other.offsets[index];
-        int olen;
-        if (index == (other.offsets.length - 1))
-            olen = other.path.length - obegin;
-        else
-            olen = other.offsets[index + 1] - obegin - 1;
-        if (mlen != olen)
-            return false;
-        int n = 0;
-        while(n < mlen) {
-            if (path[mbegin + n] != other.path[obegin + n])
-                return false;
-            n++;
-        }
-        return true;
-    }
-
-    @Override
-    public Path relativize(Path other) {
-        final JrtPath o = checkPath(other);
-        if (o.equals(this))
-            return new JrtPath(getFileSystem(), new byte[0], true);
-        if (/* this.getFileSystem() != o.getFileSystem() || */
-            this.isAbsolute() != o.isAbsolute()) {
-            throw new IllegalArgumentException();
-        }
-        int mc = this.getNameCount();
-        int oc = o.getNameCount();
-        int n = Math.min(mc, oc);
-        int i = 0;
-        while (i < n) {
-            if (!equalsNameAt(o, i))
-                break;
-            i++;
-        }
-        int dotdots = mc - i;
-        int len = dotdots * 3 - 1;
-        if (i < oc)
-            len += (o.path.length - o.offsets[i] + 1);
-        byte[] result = new byte[len];
-
-        int pos = 0;
-        while (dotdots > 0) {
-            result[pos++] = (byte)'.';
-            result[pos++] = (byte)'.';
-            if (pos < len)       // no tailing slash at the end
-                result[pos++] = (byte)'/';
-            dotdots--;
-        }
-        if (i < oc)
-            System.arraycopy(o.path, o.offsets[i],
-                             result, pos,
-                             o.path.length - o.offsets[i]);
-        return new JrtPath(getFileSystem(), result);
-    }
-
-    @Override
-    public JrtFileSystem getFileSystem() {
-        return jrtfs;
-    }
-
-    @Override
-    public boolean isAbsolute() {
-        return (this.path.length > 0 && path[0] == '/');
-    }
-
-    @Override
-    public JrtPath resolve(Path other) {
-        final JrtPath o = checkPath(other);
-        if (o.isAbsolute())
-            return o;
-        byte[] res;
-        if (this.path[path.length - 1] == '/') {
-            res = new byte[path.length + o.path.length];
-            System.arraycopy(path, 0, res, 0, path.length);
-            System.arraycopy(o.path, 0, res, path.length, o.path.length);
-        } else {
-            res = new byte[path.length + 1 + o.path.length];
-            System.arraycopy(path, 0, res, 0, path.length);
-            res[path.length] = '/';
-            System.arraycopy(o.path, 0, res, path.length + 1, o.path.length);
-        }
-        return new JrtPath(jrtfs, res);
-    }
-
-    @Override
-    public Path resolveSibling(Path other) {
-        if (other == null)
-            throw new NullPointerException();
-        Path parent = getParent();
-        return (parent == null) ? other : parent.resolve(other);
-    }
-
-    @Override
-    public boolean startsWith(Path other) {
-        final JrtPath o = checkPath(other);
-        if (o.isAbsolute() != this.isAbsolute() ||
-            o.path.length > this.path.length)
-            return false;
-        int olast = o.path.length;
-        for (int i = 0; i < olast; i++) {
-            if (o.path[i] != this.path[i])
-                return false;
-        }
-        olast--;
-        return o.path.length == this.path.length ||
-               o.path[olast] == '/' ||
-               this.path[olast + 1] == '/';
-    }
-
-    @Override
-    public boolean endsWith(Path other) {
-        final JrtPath o = checkPath(other);
-        int olast = o.path.length - 1;
-        if (olast > 0 && o.path[olast] == '/')
-            olast--;
-        int last = this.path.length - 1;
-        if (last > 0 && this.path[last] == '/')
-            last--;
-        if (olast == -1)    // o.path.length == 0
-            return last == -1;
-        if ((o.isAbsolute() &&(!this.isAbsolute() || olast != last)) ||
-            (last < olast))
-            return false;
-        for (; olast >= 0; olast--, last--) {
-            if (o.path[olast] != this.path[last])
-                return false;
-        }
-        return o.path[olast + 1] == '/' ||
-               last == -1 || this.path[last] == '/';
-    }
-
-    @Override
-    public JrtPath resolve(String other) {
-        return resolve(getFileSystem().getPath(other));
-    }
-
-    @Override
-    public final Path resolveSibling(String other) {
-        return resolveSibling(getFileSystem().getPath(other));
-    }
-
-    @Override
-    public final boolean startsWith(String other) {
-        return startsWith(getFileSystem().getPath(other));
-    }
-
-    @Override
-    public final boolean endsWith(String other) {
-        return endsWith(getFileSystem().getPath(other));
+    JrtPath(AbstractJrtFileSystem jrtfs, byte[] path, boolean normalized) {
+        super(jrtfs, path, normalized);
     }
 
     @Override
-    public Path normalize() {
-        byte[] res = getResolved();
-        if (res == path)    // no change
-            return this;
-        return new JrtPath(jrtfs, res, true);
-    }
-
-    private JrtPath checkPath(Path path) {
-        if (path == null)
-            throw new NullPointerException();
-        if (!(path instanceof JrtPath))
-            throw new ProviderMismatchException();
-        return (JrtPath) path;
-    }
-
-    // create offset list if not already created
-    private void initOffsets() {
-        if (offsets == null) {
-            int count, index;
-            // count names
-            count = 0;
-            index = 0;
-            while (index < path.length) {
-                byte c = path[index++];
-                if (c != '/') {
-                    count++;
-                    while (index < path.length && path[index] != '/')
-                        index++;
-                }
-            }
-            // populate offsets
-            int[] result = new int[count];
-            count = 0;
-            index = 0;
-            while (index < path.length) {
-                byte c = path[index];
-                if (c == '/') {
-                    index++;
-                } else {
-                    result[count++] = index++;
-                    while (index < path.length && path[index] != '/')
-                        index++;
-                }
-            }
-            synchronized (this) {
-                if (offsets == null)
-                    offsets = result;
-            }
-        }
-    }
-
-    // resolved path for locating jrt entry inside the jrt file,
-    // the result path does not contain ./ and .. components
-    // resolved bytes will always start with '/'
-    private volatile byte[] resolved = null;
-    byte[] getResolvedPath() {
-        byte[] r = resolved;
-        if (r == null) {
-            if (isAbsolute())
-                r = getResolved();
-            else
-                r = toAbsolutePath().getResolvedPath();
-            resolved = r;
-        }
-        return resolved;
-    }
-
-    // removes redundant slashs, replace "\" to separator "/"
-    // and check for invalid characters
-    private static byte[] normalize(byte[] path) {
-        if (path.length == 0)
-            return path;
-        byte prevC = 0;
-        for (int i = 0; i < path.length; i++) {
-            byte c = path[i];
-            if (c == '\\')
-                return normalize(path, i);
-            if (c == (byte)'/' && prevC == '/')
-                return normalize(path, i - 1);
-            if (c == '\u0000')
-                throw new InvalidPathException(JrtFileSystem.getString(path),
-                                               "Path: nul character not allowed");
-            prevC = c;
-        }
-
-        if (path.length > 1 && path[path.length - 1] == '/') {
-            return Arrays.copyOf(path, path.length - 1);
-        }
-
-        return path;
-    }
-
-    private static byte[] normalize(byte[] path, int off) {
-        byte[] to = new byte[path.length];
-        int n = 0;
-        while (n < off) {
-            to[n] = path[n];
-            n++;
-        }
-        int m = n;
-        byte prevC = 0;
-        while (n < path.length) {
-            byte c = path[n++];
-            if (c == (byte)'\\')
-                c = (byte)'/';
-            if (c == (byte)'/' && prevC == (byte)'/')
-                continue;
-            if (c == '\u0000')
-                throw new InvalidPathException(JrtFileSystem.getString(path),
-                                               "Path: nul character not allowed");
-            to[m++] = c;
-            prevC = c;
-        }
-        if (m > 1 && to[m - 1] == '/')
-            m--;
-        return (m == to.length)? to : Arrays.copyOf(to, m);
-    }
-
-    // Remove DotSlash(./) and resolve DotDot (..) components
-    private byte[] getResolved() {
-        if (path.length == 0)
-            return path;
-        for (int i = 0; i < path.length; i++) {
-            byte c = path[i];
-            if (c == (byte)'.')
-                return resolve0();
-        }
-
-        return path;
-    }
-
-    // TBD: performance, avoid initOffsets
-    private byte[] resolve0() {
-        byte[] to = new byte[path.length];
-        int nc = getNameCount();
-        int[] lastM = new int[nc];
-        int lastMOff = -1;
-        int m = 0;
-        for (int i = 0; i < nc; i++) {
-            int n = offsets[i];
-            int len = (i == offsets.length - 1)?
-                      (path.length - n):(offsets[i + 1] - n - 1);
-            if (len == 1 && path[n] == (byte)'.') {
-                if (m == 0 && path[0] == '/')   // absolute path
-                    to[m++] = '/';
-                continue;
-            }
-            if (len == 2 && path[n] == '.' && path[n + 1] == '.') {
-                if (lastMOff >= 0) {
-                    m = lastM[lastMOff--];  // retreat
-                    continue;
-                }
-                if (path[0] == '/') {  // "/../xyz" skip
-                    if (m == 0)
-                        to[m++] = '/';
-                } else {               // "../xyz" -> "../xyz"
-                    if (m != 0 && to[m-1] != '/')
-                        to[m++] = '/';
-                    while (len-- > 0)
-                        to[m++] = path[n++];
-                }
-                continue;
-            }
-            if (m == 0 && path[0] == '/' ||   // absolute path
-                m != 0 && to[m-1] != '/') {   // not the first name
-                to[m++] = '/';
-            }
-            lastM[++lastMOff] = m;
-            while (len-- > 0)
-                to[m++] = path[n++];
-        }
-        if (m > 1 && to[m - 1] == '/')
-            m--;
-        return (m == to.length)? to : Arrays.copyOf(to, m);
-    }
-
-    @Override
-    public String toString() {
-        return JrtFileSystem.getString(path);
-    }
-
-    @Override
-    public int hashCode() {
-        int h = hashcode;
-        if (h == 0)
-            hashcode = h = Arrays.hashCode(path);
-        return h;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        return obj != null &&
-               obj instanceof JrtPath &&
-               this.jrtfs == ((JrtPath)obj).jrtfs &&
-               compareTo((Path) obj) == 0;
-    }
-
-    @Override
-    public int compareTo(Path other) {
-        final JrtPath o = checkPath(other);
-        int len1 = this.path.length;
-        int len2 = o.path.length;
-
-        int n = Math.min(len1, len2);
-        byte v1[] = this.path;
-        byte v2[] = o.path;
-
-        int k = 0;
-        while (k < n) {
-            int c1 = v1[k] & 0xff;
-            int c2 = v2[k] & 0xff;
-            if (c1 != c2)
-                return c1 - c2;
-            k++;
-        }
-        return len1 - len2;
-    }
-
-    @Override
-    public WatchKey register(
-            WatchService watcher,
-            WatchEvent.Kind<?>[] events,
-            WatchEvent.Modifier... modifiers) {
-        if (watcher == null || events == null || modifiers == null) {
-            throw new NullPointerException();
-        }
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public WatchKey register(WatchService watcher, WatchEvent.Kind<?>... events) {
-        return register(watcher, events, new WatchEvent.Modifier[0]);
-    }
-
-    @Override
-    public final File toFile() {
-        throw new UnsupportedOperationException();
+    protected JrtPath newJrtPath(byte[] path) {
+        return new JrtPath(jrtfs, path);
     }
 
     @Override
-    public Iterator<Path> iterator() {
-        return new Iterator<Path>() {
-            private int i = 0;
-
-            @Override
-            public boolean hasNext() {
-                return (i < getNameCount());
-            }
-
-            @Override
-            public Path next() {
-                if (i < getNameCount()) {
-                    Path result = getName(i);
-                    i++;
-                    return result;
-                } else {
-                    throw new NoSuchElementException();
-                }
-            }
-
-            @Override
-            public void remove() {
-                throw new ReadOnlyFileSystemException();
-            }
-        };
-    }
-
-    /////////////////////////////////////////////////////////////////////
-    // Helpers for JrtFileSystemProvider and JrtFileSystem
-
-    int getPathLength() {
-        return path.length;
-    }
-
-
-    void createDirectory(FileAttribute<?>... attrs)
-        throws IOException
-    {
-        jrtfs.createDirectory(getResolvedPath(), attrs);
-    }
-
-    InputStream newInputStream(OpenOption... options) throws IOException
-    {
-        if (options.length > 0) {
-            for (OpenOption opt : options) {
-                if (opt != READ)
-                    throw new UnsupportedOperationException("'" + opt + "' not allowed");
-            }
-        }
-        return jrtfs.newInputStream(getResolvedPath());
-    }
-
-    DirectoryStream<Path> newDirectoryStream(Filter<? super Path> filter)
-        throws IOException
-    {
-        return new JrtDirectoryStream(this, filter);
-    }
-
-    void delete() throws IOException {
-        jrtfs.deleteFile(getResolvedPath(), true);
-    }
-
-    void deleteIfExists() throws IOException {
-        jrtfs.deleteFile(getResolvedPath(), false);
-    }
-
-    JrtFileAttributes getAttributes(LinkOption... options) throws IOException
-    {
-        JrtFileAttributes zfas = jrtfs.getFileAttributes(getResolvedPath(), options);
-        if (zfas == null)
-            throw new NoSuchFileException(toString());
-        return zfas;
-    }
-
-    void setAttribute(String attribute, Object value, LinkOption... options)
-        throws IOException
-    {
-        String type;
-        String attr;
-        int colonPos = attribute.indexOf(':');
-        if (colonPos == -1) {
-            type = "basic";
-            attr = attribute;
-        } else {
-            type = attribute.substring(0, colonPos++);
-            attr = attribute.substring(colonPos);
-        }
-        JrtFileAttributeView view = JrtFileAttributeView.get(this, type, options);
-        if (view == null)
-            throw new UnsupportedOperationException("view <" + view + "> is not supported");
-        view.setAttribute(attr, value);
-    }
-
-    void setTimes(FileTime mtime, FileTime atime, FileTime ctime)
-        throws IOException
-    {
-        jrtfs.setTimes(getResolvedPath(), mtime, atime, ctime);
-    }
-
-    Map<String, Object> readAttributes(String attributes, LinkOption... options)
-        throws IOException
-
-    {
-        String view;
-        String attrs;
-        int colonPos = attributes.indexOf(':');
-        if (colonPos == -1) {
-            view = "basic";
-            attrs = attributes;
-        } else {
-            view = attributes.substring(0, colonPos++);
-            attrs = attributes.substring(colonPos);
-        }
-        JrtFileAttributeView jrtfv = JrtFileAttributeView.get(this, view, options);
-        if (jrtfv == null) {
-            throw new UnsupportedOperationException("view not supported");
-        }
-        return jrtfv.readAttributes(attrs);
-    }
-
-    FileStore getFileStore() throws IOException {
-        // each JrtFileSystem only has one root (as requested for now)
-        if (exists())
-            return jrtfs.getFileStore(this);
-        throw new NoSuchFileException(JrtFileSystem.getString(path));
-    }
-
-    boolean isSameFile(Path other) throws IOException {
-        if (this.equals(other))
-            return true;
-        if (other == null ||
-            this.getFileSystem() != other.getFileSystem())
-            return false;
-        this.checkAccess();
-        JrtPath path = (JrtPath)other;
-        path.checkAccess();
-        return Arrays.equals(this.getResolvedPath(), path.getResolvedPath()) ||
-            jrtfs.isSameFile(this, (JrtPath)other);
-    }
-
-    SeekableByteChannel newByteChannel(Set<? extends OpenOption> options,
-                                       FileAttribute<?>... attrs)
-        throws IOException
-    {
-        return jrtfs.newByteChannel(getResolvedPath(), options, attrs);
-    }
-
-
-    FileChannel newFileChannel(Set<? extends OpenOption> options,
-                               FileAttribute<?>... attrs)
-        throws IOException
-    {
-        return jrtfs.newFileChannel(getResolvedPath(), options, attrs);
-    }
-
-    void checkAccess(AccessMode... modes) throws IOException {
-        boolean w = false;
-        boolean x = false;
-        for (AccessMode mode : modes) {
-            switch (mode) {
-                case READ:
-                    break;
-                case WRITE:
-                    w = true;
-                    break;
-                case EXECUTE:
-                    x = true;
-                    break;
-                default:
-                    throw new UnsupportedOperationException();
-            }
-        }
-        JrtFileAttributes attrs = jrtfs.getFileAttributes(getResolvedPath());
-        if (attrs == null && (path.length != 1 || path[0] != '/'))
-            throw new NoSuchFileException(toString());
-        if (w) {
-            if (jrtfs.isReadOnly())
-                throw new AccessDeniedException(toString());
-        }
-        if (x)
-            throw new AccessDeniedException(toString());
-    }
-
-    boolean exists() {
-        if (isAbsolute())
-            return true;
-        try {
-            return jrtfs.exists(getResolvedPath());
-        } catch (IOException x) {}
-        return false;
-    }
-
-    OutputStream newOutputStream(OpenOption... options) throws IOException
-    {
-        if (options.length == 0)
-            return jrtfs.newOutputStream(getResolvedPath(),
-                                       CREATE_NEW, WRITE);
-        return jrtfs.newOutputStream(getResolvedPath(), options);
-    }
-
-    void move(JrtPath target, CopyOption... options)
-        throws IOException
-    {
-        if (this.jrtfs == target.jrtfs)
-        {
-            jrtfs.copyFile(true,
-                         getResolvedPath(), target.getResolvedPath(),
-                         options);
-        } else {
-            copyToTarget(target, options);
-            delete();
-        }
-    }
-
-    void copy(JrtPath target, CopyOption... options)
-        throws IOException
-    {
-        if (this.jrtfs == target.jrtfs)
-            jrtfs.copyFile(false,
-                         getResolvedPath(), target.getResolvedPath(),
-                         options);
-        else
-            copyToTarget(target, options);
-    }
-
-    private void copyToTarget(JrtPath target, CopyOption... options)
-        throws IOException
-    {
-        boolean replaceExisting = false;
-        boolean copyAttrs = false;
-        for (CopyOption opt : options) {
-            if (opt == REPLACE_EXISTING)
-                replaceExisting = true;
-            else if (opt == COPY_ATTRIBUTES)
-                copyAttrs = true;
-        }
-        // attributes of source file
-        JrtFileAttributes jrtfas = getAttributes();
-        // check if target exists
-        boolean exists;
-        if (replaceExisting) {
-            try {
-                target.deleteIfExists();
-                exists = false;
-            } catch (DirectoryNotEmptyException x) {
-                exists = true;
-            }
-        } else {
-            exists = target.exists();
-        }
-        if (exists)
-            throw new FileAlreadyExistsException(target.toString());
-
-        if (jrtfas.isDirectory()) {
-            // create directory or file
-            target.createDirectory();
-        } else {
-            try (InputStream is = jrtfs.newInputStream(getResolvedPath()); OutputStream os = target.newOutputStream()) {
-                byte[] buf = new byte[8192];
-                int n;
-                while ((n = is.read(buf)) != -1) {
-                    os.write(buf, 0, n);
-                }
-            }
-        }
-        if (copyAttrs) {
-            BasicFileAttributeView view =
-                JrtFileAttributeView.get(target, BasicFileAttributeView.class);
-            try {
-                view.setTimes(jrtfas.lastModifiedTime(),
-                              jrtfas.lastAccessTime(),
-                              jrtfas.creationTime());
-            } catch (IOException x) {
-                // rollback?
-                try {
-                    target.delete();
-                } catch (IOException ignore) { }
-                throw x;
-            }
-        }
+    protected JrtPath newJrtPath(byte[] path, boolean normalized) {
+        return new JrtPath(jrtfs, path, normalized);
     }
 }
--- a/src/java.base/share/classes/jdk/internal/jrtfs/JrtUtils.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/jrtfs/JrtUtils.java	Thu Mar 17 19:04:16 2016 +0000
@@ -27,6 +27,13 @@
 
 import java.util.regex.PatternSyntaxException;
 
+/**
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
+ */
 final class JrtUtils {
     private JrtUtils() {}
 
--- a/src/java.base/share/classes/jdk/internal/jrtfs/SystemImages.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/jrtfs/SystemImages.java	Thu Mar 17 19:04:16 2016 +0000
@@ -22,11 +22,11 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-
 package jdk.internal.jrtfs;
 
 import java.net.URISyntaxException;
 import java.net.URL;
+import java.nio.file.Files;
 import java.nio.file.FileSystem;
 import java.nio.file.FileSystems;
 import java.nio.file.Path;
@@ -35,22 +35,52 @@
 import java.security.CodeSource;
 import java.security.PrivilegedAction;
 
+/**
+ * @implNote This class needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
+ */
 final class SystemImages {
     private SystemImages() {}
 
+
     static final String RUNTIME_HOME;
-    static final Path bootImagePath;
-    static final Path extImagePath;
-    static final Path appImagePath;
+    // "modules" jimage file Path
+    private static final Path moduleImageFile;
+    // "modules" jimage exists or not?
+    private static final boolean modulesImageExists;
+    // <JAVA_HOME>/modules directory Path
+    private static final Path explodedModulesDir;
 
     static {
         PrivilegedAction<String> pa = SystemImages::findHome;
         RUNTIME_HOME = AccessController.doPrivileged(pa);
 
         FileSystem fs = FileSystems.getDefault();
-        bootImagePath = fs.getPath(RUNTIME_HOME, "lib", "modules", "bootmodules.jimage");
-        extImagePath = fs.getPath(RUNTIME_HOME, "lib", "modules", "extmodules.jimage");
-        appImagePath = fs.getPath(RUNTIME_HOME, "lib", "modules", "appmodules.jimage");
+        moduleImageFile = fs.getPath(RUNTIME_HOME, "lib", "modules");
+        explodedModulesDir = fs.getPath(RUNTIME_HOME, "modules");
+
+        modulesImageExists = AccessController.doPrivileged(
+            new PrivilegedAction<Boolean>() {
+                @Override
+                public Boolean run() {
+                    return Files.isRegularFile(moduleImageFile);
+                }
+            });
+    }
+
+    static boolean hasModulesImage() {
+        return modulesImageExists;
+    }
+
+    static Path moduleImageFile() {
+        return moduleImageFile;
+    }
+
+    static Path explodedModulesDir() {
+        return explodedModulesDir;
     }
 
     /**
--- a/src/java.base/share/classes/jdk/internal/jrtfs/jrtfsviewer.js	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/jrtfs/jrtfsviewer.js	Thu Mar 17 19:04:16 2016 +0000
@@ -25,6 +25,13 @@
  * questions.
  */
 
+/*
+ * @implNote This script needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
+ */
 function usage() {
     print("Usage:");
     print("jdk9+: jjs -fx jrtfsviewer.js");
--- a/src/java.base/share/classes/jdk/internal/jrtfs/jrtls.js	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/jrtfs/jrtls.js	Thu Mar 17 19:04:16 2016 +0000
@@ -27,6 +27,13 @@
  * Usage: jjs jrtls.js
  *
  * Recursively list the content of / directory of the jrt fs.
+ *
+ * @implNote This script needs to maintain JDK 8 source compatibility.
+ *
+ * It is used internally in the JDK to implement jimage/jrtfs access,
+ * but also compiled and delivered as part of the jrtfs.jar to support access
+ * to the jimage file provided by the shipped JDK by tools running on JDK 8.
+ */
  */
 
 // classes used
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/loader/BootLoader.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.loader;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.module.ModuleReference;
+import java.lang.reflect.Layer;
+import java.lang.reflect.Module;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.Optional;
+import java.util.jar.JarInputStream;
+import java.util.jar.Manifest;
+import java.util.stream.Stream;
+
+import jdk.internal.misc.JavaLangAccess;
+import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.ServicesCatalog;
+
+/**
+ * Find resources and packages in modules defined to the boot class loader or
+ * resources and packages on the "boot class path" specified via -Xbootclasspath/a.
+ */
+
+public class BootLoader {
+    private BootLoader() { }
+
+    // The unnamed module for the boot loader
+    private static final Module UNNAMED_MODULE;
+    private static final String JAVA_HOME = System.getProperty("java.home");
+
+    static {
+        UNNAMED_MODULE
+            = SharedSecrets.getJavaLangReflectModuleAccess().defineUnnamedModule(null);
+        setBootLoaderUnnamedModule0(UNNAMED_MODULE);
+    }
+
+    // ServiceCatalog for the boot class loader
+    private static final ServicesCatalog SERVICES_CATALOG = new ServicesCatalog();
+
+    /**
+     * Returns the unnamed module for the boot loader.
+     */
+    public static Module getUnnamedModule() {
+        return UNNAMED_MODULE;
+    }
+
+    /**
+     * Returns the ServiceCatalog for modules defined to the boot class loader.
+     */
+    public static ServicesCatalog getServicesCatalog() {
+        return SERVICES_CATALOG;
+    }
+
+    /**
+     * Register a module with this class loader so that its classes (and
+     * resources) become visible via this class loader.
+     */
+    public static void loadModule(ModuleReference mref) {
+        ClassLoaders.bootLoader().loadModule(mref);
+    }
+
+    /**
+     * Loads the Class object with the given name defined to the boot loader.
+     */
+    public static Class<?> loadClassOrNull(String name) {
+        return ClassLoaders.bootLoader().loadClassOrNull(name);
+    }
+
+    /**
+     * Returns a URL to a resource in a named module defined to the boot loader.
+     */
+    public static URL findResource(String mn, String name) throws IOException {
+        return ClassLoaders.bootLoader().findResource(mn, name);
+    }
+
+    /**
+     * Returns an input stream to a resource in a named module defined to the
+     * boot loader.
+     */
+    public static InputStream findResourceAsStream(String mn, String name)
+        throws IOException
+    {
+        return ClassLoaders.bootLoader().findResourceAsStream(mn, name);
+    }
+
+    /**
+     * Returns the URL to the given resource if the resource can be located
+     * on the boot class path. This method does not locate a resource in any
+     * of the named modules defined to the boot loader.
+     */
+    public static URL findResource(String name) {
+        return ClassLoaders.bootLoader().findResource(name);
+    }
+
+    /**
+     * Returns an Iterator to iterate over the resources of the given name
+     * on the boot class path. This method does not locate resources in any
+     * of the named modules defined to the boot loader.
+     */
+    public static Enumeration<URL> findResources(String name) throws IOException {
+        return ClassLoaders.bootLoader().findResources(name);
+    }
+
+    /**
+     * Define a package for the given class to the boot loader, if not already
+     * defined.
+     */
+    public static Package definePackage(Class<?> c) {
+        return getDefinedPackage(c.getPackageName());
+    }
+
+    /**
+     * Returns the Package of the given name defined to the boot loader or null
+     * if the package has not been defined.
+     */
+    public static Package getDefinedPackage(String pn) {
+        Package pkg = ClassLoaders.bootLoader().getDefinedPackage(pn);
+        if (pkg == null) {
+            String location = getSystemPackageLocation(pn.replace('.', '/'));
+            if (location != null) {
+                pkg = PackageHelper.definePackage(pn.intern(), location);
+            }
+        }
+        return pkg;
+    }
+
+    /**
+     * Returns a stream of the packages defined to the boot loader.
+     */
+    public static Stream<Package> packages() {
+        return Arrays.stream(getSystemPackageNames())
+                     .map(name -> getDefinedPackage(name.replace('/', '.')));
+    }
+
+    /**
+     * Helper class to define {@code Package} objects for packages in modules
+     * defined to the boot loader.
+     */
+    static class PackageHelper {
+        private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
+
+        /**
+         * Define the {@code Package} with the given name. The specified
+         * location is a jrt URL to a named module in the run-time image, a
+         * file path to a module in an exploded run-time image, or the file
+         * path to an enty on the boot class path (java agent Boot-Class-Path
+         * or -Xbootclasspath/a.
+         *
+         * <p> If the given location is a JAR file containing a manifest,
+         * the defined Package contains the versioning information from
+         * the manifest, if present.
+         *
+         * @param name     package name
+         * @param location location where the package is (jrt URL or file path)
+         */
+        static Package definePackage(String name, String location) {
+            Module module = findModule(location);
+            if (module != null) {
+                // named module from runtime image or exploded module
+                if (name.isEmpty())
+                    throw new InternalError("empty package in " + location);
+                return JLA.definePackage(ClassLoaders.bootLoader(), name, module);
+            }
+
+            // package in unnamed module (-Xbootclasspath/a)
+            URL url = toFileURL(location);
+            Manifest man = url != null ? getManifest(location) : null;
+
+            return ClassLoaders.bootLoader().defineOrCheckPackage(name, man, url);
+        }
+
+        /**
+         * Finds the module at the given location defined to the boot loader.
+         * The module is either in runtime image or exploded image.
+         * Otherwise this method returns null.
+         */
+        private static Module findModule(String location) {
+            String mn = null;
+            if (location.startsWith("jrt:/")) {
+                // named module in runtime image ("jrt:/".length() == 5)
+                mn = location.substring(5, location.length());
+            } else {
+                // named module in exploded image
+                Path path = Paths.get(location);
+                Path modulesDir = Paths.get(JAVA_HOME, "modules");
+                if (path.startsWith(modulesDir)) {
+                    mn = path.getFileName().toString();
+                }
+            }
+
+            if (mn != null) {
+                // named module from runtime image or exploded module
+                Optional<Module> om = Layer.boot().findModule(mn);
+                if (!om.isPresent())
+                    throw new InternalError(mn + " not in boot layer");
+                return om.get();
+            }
+
+            return null;
+        }
+
+        /**
+         * Returns URL if the given location is a regular file path.
+         */
+        private static URL toFileURL(String location) {
+            return AccessController.doPrivileged(new PrivilegedAction<>() {
+                public URL run() {
+                    Path path = Paths.get(location);
+                    if (Files.isRegularFile(path)) {
+                        try {
+                            return path.toUri().toURL();
+                        } catch (MalformedURLException e) {}
+                    }
+                    return null;
+                }
+            });
+        }
+
+        /**
+         * Returns the Manifest if the given location is a JAR file
+         * containing a manifest.
+         */
+        private static Manifest getManifest(String location) {
+            return AccessController.doPrivileged(new PrivilegedAction<>() {
+                public Manifest run() {
+                    Path jar = Paths.get(location);
+                    try (InputStream in = Files.newInputStream(jar);
+                         JarInputStream jis = new JarInputStream(in, false)) {
+                        return jis.getManifest();
+                    } catch (IOException e) {
+                        return null;
+                    }
+                }
+            });
+        }
+    }
+
+    /**
+     * Returns an array of the binary name of the packages defined by
+     * the boot loader, in VM internal form (forward slashes instead of dot).
+     */
+    private static native String[] getSystemPackageNames();
+
+    /**
+     * Returns the location of the package of the given name, if
+     * defined by the boot loader; otherwise {@code null} is returned.
+     *
+     * The location may be a module from the runtime image or exploded image,
+     * or from the boot class append path (i.e. -Xbootclasspath/a or
+     * BOOT-CLASS-PATH attribute specified in java agent).
+     */
+    private static native String getSystemPackageLocation(String name);
+    private static native void setBootLoaderUnnamedModule0(Module module);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,766 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.loader;
+
+import java.io.File;
+import java.io.FilePermission;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.module.ModuleReference;
+import java.lang.module.ModuleReader;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.nio.ByteBuffer;
+import java.security.AccessController;
+import java.security.CodeSigner;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.security.SecureClassLoader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+
+import jdk.internal.module.ModulePatcher.PatchedModuleReader;
+import jdk.internal.misc.VM;
+import sun.misc.URLClassPath;
+import sun.misc.Resource;
+
+
+/**
+ * The platform or application class loader. Resources loaded from modules
+ * defined to the boot class loader are also loaded via an instance of this
+ * ClassLoader type.
+ *
+ * <p> This ClassLoader supports loading of classes and resources from modules.
+ * Modules are defined to the ClassLoader by invoking the {@link #loadModule}
+ * method. Defining a module to this ClassLoader has the effect of making the
+ * types in the module visible. </p>
+ *
+ * <p> This ClassLoader also supports loading of classes and resources from a
+ * class path of URLs that are specified to the ClassLoader at construction
+ * time. The class path may expand at runtime (the Class-Path attribute in JAR
+ * files or via instrumentation agents). </p>
+ *
+ * <p> The delegation model used by this ClassLoader differs to the regular
+ * delegation model. When requested to load a class then this ClassLoader first
+ * maps the class name to its package name. If there is a module defined to a
+ * BuiltinClassLoader containing this package then the class loader delegates
+ * directly to that class loader. If there isn't a module containing the
+ * package then it delegates the search to the parent class loader and if not
+ * found in the parent then it searches the class path. The main difference
+ * between this and the usual delegation model is that it allows the platform
+ * class loader to delegate to the application class loader, important with
+ * upgraded modules defined to the platform class loader.
+ */
+
+public class BuiltinClassLoader
+    extends SecureClassLoader
+{
+    static {
+        if (!ClassLoader.registerAsParallelCapable())
+            throw new InternalError();
+    }
+
+    // parent ClassLoader
+    private final BuiltinClassLoader parent;
+
+    // the URL class path or null if there is no class path
+    private final URLClassPath ucp;
+
+
+    /**
+     * A module defined/loaded by a built-in class loader.
+     *
+     * A LoadedModule encapsulates a ModuleReference along with its CodeSource
+     * URL to avoid needing to create this URL when define classes.
+     */
+    private static class LoadedModule {
+        private final BuiltinClassLoader loader;
+        private final ModuleReference mref;
+        private final URL codeSourceURL;          // may be null
+
+        LoadedModule(BuiltinClassLoader loader, ModuleReference mref) {
+            URL url = null;
+            if (mref.location().isPresent()) {
+                try {
+                    url = mref.location().get().toURL();
+                } catch (MalformedURLException e) { }
+            }
+            this.loader = loader;
+            this.mref = mref;
+            this.codeSourceURL = url;
+        }
+
+        BuiltinClassLoader loader() { return loader; }
+        ModuleReference mref() { return mref; }
+        String name() { return mref.descriptor().name(); }
+        URL codeSourceURL() { return codeSourceURL; }
+    }
+
+
+    // maps package name to loaded module for modules in the boot layer
+    private static final Map<String, LoadedModule> packageToModule
+        = new ConcurrentHashMap<>(1024);
+
+    // maps a module name to a module reference
+    private final Map<String, ModuleReference> nameToModule;
+
+    // maps a module reference to a module reader
+    private final Map<ModuleReference, ModuleReader> moduleToReader;
+
+
+    /**
+     * Create a new instance.
+     */
+    BuiltinClassLoader(BuiltinClassLoader parent, URLClassPath ucp) {
+        // ensure getParent() returns null when the parent is the boot loader
+        super(parent == null || parent == ClassLoaders.bootLoader() ? null : parent);
+
+        this.parent = parent;
+        this.ucp = ucp;
+
+        this.nameToModule = new ConcurrentHashMap<>();
+        this.moduleToReader = new ConcurrentHashMap<>();
+    }
+
+    /**
+     * Register a module this this class loader. This has the effect of making
+     * the types in the module visible.
+     */
+    public void loadModule(ModuleReference mref) {
+        String mn = mref.descriptor().name();
+        if (nameToModule.putIfAbsent(mn, mref) != null) {
+            throw new InternalError(mn + " already defined to this loader");
+        }
+
+        LoadedModule loadedModule = new LoadedModule(this, mref);
+        for (String pn : mref.descriptor().packages()) {
+            LoadedModule other = packageToModule.putIfAbsent(pn, loadedModule);
+            if (other != null) {
+                throw new InternalError(pn + " in modules " + mn + " and "
+                                        + other.mref().descriptor().name());
+            }
+        }
+    }
+
+    /**
+     * Returns the {@code ModuleReference} for the named module defined to
+     * this class loader; or {@code null} if not defined.
+     *
+     * @param name The name of the module to find
+     */
+    protected ModuleReference findModule(String name) {
+        return nameToModule.get(name);
+    }
+
+
+    // -- finding resources
+
+    /**
+     * Returns a URL to a resource of the given name in a module defined to
+     * this class loader.
+     */
+    @Override
+    public URL findResource(String mn, String name) throws IOException {
+        ModuleReference mref = nameToModule.get(mn);
+        if (mref == null)
+            return null;   // not defined to this class loader
+
+        URL url;
+
+        try {
+            url = AccessController.doPrivileged(
+                new PrivilegedExceptionAction<URL>() {
+                    @Override
+                    public URL run() throws IOException {
+                        URI u = moduleReaderFor(mref).find(name).orElse(null);
+                        if (u != null) {
+                            try {
+                                return u.toURL();
+                            } catch (MalformedURLException e) { }
+                        }
+                        return null;
+                    }
+                });
+        } catch (PrivilegedActionException pae) {
+            throw (IOException) pae.getCause();
+        }
+
+        // check access to the URL
+        return checkURL(url);
+    }
+
+    /**
+     * Returns an input stream to a resource of the given name in a module
+     * defined to this class loader.
+     */
+    public InputStream findResourceAsStream(String mn, String name)
+        throws IOException
+    {
+        // Need URL to resource when running with a security manager so that
+        // the right permission check is done.
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+
+            URL url = findResource(mn, name);
+            return (url != null) ? url.openStream() : null;
+
+        } else {
+
+            ModuleReference mref = nameToModule.get(mn);
+            if (mref == null)
+                return null;   // not defined to this class loader
+
+            try {
+                return AccessController.doPrivileged(
+                    new PrivilegedExceptionAction<InputStream>() {
+                        @Override
+                        public InputStream run() throws IOException {
+                            return moduleReaderFor(mref).open(name).orElse(null);
+                        }
+                    });
+            } catch (PrivilegedActionException pae) {
+                throw (IOException) pae.getCause();
+            }
+        }
+    }
+
+    /**
+     * Finds the resource with the given name on the class path of this class
+     * loader.
+     */
+    @Override
+    public URL findResource(String name) {
+        if (ucp != null) {
+            PrivilegedAction<URL> pa = () -> ucp.findResource(name, false);
+            URL url = AccessController.doPrivileged(pa);
+            return checkURL(url);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Returns an enumeration of URL objects to all the resources with the
+     * given name on the class path of this class loader.
+     */
+    @Override
+    public Enumeration<URL> findResources(String name) throws IOException {
+        if (ucp != null) {
+            List<URL> result = new ArrayList<>();
+            PrivilegedAction<Enumeration<URL>> pa = () -> ucp.findResources(name, false);
+            Enumeration<URL> e = AccessController.doPrivileged(pa);
+            while (e.hasMoreElements()) {
+                URL url = checkURL(e.nextElement());
+                if (url != null) {
+                    result.add(url);
+                }
+            }
+            return Collections.enumeration(result); // checked URLs
+        } else {
+            return Collections.emptyEnumeration();
+        }
+    }
+
+
+    // -- finding/loading classes
+
+    /**
+     * Finds the class with the specified binary name.
+     */
+    @Override
+    protected Class<?> findClass(String cn) throws ClassNotFoundException {
+        // no class loading until VM is fully initialized
+        if (!VM.isModuleSystemInited())
+            throw new ClassNotFoundException(cn);
+
+        // find the candidate module for this class
+        LoadedModule loadedModule = findLoadedModule(cn);
+
+        Class<?> c = null;
+        if (loadedModule != null) {
+
+            // attempt to load class in module defined to this loader
+            if (loadedModule.loader() == this) {
+                c = findClassInModuleOrNull(loadedModule, cn);
+            }
+
+        } else {
+
+            // search class path
+            if (ucp != null) {
+                c = findClassOnClassPathOrNull(cn);
+            }
+
+        }
+
+        // not found
+        if (c == null)
+            throw new ClassNotFoundException(cn);
+
+        return c;
+    }
+
+    /**
+     * Finds the class with the specified binary name in a given module.
+     * This method returns {@code null} if the class cannot be found.
+     */
+    @Override
+    protected Class<?> findClass(String mn, String cn) {
+        ModuleReference mref = nameToModule.get(mn);
+        if (mref == null)
+            return null;   // not defined to this class loader
+
+        // find the candidate module for this class
+        LoadedModule loadedModule = findLoadedModule(cn);
+        if (loadedModule == null || !loadedModule.name().equals(mn)) {
+            return null;   // module name does not match
+        }
+
+        // attempt to load class in module defined to this loader
+        assert loadedModule.loader() == this;
+        return findClassInModuleOrNull(loadedModule, cn);
+    }
+
+    /**
+     * Loads the class with the specified binary name.
+     */
+    @Override
+    protected Class<?> loadClass(String cn, boolean resolve)
+        throws ClassNotFoundException
+    {
+        Class<?> c = loadClassOrNull(cn, resolve);
+        if (c == null)
+            throw new ClassNotFoundException(cn);
+        return c;
+    }
+
+    /**
+     * A variation of {@code loadCass} to load a class with the specified
+     * binary name. This method returns {@code null} when the class is not
+     * found.
+     */
+    protected Class<?> loadClassOrNull(String cn, boolean resolve) {
+        synchronized (getClassLoadingLock(cn)) {
+            // check if already loaded
+            Class<?> c = findLoadedClass(cn);
+
+            if (c == null) {
+
+                // find the candidate module for this class
+                LoadedModule loadedModule = findLoadedModule(cn);
+                if (loadedModule != null) {
+
+                    // package is in a module
+                    BuiltinClassLoader loader = loadedModule.loader();
+                    if (loader == this) {
+                        if (VM.isModuleSystemInited()) {
+                            c = findClassInModuleOrNull(loadedModule, cn);
+                        }
+                    } else {
+                        // delegate to the other loader
+                        c = loader.loadClassOrNull(cn);
+                    }
+
+                } else {
+
+                    // check parent
+                    if (parent != null) {
+                        c = parent.loadClassOrNull(cn);
+                    }
+
+                    // check class path
+                    if (c == null && ucp != null && VM.isModuleSystemInited()) {
+                        c = findClassOnClassPathOrNull(cn);
+                    }
+                }
+
+            }
+
+            if (resolve && c != null)
+                resolveClass(c);
+
+            return c;
+        }
+    }
+
+    /**
+     * A variation of {@code loadCass} to load a class with the specified
+     * binary name. This method returns {@code null} when the class is not
+     * found.
+     */
+    protected  Class<?> loadClassOrNull(String cn) {
+        return loadClassOrNull(cn, false);
+    }
+
+    /**
+     * Find the candidate loaded module for the given class name.
+     * Returns {@code null} if none of the modules defined to this
+     * class loader contain the API package for the class.
+     */
+    private LoadedModule findLoadedModule(String cn) {
+        int pos = cn.lastIndexOf('.');
+        if (pos < 0)
+            return null; // unnamed package
+
+        String pn = cn.substring(0, pos);
+        return packageToModule.get(pn);
+    }
+
+    /**
+     * Finds the class with the specified binary name if in a module
+     * defined to this ClassLoader.
+     *
+     * @return the resulting Class or {@code null} if not found
+     */
+    private Class<?> findClassInModuleOrNull(LoadedModule loadedModule, String cn) {
+        PrivilegedAction<Class<?>> pa = () -> defineClass(cn, loadedModule);
+        return AccessController.doPrivileged(pa);
+    }
+
+    /**
+     * Finds the class with the specified binary name on the class path.
+     *
+     * @return the resulting Class or {@code null} if not found
+     */
+    private Class<?> findClassOnClassPathOrNull(String cn) {
+        return AccessController.doPrivileged(
+            new PrivilegedAction<Class<?>>() {
+                public Class<?> run() {
+                    String path = cn.replace('.', '/').concat(".class");
+                    Resource res = ucp.getResource(path, false);
+                    if (res != null) {
+                        try {
+                            return defineClass(cn, res);
+                        } catch (IOException ioe) {
+                            // TBD on how I/O errors should be propagated
+                        }
+                    }
+                    return null;
+                }
+            });
+    }
+
+    /**
+     * Defines the given binary class name to the VM, loading the class
+     * bytes from the given module.
+     *
+     * @return the resulting Class or {@code null} if an I/O error occurs
+     */
+    private Class<?> defineClass(String cn, LoadedModule loadedModule) {
+        ModuleReference mref = loadedModule.mref();
+        ModuleReader reader = moduleReaderFor(mref);
+
+        try {
+            ByteBuffer bb = null;
+            URL csURL = null;
+
+            // locate class file, special handling for patched modules to
+            // avoid locating the resource twice
+            String rn = cn.replace('.', '/').concat(".class");
+            if (reader instanceof PatchedModuleReader) {
+                Resource r = ((PatchedModuleReader)reader).findResource(rn);
+                if (r != null) {
+                    bb = r.getByteBuffer();
+                    csURL = r.getCodeSourceURL();
+                }
+            } else {
+                bb = reader.read(rn).orElse(null);
+                csURL = loadedModule.codeSourceURL();
+            }
+
+            if (bb == null) {
+                // class not found
+                return null;
+            }
+
+            CodeSource cs = new CodeSource(csURL, (CodeSigner[]) null);
+            try {
+                // define class to VM
+                return defineClass(cn, bb, cs);
+
+            } finally {
+                reader.release(bb);
+            }
+
+        } catch (IOException ioe) {
+            // TBD on how I/O errors should be propagated
+            return null;
+        }
+    }
+
+    /**
+     * Defines the given binary class name to the VM, loading the class
+     * bytes via the given Resource object.
+     *
+     * @return the resulting Class
+     * @throws IOException if reading the resource fails
+     * @throws SecurityException if there is a sealing violation (JAR spec)
+     */
+    private Class<?> defineClass(String cn, Resource res) throws IOException {
+        URL url = res.getCodeSourceURL();
+
+        // if class is in a named package then ensure that the package is defined
+        int pos = cn.lastIndexOf('.');
+        if (pos != -1) {
+            String pn = cn.substring(0, pos);
+            Manifest man = res.getManifest();
+            defineOrCheckPackage(pn, man, url);
+        }
+
+        // defines the class to the runtime
+        ByteBuffer bb = res.getByteBuffer();
+        if (bb != null) {
+            CodeSigner[] signers = res.getCodeSigners();
+            CodeSource cs = new CodeSource(url, signers);
+            return defineClass(cn, bb, cs);
+        } else {
+            byte[] b = res.getBytes();
+            CodeSigner[] signers = res.getCodeSigners();
+            CodeSource cs = new CodeSource(url, signers);
+            return defineClass(cn, b, 0, b.length, cs);
+        }
+    }
+
+
+    // -- packages
+
+    /**
+     * Defines a package in this ClassLoader. If the package is already defined
+     * then its sealing needs to be checked if sealed by the legacy sealing
+     * mechanism.
+     *
+     * @throws SecurityException if there is a sealing violation (JAR spec)
+     */
+    protected Package defineOrCheckPackage(String pn, Manifest man, URL url) {
+        Package pkg = getAndVerifyPackage(pn, man, url);
+        if (pkg == null) {
+            try {
+                if (man != null) {
+                    pkg = definePackage(pn, man, url);
+                } else {
+                    pkg = definePackage(pn, null, null, null, null, null, null, null);
+                }
+            } catch (IllegalArgumentException iae) {
+                // defined by another thread so need to re-verify
+                pkg = getAndVerifyPackage(pn, man, url);
+                if (pkg == null)
+                    throw new InternalError("Cannot find package: " + pn);
+            }
+        }
+        return pkg;
+    }
+
+    /**
+     * Get the Package with the specified package name. If defined
+     * then verify that it against the manifest and code source.
+     *
+     * @throws SecurityException if there is a sealing violation (JAR spec)
+     */
+    private Package getAndVerifyPackage(String pn, Manifest man, URL url) {
+        Package pkg = getDefinedPackage(pn);
+        if (pkg != null) {
+            if (pkg.isSealed()) {
+                if (!pkg.isSealed(url)) {
+                    throw new SecurityException(
+                        "sealing violation: package " + pn + " is sealed");
+                }
+            } else {
+                // can't seal package if already defined without sealing
+                if ((man != null) && isSealed(pn, man)) {
+                    throw new SecurityException(
+                        "sealing violation: can't seal package " + pn +
+                        ": already defined");
+                }
+            }
+        }
+        return pkg;
+    }
+
+    /**
+     * Defines a new package in this ClassLoader. The attributes in the specified
+     * Manifest are use to get the package version and sealing information.
+     *
+     * @throws IllegalArgumentException if the package name duplicates an
+     * existing package either in this class loader or one of its ancestors
+     */
+    private Package definePackage(String pn, Manifest man, URL url) {
+        String specTitle = null;
+        String specVersion = null;
+        String specVendor = null;
+        String implTitle = null;
+        String implVersion = null;
+        String implVendor = null;
+        String sealed = null;
+        URL sealBase = null;
+
+        if (man != null) {
+            Attributes attr = man.getAttributes(pn.replace('.', '/').concat("/"));
+            if (attr != null) {
+                specTitle = attr.getValue(Attributes.Name.SPECIFICATION_TITLE);
+                specVersion = attr.getValue(Attributes.Name.SPECIFICATION_VERSION);
+                specVendor = attr.getValue(Attributes.Name.SPECIFICATION_VENDOR);
+                implTitle = attr.getValue(Attributes.Name.IMPLEMENTATION_TITLE);
+                implVersion = attr.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
+                implVendor = attr.getValue(Attributes.Name.IMPLEMENTATION_VENDOR);
+                sealed = attr.getValue(Attributes.Name.SEALED);
+            }
+
+            attr = man.getMainAttributes();
+            if (attr != null) {
+                if (specTitle == null)
+                    specTitle = attr.getValue(Attributes.Name.SPECIFICATION_TITLE);
+                if (specVersion == null)
+                    specVersion = attr.getValue(Attributes.Name.SPECIFICATION_VERSION);
+                if (specVendor == null)
+                    specVendor = attr.getValue(Attributes.Name.SPECIFICATION_VENDOR);
+                if (implTitle == null)
+                    implTitle = attr.getValue(Attributes.Name.IMPLEMENTATION_TITLE);
+                if (implVersion == null)
+                    implVersion = attr.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
+                if (implVendor == null)
+                    implVendor = attr.getValue(Attributes.Name.IMPLEMENTATION_VENDOR);
+                if (sealed == null)
+                    sealed = attr.getValue(Attributes.Name.SEALED);
+            }
+
+            // package is sealed
+            if ("true".equalsIgnoreCase(sealed))
+                sealBase = url;
+        }
+        return definePackage(pn,
+                             specTitle,
+                             specVersion,
+                             specVendor,
+                             implTitle,
+                             implVersion,
+                             implVendor,
+                             sealBase);
+    }
+
+    /**
+     * Returns {@code true} if the specified package name is sealed according to
+     * the given manifest.
+     */
+    private boolean isSealed(String pn, Manifest man) {
+        String path = pn.replace('.', '/').concat("/");
+        Attributes attr = man.getAttributes(path);
+        String sealed = null;
+        if (attr != null)
+            sealed = attr.getValue(Attributes.Name.SEALED);
+        if (sealed == null && (attr = man.getMainAttributes()) != null)
+            sealed = attr.getValue(Attributes.Name.SEALED);
+        return "true".equalsIgnoreCase(sealed);
+    }
+
+    // -- permissions
+
+    /**
+     * Returns the permissions for the given CodeSource.
+     */
+    @Override
+    protected PermissionCollection getPermissions(CodeSource cs) {
+        PermissionCollection perms = super.getPermissions(cs);
+
+        // add the permission to access the resource
+        URL url = cs.getLocation();
+        if (url == null)
+            return perms;
+        Permission p = null;
+        try {
+            p = url.openConnection().getPermission();
+            if (p != null) {
+                // for directories then need recursive access
+                if (p instanceof FilePermission) {
+                    String path = p.getName();
+                    if (path.endsWith(File.separator)) {
+                        path += "-";
+                        p = new FilePermission(path, "read");
+                    }
+                }
+                perms.add(p);
+            }
+        } catch (IOException ioe) { }
+
+        return perms;
+    }
+
+
+    // -- miscellaneous supporting methods
+
+    /**
+     * Returns the ModuleReader for the given module.
+     */
+    private ModuleReader moduleReaderFor(ModuleReference mref) {
+        return moduleToReader.computeIfAbsent(mref, m -> createModuleReader(mref));
+    }
+
+    /**
+     * Creates a ModuleReader for the given module.
+     */
+    private ModuleReader createModuleReader(ModuleReference mref) {
+        try {
+            return mref.open();
+        } catch (IOException e) {
+            // Return a null module reader to avoid a future class load
+            // attempting to open the module again.
+            return new NullModuleReader();
+        }
+    }
+
+    /**
+     * A ModuleReader that doesn't read any resources.
+     */
+    private static class NullModuleReader implements ModuleReader {
+        @Override
+        public Optional<URI> find(String name) {
+            return Optional.empty();
+        }
+        @Override
+        public void close() {
+            throw new InternalError("Should not get here");
+        }
+    };
+
+    /**
+     * Checks access to the given URL. We use URLClassPath for consistent
+     * checking with java.net.URLClassLoader.
+     */
+    private static URL checkURL(URL url) {
+        return URLClassPath.checkURL(url);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.loader;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Module;
+import java.net.URL;
+import java.nio.file.InvalidPathException;
+import java.nio.file.Paths;
+import java.security.CodeSource;
+import java.security.PermissionCollection;
+import java.util.jar.Manifest;
+
+import jdk.internal.misc.JavaLangAccess;
+import jdk.internal.misc.SharedSecrets;
+import jdk.internal.misc.VM;
+import sun.misc.URLClassPath;
+
+
+/**
+ * Creates and provides access to the built-in platform and application class
+ * loaders. It also creates the class loader that is used to locate resources
+ * in modules defined to the boot class loader.
+ */
+
+public class ClassLoaders {
+
+    private ClassLoaders() { }
+
+    private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
+
+    // the built-in class loaders
+    private static final BootClassLoader BOOT_LOADER;
+    private static final PlatformClassLoader PLATFORM_LOADER;
+    private static final AppClassLoader APP_LOADER;
+
+    /**
+     * Creates the built-in class loaders
+     */
+    static {
+
+        // -Xbootclasspth/a or -javaagent Boot-Class-Path
+        URLClassPath bcp = null;
+        String s = VM.getSavedProperty("jdk.boot.class.path.append");
+        if (s != null && s.length() > 0)
+            bcp = toURLClassPath(s);
+
+        // we have a class path if -cp is specified or -m is not specified
+        URLClassPath ucp = null;
+        String mainMid = System.getProperty("jdk.module.main");
+        String cp = System.getProperty("java.class.path");
+        if (mainMid == null && (cp == null || cp.length() == 0))
+            cp = ".";
+        if (cp != null && cp.length() > 0)
+            ucp = toURLClassPath(cp);
+
+
+        // create the class loaders
+        BOOT_LOADER = new BootClassLoader(bcp);
+        PLATFORM_LOADER = new PlatformClassLoader(BOOT_LOADER);
+        APP_LOADER = new AppClassLoader(PLATFORM_LOADER, ucp);
+    }
+
+    /**
+     * Returns the class loader that is used to find resources in modules
+     * defined to the boot class loader.
+     *
+     * @apiNote This method is not public, it should instead be used via
+     * the BootLoader class that provides a restricted API to this class
+     * loader.
+     */
+    static BuiltinClassLoader bootLoader() {
+        return BOOT_LOADER;
+    }
+
+    /**
+     * Returns the platform class loader.
+     */
+    public static ClassLoader platformClassLoader() {
+        return PLATFORM_LOADER;
+    }
+
+    /**
+     * Returns the application class loader.
+     */
+    public static ClassLoader appClassLoader() {
+        return APP_LOADER;
+    }
+
+    /**
+     * The class loader that is used to find resources in modules defined to
+     * the boot class loader. It is not used for class loading.
+     */
+    private static class BootClassLoader extends BuiltinClassLoader {
+        BootClassLoader(URLClassPath bcp) {
+            super(null, bcp);
+        }
+
+        @Override
+        protected Class<?> loadClassOrNull(String cn) {
+            return JLA.findBootstrapClassOrNull(this, cn);
+        }
+    };
+
+    /**
+     * The platform class loader, a unique type to make it easier to distinguish
+     * from the application class loader.
+     */
+    private static class PlatformClassLoader extends BuiltinClassLoader {
+        static {
+            if (!ClassLoader.registerAsParallelCapable())
+                throw new InternalError();
+        }
+
+        PlatformClassLoader(BootClassLoader parent) {
+            super(parent, null);
+        }
+
+        /**
+         * Called by the VM to support define package for AppCDS.
+         *
+         * Shared classes are returned in ClassLoader::findLoadedClass
+         * that bypass the defineClass call.
+         */
+        private Package definePackage(String pn, Module module) {
+            return JLA.definePackage(this, pn, module);
+        }
+    }
+
+    /**
+     * The application class loader that is a {@code BuiltinClassLoader} with
+     * customizations to be compatible with long standing behavior.
+     */
+    private static class AppClassLoader extends BuiltinClassLoader {
+        static {
+            if (!ClassLoader.registerAsParallelCapable())
+                throw new InternalError();
+        }
+
+        final URLClassPath ucp;
+
+        AppClassLoader(PlatformClassLoader parent, URLClassPath ucp) {
+            super(parent, ucp);
+            this.ucp = ucp;
+        }
+
+        @Override
+        protected Class<?> loadClass(String cn, boolean resolve)
+            throws ClassNotFoundException
+        {
+            // for compatibility reasons, say where restricted package list has
+            // been updated to list API packages in the unnamed module.
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                int i = cn.lastIndexOf('.');
+                if (i != -1) {
+                    sm.checkPackageAccess(cn.substring(0, i));
+                }
+            }
+
+            return super.loadClass(cn, resolve);
+        }
+
+        @Override
+        protected PermissionCollection getPermissions(CodeSource cs) {
+            PermissionCollection perms = super.getPermissions(cs);
+            perms.add(new RuntimePermission("exitVM"));
+            return perms;
+        }
+
+        /**
+         * Called by the VM to support dynamic additions to the class path
+         *
+         * @see java.lang.instrument.Instrumentation#appendToSystemClassLoaderSearch
+         */
+        void appendToClassPathForInstrumentation(String path) {
+            appendToUCP(path, ucp);
+        }
+
+        /**
+         * Called by the VM to support define package for AppCDS
+         *
+         * Shared classes are returned in ClassLoader::findLoadedClass
+         * that bypass the defineClass call.
+         */
+        private Package definePackage(String pn, Module module) {
+            return JLA.definePackage(this, pn, module);
+        }
+
+        /**
+         * Called by the VM to support define package for AppCDS
+         */
+        protected Package defineOrCheckPackage(String pn, Manifest man, URL url) {
+            return super.defineOrCheckPackage(pn, man, url);
+        }
+    }
+
+    /**
+     * Returns a {@code URLClassPath} of file URLs to each of the elements in
+     * the given class path.
+     */
+    private static URLClassPath toURLClassPath(String cp) {
+        URLClassPath ucp = new URLClassPath(new URL[0]);
+        appendToUCP(cp, ucp);
+        return ucp;
+    }
+
+    /**
+     * Converts the elements in the given class path to file URLs and adds
+     * them to the given URLClassPath.
+     */
+    private static void appendToUCP(String cp, URLClassPath ucp) {
+        String[] elements = cp.split(File.pathSeparator);
+        if (elements.length == 0) {
+            // contains path separator(s) only, default to current directory
+            // to be compatible with long standing behavior
+            elements = new String[] { "" };
+        }
+        for (String s: elements) {
+            try {
+                URL url = Paths.get(s).toRealPath().toUri().toURL();
+                ucp.addURL(url);
+            } catch (InvalidPathException | IOException ignore) {
+                // malformed path string or class path element does not exist
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/loader/Loader.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,540 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.loader;
+
+import java.io.File;
+import java.io.FilePermission;
+import java.io.IOException;
+import java.lang.module.Configuration;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleReader;
+import java.lang.module.ModuleReference;
+import java.lang.module.ResolvedModule;
+import java.lang.reflect.Layer;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.nio.ByteBuffer;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.CodeSigner;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.security.SecureClassLoader;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+
+
+/**
+ * A class loader that loads classes and resources from a collection of
+ * modules, or from a single module where the class loader is a member
+ * of a pool of class loaders.
+ *
+ * <p> The delegation model used by this ClassLoader differs to the regular
+ * delegation model. When requested to load a class then this ClassLoader first
+ * maps the class name to its package name. If there a module defined to the
+ * Loader containing the package then the class loader attempts to load from
+ * that module. If the package is instead defined to a module in a "remote"
+ * ClassLoader then this class loader delegates directly to that class loader.
+ * The map of package name to remote class loader is created based on the
+ * modules read by modules defined to this class loader. If the package is not
+ * local or remote then this class loader will delegate to the parent class
+ * loader. This allows automatic modules (for example) to link to types in the
+ * unnamed module of the parent class loader.
+ *
+ * @see Layer#createWithOneLoader
+ * @see Layer#createWithManyLoaders
+ */
+
+public final class Loader extends SecureClassLoader {
+
+    static {
+        ClassLoader.registerAsParallelCapable();
+    }
+
+    // the loader pool is in a pool, can be null
+    private final LoaderPool pool;
+
+    // parent ClassLoader, can be null
+    private final ClassLoader parent;
+
+    // maps a module name to a module reference
+    private final Map<String, ModuleReference> nameToModule;
+
+    // maps package name to a module loaded by this class loader
+    private final Map<String, LoadedModule> localPackageToModule;
+
+    // maps package name to a remote class loader, populated post initialization
+    private final Map<String, ClassLoader> remotePackageToLoader
+        = new ConcurrentHashMap<>();
+
+    // maps a module reference to a module reader, populated lazily
+    private final Map<ModuleReference, ModuleReader> moduleToReader
+        = new ConcurrentHashMap<>();
+
+    // ACC used when loading classes and resources */
+    private final AccessControlContext acc;
+
+    /**
+     * A module defined/loaded to a {@code Loader}.
+     */
+    private static class LoadedModule {
+        private final ModuleReference mref;
+        private final URL url;          // may be null
+        private final CodeSource cs;
+
+        LoadedModule(ModuleReference mref) {
+            URL url = null;
+            if (mref.location().isPresent()) {
+                try {
+                    url = mref.location().get().toURL();
+                } catch (MalformedURLException e) { }
+            }
+            this.mref = mref;
+            this.url = url;
+            this.cs = new CodeSource(url, (CodeSigner[]) null);
+        }
+
+        ModuleReference mref() { return mref; }
+        String name() { return mref.descriptor().name(); }
+        URL location() { return url; }
+        CodeSource codeSource() { return cs; }
+    }
+
+
+    /**
+     * Creates a {@code Loader} in a loader pool that loads classes/resources
+     * from one module.
+     */
+    public Loader(ResolvedModule resolvedModule,
+                  LoaderPool pool,
+                  ClassLoader parent)
+    {
+        super(parent);
+
+        this.pool = pool;
+        this.parent = parent;
+
+        ModuleReference mref = resolvedModule.reference();
+        ModuleDescriptor descriptor = mref.descriptor();
+        String mn = descriptor.name();
+        this.nameToModule = Map.of(mn, mref);
+
+        Map<String, LoadedModule> localPackageToModule = new HashMap<>();
+        LoadedModule lm = new LoadedModule(mref);
+        descriptor.packages().forEach(pn -> localPackageToModule.put(pn, lm));
+        this.localPackageToModule = localPackageToModule;
+
+        this.acc = AccessController.getContext();
+    }
+
+    /**
+     * Creates a {@code Loader} that loads classes/resources from a collection
+     * of modules.
+     *
+     * @throws IllegalArgumentException
+     *         If two or more modules have the same package
+     */
+    public Loader(Collection<ResolvedModule> modules, ClassLoader parent) {
+        super(parent);
+
+        this.pool = null;
+        this.parent = parent;
+
+        Map<String, ModuleReference> nameToModule = new HashMap<>();
+        Map<String, LoadedModule> localPackageToModule = new HashMap<>();
+        for (ResolvedModule resolvedModule : modules) {
+            ModuleReference mref = resolvedModule.reference();
+            ModuleDescriptor descriptor = mref.descriptor();
+            nameToModule.put(descriptor.name(), mref);
+            descriptor.packages().forEach(pn -> {
+                LoadedModule lm = new LoadedModule(mref);
+                if (localPackageToModule.put(pn, lm) != null)
+                    throw new IllegalArgumentException("Package "
+                        + pn + " in more than one module");
+            });
+        }
+        this.nameToModule = nameToModule;
+        this.localPackageToModule = localPackageToModule;
+
+        this.acc = AccessController.getContext();
+    }
+
+
+    /**
+     * Completes initialization of this Loader. This method populates
+     * remotePackageToLoader with the packages of the remote modules, where
+     * "remote modules" are the modules read by modules defined to this loader.
+     *
+     * @param cf the Configuration containing at least modules to be defined to
+     *           this class loader
+     *
+     * @param parentLayer the parent Layer
+     */
+    public Loader initRemotePackageMap(Configuration cf, Layer parentLayer) {
+
+        for (String name : nameToModule.keySet()) {
+
+            ResolvedModule resolvedModule = cf.findModule(name).get();
+            assert resolvedModule.configuration() == cf;
+
+            for (ResolvedModule other : resolvedModule.reads()) {
+                String mn = other.name();
+                ClassLoader loader;
+
+                if (other.configuration() == cf) {
+
+                    // The module reads another module in the newly created
+                    // layer. If all modules are defined to the same class
+                    // loader then the packages are local.
+                    if (pool == null) {
+                        assert nameToModule.containsKey(mn);
+                        continue;
+                    }
+
+                    loader = pool.loaderFor(mn);
+                    assert loader != null;
+
+                } else {
+
+                    // find the layer contains the module that is read
+                    Layer layer = parentLayer;
+                    while (layer != null) {
+                        if (layer.configuration() == other.configuration()) {
+                            break;
+                        }
+                        layer = layer.parent().orElse(null);
+                    }
+                    assert layer != null;
+
+                    // find the class loader for the module in the layer
+                    // For now we use the platform loader for modules defined to the
+                    // boot loader
+                    assert layer.findModule(mn).isPresent();
+                    loader = layer.findLoader(mn);
+                    if (loader == null)
+                        loader = ClassLoaders.platformClassLoader();
+                }
+
+                // find the packages that are exported to the target module
+                String target = resolvedModule.name();
+                ModuleDescriptor descriptor = other.reference().descriptor();
+                for (ModuleDescriptor.Exports e : descriptor.exports()) {
+                    boolean delegate;
+                    if (e.isQualified()) {
+                        // qualified export in same configuration
+                        delegate = (other.configuration() == cf)
+                                && e.targets().contains(target);
+                    } else {
+                        // unqualified
+                        delegate = true;
+                    }
+
+                    if (delegate) {
+                        String pn = e.source();
+                        ClassLoader l = remotePackageToLoader.putIfAbsent(pn, loader);
+                        if (l != null && l != loader) {
+                            throw new IllegalArgumentException("Package "
+                                + pn + " cannot be imported from multiple loaders");
+                        }
+
+                    }
+                }
+            }
+
+        }
+
+        return this;
+    }
+
+    /**
+     * Returns the loader pool that this loader is in or {@code null} if this
+     * loader is not in a loader pool.
+     */
+    public LoaderPool pool() {
+        return pool;
+    }
+
+
+    // -- resources --
+
+
+    /**
+     * Returns a URL to a resource of the given name in a module defined to
+     * this class loader.
+     */
+    @Override
+    protected URL findResource(String mn, String name) throws IOException {
+        ModuleReference mref = nameToModule.get(mn);
+        if (mref == null)
+            return null;   // not defined to this class loader
+
+        try {
+            return AccessController.doPrivileged(
+                new PrivilegedExceptionAction<URL>() {
+                    @Override
+                    public URL run() throws IOException {
+                        Optional<URI> ouri = moduleReaderFor(mref).find(name);
+                        if (ouri.isPresent()) {
+                            try {
+                                return ouri.get().toURL();
+                            } catch (MalformedURLException e) { }
+                        }
+                        return null;
+                    }
+                }, acc);
+        } catch (PrivilegedActionException pae) {
+            throw (IOException) pae.getCause();
+        }
+    }
+
+
+    // -- finding/loading classes
+
+    /**
+     * Finds the class with the specified binary name.
+     */
+    @Override
+    protected Class<?> findClass(String cn) throws ClassNotFoundException {
+        Class<?> c = null;
+        LoadedModule loadedModule = findLoadedModule(cn);
+        if (loadedModule != null)
+            c = findClassInModuleOrNull(loadedModule, cn);
+        if (c == null)
+            throw new ClassNotFoundException(cn);
+        return c;
+    }
+
+    /**
+     * Finds the class with the specified binary name in a given module.
+     * This method returns {@code null} if the class cannot be found.
+     */
+    @Override
+    protected Class<?> findClass(String mn, String cn) {
+        Class<?> c = null;
+        LoadedModule loadedModule = findLoadedModule(cn);
+        if (loadedModule != null && loadedModule.name().equals(mn))
+            c = findClassInModuleOrNull(loadedModule, cn);
+        return c;
+    }
+
+    /**
+     * Loads the class with the specified binary name.
+     */
+    @Override
+    protected Class<?> loadClass(String cn, boolean resolve)
+        throws ClassNotFoundException
+    {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            String pn = packageName(cn);
+            if (!pn.isEmpty()) {
+                sm.checkPackageAccess(pn);
+            }
+        }
+
+        synchronized (getClassLoadingLock(cn)) {
+            // check if already loaded
+            Class<?> c = findLoadedClass(cn);
+
+            if (c == null) {
+
+                LoadedModule loadedModule = findLoadedModule(cn);
+
+                if (loadedModule != null) {
+
+                    // class is in module defined to this class loader
+                    c = findClassInModuleOrNull(loadedModule, cn);
+
+                } else {
+
+                    // type in another module or visible via the parent loader
+                    String pn = packageName(cn);
+                    ClassLoader loader = remotePackageToLoader.get(pn);
+                    if (loader == null) {
+                        // type not in a module read by any of the modules
+                        // defined to this loader, so delegate to parent
+                        // class loader
+                        loader = parent;
+                    }
+                    if (loader == null) {
+                        c = BootLoader.loadClassOrNull(cn);
+                    } else {
+                        c = loader.loadClass(cn);
+                    }
+
+                }
+            }
+
+            if (c == null)
+                throw new ClassNotFoundException(cn);
+
+            if (resolve)
+                resolveClass(c);
+
+            return c;
+        }
+    }
+
+
+    /**
+     * Finds the class with the specified binary name if in a module
+     * defined to this ClassLoader.
+     *
+     * @return the resulting Class or {@code null} if not found
+     */
+    private Class<?> findClassInModuleOrNull(LoadedModule loadedModule, String cn) {
+        PrivilegedAction<Class<?>> pa = () -> defineClass(cn, loadedModule);
+        return AccessController.doPrivileged(pa, acc);
+    }
+
+    /**
+     * Defines the given binary class name to the VM, loading the class
+     * bytes from the given module.
+     *
+     * @return the resulting Class or {@code null} if an I/O error occurs
+     */
+    private Class<?> defineClass(String cn, LoadedModule loadedModule) {
+        ModuleReader reader = moduleReaderFor(loadedModule.mref());
+
+        try {
+            // read class file
+            String rn = cn.replace('.', '/').concat(".class");
+            ByteBuffer bb = reader.read(rn).orElse(null);
+            if (bb == null) {
+                // class not found
+                return null;
+            }
+
+            try {
+                return defineClass(cn, bb, loadedModule.codeSource());
+            } finally {
+                reader.release(bb);
+            }
+
+        } catch (IOException ioe) {
+            // TBD on how I/O errors should be propagated
+            return null;
+        }
+    }
+
+
+    // -- permissions
+
+    /**
+     * Returns the permissions for the given CodeSource.
+     */
+    @Override
+    protected PermissionCollection getPermissions(CodeSource cs) {
+        PermissionCollection perms = super.getPermissions(cs);
+
+        URL url = cs.getLocation();
+        if (url == null)
+            return perms;
+
+        // add the permission to access the resource
+        try {
+            Permission p = url.openConnection().getPermission();
+            if (p != null) {
+                // for directories then need recursive access
+                if (p instanceof FilePermission) {
+                    String path = p.getName();
+                    if (path.endsWith(File.separator)) {
+                        path += "-";
+                        p = new FilePermission(path, "read");
+                    }
+                }
+                perms.add(p);
+            }
+        } catch (IOException ioe) { }
+
+        return perms;
+    }
+
+
+    // -- miscellaneous supporting methods
+
+    /**
+     * Find the candidate module for the given class name.
+     * Returns {@code null} if none of the modules defined to this
+     * class loader contain the API package for the class.
+     */
+    private LoadedModule findLoadedModule(String cn) {
+        String pn = packageName(cn);
+        return pn.isEmpty() ? null : localPackageToModule.get(pn);
+    }
+
+    /**
+     * Returns the package name for the given class name
+     */
+    private String packageName(String cn) {
+        int pos = cn.lastIndexOf('.');
+        return (pos < 0) ? "" : cn.substring(0, pos);
+    }
+
+
+    /**
+     * Returns the ModuleReader for the given module.
+     */
+    private ModuleReader moduleReaderFor(ModuleReference mref) {
+        return moduleToReader.computeIfAbsent(mref, m -> createModuleReader(mref));
+    }
+
+    /**
+     * Creates a ModuleReader for the given module.
+     */
+    private ModuleReader createModuleReader(ModuleReference mref) {
+        try {
+            return mref.open();
+        } catch (IOException e) {
+            // Return a null module reader to avoid a future class load
+            // attempting to open the module again.
+            return new NullModuleReader();
+        }
+    }
+
+    /**
+     * A ModuleReader that doesn't read any resources.
+     */
+    private static class NullModuleReader implements ModuleReader {
+        @Override
+        public Optional<URI> find(String name) {
+            return Optional.empty();
+        }
+        @Override
+        public void close() {
+            throw new InternalError("Should not get here");
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/loader/LoaderPool.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.loader;
+
+import java.lang.module.Configuration;
+import java.lang.module.ModuleReference;
+import java.lang.module.ResolvedModule;
+import java.lang.reflect.Layer;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.stream.Stream;
+
+/**
+ * A pool of class loaders.
+ *
+ * @see Layer#defineModulesWithManyLoaders
+ */
+
+public final class LoaderPool {
+
+    // maps module names to class loaders
+    private final Map<String, Loader> loaders;
+
+
+    /**
+     * Creates a pool of class loaders. Each module in the given configuration
+     * will be loaded its own class loader in the pool. The class loader is
+     * created with the given parent class loader as its parent.
+     */
+    public LoaderPool(Configuration cf,
+                      Layer parentLayer,
+                      ClassLoader parentLoader)
+    {
+        Map<String, Loader> loaders = new HashMap<>();
+        for (ResolvedModule resolvedModule : cf.modules()) {
+            Loader loader = new Loader(resolvedModule, this, parentLoader);
+            String mn = resolvedModule.name();
+            loaders.put(mn, loader);
+        }
+        this.loaders = loaders;
+
+        // complete the initialization
+        loaders.values().forEach(l -> l.initRemotePackageMap(cf, parentLayer));
+    }
+
+
+    /**
+     * Returns the class loader for the named module
+     */
+    public Loader loaderFor(String name) {
+        Loader loader = loaders.get(name);
+        assert loader != null;
+        return loader;
+    }
+
+    /**
+     * Returns a stream of the loaders in this pool.
+     */
+    public Stream<Loader> loaders() {
+        return loaders.values().stream();
+    }
+
+}
+
--- a/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java	Thu Mar 17 19:04:16 2016 +0000
@@ -25,11 +25,17 @@
 
 package jdk.internal.misc;
 
+import java.io.IOException;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Executable;
+import java.lang.reflect.Layer;
+import java.lang.reflect.Module;
+import java.net.URL;
 import java.security.AccessControlContext;
 import java.util.Map;
+import java.util.stream.Stream;
 
+import jdk.internal.module.ServicesCatalog;
 import sun.reflect.ConstantPool;
 import sun.reflect.annotation.AnnotationType;
 import sun.nio.ch.Interruptible;
@@ -124,6 +130,43 @@
     void invokeFinalize(Object o) throws Throwable;
 
     /**
+     * Returns the boot Layer
+     */
+    Layer getBootLayer();
+
+    /**
+     * Returns the ServicesCatalog for the given class loader.
+     */
+    ServicesCatalog getServicesCatalog(ClassLoader cl);
+
+    /**
+     * Returns the ServicesCatalog for the given class loader, creating it
+     * if doesn't already exist.
+     */
+    ServicesCatalog createOrGetServicesCatalog(ClassLoader cl);
+
+    /**
+     * Returns a class loaded by the bootstrap class loader.
+     */
+    Class<?> findBootstrapClassOrNull(ClassLoader cl, String name);
+
+    /**
+     * Returns a URL to a resource with the given name in a module that is
+     * defined to the given class loader.
+     */
+    URL findResource(ClassLoader cl, String moduleName, String name) throws IOException;
+
+    /**
+     * Returns the Packages for the given class loader.
+     */
+    Stream<Package> packages(ClassLoader cl);
+
+    /**
+     * Define a Package of the given name and module by the given class loader.
+     */
+    Package definePackage(ClassLoader cl, String name, Module module);
+
+    /**
      * Invokes Long.fastUUID
      */
     String fastUUID(long lsb, long msb);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.misc;
+
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Exports;
+import java.lang.module.ModuleDescriptor.Requires;
+import java.lang.module.ModuleDescriptor.Provides;
+import java.lang.module.ModuleDescriptor.Version;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Provides access to non-public methods in java.lang.module.
+ */
+
+public interface JavaLangModuleAccess {
+
+    /**
+     * Returns {@code ModuleDescriptor.Requires} of the given modifier
+     * and module name.
+     */
+    Requires newRequires(Set<Requires.Modifier> ms, String mn);
+
+    /**
+     * Returns an unqualified {@code ModuleDescriptor.Exports}
+     * of the given package name.
+     */
+    Exports newExports(String source);
+
+    /**
+     * Returns a qualified {@code ModuleDescriptor.Exports}
+     * of the given package name and targets.
+     */
+    Exports newExports(String source, Set<String> targets);
+
+    /**
+     * Returns a {@code ModuleDescriptor.Provides}
+     * of the given service name and providers.
+     */
+    Provides newProvides(String service, Set<String> providers);
+
+    /**
+     * Returns a {@code ModuleDescriptor.Version} of the given version.
+     */
+    Version newVersion(String v);
+
+    /**
+     * Clones the given module descriptor with an augmented set of packages
+     */
+    ModuleDescriptor newModuleDescriptor(ModuleDescriptor md, Set<String> pkgs);
+
+    /**
+     * Returns a new {@code ModuleDescriptor} instance.
+     */
+    ModuleDescriptor newModuleDescriptor(String name,
+                                         boolean automatic,
+                                         boolean synthetic,
+                                         Set<Requires> requires,
+                                         Set<String> uses,
+                                         Set<Exports> exports,
+                                         Map<String, Provides> provides,
+                                         Version version,
+                                         String mainClass,
+                                         String osName,
+                                         String osArch,
+                                         String osVersion,
+                                         Set<String> conceals,
+                                         Set<String> packages);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/misc/JavaLangReflectModuleAccess.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.misc;
+
+import java.lang.module.ModuleDescriptor;
+import java.lang.reflect.Module;
+import java.net.URI;
+
+/**
+ * Provides access to non-public methods in java.lang.reflect.Module
+ */
+
+public interface JavaLangReflectModuleAccess {
+
+    /**
+     * Defines the unnamed module for the given class loader.
+     */
+    Module defineUnnamedModule(ClassLoader loader);
+
+    /**
+     * Defines a new module to the Java virtual machine. The module
+     * is defined to the given class loader.
+     *
+     * The URI is for information purposes only, it can be {@code null}.
+     */
+    Module defineModule(ClassLoader loader, ModuleDescriptor descriptor, URI uri);
+
+    /**
+     * Updates the readability so that module m1 reads m2. The new read edge
+     * does not result in a strong reference to m2 (m2 can be GC'ed).
+     *
+     * This method is the same as m1.addReads(m2) but without a permission check.
+     */
+    void addReads(Module m1, Module m2);
+
+    /**
+     * Updates module m1 to export a package to module m2. The export does
+     * not result in a strong reference to m2 (m2 can be GC'ed).
+     */
+    void addExports(Module m1, String pkg, Module m2);
+
+    /**
+     * Updates a module m to export a package to all modules.
+     */
+    void addExportsToAll(Module m, String pkg);
+
+    /**
+     * Updates a module m to export a package to all unnamed modules.
+     */
+    void addExportsToAllUnnamed(Module m, String pkg);
+
+    /**
+     * Add a package to the given module.
+     */
+    void addPackage(Module m, String pkg);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/misc/JavaUtilResourceBundleAccess.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.misc;
+
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+/**
+ * Provides access to non-public methods in java.util.ResourceBundle.
+ */
+public interface JavaUtilResourceBundleAccess {
+    /**
+     * Sets the bundle's parent to the given parent.
+     */
+    void setParent(ResourceBundle bundle, ResourceBundle parent);
+
+    /**
+     * Returns the parent of the given bundle or null if the bundle has no parent.
+     */
+    ResourceBundle getParent(ResourceBundle bundle);
+
+    /**
+     * Sets the bundle's locale to the given locale.
+     */
+    void setLocale(ResourceBundle bundle, Locale locale);
+
+    /**
+     * Sets the bundle's base name to the given name.
+     */
+    void setName(ResourceBundle bundle, String name);
+}
--- a/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java	Thu Mar 17 19:04:16 2016 +0000
@@ -25,6 +25,7 @@
 
 package jdk.internal.misc;
 
+import java.lang.module.ModuleDescriptor;
 import java.util.jar.JarFile;
 import java.io.Console;
 import java.io.FileDescriptor;
@@ -45,6 +46,8 @@
     private static final Unsafe unsafe = Unsafe.getUnsafe();
     private static JavaUtilJarAccess javaUtilJarAccess;
     private static JavaLangAccess javaLangAccess;
+    private static JavaLangModuleAccess javaLangModuleAccess;
+    private static JavaLangReflectModuleAccess javaLangReflectModuleAccess;
     private static JavaLangInvokeAccess javaLangInvokeAccess;
     private static JavaLangRefAccess javaLangRefAccess;
     private static JavaIOAccess javaIOAccess;
@@ -56,6 +59,7 @@
     private static JavaSecurityProtectionDomainAccess javaSecurityProtectionDomainAccess;
     private static JavaSecurityAccess javaSecurityAccess;
     private static JavaUtilZipFileAccess javaUtilZipFileAccess;
+    private static JavaUtilResourceBundleAccess javaUtilResourceBundleAccess;
     private static JavaAWTAccess javaAWTAccess;
     private static JavaAWTFontAccess javaAWTFontAccess;
     private static JavaBeansAccess javaBeansAccess;
@@ -95,6 +99,27 @@
         return javaLangInvokeAccess;
     }
 
+    public static void setJavaLangModuleAccess(JavaLangModuleAccess jlrma) {
+        javaLangModuleAccess = jlrma;
+    }
+
+    public static JavaLangModuleAccess getJavaLangModuleAccess() {
+        if (javaLangModuleAccess == null) {
+            unsafe.ensureClassInitialized(ModuleDescriptor.class);
+        }
+        return javaLangModuleAccess;
+    }
+
+    public static void setJavaLangReflectModuleAccess(JavaLangReflectModuleAccess jlrma) {
+        javaLangReflectModuleAccess = jlrma;
+    }
+
+    public static JavaLangReflectModuleAccess getJavaLangReflectModuleAccess() {
+        if (javaLangReflectModuleAccess == null)
+            unsafe.ensureClassInitialized(java.lang.reflect.Module.class);
+        return javaLangReflectModuleAccess;
+    }
+
     public static void setJavaLangRefAccess(JavaLangRefAccess jlra) {
         javaLangRefAccess = jlra;
     }
@@ -229,4 +254,12 @@
     public static void setJavaBeansAccess(JavaBeansAccess access) {
         javaBeansAccess = access;
     }
+
+    public static JavaUtilResourceBundleAccess getJavaUtilResourceBundleAccess() {
+        return javaUtilResourceBundleAccess;
+    }
+
+    public static void setJavaUtilResourceBundleAccess(JavaUtilResourceBundleAccess access) {
+        javaUtilResourceBundleAccess = access;
+    }
 }
--- a/src/java.base/share/classes/jdk/internal/misc/VM.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/misc/VM.java	Thu Mar 17 19:04:16 2016 +0000
@@ -144,36 +144,67 @@
     // public native static void writeJavaProfilerReport();
 
 
-    private static volatile boolean booted = false;
+    // the init level when the VM is fully initialized
+    private static final int JAVA_LANG_SYSTEM_INITED     = 1;
+    private static final int MODULE_SYSTEM_INITED        = 2;
+    private static final int SYSTEM_LOADER_INITIALIZING  = 3;
+    private static final int SYSTEM_BOOTED               = 4;
+
+    // 0, 1, 2, ...
+    private static volatile int initLevel;
     private static final Object lock = new Object();
 
-    // Invoked by System.initializeSystemClass just before returning.
-    // Subsystems that are invoked during initialization can check this
-    // property in order to avoid doing things that should wait until the
-    // application class loader has been set up.
-    //
-    public static void booted() {
+    /**
+     * Sets the init level.
+     *
+     * @see java.lang.System#initPhase1
+     * @see java.lang.System#initPhase2
+     * @see java.lang.System#initPhase3
+     */
+    public static void initLevel(int value) {
         synchronized (lock) {
-            booted = true;
+            if (value <= initLevel || value > SYSTEM_BOOTED)
+                throw new InternalError();
+            initLevel = value;
             lock.notifyAll();
         }
     }
 
-    public static boolean isBooted() {
-        return booted;
+    /**
+     * Returns the current init level.
+     */
+    public static int initLevel() {
+        return initLevel;
     }
 
-    // Waits until VM completes initialization
-    //
-    // This method is invoked by the Finalizer thread
-    public static void awaitBooted() throws InterruptedException {
+    /**
+     * Waits for the init level to get the given value.
+     *
+     * @see java.lang.ref.Finalizer
+     */
+    public static void awaitInitLevel(int value) throws InterruptedException {
         synchronized (lock) {
-            while (!booted) {
+            while (initLevel < value) {
                 lock.wait();
             }
         }
     }
 
+    /**
+     * Returns {@code true} if the module system has been initialized.
+     * @see java.lang.System#initPhase2
+     */
+    public static boolean isModuleSystemInited() {
+        return VM.initLevel() >= MODULE_SYSTEM_INITED;
+    }
+
+    /**
+     * Returns {@code true} if the VM is fully initialized.
+     */
+    public static boolean isBooted() {
+        return initLevel >= SYSTEM_BOOTED;
+    }
+
     // A user-settable upper limit on the maximum amount of allocatable direct
     // buffer memory.  This value may be changed during VM initialization if
     // "java" is launched with "-XX:MaxDirectMemorySize=<size>".
@@ -240,8 +271,8 @@
     //
     // This method can only be invoked during system initialization.
     public static void saveAndRemoveProperties(Properties props) {
-        if (booted)
-            throw new IllegalStateException("System initialization has completed");
+        if (initLevel() != 0)
+            throw new IllegalStateException("Wrong init level");
 
         savedProps.putAll(props);
 
@@ -273,13 +304,16 @@
 
         // used by sun.launcher.LauncherHelper
         props.remove("sun.java.launcher.diag");
+
+        // used by jdk.internal.loader.ClassLoaders
+        props.remove("jdk.boot.class.path.append");
     }
 
-    // Initialize any miscellenous operating system settings that need to be
+    // Initialize any miscellaneous operating system settings that need to be
     // set for the class libraries.
     //
     public static void initializeOSEnvironment() {
-        if (!booted) {
+        if (initLevel() == 0) {
             OSEnvironment.initialize();
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/Builder.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.module;
+
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Exports;
+import java.lang.module.ModuleDescriptor.Provides;
+import java.lang.module.ModuleDescriptor.Requires;
+import java.lang.module.ModuleDescriptor.Version;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import jdk.internal.misc.JavaLangModuleAccess;
+import jdk.internal.misc.SharedSecrets;
+
+/**
+ * This builder is optimized for reconstituting ModuleDescriptor
+ * for installed modules.  The validation should be done at jlink time.
+ *
+ * 1. skip name validation
+ * 2. ignores dependency hashes.
+ * 3. ModuleDescriptor skips the defensive copy and directly uses the
+ *    sets/maps created in this Builder.
+ *
+ * SystemModules should contain modules for the boot layer.
+ */
+final class Builder {
+    private static final JavaLangModuleAccess jlma =
+        SharedSecrets.getJavaLangModuleAccess();
+
+    private static final Set<Requires.Modifier> MANDATED =
+        Collections.singleton(Requires.Modifier.MANDATED);
+    private static final Set<Requires.Modifier> PUBLIC =
+        Collections.singleton(Requires.Modifier.PUBLIC);
+
+    // Static cache of the most recently seen Version to cheaply deduplicate
+    // most Version objects.  JDK modules have the same version.
+    static Version cachedVersion;
+
+    final String name;
+    final Set<Requires> requires;
+    final Set<Exports> exports;
+    final Map<String, Provides> provides;
+    final Set<String> conceals;
+    final int numPackages;
+    Set<String> uses;
+    Version version;
+    String mainClass;
+    String osName;
+    String osArch;
+    String osVersion;
+
+    Builder(String name, int reqs, int exports,
+            int provides, int conceals, int packages) {
+        this.name = name;
+        this.requires = reqs > 0 ? new HashSet<>(reqs) : Collections.emptySet();
+        this.exports  = exports > 0 ? new HashSet<>(exports) : Collections.emptySet();
+        this.provides = provides > 0 ? new HashMap<>(provides) : Collections.emptyMap();
+        this.conceals = conceals > 0 ? new HashSet<>(conceals) : Collections.emptySet();
+        this.uses = Collections.emptySet();
+        this.numPackages = packages;
+    }
+
+    /**
+     * Adds a module dependence with the given (and possibly empty) set
+     * of modifiers.
+     */
+    public Builder requires(Set<Requires.Modifier> mods, String mn) {
+        requires.add(jlma.newRequires(Collections.unmodifiableSet(mods), mn));
+        return this;
+    }
+
+    /**
+     * Adds a module dependence with an empty set of modifiers.
+     */
+    public Builder requires(String mn) {
+        requires.add(jlma.newRequires(Collections.emptySet(), mn));
+        return this;
+    }
+
+    /**
+     * Adds a module dependence with the given modifier.
+     */
+    public Builder requires(Requires.Modifier mod, String mn) {
+        if (mod == Requires.Modifier.MANDATED) {
+            requires.add(jlma.newRequires(MANDATED, mn));
+        } else if (mod == Requires.Modifier.PUBLIC) {
+            requires.add(jlma.newRequires(PUBLIC, mn));
+        } else {
+            requires.add(jlma.newRequires(Collections.singleton(mod), mn));
+        }
+        return this;
+    }
+
+    /**
+     * Sets the set of service dependences.
+     */
+    public Builder uses(Set<String> uses) {
+        this.uses = uses;
+        return this;
+    }
+
+    /**
+     * Adds an export to a set of target modules.
+     */
+    public Builder exports(String pn, Set<String> targets) {
+        exports.add(jlma.newExports(pn, targets));
+        return this;
+    }
+
+    /**
+     * Adds an export to a target module.
+     */
+    public Builder exports(String pn, String target) {
+        return exports(pn, Collections.singleton(target));
+    }
+
+    /**
+     * Adds an export.
+     */
+    public Builder exports(String pn) {
+        exports.add(jlma.newExports(pn));
+        return this;
+    }
+
+    /**
+     * Provides service {@code st} with implementations {@code pcs}.
+     */
+    public Builder provides(String st, Set<String> pcs) {
+        if (provides.containsKey(st))
+            throw new IllegalStateException("Providers of service "
+                    + st + " already declared");
+        provides.put(st, jlma.newProvides(st, pcs));
+        return this;
+    }
+
+    /**
+     * Provides service {@code st} with implementation {@code pc}.
+     */
+    public Builder provides(String st, String pc) {
+        return provides(st, Collections.singleton(pc));
+    }
+
+    /**
+     * Adds a set of (possible empty) concealed packages.
+     */
+    public Builder conceals(Set<String> packages) {
+        conceals.addAll(packages);
+        return this;
+    }
+
+    /**
+     * Adds a concealed package.
+     */
+    public Builder conceals(String pn) {
+        conceals.add(pn);
+        return this;
+    }
+
+    /**
+     * Sets the module version.
+     *
+     * @throws IllegalArgumentException if {@code v} is null or cannot be
+     *         parsed as a version string
+     * @throws IllegalStateException if the module version is already set
+     *
+     * @see Version#parse(String)
+     */
+    public Builder version(String v) {
+        if (version != null)
+            throw new IllegalStateException("module version already set");
+        Version ver = cachedVersion;
+        if (ver != null && v.equals(ver.toString())) {
+            version = ver;
+        } else {
+            cachedVersion = version = Version.parse(v);
+        }
+        return this;
+    }
+
+    /**
+     * Sets the module main class.
+     *
+     * @throws IllegalStateException if already set
+     */
+    public Builder mainClass(String mc) {
+        if (mainClass != null)
+            throw new IllegalStateException("main class already set");
+        mainClass = mc;
+        return this;
+    }
+
+    /**
+     * Sets the OS name.
+     *
+     * @throws IllegalStateException if already set
+     */
+    public Builder osName(String name) {
+        if (osName != null)
+            throw new IllegalStateException("OS name already set");
+        this.osName = name;
+        return this;
+    }
+
+    /**
+     * Sets the OS arch.
+     *
+     * @throws IllegalStateException if already set
+     */
+    public Builder osArch(String arch) {
+        if (osArch != null)
+            throw new IllegalStateException("OS arch already set");
+        this.osArch = arch;
+        return this;
+    }
+
+    /**
+     * Sets the OS version.
+     *
+     * @throws IllegalStateException if already set
+     */
+    public Builder osVersion(String version) {
+        if (osVersion != null)
+            throw new IllegalStateException("OS version already set");
+        this.osVersion = version;
+        return this;
+    }
+
+    /**
+     * Returns the set of packages that is the union of the exported and
+     * concealed packages.
+     */
+    private Set<String> computePackages(Set<Exports> exports, Set<String> conceals) {
+        if (exports.isEmpty())
+            return conceals;
+
+        Set<String> pkgs = new HashSet<>(numPackages);
+        pkgs.addAll(conceals);
+        for (Exports e : exports) {
+            pkgs.add(e.source());
+        }
+        return pkgs;
+    }
+
+    /**
+     * Builds a {@code ModuleDescriptor} from the components.
+     */
+    public ModuleDescriptor build() {
+        assert name != null;
+
+        return jlma.newModuleDescriptor(name,
+                                        false,    // automatic
+                                        false,    // assume not synthetic for now
+                                        requires,
+                                        uses,
+                                        exports,
+                                        provides,
+                                        version,
+                                        mainClass,
+                                        osName,
+                                        osArch,
+                                        osVersion,
+                                        conceals,
+                                        computePackages(exports, conceals));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/Checks.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.module;
+
+
+public final class Checks {
+
+    private Checks() { }
+
+    private static void fail(String what, String id, int i) {
+        throw new IllegalArgumentException(id
+                                           + ": Invalid " + what + ": "
+                                           + " Illegal character"
+                                           + " at index " + i);
+    }
+
+    /**
+     * Returns {@code true} if the given identifier is a legal Java identifier.
+     */
+    public static boolean isJavaIdentifier(String id) {
+        int n = id.length();
+        if (n == 0)
+            return false;
+        if (!Character.isJavaIdentifierStart(id.codePointAt(0)))
+            return false;
+        int cp = id.codePointAt(0);
+        int i = Character.charCount(cp);
+        for (; i < n; i += Character.charCount(cp)) {
+            cp = id.codePointAt(i);
+            if (!Character.isJavaIdentifierPart(cp) && id.charAt(i) != '.')
+                return false;
+        }
+        if (cp == '.')
+            return false;
+
+        return true;
+    }
+
+    /**
+     * Checks if a given identifier is a legal Java identifier.
+     */
+    public static String requireJavaIdentifier(String what, String id) {
+        if (id == null)
+            throw new IllegalArgumentException("Null " + what);
+        int n = id.length();
+        if (n == 0)
+            throw new IllegalArgumentException("Empty " + what);
+        if (!Character.isJavaIdentifierStart(id.codePointAt(0)))
+            fail(what, id, 0);
+        int cp = id.codePointAt(0);
+        int i = Character.charCount(cp);
+        int last = 0;
+        for (; i < n; i += Character.charCount(cp)) {
+            cp = id.codePointAt(i);
+            if (!Character.isJavaIdentifierPart(cp) && id.charAt(i) != '.')
+                fail(what, id, i);
+            last = i;
+        }
+        if (cp == '.')
+            fail(what, id, last);
+
+        return id;
+    }
+
+    public static String requireModuleName(String id) {
+        return requireJavaIdentifier("module name", id);
+    }
+
+    public static String requirePackageName(String id) {
+        return requireJavaIdentifier("package name", id);
+    }
+
+    public static String requireServiceTypeName(String id) {
+        return requireJavaIdentifier("service type name", id);
+    }
+
+    public static String requireServiceProviderName(String id) {
+        return requireJavaIdentifier("service provider name", id);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,647 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.module;
+
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Requires;
+import java.lang.module.ModuleDescriptor.Requires.Modifier;
+import java.lang.module.ModuleDescriptor.Exports;
+import java.lang.module.ModuleDescriptor.Provides;
+import java.lang.module.ModuleDescriptor.Version;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import jdk.internal.org.objectweb.asm.Attribute;
+import jdk.internal.org.objectweb.asm.ByteVector;
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.Label;
+import jdk.internal.module.Hasher.DependencyHashes;
+import static jdk.internal.module.ClassFileConstants.*;
+
+
+/**
+ * Provides ASM implementations of {@code Attribute} to read and write the
+ * class file attributes in a module-info class file.
+ */
+
+class ClassFileAttributes {
+
+    private ClassFileAttributes() { }
+
+    /**
+     * Module_attribute {
+     *   // See lang-vm.html for details.
+     * }
+     */
+    static class ModuleAttribute extends Attribute {
+
+        private ModuleDescriptor descriptor;
+
+        ModuleAttribute(ModuleDescriptor descriptor) {
+            super(MODULE);
+            this.descriptor = descriptor;
+        }
+
+        ModuleAttribute() {
+            super(MODULE);
+        }
+
+        @Override
+        protected Attribute read(ClassReader cr,
+                                 int off,
+                                 int len,
+                                 char[] buf,
+                                 int codeOff,
+                                 Label[] labels)
+        {
+            ModuleDescriptor.Builder builder
+                = new ModuleDescriptor.Builder("xyzzy"); // Name never used
+            ModuleAttribute attr = new ModuleAttribute();
+
+            // requires_count and requires[requires_count]
+            int requires_count = cr.readUnsignedShort(off);
+            off += 2;
+            for (int i=0; i<requires_count; i++) {
+                String dn = cr.readUTF8(off, buf);
+                int flags = cr.readUnsignedShort(off + 2);
+                Set<Modifier> mods;
+                if (flags == 0) {
+                    mods = Collections.emptySet();
+                } else {
+                    mods = new HashSet<>();
+                    if ((flags & ACC_PUBLIC) != 0)
+                        mods.add(Modifier.PUBLIC);
+                    if ((flags & ACC_SYNTHETIC) != 0)
+                        mods.add(Modifier.SYNTHETIC);
+                    if ((flags & ACC_MANDATED) != 0)
+                        mods.add(Modifier.MANDATED);
+                }
+                builder.requires(mods, dn);
+                off += 4;
+            }
+
+            // exports_count and exports[exports_count]
+            int exports_count = cr.readUnsignedShort(off);
+            off += 2;
+            if (exports_count > 0) {
+                for (int i=0; i<exports_count; i++) {
+                    String pkg = cr.readUTF8(off, buf).replace('/', '.');
+                    int exports_to_count = cr.readUnsignedShort(off+2);
+                    off += 4;
+                    if (exports_to_count > 0) {
+                        Set<String> targets = new HashSet<>();
+                        for (int j=0; j<exports_to_count; j++) {
+                            String t = cr.readUTF8(off, buf);
+                            off += 2;
+                            targets.add(t);
+                        }
+                        builder.exports(pkg, targets);
+                    } else {
+                        builder.exports(pkg);
+                    }
+                }
+            }
+
+            // uses_count and uses_index[uses_count]
+            int uses_count = cr.readUnsignedShort(off);
+            off += 2;
+            if (uses_count > 0) {
+                for (int i=0; i<uses_count; i++) {
+                    String sn = cr.readClass(off, buf).replace('/', '.');
+                    builder.uses(sn);
+                    off += 2;
+                }
+            }
+
+            // provides_count and provides[provides_count]
+            int provides_count = cr.readUnsignedShort(off);
+            off += 2;
+            if (provides_count > 0) {
+                Map<String, Set<String>> provides = new HashMap<>();
+                for (int i=0; i<provides_count; i++) {
+                    String sn = cr.readClass(off, buf).replace('/', '.');
+                    String cn = cr.readClass(off + 2, buf).replace('/', '.');
+                    provides.computeIfAbsent(sn, k -> new HashSet<>()).add(cn);
+                    off += 4;
+                }
+                provides.entrySet().forEach(e -> builder.provides(e.getKey(),
+                                                                  e.getValue()));
+            }
+
+            attr.descriptor = builder.build();
+            return attr;
+        }
+
+        @Override
+        protected ByteVector write(ClassWriter cw,
+                                   byte[] code,
+                                   int len,
+                                   int maxStack,
+                                   int maxLocals)
+        {
+            assert descriptor != null;
+            ByteVector attr = new ByteVector();
+
+            // requires_count
+            attr.putShort(descriptor.requires().size());
+
+            // requires[requires_count]
+            for (Requires md : descriptor.requires()) {
+                String dn = md.name();
+                int flags = 0;
+                if (md.modifiers().contains(Modifier.PUBLIC))
+                    flags |= ACC_PUBLIC;
+                if (md.modifiers().contains(Modifier.SYNTHETIC))
+                    flags |= ACC_SYNTHETIC;
+                if (md.modifiers().contains(Modifier.MANDATED))
+                    flags |= ACC_MANDATED;
+                int index = cw.newUTF8(dn);
+                attr.putShort(index);
+                attr.putShort(flags);
+            }
+
+            // exports_count and exports[exports_count];
+            if (descriptor.exports().isEmpty()) {
+                attr.putShort(0);
+            } else {
+                attr.putShort(descriptor.exports().size());
+                for (Exports e : descriptor.exports()) {
+                    String pkg = e.source().replace('.', '/');
+                    attr.putShort(cw.newUTF8(pkg));
+                    if (e.isQualified()) {
+                        Set<String> ts = e.targets();
+                        attr.putShort(ts.size());
+                        ts.forEach(t -> attr.putShort(cw.newUTF8(t)));
+                    } else {
+                        attr.putShort(0);
+                    }
+                }
+            }
+
+            // uses_count and uses_index[uses_count]
+            if (descriptor.uses().isEmpty()) {
+                attr.putShort(0);
+            } else {
+                attr.putShort(descriptor.uses().size());
+                for (String s : descriptor.uses()) {
+                    String service = s.replace('.', '/');
+                    int index = cw.newClass(service);
+                    attr.putShort(index);
+                }
+            }
+
+            // provides_count and provides[provides_count]
+            if (descriptor.provides().isEmpty()) {
+                attr.putShort(0);
+            } else {
+                int count = descriptor.provides().values()
+                    .stream().mapToInt(ps -> ps.providers().size()).sum();
+                attr.putShort(count);
+                for (Provides p : descriptor.provides().values()) {
+                    String service = p.service().replace('.', '/');
+                    int index = cw.newClass(service);
+                    for (String provider : p.providers()) {
+                        attr.putShort(index);
+                        attr.putShort(cw.newClass(provider.replace('.', '/')));
+                    }
+                }
+            }
+
+            return attr;
+        }
+    }
+
+    /**
+     * Synthetic attribute.
+     */
+    static class SyntheticAttribute extends Attribute {
+        SyntheticAttribute() {
+            super(SYNTHETIC);
+        }
+
+        @Override
+        protected Attribute read(ClassReader cr,
+                                 int off,
+                                 int len,
+                                 char[] buf,
+                                 int codeOff,
+                                 Label[] labels)
+        {
+            return new SyntheticAttribute();
+        }
+
+        @Override
+        protected ByteVector write(ClassWriter cw,
+                                   byte[] code,
+                                   int len,
+                                   int maxStack,
+                                   int maxLocals)
+        {
+            ByteVector attr = new ByteVector();
+            return attr;
+        }
+    }
+
+    /**
+     * ConcealedPackages attribute.
+     *
+     * <pre> {@code
+     *
+     * ConcealedPackages_attribute {
+     *   // index to CONSTANT_utf8_info structure in constant pool representing
+     *   // the string "ConcealedPackages"
+     *   u2 attribute_name_index;
+     *   u4 attribute_length;
+     *
+     *   // the number of entries in the packages table
+     *   u2 package_count;
+     *   { // index to CONSTANT_CONSTANT_utf8_info structure with the package name
+     *     u2 package_index
+     *   } package[package_count];
+     *
+     * }</pre>
+     */
+    static class ConcealedPackagesAttribute extends Attribute {
+        private final Set<String> packages;
+
+        ConcealedPackagesAttribute(Set<String> packages) {
+            super(CONCEALED_PACKAGES);
+            this.packages = packages;
+        }
+
+        ConcealedPackagesAttribute() {
+            this(null);
+        }
+
+        @Override
+        protected Attribute read(ClassReader cr,
+                                 int off,
+                                 int len,
+                                 char[] buf,
+                                 int codeOff,
+                                 Label[] labels)
+        {
+            // package count
+            int package_count = cr.readUnsignedShort(off);
+            off += 2;
+
+            // packages
+            Set<String> packages = new HashSet<>();
+            for (int i=0; i<package_count; i++) {
+                String pkg = cr.readUTF8(off, buf).replace('/', '.');
+                packages.add(pkg);
+                off += 2;
+            }
+
+            return new ConcealedPackagesAttribute(packages);
+        }
+
+        @Override
+        protected ByteVector write(ClassWriter cw,
+                                   byte[] code,
+                                   int len,
+                                   int maxStack,
+                                   int maxLocals)
+        {
+            assert packages != null;
+
+            ByteVector attr = new ByteVector();
+
+            // package_count
+            attr.putShort(packages.size());
+
+            // packages
+            packages.stream()
+                .map(p -> p.replace('.', '/'))
+                .forEach(p -> attr.putShort(cw.newUTF8(p)));
+
+            return attr;
+        }
+
+    }
+
+    /**
+     * Version attribute.
+     *
+     * <pre> {@code
+     *
+     * Version_attribute {
+     *   // index to CONSTANT_utf8_info structure in constant pool representing
+     *   // the string "Version"
+     *   u2 attribute_name_index;
+     *   u4 attribute_length;
+     *
+     *   // index to CONSTANT_CONSTANT_utf8_info structure with the version
+     *   u2 version_index;
+     * }
+     *
+     * } </pre>
+     */
+    static class VersionAttribute extends Attribute {
+        private final Version version;
+
+        VersionAttribute(Version version) {
+            super(VERSION);
+            this.version = version;
+        }
+
+        VersionAttribute() {
+            this(null);
+        }
+
+        @Override
+        protected Attribute read(ClassReader cr,
+                                 int off,
+                                 int len,
+                                 char[] buf,
+                                 int codeOff,
+                                 Label[] labels)
+        {
+            String value = cr.readUTF8(off, buf);
+            return new VersionAttribute(Version.parse(value));
+        }
+
+        @Override
+        protected ByteVector write(ClassWriter cw,
+                                   byte[] code,
+                                   int len,
+                                   int maxStack,
+                                   int maxLocals)
+        {
+            ByteVector attr = new ByteVector();
+            int index = cw.newUTF8(version.toString());
+            attr.putShort(index);
+            return attr;
+        }
+    }
+
+    /**
+     * MainClass attribute.
+     *
+     * <pre> {@code
+     *
+     * MainClass_attribute {
+     *   // index to CONSTANT_utf8_info structure in constant pool representing
+     *   // the string "MainClass"
+     *   u2 attribute_name_index;
+     *   u4 attribute_length;
+     *
+     *   // index to CONSTANT_Class_info structure with the main class name
+     *   u2 main_class_index;
+     * }
+     *
+     * } </pre>
+     */
+    static class MainClassAttribute extends Attribute {
+        private final String mainClass;
+
+        MainClassAttribute(String mainClass) {
+            super(MAIN_CLASS);
+            this.mainClass = mainClass;
+        }
+
+        MainClassAttribute() {
+            this(null);
+        }
+
+        @Override
+        protected Attribute read(ClassReader cr,
+                                 int off,
+                                 int len,
+                                 char[] buf,
+                                 int codeOff,
+                                 Label[] labels)
+        {
+            String value = cr.readClass(off, buf);
+            return new MainClassAttribute(value);
+        }
+
+        @Override
+        protected ByteVector write(ClassWriter cw,
+                                   byte[] code,
+                                   int len,
+                                   int maxStack,
+                                   int maxLocals)
+        {
+            ByteVector attr = new ByteVector();
+            int index = cw.newClass(mainClass);
+            attr.putShort(index);
+            return attr;
+        }
+    }
+
+    /**
+     * TargetPlatform attribute.
+     *
+     * <pre> {@code
+     *
+     * TargetPlatform_attribute {
+     *   // index to CONSTANT_utf8_info structure in constant pool representing
+     *   // the string "TargetPlatform"
+     *   u2 attribute_name_index;
+     *   u4 attribute_length;
+     *
+     *   // index to CONSTANT_CONSTANT_utf8_info structure with the OS name
+     *   u2 os_name_index;
+     *   // index to CONSTANT_CONSTANT_utf8_info structure with the OS arch
+     *   u2 os_arch_index
+     *   // index to CONSTANT_CONSTANT_utf8_info structure with the OS version
+     *   u2 os_version_index;
+     * }
+     *
+     * } </pre>
+     */
+    static class TargetPlatformAttribute extends Attribute {
+        private final String osName;
+        private final String osArch;
+        private final String osVersion;
+
+        TargetPlatformAttribute(String osName, String osArch, String osVersion) {
+            super(TARGET_PLATFORM);
+            this.osName = osName;
+            this.osArch = osArch;
+            this.osVersion = osVersion;
+        }
+
+        TargetPlatformAttribute() {
+            this(null, null, null);
+        }
+
+        @Override
+        protected Attribute read(ClassReader cr,
+                                 int off,
+                                 int len,
+                                 char[] buf,
+                                 int codeOff,
+                                 Label[] labels)
+        {
+
+            String osName = null;
+            String osArch = null;
+            String osVersion = null;
+
+            int name_index = cr.readUnsignedShort(off);
+            if (name_index != 0)
+                osName = cr.readUTF8(off, buf);
+            off += 2;
+
+            int arch_index = cr.readUnsignedShort(off);
+            if (arch_index != 0)
+                osArch = cr.readUTF8(off, buf);
+            off += 2;
+
+            int version_index = cr.readUnsignedShort(off);
+            if (version_index != 0)
+                osVersion = cr.readUTF8(off, buf);
+            off += 2;
+
+            return new TargetPlatformAttribute(osName, osArch, osVersion);
+        }
+
+        @Override
+        protected ByteVector write(ClassWriter cw,
+                                   byte[] code,
+                                   int len,
+                                   int maxStack,
+                                   int maxLocals)
+        {
+            ByteVector attr = new ByteVector();
+
+            int name_index = 0;
+            if (osName != null && osName.length() > 0)
+                name_index = cw.newUTF8(osName);
+            attr.putShort(name_index);
+
+            int arch_index = 0;
+            if (osArch != null && osArch.length() > 0)
+                arch_index = cw.newUTF8(osArch);
+            attr.putShort(arch_index);
+
+            int version_index = 0;
+            if (osVersion != null && osVersion.length() > 0)
+                version_index = cw.newUTF8(osVersion);
+            attr.putShort(version_index);
+
+            return attr;
+        }
+    }
+
+    /**
+     * Hashes attribute.
+     *
+     * <pre> {@code
+     *
+     * Hashes_attribute {
+     *   // index to CONSTANT_utf8_info structure in constant pool representing
+     *   // the string "Hashes"
+     *   u2 attribute_name_index;
+     *   u4 attribute_length;
+     *
+     *   // index to CONSTANT_CONSTANT_utf8_info structure with algorithm name
+     *   u2 algorithm_index;
+     *
+     *   // the number of entries in the hashes table
+     *   u2 hash_count;
+     *   {   u2 requires_index
+     *       u2 hash_index;
+     *   } hashes[hash_count];
+     *
+     * } </pre>
+     *
+     * @apiNote For now the hash is stored in base64 as a UTF-8 string, an
+     * alternative is to store it as an array of u1.
+     */
+    static class HashesAttribute extends Attribute {
+        private final DependencyHashes hashes;
+
+        HashesAttribute(DependencyHashes hashes) {
+            super(HASHES);
+            this.hashes = hashes;
+        }
+
+        HashesAttribute() {
+            this(null);
+        }
+
+        @Override
+        protected Attribute read(ClassReader cr,
+                                 int off,
+                                 int len,
+                                 char[] buf,
+                                 int codeOff,
+                                 Label[] labels)
+        {
+            String algorithm = cr.readUTF8(off, buf);
+            off += 2;
+
+            int hash_count = cr.readUnsignedShort(off);
+            off += 2;
+
+            Map<String, String> map = new HashMap<>();
+            for (int i=0; i<hash_count; i++) {
+                String dn = cr.readUTF8(off, buf);
+                off += 2;
+                String hash = cr.readUTF8(off, buf);
+                off += 2;
+                map.put(dn, hash);
+            }
+
+            DependencyHashes hashes = new DependencyHashes(algorithm, map);
+
+            return new HashesAttribute(hashes);
+        }
+
+        @Override
+        protected ByteVector write(ClassWriter cw,
+                                   byte[] code,
+                                   int len,
+                                   int maxStack,
+                                   int maxLocals)
+        {
+            ByteVector attr = new ByteVector();
+
+            int index = cw.newUTF8(hashes.algorithm());
+            attr.putShort(index);
+
+            Set<String> names = hashes.names();
+            attr.putShort(names.size());
+
+            for (String dn : names) {
+                String hash = hashes.hashFor(dn);
+                assert hash != null;
+                attr.putShort(cw.newUTF8(dn));
+                attr.putShort(cw.newUTF8(hash));
+            }
+
+            return attr;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.module;
+
+
+// Constants in module-info.class files
+
+public class ClassFileConstants {
+
+    private ClassFileConstants() { }
+
+    // Attribute names
+    public static final String MODULE             = "Module";
+    public static final String SOURCE_FILE        = "SourceFile";
+    public static final String SYNTHETIC          = "Synthetic";
+    public static final String SDE                = "SourceDebugExtension";
+
+    public static final String CONCEALED_PACKAGES = "ConcealedPackages";
+    public static final String VERSION            = "Version";
+    public static final String MAIN_CLASS         = "MainClass";
+    public static final String TARGET_PLATFORM    = "TargetPlatform";
+    public static final String HASHES             = "Hashes";
+
+    // access and requires flags
+    public static final int ACC_MODULE       = 0x8000;
+    public static final int ACC_PUBLIC       = 0x0020;
+    public static final int ACC_SYNTHETIC    = 0x1000;
+    public static final int ACC_MANDATED     = 0x8000;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/ConfigurableModuleFinder.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.module;
+
+import java.lang.module.ModuleFinder;
+
+/**
+ * A ModuleFinder that may be configured to work at either run-time
+ * or link-time.
+ */
+
+public interface ConfigurableModuleFinder extends ModuleFinder {
+
+    public static enum Phase {
+        RUN_TIME,
+        LINK_TIME
+    }
+
+    /**
+     * Configures this finder to work in the given phase.
+     */
+    void configurePhase(Phase phase);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/Hasher.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.module;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.file.Path;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Supporting class for computing, encoding and decoding hashes (message
+ * digests).
+ */
+
+public class Hasher {
+    private Hasher() { }
+
+    /**
+     * A supplier of an encoded message digest.
+     */
+    public static interface HashSupplier {
+        String generate(String algorithm);
+    }
+
+    /**
+     * Encapsulates the result of hashing the contents of a number of module
+     * artifacts.
+     */
+    public static class DependencyHashes {
+        private final String algorithm;
+        private final Map<String, String> nameToHash;
+
+        public DependencyHashes(String algorithm, Map<String, String> nameToHash) {
+            this.algorithm = algorithm;
+            this.nameToHash = nameToHash;
+        }
+
+        /**
+         * Returns the algorithm used to hash the dependences ("SHA-256" or
+         * "MD5" for example).
+         */
+        public String algorithm() {
+            return algorithm;
+        }
+
+        /**
+         * Returns the set of module names for which hashes are recorded.
+         */
+        public Set<String> names() {
+            return nameToHash.keySet();
+        }
+
+        /**
+         * Retruns the hash string for the given module name, {@code null}
+         * if there is no hash recorded for the module.
+         */
+        public String hashFor(String dn) {
+            return nameToHash.get(dn);
+        }
+    }
+
+
+    /**
+     * Computes the hash for the given file with the given message digest
+     * algorithm. Returns the results a base64-encoded String.
+     *
+     * @throws UncheckedIOException if an I/O error occurs
+     * @throws RuntimeException if the algorithm is not available
+     */
+    public static String generate(Path file, String algorithm) {
+        try {
+            MessageDigest md = MessageDigest.getInstance(algorithm);
+
+            // Ideally we would just mmap the file but this consumes too much
+            // memory when jlink is running concurrently on very large jmods
+            try (FileChannel fc = FileChannel.open(file)) {
+                ByteBuffer bb = ByteBuffer.allocate(32*1024);
+                int nread;
+                while ((nread = fc.read(bb)) > 0) {
+                    bb.flip();
+                    md.update(bb);
+                    assert bb.remaining() == 0;
+                    bb.clear();
+                }
+            }
+
+            byte[] bytes = md.digest();
+            return Base64.getEncoder().encodeToString(bytes);
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException(e);
+        } catch (IOException ioe) {
+            throw new UncheckedIOException(ioe);
+        }
+    }
+
+    /**
+     * Computes the hash for every entry in the given map, returning a
+     * {@code DependencyHashes} to encapsulate the result. The map key is
+     * the entry name, typically the module name. The map value is the file
+     * path to the entry (module artifact).
+     *
+     * @return DependencyHashes encapsulate the hashes
+     */
+    public static DependencyHashes generate(Map<String, Path> map, String algorithm) {
+        Map<String, String> nameToHash = new HashMap<>();
+        for (Map.Entry<String, Path> entry: map.entrySet()) {
+            String name = entry.getKey();
+            Path path = entry.getValue();
+            nameToHash.put(name, generate(path, algorithm));
+        }
+        return new DependencyHashes(algorithm, nameToHash);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,533 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.module;
+
+import java.io.File;
+import java.lang.module.Configuration;
+import java.lang.module.ModuleReference;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ResolvedModule;
+import java.lang.reflect.Layer;
+import java.lang.reflect.Module;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import jdk.internal.loader.BootLoader;
+import jdk.internal.loader.BuiltinClassLoader;
+import jdk.internal.perf.PerfCounter;
+
+/**
+ * Initializes/boots the module system.
+ *
+ * The {@link #boot() boot} method is called early in the startup to initialize
+ * the module system. In summary, the boot method creates a Configuration by
+ * resolving a set of module names specified via the launcher (or equivalent)
+ * -m and -addmods options. The modules are located on a module path that is
+ * constructed from the upgrade, system and application module paths. The
+ * Configuration is reified by creating the boot Layer with each module in the
+ * the configuration defined to one of the built-in class loaders. The mapping
+ * of modules to class loaders is statically mapped in a helper class.
+ */
+
+public final class ModuleBootstrap {
+    private ModuleBootstrap() { }
+
+    private static final String JAVA_BASE = "java.base";
+
+    // the token for "all unnamed modules"
+    private static final String ALL_UNNAMED = "ALL-UNNAMED";
+
+    // the token for "all system modules"
+    private static final String ALL_SYSTEM = "ALL-SYSTEM";
+
+    // the token for "all modules on the module path"
+    private static final String ALL_MODULE_PATH = "ALL-MODULE-PATH";
+
+    // ModuleFinder for the initial configuration
+    private static ModuleFinder initialFinder;
+
+    /**
+     * Returns the ModuleFinder for the initial configuration
+     */
+    public static ModuleFinder finder() {
+        assert initialFinder != null;
+        return initialFinder;
+    }
+
+    /**
+     * Initialize the module system, returning the boot Layer.
+     *
+     * @see java.lang.System#initPhase2()
+     */
+    public static Layer boot() {
+
+        long t0 = System.nanoTime();
+
+        // system module path
+        ModuleFinder systemModulePath = ModuleFinder.ofSystem();
+
+        // Once we have the system module path then we define the base module.
+        // We do this here so that java.base is defined to the VM as early as
+        // possible and also that resources in the base module can be located
+        // for error messages that may happen from here on.
+        Optional<ModuleReference> obase = systemModulePath.find(JAVA_BASE);
+        if (!obase.isPresent())
+            throw new InternalError(JAVA_BASE + " not found");
+        ModuleReference base = obase.get();
+        BootLoader.loadModule(base);
+        Modules.defineModule(null, base.descriptor(), base.location().orElse(null));
+
+
+        // -upgrademodulepath option specified to launcher
+        ModuleFinder upgradeModulePath
+            = createModulePathFinder("jdk.upgrade.module.path");
+
+        // -modulepath option specified to the launcher
+        ModuleFinder appModulePath = createModulePathFinder("jdk.module.path");
+
+        // The module finder: [-upgrademodulepath] system-module-path [-modulepath]
+        ModuleFinder finder = systemModulePath;
+        if (upgradeModulePath != null)
+            finder = ModuleFinder.compose(upgradeModulePath, finder);
+        if (appModulePath != null)
+            finder = ModuleFinder.compose(finder, appModulePath);
+
+        // launcher -m option to specify the initial module
+        String mainModule = System.getProperty("jdk.module.main");
+
+        // additional module(s) specified by -addmods
+        boolean addAllSystemModules = false;
+        boolean addAllApplicationModules = false;
+        Set<String> addModules = null;
+        String propValue = System.getProperty("jdk.launcher.addmods");
+        if (propValue != null) {
+            addModules = new HashSet<>();
+            for (String mod: propValue.split(",")) {
+                switch (mod) {
+                    case ALL_SYSTEM:
+                        addAllSystemModules = true;
+                        break;
+                    case ALL_MODULE_PATH:
+                        addAllApplicationModules = true;
+                        break;
+                    default :
+                        addModules.add(mod);
+                }
+            }
+        }
+
+        // The root modules to resolve
+        Set<String> roots = new HashSet<>();
+
+        // main/initial module
+        if (mainModule != null) {
+            roots.add(mainModule);
+            if (addAllApplicationModules)
+                fail(ALL_MODULE_PATH + " not allowed with initial module");
+        }
+
+        // If -addmods is specified then those modules need to be resolved
+        if (addModules != null)
+            roots.addAll(addModules);
+
+
+        // -limitmods
+        boolean limitmods = false;
+        propValue = System.getProperty("jdk.launcher.limitmods");
+        if (propValue != null) {
+            Set<String> mods = new HashSet<>();
+            for (String mod: propValue.split(",")) {
+                mods.add(mod);
+            }
+            finder = limitFinder(finder, mods, roots);
+            limitmods = true;
+        }
+
+
+        // If there is no initial module specified then assume that the
+        // initial module is the unnamed module of the application class
+        // loader. By convention, and for compatibility, this is
+        // implemented by putting the names of all modules on the system
+        // module path into the set of modules to resolve.
+        //
+        // If `-addmods ALL-SYSTEM` is used then all modules on the system
+        // module path will be resolved, irrespective of whether an initial
+        // module is specified.
+        //
+        // If `-addmods ALL-MODULE-PATH` is used, and no initial module is
+        // specified, then all modules on the application module path will
+        // be resolved.
+        //
+        if (mainModule == null || addAllSystemModules) {
+            Set<ModuleReference> mrefs;
+            if (addAllApplicationModules) {
+                assert mainModule == null;
+                mrefs = finder.findAll();
+            } else {
+                mrefs = systemModulePath.findAll();
+                if (limitmods) {
+                    ModuleFinder f = finder;
+                    mrefs = mrefs.stream()
+                        .filter(m -> f.find(m.descriptor().name()).isPresent())
+                        .collect(Collectors.toSet());
+                }
+            }
+            // map to module names
+            for (ModuleReference mref : mrefs) {
+                roots.add(mref.descriptor().name());
+            }
+        }
+
+        long t1 = System.nanoTime();
+
+        // run the resolver to create the configuration
+
+        Configuration cf = Configuration.empty()
+                .resolveRequiresAndUses(finder,
+                                        ModuleFinder.empty(),
+                                        roots);
+
+        // time to create configuration
+        PerfCounters.resolveTime.addElapsedTimeFrom(t1);
+
+        // mapping of modules to class loaders
+        Function<String, ClassLoader> clf = ModuleLoaderMap.mappingFunction(cf);
+
+        // check that all modules to be mapped to the boot loader will be
+        // loaded from the system module path
+        if (finder != systemModulePath) {
+            for (ResolvedModule resolvedModule : cf.modules()) {
+                ModuleReference mref = resolvedModule.reference();
+                String name = mref.descriptor().name();
+                ClassLoader cl = clf.apply(name);
+                if (cl == null) {
+
+                    if (upgradeModulePath != null
+                            && upgradeModulePath.find(name).isPresent())
+                        fail(name + ": cannot be loaded from upgrade module path");
+
+                    if (!systemModulePath.find(name).isPresent())
+                        fail(name + ": cannot be loaded from application module path");
+                }
+            }
+        }
+
+        long t2 = System.nanoTime();
+
+        // define modules to VM/runtime
+        Layer bootLayer = Layer.empty().defineModules(cf, clf);
+
+        PerfCounters.layerCreateTime.addElapsedTimeFrom(t2);
+
+        long t3 = System.nanoTime();
+
+        // define the module to its class loader, except java.base
+        for (ResolvedModule resolvedModule : cf.modules()) {
+            ModuleReference mref = resolvedModule.reference();
+            String name = mref.descriptor().name();
+            ClassLoader cl = clf.apply(name);
+            if (cl == null) {
+                if (!name.equals(JAVA_BASE)) BootLoader.loadModule(mref);
+            } else {
+                ((BuiltinClassLoader)cl).loadModule(mref);
+            }
+        }
+
+        PerfCounters.loadModulesTime.addElapsedTimeFrom(t3);
+
+        // -XaddReads and -XaddExports
+        addExtraReads(bootLayer);
+        addExtraExports(bootLayer);
+
+        // total time to initialize
+        PerfCounters.bootstrapTime.addElapsedTimeFrom(t0);
+
+        // remember the ModuleFinder
+        initialFinder = finder;
+
+        return bootLayer;
+    }
+
+    /**
+     * Returns a ModuleFinder that limits observability to the given root
+     * modules, their transitive dependences, plus a set of other modules.
+     */
+    private static ModuleFinder limitFinder(ModuleFinder finder,
+                                            Set<String> roots,
+                                            Set<String> otherMods)
+    {
+        // resolve all root modules
+        Configuration cf = Configuration.empty()
+                .resolveRequires(finder,
+                                 ModuleFinder.empty(),
+                                 roots);
+
+        // module name -> reference
+        Map<String, ModuleReference> map = new HashMap<>();
+        cf.modules().stream()
+            .map(ResolvedModule::reference)
+            .forEach(mref -> map.put(mref.descriptor().name(), mref));
+
+        // set of modules that are observable
+        Set<ModuleReference> mrefs = new HashSet<>(map.values());
+
+        // add the other modules
+        for (String mod : otherMods) {
+            Optional<ModuleReference> omref = finder.find(mod);
+            if (omref.isPresent()) {
+                ModuleReference mref = omref.get();
+                map.putIfAbsent(mod, mref);
+                mrefs.add(mref);
+            } else {
+                // no need to fail
+            }
+        }
+
+        return new ModuleFinder() {
+            @Override
+            public Optional<ModuleReference> find(String name) {
+                return Optional.ofNullable(map.get(name));
+            }
+            @Override
+            public Set<ModuleReference> findAll() {
+                return mrefs;
+            }
+        };
+    }
+
+    /**
+     * Creates a finder from the module path that is the value of the given
+     * system property.
+     */
+    private static ModuleFinder createModulePathFinder(String prop) {
+        String s = System.getProperty(prop);
+        if (s == null) {
+            return null;
+        } else {
+            String[] dirs = s.split(File.pathSeparator);
+            Path[] paths = new Path[dirs.length];
+            int i = 0;
+            for (String dir: dirs) {
+                paths[i++] = Paths.get(dir);
+            }
+            return ModuleFinder.of(paths);
+        }
+    }
+
+
+    /**
+     * Process the -XaddReads options to add any additional read edges that
+     * are specified on the command-line.
+     */
+    private static void addExtraReads(Layer bootLayer) {
+
+        // decode the command line options
+        Map<String, Set<String>> map = decode("jdk.launcher.addreads.");
+
+        for (Map.Entry<String, Set<String>> e : map.entrySet()) {
+
+            // the key is $MODULE
+            String mn = e.getKey();
+            Optional<Module> om = bootLayer.findModule(mn);
+            if (!om.isPresent())
+                fail("Unknown module: " + mn);
+            Module m = om.get();
+
+            // the value is the set of other modules (by name)
+            for (String name : e.getValue()) {
+
+                Module other;
+                if (ALL_UNNAMED.equals(name)) {
+                    other = null;  // loose
+                } else {
+                    om = bootLayer.findModule(name);
+                    if (!om.isPresent())
+                        fail("Unknown module: " + name);
+                    other = om.get();
+                }
+
+                Modules.addReads(m, other);
+            }
+        }
+    }
+
+
+    /**
+     * Process the -XaddExports options to add any additional read edges that
+     * are specified on the command-line.
+     */
+    private static void addExtraExports(Layer bootLayer) {
+
+        // decode the command line options
+        Map<String, Set<String>> map = decode("jdk.launcher.addexports.");
+
+        for (Map.Entry<String, Set<String>> e : map.entrySet()) {
+
+            // the key is $MODULE/$PACKAGE
+            String key = e.getKey();
+            String[] s = key.split("/");
+            if (s.length != 2)
+                fail("Unable to parse: " + key);
+
+            String mn = s[0];
+            String pn = s[1];
+
+            // The exporting module is in the boot layer
+            Module m;
+            Optional<Module> om = bootLayer.findModule(mn);
+            if (!om.isPresent())
+                fail("Unknown module: " + mn);
+            m = om.get();
+
+            // the value is the set of modules to export to (by name)
+            for (String name : e.getValue()) {
+                boolean allUnnamed = false;
+                Module other = null;
+                if (ALL_UNNAMED.equals(name)) {
+                    allUnnamed = true;
+                } else {
+                    om = bootLayer.findModule(name);
+                    if (om.isPresent()) {
+                        other = om.get();
+                    } else {
+                        fail("Unknown module: " + name);
+                    }
+                }
+
+                if (allUnnamed) {
+                    Modules.addExportsToAllUnnamed(m, pn);
+                } else {
+                    Modules.addExports(m, pn, other);
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Decodes the values of -XaddReads or -XaddExports options
+     *
+     * The format of the options is: $KEY=$MODULE(,$MODULE)*
+     *
+     * For transition purposes, this method allows the first usage to be
+     *     $KEY=$MODULE(,$KEY=$MODULE)
+     * This format will eventually be removed.
+     */
+    private static Map<String, Set<String>> decode(String prefix) {
+        int index = 0;
+        String value = System.getProperty(prefix + index);
+        if (value == null)
+            return Collections.emptyMap();
+
+        Map<String, Set<String>> map = new HashMap<>();
+
+        while (value != null) {
+
+            int pos = value.indexOf('=');
+            if (pos == -1)
+                fail("Unable to parse: " + value);
+            if (pos == 0)
+                fail("Missing module name in: " + value);
+
+            // key is <module> or <module>/<package>
+            String key = value.substring(0, pos);
+
+            String rhs = value.substring(pos+1);
+            if (rhs.isEmpty())
+                fail("Unable to parse: " + value);
+
+            // new format $MODULE(,$MODULE)* or old format $(MODULE)=...
+            pos = rhs.indexOf('=');
+
+            // old format only allowed in first -X option
+            if (pos >= 0 && index > 0)
+                fail("Unable to parse: " + value);
+
+            if (pos == -1) {
+
+                // new format: $KEY=$MODULE(,$MODULE)*
+
+                Set<String> values = map.get(key);
+                if (values != null)
+                    fail(key + " specified more than once");
+
+                values = new HashSet<>();
+                map.put(key, values);
+                for (String s : rhs.split(",")) {
+                    if (s.length() > 0) values.add(s);
+                }
+
+            } else {
+
+                // old format: $KEY=$MODULE(,$KEY=$MODULE)*
+
+                assert index == 0;  // old format only allowed in first usage
+
+                for (String expr : value.split(",")) {
+                    if (expr.length() > 0) {
+                        String[] s = expr.split("=");
+                        if (s.length != 2)
+                            fail("Unable to parse: " + expr);
+
+                        map.computeIfAbsent(s[0], k -> new HashSet<>()).add(s[1]);
+                    }
+                }
+            }
+
+            index++;
+            value = System.getProperty(prefix + index);
+        }
+
+        return map;
+    }
+
+
+    /**
+     * Throws a RuntimeException with the given message
+     */
+    static void fail(String m) {
+        throw new RuntimeException(m);
+    }
+
+    static class PerfCounters {
+        static PerfCounter resolveTime
+            = PerfCounter.newPerfCounter("jdk.module.bootstrap.resolveTime");
+        static PerfCounter layerCreateTime
+            = PerfCounter.newPerfCounter("jdk.module.bootstrap.layerCreateTime");
+        static PerfCounter loadModulesTime
+            = PerfCounter.newPerfCounter("jdk.module.bootstrap.loadModulesTime");
+        static PerfCounter bootstrapTime
+            = PerfCounter.newPerfCounter("jdk.module.bootstrap.totalTime");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.module;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.module.ModuleDescriptor.Version;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import jdk.internal.org.objectweb.asm.Attribute;
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.ClassVisitor;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.internal.module.Hasher.DependencyHashes;
+
+import static jdk.internal.module.ClassFileAttributes.*;
+
+/**
+ * Utility class to extend a module-info.class with additional attributes.
+ */
+
+public final class ModuleInfoExtender {
+
+    // the input stream to read the original module-info.class
+    private final InputStream in;
+
+    // the packages in the ConcealedPackages attribute
+    private Set<String> conceals;
+
+    // the value of the Version attribute
+    private Version version;
+
+    // the value of the MainClass attribute
+    private String mainClass;
+
+    // the values for the TargetPlatform attribute
+    private String osName;
+    private String osArch;
+    private String osVersion;
+
+    // the hashes for the Hashes attribute
+    private DependencyHashes hashes;
+
+    private ModuleInfoExtender(InputStream in) {
+        this.in = in;
+    }
+
+    /**
+     * Sets the set of packages for the ConcealedPackages attribute
+     */
+    public ModuleInfoExtender conceals(Set<String> packages) {
+        this.conceals = Collections.unmodifiableSet(packages);
+        return this;
+    }
+
+    /**
+     * Sets the value of the Version attribute.
+     */
+    public ModuleInfoExtender version(Version version) {
+        this.version = version;
+        return this;
+    }
+
+    /**
+     * Sets the value of the MainClass attribute.
+     */
+    public ModuleInfoExtender mainClass(String mainClass) {
+        this.mainClass = mainClass;
+        return this;
+    }
+
+    /**
+     * Sets the values for the TargetPlatform attribute.
+     */
+    public ModuleInfoExtender targetPlatform(String osName,
+                                             String osArch,
+                                             String osVersion) {
+        this.osName = osName;
+        this.osArch = osArch;
+        this.osVersion = osVersion;
+        return this;
+    }
+
+    /**
+     * The Hashes attribute will be emitted to the module-info with
+     * the hashes encapsulated in the given {@code DependencyHashes}
+     * object.
+     */
+    public ModuleInfoExtender hashes(DependencyHashes hashes) {
+        this.hashes = hashes;
+        return this;
+    }
+
+    /**
+     * A ClassVisitor that supports adding class file attributes. If an
+     * attribute already exists then the first occurence of the attribute
+     * is replaced.
+     */
+    private static class AttributeAddingClassVisitor extends ClassVisitor {
+        private Map<String, Attribute> attrs = new HashMap<>();
+
+        AttributeAddingClassVisitor(int api, ClassVisitor cv) {
+            super(api, cv);
+        }
+
+        void addAttribute(Attribute attr) {
+            attrs.put(attr.type, attr);
+        }
+
+        @Override
+        public void visitAttribute(Attribute attr) {
+            String name = attr.type;
+            Attribute replacement = attrs.get(name);
+            if (replacement != null) {
+                attr = replacement;
+                attrs.remove(name);
+            }
+            super.visitAttribute(attr);
+        }
+
+        /**
+         * Adds any remaining attributes that weren't replaced to the
+         * class file.
+         */
+        void finish() {
+            attrs.values().forEach(a -> super.visitAttribute(a));
+            attrs.clear();
+        }
+    }
+
+    /**
+     * Outputs the modified module-info.class to the given output stream.
+     * Once this method has been called then the Extender object should
+     * be discarded.
+     */
+    public void write(OutputStream out) throws IOException {
+        ClassWriter cw
+            = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
+
+        AttributeAddingClassVisitor cv
+            = new AttributeAddingClassVisitor(Opcodes.ASM5, cw);
+
+        ClassReader cr = new ClassReader(in);
+
+        if (conceals != null)
+            cv.addAttribute(new ConcealedPackagesAttribute(conceals));
+        if (version != null)
+            cv.addAttribute(new VersionAttribute(version));
+        if (mainClass != null)
+            cv.addAttribute(new MainClassAttribute(mainClass));
+        if (osName != null || osArch != null || osVersion != null)
+            cv.addAttribute(new TargetPlatformAttribute(osName, osArch, osVersion));
+        if (hashes != null)
+            cv.addAttribute(new HashesAttribute(hashes));
+
+        List<Attribute> attrs = new ArrayList<>();
+
+        // prototypes of attributes that should be parsed
+        attrs.add(new ModuleAttribute());
+        attrs.add(new ConcealedPackagesAttribute());
+        attrs.add(new VersionAttribute());
+        attrs.add(new MainClassAttribute());
+        attrs.add(new TargetPlatformAttribute());
+        attrs.add(new HashesAttribute());
+
+        cr.accept(cv, attrs.toArray(new Attribute[0]), 0);
+
+        // add any attributes that didn't replace previous attributes
+        cv.finish();
+
+        // emit to the output stream
+        out.write(cw.toByteArray());
+    }
+
+    /**
+     * Returns an {@code Extender} that may be used to add additional
+     * attributes to the module-info.class read from the given input
+     * stream.
+     */
+    public static ModuleInfoExtender newExtender(InputStream in) {
+        return new ModuleInfoExtender(in);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.module;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Version;
+import java.nio.ByteBuffer;
+import java.util.Optional;
+
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.Opcodes;
+
+import static jdk.internal.module.ClassFileAttributes.*;
+import static jdk.internal.module.ClassFileConstants.ACC_MODULE;
+
+/**
+ * Utility class to write a ModuleDescriptor as a module-info.class.
+ */
+
+public final class ModuleInfoWriter {
+
+    private ModuleInfoWriter() { }
+
+    /**
+     * Writes the given module descriptor to a module-info.class file,
+     * returning it in a byte array.
+     */
+    private static byte[] toModuleInfo(ModuleDescriptor descriptor) {
+
+        ClassWriter cw = new ClassWriter(0);
+
+        String name = descriptor.name().replace('.', '/') + "/module-info";
+        cw.visit(Opcodes.V1_8, ACC_MODULE, name, null, null, null);
+
+        cw.visitAttribute(new ModuleAttribute(descriptor));
+        cw.visitAttribute(new ConcealedPackagesAttribute(descriptor.conceals()));
+
+        Optional<Version> oversion = descriptor.version();
+        if (oversion.isPresent())
+            cw.visitAttribute(new VersionAttribute(oversion.get()));
+
+        Optional<String> omain = descriptor.mainClass();
+        if (omain.isPresent())
+            cw.visitAttribute(new MainClassAttribute(omain.get()));
+
+        // write the TargetPlatform attribute if have any of OS name/arch/version
+        String osName = descriptor.osName().orElse(null);
+        String osArch = descriptor.osArch().orElse(null);
+        String osVersion = descriptor.osVersion().orElse(null);
+        if (osName != null || osArch != null || osVersion != null) {
+            cw.visitAttribute(new TargetPlatformAttribute(osName,
+                                                          osArch,
+                                                          osVersion));
+        }
+
+        cw.visitEnd();
+
+        return cw.toByteArray();
+    }
+
+    /**
+     * Writes a module descriptor to the given output stream as a
+     * module-info.class.
+     */
+    public static void write(ModuleDescriptor descriptor, OutputStream out)
+        throws IOException
+    {
+        byte[] bytes = toModuleInfo(descriptor);
+        out.write(bytes);
+    }
+
+    /**
+     * Returns a {@code ByteBuffer} containing the given module descriptor
+     * in module-info.class format.
+     */
+    public static ByteBuffer toByteBuffer(ModuleDescriptor descriptor) {
+        byte[] bytes = toModuleInfo(descriptor);
+        return ByteBuffer.wrap(bytes);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.module;
+
+import java.lang.module.Configuration;
+import java.lang.module.ResolvedModule;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+
+import jdk.internal.loader.ClassLoaders;
+
+
+/**
+ * The module to class loader map.  The list of boot modules and platform modules
+ * are generated at build time.
+ */
+final class ModuleLoaderMap {
+    /*
+     * The list of boot modules and platform modules are generated at build time.
+     */
+    private static final String[] BOOT_MODULES
+        = new String[] { "@@BOOT_MODULE_NAMES@@" };
+    private static final String[] PLATFORM_MODULES
+        = new String[] { "@@PLATFORM_MODULE_NAMES@@" };
+
+    /**
+     * Returns the function to map modules in the given configuration to the
+     * built-in class loaders.
+     */
+    static Function<String, ClassLoader> mappingFunction(Configuration cf) {
+
+        Set<String> bootModules = new HashSet<>(BOOT_MODULES.length);
+        for (String mn : BOOT_MODULES) {
+            bootModules.add(mn);
+        }
+
+        Set<String> platformModules = new HashSet<>(PLATFORM_MODULES.length);
+        for (String mn : PLATFORM_MODULES) {
+            platformModules.add(mn);
+        }
+
+        ClassLoader platformClassLoader = ClassLoaders.platformClassLoader();
+        ClassLoader appClassLoader = ClassLoaders.appClassLoader();
+
+        Map<String, ClassLoader> map = new HashMap<>();
+
+        for (ResolvedModule resolvedModule : cf.modules()) {
+            String mn = resolvedModule.name();
+            if (!bootModules.contains(mn)) {
+                if (platformModules.contains(mn)) {
+                    map.put(mn, platformClassLoader);
+                } else {
+                    map.put(mn, appClassLoader);
+                }
+            }
+        }
+
+        return new Function<String, ClassLoader> () {
+            @Override
+            public ClassLoader apply(String mn) {
+                return map.get(mn);
+            }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,586 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.module;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.IOError;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleReader;
+import java.lang.module.ModuleReference;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.nio.ByteBuffer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+import jdk.internal.misc.JavaLangModuleAccess;
+import jdk.internal.misc.SharedSecrets;
+import sun.misc.Resource;
+import sun.net.www.ParseUtil;
+
+
+/**
+ * Provides support for patching modules in the boot layer with -Xpatch.
+ */
+
+public final class ModulePatcher {
+
+    private static final JavaLangModuleAccess JLMA
+        = SharedSecrets.getJavaLangModuleAccess();
+
+    // the prefix of the system properties that encode the value of -Xpatch
+    private static final String PATCH_PROPERTY_PREFIX = "jdk.launcher.patch.";
+
+    // module name -> sequence of patches (directories or JAR files)
+    private static final Map<String, List<Path>> PATCH_MAP = decodeProperties();
+
+    private ModulePatcher() { }
+
+
+    /**
+     * Decodes the values of -Xpatch options, returning a Map of module name to
+     * list of file paths.
+     *
+     * @throws IllegalArgumentException if the the module name is missing or
+     *         -Xpatch is used more than once to patch the same module
+     */
+    private static Map<String, List<Path>> decodeProperties() {
+
+        int index = 0;
+        String value = System.getProperty(PATCH_PROPERTY_PREFIX + index);
+        if (value == null)
+            return Collections.emptyMap();  // -Xpatch not specified
+
+        Map<String, List<Path>> map = new HashMap<>();
+        while (value != null) {
+            int pos = value.indexOf('=');
+
+            if (pos == -1 && index > 0)
+                throwIAE("Unable to parse: " + value);
+
+            if (pos == 0)
+                throwIAE("Missing module name: " + value);
+
+            if (pos > 0) {
+
+                // new format: <module>=<file>(:<file>)*
+
+                String mn = value.substring(0, pos);
+                List<Path> list = map.get(mn);
+                if (list != null)
+                    throwIAE("Module " + mn + " specified more than once");
+                list = new ArrayList<>();
+                map.put(mn, list);
+
+                String paths = value.substring(pos+1);
+                for (String path : paths.split(File.pathSeparator)) {
+                    if (!path.isEmpty()) {
+                        list.add(Paths.get(path));
+                    }
+                }
+
+            } else {
+
+                // old format: <dir>(:<dir>)*
+
+                assert index == 0; // old format only allowed in first -Xpatch
+
+                String[] dirs = value.split(File.pathSeparator);
+                for (String d : dirs) {
+                    if (d.length() > 0) {
+                        Path top = Paths.get(d);
+                        try {
+                            Files.list(top).forEach(e -> {
+                                String mn = e.getFileName().toString();
+                                Path dir = top.resolve(mn);
+                                map.computeIfAbsent(mn, k -> new ArrayList<>())
+                                    .add(dir);
+                            });
+                        } catch (IOException ignore) { }
+                    }
+                }
+
+            }
+
+
+            index++;
+            value = System.getProperty(PATCH_PROPERTY_PREFIX + index);
+        }
+
+        return map;
+    }
+
+
+    /**
+     * Returns a module reference that interposes on the given module if
+     * needed. If there are no patches for the given module then the module
+     * reference is simply returned. Otherwise the patches for the module
+     * are scanned (to find any new concealed packages) and a new module
+     * reference is returned.
+     *
+     * @throws UncheckedIOException if an I/O error is detected
+     */
+    public static ModuleReference interposeIfNeeded(ModuleReference mref) {
+
+        ModuleDescriptor descriptor = mref.descriptor();
+        String mn = descriptor.name();
+
+        // if there are no patches for the module then nothing to do
+        List<Path> paths = PATCH_MAP.get(mn);
+        if (paths == null)
+            return mref;
+
+
+        // scan the JAR file or directory tree to get the set of packages
+        Set<String> packages = new HashSet<>();
+        try {
+            for (Path file : paths) {
+                if (Files.isRegularFile(file)) {
+
+                    // JAR file
+                    try (JarFile jf = new JarFile(file.toFile())) {
+                        jf.stream()
+                          .filter(e -> e.getName().endsWith(".class"))
+                          .map(e -> toPackageName(file, e))
+                          .filter(pn -> pn.length() > 0)
+                          .forEach(packages::add);
+                    }
+
+                } else if (Files.isDirectory(file)) {
+
+                    // exploded directory
+                    Path top = file;
+                    Files.find(top, Integer.MAX_VALUE,
+                            ((path, attrs) -> attrs.isRegularFile() &&
+                                    path.toString().endsWith(".class")))
+                            .map(path -> toPackageName(top, path))
+                            .filter(pn -> pn.length() > 0)
+                            .forEach(packages::add);
+
+                }
+            }
+
+        } catch (IOException ioe) {
+            throw new UncheckedIOException(ioe);
+        }
+
+        // if there are new packages then we need a new ModuleDescriptor
+        Set<String> original = descriptor.packages();
+        packages.addAll(original);
+        if (packages.size() > original.size()) {
+            descriptor = JLMA.newModuleDescriptor(descriptor, packages);
+        }
+
+        // return a new module reference
+        URI location = mref.location().orElse(null);
+        return new ModuleReference(descriptor, location,
+                                   () -> new PatchedModuleReader(paths, mref));
+
+    }
+
+
+    /**
+     * A ModuleReader that reads resources from a patched module.
+     *
+     * This class is public so as to expose the findResource method to the
+     * built-in class loaders and avoid locating the resource twice during
+     * class loading (once to locate the resource, the second to gets the
+     * URL for the CodeSource).
+     */
+    public static class PatchedModuleReader implements ModuleReader {
+        private final List<ResourceFinder> finders;
+        private final ModuleReference mref;
+        private final URL delegateCodeSourceURL;
+        private volatile ModuleReader delegate;
+
+        /**
+         * Creates the ModuleReader to reads resources a patched module.
+         */
+        PatchedModuleReader(List<Path> patches, ModuleReference mref) {
+            List<ResourceFinder> finders = new ArrayList<>();
+            boolean initialized = false;
+            try {
+                for (Path file : patches) {
+                    if (Files.isRegularFile(file)) {
+                        finders.add(new JarResourceFinder(file));
+                    } else {
+                        finders.add(new ExplodedResourceFinder(file));
+                    }
+                }
+                initialized = true;
+            } catch (IOException ioe) {
+                throw new UncheckedIOException(ioe);
+            } finally {
+                // close all ResourceFinder in the event of an error
+                if (!initialized) closeAll(finders);
+            }
+
+            this.finders = finders;
+            this.mref = mref;
+            this.delegateCodeSourceURL = codeSourceURL(mref);
+        }
+
+        /**
+         * Closes all resource finders.
+         */
+        private static void closeAll(List<ResourceFinder> finders) {
+            for (ResourceFinder finder : finders) {
+                try { finder.close(); } catch (IOException ioe) { }
+            }
+        }
+
+        /**
+         * Returns the code source URL for the given module.
+         */
+        private static URL codeSourceURL(ModuleReference mref) {
+            try {
+                Optional<URI> ouri = mref.location();
+                if (ouri.isPresent())
+                    return ouri.get().toURL();
+            } catch (MalformedURLException e) { }
+            return null;
+        }
+
+        /**
+         * Returns the ModuleReader to delegate to when the resource is not
+         * found in a patch location.
+         */
+        private ModuleReader delegate() throws IOException {
+            ModuleReader r = delegate;
+            if (r == null) {
+                synchronized (this) {
+                    r = delegate;
+                    if (r == null) {
+                        delegate = r = mref.open();
+                    }
+                }
+            }
+            return r;
+        }
+
+        /**
+         * Finds a resources in the patch locations. Returns null if not found.
+         */
+        private Resource findResourceInPatch(String name) throws IOException {
+            for (ResourceFinder finder : finders) {
+                Resource r = finder.find(name);
+                if (r != null)
+                    return r;
+            }
+            return null;
+        }
+
+        /**
+         * Finds a resource of the given name in the patched module.
+         */
+        public Resource findResource(String name) throws IOException {
+
+            // patch locations
+            Resource r = findResourceInPatch(name);
+            if (r != null)
+                return r;
+
+            // original module
+            ByteBuffer bb = delegate().read(name).orElse(null);
+            if (bb == null)
+                return null;
+
+            return new Resource() {
+                private <T> T shouldNotGetHere(Class<T> type) {
+                    throw new InternalError("should not get here");
+                }
+                @Override
+                public String getName() {
+                    return shouldNotGetHere(String.class);
+                }
+                @Override
+                public URL getURL() {
+                    return shouldNotGetHere(URL.class);
+                }
+                @Override
+                public URL getCodeSourceURL() {
+                    return delegateCodeSourceURL;
+                }
+                @Override
+                public ByteBuffer getByteBuffer() throws IOException {
+                    return bb;
+                }
+                @Override
+                public InputStream getInputStream() throws IOException {
+                    return shouldNotGetHere(InputStream.class);
+                }
+                @Override
+                public int getContentLength() throws IOException {
+                    return shouldNotGetHere(int.class);
+                }
+            };
+        }
+
+        @Override
+        public Optional<URI> find(String name) throws IOException {
+            Resource r = findResourceInPatch(name);
+            if (r != null) {
+                URI uri = URI.create(r.getURL().toString());
+                return Optional.of(uri);
+            } else {
+                return delegate().find(name);
+            }
+        }
+
+        @Override
+        public Optional<InputStream> open(String name) throws IOException {
+            Resource r = findResourceInPatch(name);
+            if (r != null) {
+                return Optional.of(r.getInputStream());
+            } else {
+                return delegate().open(name);
+            }
+        }
+
+        @Override
+        public Optional<ByteBuffer> read(String name) throws IOException {
+            Resource r = findResourceInPatch(name);
+            if (r != null) {
+                ByteBuffer bb = r.getByteBuffer();
+                assert !bb.isDirect();
+                return Optional.of(bb);
+            } else {
+                return delegate().read(name);
+            }
+        }
+
+        @Override
+        public void release(ByteBuffer bb) {
+            if (bb.isDirect()) {
+                try {
+                    delegate().release(bb);
+                } catch (IOException ioe) {
+                    throw new InternalError(ioe);
+                }
+            }
+        }
+
+        @Override
+        public void close() throws IOException {
+            closeAll(finders);
+            delegate().close();
+        }
+    }
+
+
+    /**
+     * A resource finder that find resources in a patch location.
+     */
+    private static interface ResourceFinder extends Closeable {
+        Resource find(String name) throws IOException;
+    }
+
+
+    /**
+     * A ResourceFinder that finds resources in a JAR file.
+     */
+    private static class JarResourceFinder implements ResourceFinder {
+        private final JarFile jf;
+        private final URL csURL;
+
+        JarResourceFinder(Path path) throws IOException {
+            this.jf = new JarFile(path.toFile());
+            this.csURL = path.toUri().toURL();
+        }
+
+        @Override
+        public void close() throws IOException {
+            jf.close();
+        }
+
+        @Override
+        public Resource find(String name) throws IOException {
+            JarEntry entry = jf.getJarEntry(name);
+            if (entry == null)
+                return null;
+
+            return new Resource() {
+                @Override
+                public String getName() {
+                    return name;
+                }
+                @Override
+                public URL getURL() {
+                    String encodedPath = ParseUtil.encodePath(name, false);
+                    try {
+                        return new URL("jar:" + csURL + "!/" + encodedPath);
+                    } catch (MalformedURLException e) {
+                        return null;
+                    }
+                }
+                @Override
+                public URL getCodeSourceURL() {
+                    return csURL;
+                }
+                @Override
+                public ByteBuffer getByteBuffer() throws IOException {
+                    byte[] bytes = getInputStream().readAllBytes();
+                    return ByteBuffer.wrap(bytes);
+                }
+                @Override
+                public InputStream getInputStream() throws IOException {
+                    return jf.getInputStream(entry);
+                }
+                @Override
+                public int getContentLength() throws IOException {
+                    long size = entry.getSize();
+                    return (size > Integer.MAX_VALUE) ? -1 : (int) size;
+                }
+            };
+        }
+    }
+
+
+    /**
+     * A ResourceFinder that finds resources on the file system.
+     */
+    private static class ExplodedResourceFinder implements ResourceFinder {
+        private final Path dir;
+
+        ExplodedResourceFinder(Path dir) {
+            this.dir = dir;
+        }
+
+        @Override
+        public void close() { }
+
+        @Override
+        public Resource find(String name) throws IOException {
+            Path file = Paths.get(name.replace('/', File.separatorChar));
+            if (file.getRoot() == null) {
+                file = dir.resolve(file);
+            } else {
+                // drop the root component so that the resource is
+                // located relative to the module directory
+                int n = file.getNameCount();
+                if (n == 0)
+                    return null;
+                file = dir.resolve(file.subpath(0, n));
+            }
+
+            if (Files.isRegularFile(file)) {
+                return newResource(name, dir, file);
+            } else {
+                return null;
+            }
+        }
+
+        private Resource newResource(String name, Path top, Path file) {
+            return new Resource() {
+                @Override
+                public String getName() {
+                    return name;
+                }
+                @Override
+                public URL getURL() {
+                    try {
+                        return file.toUri().toURL();
+                    } catch (IOException | IOError e) {
+                        return null;
+                    }
+                }
+                @Override
+                public URL getCodeSourceURL() {
+                    try {
+                        return top.toUri().toURL();
+                    } catch (IOException | IOError e) {
+                        return null;
+                    }
+                }
+                @Override
+                public ByteBuffer getByteBuffer() throws IOException {
+                    return ByteBuffer.wrap(Files.readAllBytes(file));
+                }
+                @Override
+                public InputStream getInputStream() throws IOException {
+                    return Files.newInputStream(file);
+                }
+                @Override
+                public int getContentLength() throws IOException {
+                    long size = Files.size(file);
+                    return (size > Integer.MAX_VALUE) ? -1 : (int)size;
+                }
+            };
+        }
+    }
+
+
+    /**
+     * Derives a package name from a file path to a .class file.
+     */
+    private static String toPackageName(Path top, Path file) {
+        Path entry = top.relativize(file);
+        Path parent = entry.getParent();
+        if (parent == null) {
+            return warnUnnamedPackage(top, entry.toString());
+        } else {
+            return parent.toString().replace(File.separatorChar, '.');
+        }
+    }
+
+    /**
+     * Derives a package name from the name of an entry in a JAR file.
+     */
+    private static String toPackageName(Path file, JarEntry entry) {
+        String name = entry.getName();
+        int index = name.lastIndexOf("/");
+        if (index == -1) {
+            return warnUnnamedPackage(file, name);
+        } else {
+            return name.substring(0, index).replace('/', '.');
+        }
+    }
+
+    private static String warnUnnamedPackage(Path file, String e) {
+        System.err.println("WARNING: " + e + " not allowed in patch: " + file);
+        return "";
+    }
+
+    private static void throwIAE(String msg) {
+        throw new IllegalArgumentException(msg);
+    }
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/Modules.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.module;
+
+import java.lang.module.ModuleDescriptor;
+import java.lang.reflect.Module;
+import java.net.URI;
+import java.util.Set;
+
+import jdk.internal.loader.BootLoader;
+import jdk.internal.loader.ClassLoaders;
+import jdk.internal.misc.JavaLangReflectModuleAccess;
+import jdk.internal.misc.SharedSecrets;
+
+
+/**
+ * A helper class to allow JDK classes create dynamic modules and to update
+ * modules, exports and the readability graph. It is also invoked by the VM
+ * to add read edges when agents are instrumenting code that need to link
+ * to supporting classes.
+ *
+ * The parameters that are package names in this API are the fully-qualified
+ * names of the packages as defined in section 6.5.3 of <cite>The Java&trade;
+ * Language Specification </cite>, for example, {@code "java.lang"}.
+ */
+
+public class Modules {
+    private Modules() { }
+
+    private static final JavaLangReflectModuleAccess JLRMA
+        = SharedSecrets.getJavaLangReflectModuleAccess();
+
+
+    /**
+     * Creates a new Module. The module has the given ModuleDescriptor and
+     * is defined to the given class loader.
+     *
+     * The resulting Module is in a larva state in that it does not not read
+     * any other module and does not have any exports.
+     *
+     * The URI is for information purposes only.
+     */
+    public static Module defineModule(ClassLoader loader,
+                                      ModuleDescriptor descriptor,
+                                      URI uri)
+    {
+        return JLRMA.defineModule(loader, descriptor, uri);
+    }
+
+    /**
+     * Define a new module to the VM. The module has the given set of
+     * concealed packages and is defined to the given class loader.
+     *
+     * The resulting Module is in a larva state in that it does not not read
+     * any other module and does not have any exports.
+     */
+    public static Module defineModule(ClassLoader loader,
+                                      String name,
+                                      Set<String> packages)
+    {
+        ModuleDescriptor descriptor
+            = new ModuleDescriptor.Builder(name).conceals(packages).build();
+
+        return JLRMA.defineModule(loader, descriptor, null);
+    }
+
+    /**
+     * Adds a read-edge so that module {@code m1} reads module {@code m1}.
+     * Same as m1.addReads(m2) but without a caller check.
+     */
+    public static void addReads(Module m1, Module m2) {
+        JLRMA.addReads(m1, m2);
+    }
+
+    /**
+     * Updates module m1 to export a package to module m2.
+     * Same as m1.addExports(pkg, m2) but without a caller check.
+     */
+    public static void addExports(Module m1, String pn, Module m2) {
+        JLRMA.addExports(m1, pn, m2);
+    }
+
+    /**
+     * Updates a module m to export a package to all modules.
+     */
+    public static void addExportsToAll(Module m, String pn) {
+        JLRMA.addExportsToAll(m, pn);
+    }
+
+    /**
+     * Updates module m to export a package to all unnamed modules.
+     */
+    public static void addExportsToAllUnnamed(Module m, String pn) {
+        JLRMA.addExportsToAllUnnamed(m, pn);
+    }
+
+    /**
+     * Adds a package to a module's content.
+     *
+     * This method is a no-op if the module already contains the package.
+     */
+    public static void addPackage(Module m, String pn) {
+        JLRMA.addPackage(m, pn);
+    }
+
+    /**
+     * Called by the VM when code in the given Module has been transformed by
+     * an agent and so may have been instrumented to call into supporting
+     * classes on the boot class path or application class path.
+     */
+    public static void transformedByAgent(Module m) {
+        addReads(m, BootLoader.getUnnamedModule());
+        addReads(m, ClassLoaders.appClassLoader().getUnnamedModule());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/ServicesCatalog.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.module;
+
+import java.lang.reflect.Module;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Provides;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * A services catalog. Each {@code ClassLoader} has an optional {@code
+ * ServicesCatalog} for modules that provide services. This is to support
+ * ClassLoader centric ServiceLoader.load methods.
+ */
+public class ServicesCatalog {
+
+    // use RW locks as register is rare
+    private final ReadWriteLock lock = new ReentrantReadWriteLock();
+    private final Lock readLock = lock.readLock();
+    private final Lock writeLock = lock.writeLock();
+
+    /**
+     * Represents a service provider in the services catalog.
+     */
+    public class ServiceProvider {
+        private final Module module;
+        private final String providerName;
+        ServiceProvider(Module module, String providerName) {
+            this.module = module;
+            this.providerName = providerName;
+        }
+        public Module module() {
+            return module;
+        }
+        public String providerName() {
+            return providerName;
+        }
+    }
+
+    // service providers
+    private final Map<String, Set<ServiceProvider>> loaderServices = new HashMap<>();
+
+    /**
+     * Creates a new module catalog.
+     */
+    public ServicesCatalog() { }
+
+    /**
+     * Registers the module in this module catalog.
+     */
+    public void register(Module m) {
+        ModuleDescriptor descriptor = m.getDescriptor();
+
+        writeLock.lock();
+        try {
+            // extend the services map
+            for (Provides ps : descriptor.provides().values()) {
+                String service = ps.service();
+                Set<String> providerNames = ps.providers();
+
+                // create a new set to replace the existing
+                Set<ServiceProvider> result = new HashSet<>();
+                Set<ServiceProvider> providers = loaderServices.get(service);
+                if (providers != null) {
+                    result.addAll(providers);
+                }
+                for (String pn : providerNames) {
+                    result.add(new ServiceProvider(m, pn));
+                }
+                loaderServices.put(service, Collections.unmodifiableSet(result));
+            }
+
+        } finally {
+            writeLock.unlock();
+        }
+    }
+
+    /**
+     * Returns the (possibly empty) set of service providers that implement the
+     * given service type.
+     *
+     * @see java.util.ServiceLoader
+     */
+    public Set<ServiceProvider> findServices(String service) {
+        readLock.lock();
+        try {
+            return loaderServices.getOrDefault(service, Collections.emptySet());
+        } finally {
+            readLock.unlock();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/SystemModules.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.module;
+
+import java.lang.module.ModuleDescriptor;
+
+/*
+ * SystemModules class will be generated at link time to create
+ * ModuleDescriptor for the installed modules directly to improve
+ * the module descriptor reconstitution time.
+ *
+ * This will skip parsing of module-info.class file and validating
+ * names such as module name, package name, service and provider type names.
+ * It also avoids taking a defensive copy of any collection.
+ *
+ * @see jdk.tools.jlink.internal.plugins.SystemModuleDescriptorPlugin
+ */
+public final class SystemModules {
+    /**
+     * Name of the installed modules.
+     *
+     * This array provides a way for InstalledModuleFinder to fallback
+     * and read module-info.class from the run-time image instead of
+     * the fastpath.
+     */
+    public static final String[] MODULE_NAMES = new String[1];
+
+    /**
+     * Number of packages in the boot layer from the installed modules.
+     *
+     * Don't make it final to avoid inlining during compile time as
+     * the value will be changed at jlink time.
+     */
+    public static final int PACKAGES_IN_BOOT_LAYER = 1024;
+
+    /**
+     * Returns a non-empty array of ModuleDescriptors in the run-time image.
+     *
+     * When running an exploded image it returns an empty array.
+     */
+    public static ModuleDescriptor[] modules() {
+        return new ModuleDescriptor[0];
+    }
+}
\ No newline at end of file
--- a/src/java.base/share/classes/jdk/internal/perf/PerfCounter.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/perf/PerfCounter.java	Thu Mar 17 19:04:16 2016 +0000
@@ -67,11 +67,11 @@
         this.lb = bb.asLongBuffer();
     }
 
-    static PerfCounter newPerfCounter(String name) {
+    public static PerfCounter newPerfCounter(String name) {
         return new PerfCounter(name, V_Variable);
     }
 
-    static PerfCounter newConstantPerfCounter(String name) {
+    public static PerfCounter newConstantPerfCounter(String name) {
         PerfCounter c = new PerfCounter(name, V_Constant);
         return c;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/vm/cds/resources/ModuleLoaderMap.dat	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,4 @@
+BOOT
+@@BOOT_MODULE_NAMES@@
+PLATFORM
+@@PLATFORM_MODULE_NAMES@@
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * java.base defines and exports the core APIs of the Java SE platform.
+ */
+
+module java.base {
+
+    exports java.io;
+    exports java.lang;
+    exports java.lang.annotation;
+    exports java.lang.invoke;
+    exports java.lang.module;
+    exports java.lang.ref;
+    exports java.lang.reflect;
+    exports java.math;
+    exports java.net;
+    exports java.net.spi;
+    exports java.nio;
+    exports java.nio.channels;
+    exports java.nio.channels.spi;
+    exports java.nio.charset;
+    exports java.nio.charset.spi;
+    exports java.nio.file;
+    exports java.nio.file.attribute;
+    exports java.nio.file.spi;
+    exports java.security;
+    exports java.security.acl;
+    exports java.security.cert;
+    exports java.security.interfaces;
+    exports java.security.spec;
+    exports java.text;
+    exports java.text.spi;
+    exports java.time;
+    exports java.time.chrono;
+    exports java.time.format;
+    exports java.time.temporal;
+    exports java.time.zone;
+    exports java.util;
+    exports java.util.concurrent;
+    exports java.util.concurrent.atomic;
+    exports java.util.concurrent.locks;
+    exports java.util.function;
+    exports java.util.jar;
+    exports java.util.regex;
+    exports java.util.spi;
+    exports java.util.stream;
+    exports java.util.zip;
+    exports javax.crypto;
+    exports javax.crypto.interfaces;
+    exports javax.crypto.spec;
+    exports javax.net;
+    exports javax.net.ssl;
+    exports javax.security.auth;
+    exports javax.security.auth.callback;
+    exports javax.security.auth.login;
+    exports javax.security.auth.spi;
+    exports javax.security.auth.x500;
+    exports javax.security.cert;
+
+    // see JDK-8144062
+    exports jdk;
+    // see JDK-8044773
+    exports jdk.net;
+
+    // These will move to a jdk.internal module via JEP-260
+    exports sun.misc;
+    exports sun.reflect;
+
+
+    // the service types defined by the APIs in this module
+
+    uses java.lang.System.LoggerFinder;
+    uses java.net.ContentHandlerFactory;
+    uses java.net.spi.URLStreamHandlerProvider;
+    uses java.nio.channels.spi.AsynchronousChannelProvider;
+    uses java.nio.channels.spi.SelectorProvider;
+    uses java.nio.charset.spi.CharsetProvider;
+    uses java.nio.file.spi.FileSystemProvider;
+    uses java.nio.file.spi.FileTypeDetector;
+    uses java.security.Provider;
+    uses java.text.spi.BreakIteratorProvider;
+    uses java.text.spi.CollatorProvider;
+    uses java.text.spi.DateFormatProvider;
+    uses java.text.spi.DateFormatSymbolsProvider;
+    uses java.text.spi.DecimalFormatSymbolsProvider;
+    uses java.text.spi.NumberFormatProvider;
+    uses java.time.chrono.AbstractChronology;
+    uses java.time.chrono.Chronology;
+    uses java.time.zone.ZoneRulesProvider;
+    uses java.util.spi.CalendarDataProvider;
+    uses java.util.spi.CalendarNameProvider;
+    uses java.util.spi.CurrencyNameProvider;
+    uses java.util.spi.LocaleNameProvider;
+    uses java.util.spi.ResourceBundleControlProvider;
+    uses java.util.spi.ResourceBundleProvider;
+    uses java.util.spi.TimeZoneNameProvider;
+    uses javax.security.auth.spi.LoginModule;
+
+
+    // additional qualified exports may be inserted at build time
+    // see make/gensrc/GenModuleInfo.gmk
+
+    // CORBA serialization needs reflective access
+    exports sun.util.calendar to
+        java.corba;
+
+    exports com.sun.security.ntlm to
+        java.security.sasl;
+    exports jdk.internal.jimage to
+        jdk.jlink;
+    exports jdk.internal.jimage.decompressor to
+        jdk.jlink;
+    exports jdk.internal.logger to
+        java.logging;
+    exports jdk.internal.org.objectweb.asm to
+        jdk.jlink,
+        jdk.scripting.nashorn,
+        jdk.vm.ci;
+    exports jdk.internal.org.objectweb.asm.tree to
+        jdk.jlink;
+    exports jdk.internal.org.objectweb.asm.util to
+        jdk.jlink,
+        jdk.scripting.nashorn;
+    exports jdk.internal.org.objectweb.asm.tree.analysis to
+        jdk.jlink;
+    exports jdk.internal.org.objectweb.asm.commons to
+        jdk.scripting.nashorn;
+    exports jdk.internal.org.objectweb.asm.signature to
+        jdk.scripting.nashorn;
+    exports jdk.internal.math to
+        java.desktop;
+    exports jdk.internal.module to
+        java.instrument,
+        java.management,
+        java.xml,
+        jdk.dynalink,
+        jdk.jartool,
+        jdk.jlink,
+        jdk.scripting.nashorn;
+    exports jdk.internal.misc to
+        java.corba,
+        java.desktop,
+        java.logging,
+        java.management,
+        java.naming,
+        java.rmi,
+        java.security.jgss,
+        java.sql,
+        java.xml,
+        jdk.charsets,
+        jdk.scripting.nashorn,
+        jdk.vm.ci;
+    exports jdk.internal.perf to
+        java.desktop,
+        java.management,
+        jdk.jvmstat;
+    exports jdk.internal.ref to
+        java.desktop;
+    exports sun.net to
+        java.httpclient;
+    exports sun.net.dns to
+        java.security.jgss,
+        jdk.naming.dns;
+    exports sun.net.spi.nameservice to
+        jdk.naming.dns;
+    exports sun.net.util to
+        java.desktop,
+        jdk.jconsole,
+        jdk.naming.dns;
+    exports sun.net.www to
+        java.desktop,
+        jdk.jartool;
+    exports sun.net.www.protocol.http to
+        java.security.jgss;
+    exports sun.nio.ch to
+        java.management,
+        jdk.crypto.pkcs11,
+        jdk.sctp;
+    exports sun.nio.cs to
+        java.desktop,
+        jdk.charsets;
+    exports sun.reflect.annotation to
+        jdk.compiler;
+    exports sun.reflect.generics.reflectiveObjects to
+        java.desktop;
+    exports sun.reflect.misc to
+        java.corba,
+        java.desktop,
+        java.datatransfer,
+        java.management,
+        java.rmi,
+        java.sql.rowset,
+        java.xml,
+        java.xml.ws;
+    exports sun.security.action to
+        java.desktop,
+        java.security.jgss,
+        jdk.crypto.pkcs11;
+    exports sun.security.internal.interfaces to
+        jdk.crypto.pkcs11;
+    exports sun.security.internal.spec to
+        jdk.crypto.pkcs11;
+    exports sun.security.jca to
+        java.smartcardio,
+        java.xml.crypto,
+        jdk.crypto.ec,
+        jdk.crypto.pkcs11,
+        jdk.naming.dns;
+    exports sun.security.pkcs to
+        jdk.crypto.ec,
+        jdk.jartool;
+    exports sun.security.provider to
+        java.rmi,
+        java.security.jgss,
+        jdk.crypto.pkcs11,
+        jdk.policytool,
+        jdk.security.auth;
+    exports sun.security.provider.certpath to
+        java.naming;
+    exports sun.security.rsa to
+        jdk.crypto.pkcs11;
+    exports sun.security.ssl to
+        java.security.jgss;
+    exports sun.security.tools to
+        jdk.jartool;
+    exports sun.security.util to
+        java.desktop,
+        java.naming,
+        java.rmi,
+        java.security.jgss,
+        java.security.sasl,
+        java.smartcardio,
+        jdk.crypto.ec,
+        jdk.crypto.pkcs11,
+        jdk.jartool,
+        jdk.policytool,
+        jdk.security.auth,
+        jdk.security.jgss;
+    exports sun.security.x509 to
+        jdk.crypto.ec,
+        jdk.crypto.pkcs11,
+        jdk.jartool,
+        jdk.security.auth;
+    exports sun.text.resources to
+        jdk.localedata;
+    exports sun.util.resources to
+        jdk.localedata;
+    exports sun.util.locale.provider to
+        java.desktop,
+        jdk.localedata;
+    exports sun.util.logging to
+        java.desktop,
+        java.httpclient,
+        java.logging,
+        java.prefs;
+
+    // JDK-internal service types
+    uses jdk.internal.logger.DefaultLoggerFinder;
+    uses sun.net.spi.nameservice.NameServiceDescriptor;
+    uses sun.security.ssl.ClientKeyExchangeService;
+    uses sun.util.spi.CalendarProvider;
+    uses sun.util.locale.provider.LocaleDataMetaInfo;
+    uses sun.util.resources.LocaleData.CommonResourceBundleProvider;
+    uses sun.util.resources.LocaleData.SupplementaryResourceBundleProvider;
+
+
+    // Built-in service providers that are located via ServiceLoader
+
+    provides java.nio.file.spi.FileSystemProvider with
+        jdk.internal.jrtfs.JrtFileSystemProvider;
+    provides java.security.Provider with sun.security.provider.Sun;
+    provides java.security.Provider with sun.security.rsa.SunRsaSign;
+    provides java.security.Provider with com.sun.crypto.provider.SunJCE;
+    provides java.security.Provider with com.sun.net.ssl.internal.ssl.Provider;
+}
+
--- a/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java	Thu Mar 17 19:04:16 2016 +0000
@@ -27,6 +27,7 @@
 
 import java.lang.reflect.Modifier;
 import static java.lang.reflect.Modifier.*;
+import java.lang.reflect.Module;
 import sun.reflect.Reflection;
 
 /**
@@ -37,6 +38,7 @@
 
     private VerifyAccess() { }  // cannot instantiate
 
+    private static final int MODULE_ALLOWED = java.lang.invoke.MethodHandles.Lookup.MODULE;
     private static final int PACKAGE_ONLY = 0;
     private static final int PACKAGE_ALLOWED = java.lang.invoke.MethodHandles.Lookup.PACKAGE;
     private static final int PROTECTED_OR_PACKAGE_ALLOWED = (PACKAGE_ALLOWED|PROTECTED);
@@ -89,7 +91,7 @@
                                              int      allowedModes) {
         if (allowedModes == 0)  return false;
         assert((allowedModes & PUBLIC) != 0 &&
-               (allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED)) == 0);
+               (allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED)) == 0);
         // The symbolic reference class (refc) must always be fully verified.
         if (!isClassAccessible(refc, lookupClass, allowedModes)) {
             return false;
@@ -157,8 +159,10 @@
      * Evaluate the JVM linkage rules for access to the given class on behalf of caller.
      * <h3>JVM Specification, 5.4.4 "Access Control"</h3>
      * A class or interface C is accessible to a class or interface D
-     * if and only if either of the following conditions are true:<ul>
-     * <li>C is public.
+     * if and only if any of the following conditions are true:<ul>
+     * <li>C is public and in the same module as D.
+     * <li>D is in a module that reads the module containing C, C is public and in a
+     * package that is exported to the module that contains D.
      * <li>C and D are members of the same runtime package.
      * </ul>
      * @param refc the symbolic reference class to which access is being checked (C)
@@ -168,10 +172,52 @@
                                             int allowedModes) {
         if (allowedModes == 0)  return false;
         assert((allowedModes & PUBLIC) != 0 &&
-               (allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED)) == 0);
+               (allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED)) == 0);
         int mods = getClassModifiers(refc);
-        if (isPublic(mods))
-            return true;
+        if (isPublic(mods)) {
+
+            Module lookupModule = lookupClass.getModule();
+            Module refModule = refc.getModule();
+
+            // early VM startup case, java.base not defined
+            if (lookupModule == null) {
+                assert refModule == null;
+                return true;
+            }
+
+            // trivially allow
+            if ((allowedModes & MODULE_ALLOWED) != 0 &&
+                (lookupModule == refModule))
+                return true;
+
+            // check readability
+            if (lookupModule.canRead(refModule)) {
+
+                // check that refc is in an exported package
+                Class<?> c = refc;
+                while (c.isArray()) {
+                    c = c.getComponentType();
+                }
+                if (c.isPrimitive())
+                    return true;
+                if ((allowedModes & MODULE_ALLOWED) != 0) {
+                    if (refModule.isExported(c.getPackageName(), lookupModule))
+                        return true;
+                } else {
+                    // exported unconditionally
+                    if (refModule.isExported(c.getPackageName()))
+                        return true;
+                }
+
+                // not exported but allow access during VM initialization
+                // because java.base does not have its exports setup
+                if (!jdk.internal.misc.VM.isModuleSystemInited())
+                    return true;
+            }
+
+            // public class not accessible to lookupClass
+            return false;
+        }
         if ((allowedModes & PACKAGE_ALLOWED) != 0 &&
             isSamePackage(lookupClass, refc))
             return true;
@@ -219,6 +265,16 @@
     }
 
     /**
+     * Tests if two classes are in the same module.
+     * @param class1 a class
+     * @param class2 another class
+     * @return whether they are in the same module
+     */
+    public static boolean isSameModule(Class<?> class1, Class<?> class2) {
+        return class1.getModule() == class2.getModule();
+    }
+
+    /**
      * Test if two classes have the same class loader and package qualifier.
      * @param class1 a class
      * @param class2 another class
@@ -244,10 +300,10 @@
     /** Return the package name for this class.
      */
     public static String getPackageName(Class<?> cls) {
-        assert(!cls.isArray());
+        assert (!cls.isArray());
         String name = cls.getName();
         int dot = name.lastIndexOf('.');
-        if (dot < 0)  return "";
+        if (dot < 0) return "";
         return name.substring(0, dot);
     }
 
--- a/src/java.base/share/classes/sun/launcher/LauncherHelper.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/sun/launcher/LauncherHelper.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -43,24 +43,39 @@
 import java.io.IOException;
 import java.io.PrintStream;
 import java.io.UnsupportedEncodingException;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReference;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Requires;
+import java.lang.module.ModuleDescriptor.Exports;
+import java.lang.module.ModuleDescriptor.Provides;
+import java.lang.reflect.Layer;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
+import java.lang.reflect.Module;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
+import java.net.URI;
 import java.nio.charset.Charset;
 import java.nio.file.DirectoryStream;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.text.Normalizer;
-import java.util.ResourceBundle;
 import java.text.MessageFormat;
+import java.util.ResourceBundle;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import java.util.Locale.Category;
+import java.util.Optional;
 import java.util.Properties;
+import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.jar.Attributes;
@@ -68,6 +83,7 @@
 import java.util.jar.Manifest;
 import jdk.internal.misc.VM;
 
+
 public enum LauncherHelper {
     INSTANCE;
 
@@ -98,7 +114,6 @@
                 ResourceBundle.getBundle(defaultBundleName);
     }
     private static PrintStream ostream;
-    private static final ClassLoader scloader = ClassLoader.getSystemClassLoader();
     private static Class<?> appClass; // application class, for GUI/reporting purposes
 
     /*
@@ -439,11 +454,12 @@
     }
 
     // From src/share/bin/java.c:
-    //   enum LaunchMode { LM_UNKNOWN = 0, LM_CLASS, LM_JAR };
+    //   enum LaunchMode { LM_UNKNOWN = 0, LM_CLASS, LM_JAR, LM_MODULE }
 
     private static final int LM_UNKNOWN = 0;
     private static final int LM_CLASS   = 1;
     private static final int LM_JAR     = 2;
+    private static final int LM_MODULE  = 3;
 
     static void abort(Throwable t, String msgKey, Object... args) {
         if (msgKey != null) {
@@ -460,33 +476,95 @@
     }
 
     /**
-     * This method does the following:
-     * 1. gets the classname from a Jar's manifest, if necessary
-     * 2. loads the class using the System ClassLoader
-     * 3. ensures the availability and accessibility of the main method,
-     *    using signatureDiagnostic method.
-     *    a. does the class exist
-     *    b. is there a main
-     *    c. is the main public
-     *    d. is the main static
-     *    e. does the main take a String array for args
-     * 4. if no main method and if the class extends FX Application, then call
-     *    on FXHelper to determine the main class to launch
-     * 5. and off we go......
+     * This method:
+     * 1. Loads the main class from the module or class path
+     * 2. Checks the public static void main method.
      *
      * @param printToStderr if set, all output will be routed to stderr
      * @param mode LaunchMode as determined by the arguments passed on the
-     * command line
-     * @param what either the jar file to launch or the main class when using
-     * LM_CLASS mode
+     *             command line
+     * @param what the module name[/class], JAR file, or the main class
+     *             depending on the mode
+     *
      * @return the application's main class
      */
     public static Class<?> checkAndLoadMain(boolean printToStderr,
                                             int mode,
                                             String what) {
         initOutput(printToStderr);
+
+        Class<?> mainClass = (mode == LM_MODULE) ? loadModuleMainClass(what)
+                                                 : loadMainClass(mode, what);
+
+        validateMainClass(mainClass);
+
+        // record main class if not already set
+        if (appClass == null)
+            appClass = mainClass;
+
+        return mainClass;
+    }
+
+    /**
+     * Returns the main class for a module. The query is either a module name
+     * or module-name/main-class. For the former then the module's main class
+     * is obtained from the module descriptor (MainClass attribute).
+     */
+    private static Class<?> loadModuleMainClass(String what) {
+        int i = what.indexOf('/');
+        String mainModule;
+        String mainClass;
+        if (i == -1) {
+            mainModule = what;
+            mainClass = null;
+        } else {
+            mainModule = what.substring(0, i);
+            mainClass = what.substring(i+1);
+        }
+
+        // main module is in the boot layer
+        Layer layer = Layer.boot();
+        Optional<Module> om = layer.findModule(mainModule);
+        if (!om.isPresent()) {
+            // should not happen
+            throw new InternalError("Module " + mainModule + " not in boot Layer");
+        }
+        Module m = om.get();
+
+        // get main class
+        if (mainClass == null) {
+            Optional<String> omc = m.getDescriptor().mainClass();
+            if (!omc.isPresent()) {
+                abort(null, "java.launcher.module.error1", mainModule);
+            }
+            mainClass = omc.get();
+        }
+
+        // load the class from the module
+        Class<?> c = Class.forName(m, mainClass);
+        if (c == null &&  System.getProperty("os.name", "").contains("OS X")
+                && Normalizer.isNormalized(mainClass, Normalizer.Form.NFD)) {
+
+            String cn = Normalizer.normalize(mainClass, Normalizer.Form.NFC);
+            c = Class.forName(m, cn);
+
+        }
+        if (c == null) {
+            abort(null, "java.launcher.module.error2", mainClass, mainModule);
+        }
+
+        System.setProperty("jdk.module.main.class", c.getName());
+        return c;
+    }
+
+    /**
+     * Loads the main class from the class path (LM_CLASS or LM_JAR).
+     * If the main class extends FX Application then call on FXHelper to
+     * determine the main class to launch.
+     */
+    private static Class<?> loadMainClass(int mode, String what) {
         // get the class name
-        String cn = null;
+        String cn;
         switch (mode) {
             case LM_CLASS:
                 cn = what;
@@ -498,18 +576,21 @@
                 // should never happen
                 throw new InternalError("" + mode + ": Unknown launch mode");
         }
+
+        // load the main class
         cn = cn.replace('/', '.');
         Class<?> mainClass = null;
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
         try {
-            mainClass = scloader.loadClass(cn);
+            mainClass = scl.loadClass(cn);
         } catch (NoClassDefFoundError | ClassNotFoundException cnfe) {
             if (System.getProperty("os.name", "").contains("OS X")
-                && Normalizer.isNormalized(cn, Normalizer.Form.NFD)) {
+                    && Normalizer.isNormalized(cn, Normalizer.Form.NFD)) {
                 try {
                     // On Mac OS X since all names with diacretic symbols are given as decomposed it
                     // is possible that main class name comes incorrectly from the command line
                     // and we have to re-compose it
-                    mainClass = scloader.loadClass(Normalizer.normalize(cn, Normalizer.Form.NFC));
+                    mainClass = scl.loadClass(Normalizer.normalize(cn, Normalizer.Form.NFC));
                 } catch (NoClassDefFoundError | ClassNotFoundException cnfe1) {
                     abort(cnfe, "java.launcher.cls.error1", cn);
                 }
@@ -517,7 +598,8 @@
                 abort(cnfe, "java.launcher.cls.error1", cn);
             }
         }
-        // set to mainClass
+
+        // record the main class
         appClass = mainClass;
 
         /*
@@ -531,8 +613,6 @@
             FXHelper.setFXLaunchParameters(what, mode);
             return FXHelper.class;
         }
-
-        validateMainClass(mainClass);
         return mainClass;
     }
 
@@ -693,6 +773,9 @@
 
     static final class FXHelper {
 
+        private static final String JAVAFX_GRAPHICS_MODULE_NAME =
+                "javafx.graphics";
+
         private static final String JAVAFX_LAUNCHER_CLASS_NAME =
                 "com.sun.javafx.application.LauncherImpl";
 
@@ -725,9 +808,20 @@
          * issue with loading the FX runtime or with the launcher method.
          */
         private static void setFXLaunchParameters(String what, int mode) {
-            // Check for the FX launcher classes
+
+            // find the module with the FX launcher
+            Optional<Module> om = Layer.boot().findModule(JAVAFX_GRAPHICS_MODULE_NAME);
+            if (!om.isPresent()) {
+                abort(null, "java.launcher.cls.error5");
+            }
+
+            // load the FX launcher class
+            fxLauncherClass = Class.forName(om.get(), JAVAFX_LAUNCHER_CLASS_NAME);
+            if (fxLauncherClass == null) {
+                abort(null, "java.launcher.cls.error5");
+            }
+
             try {
-                fxLauncherClass = scloader.loadClass(JAVAFX_LAUNCHER_CLASS_NAME);
                 /*
                  * signature must be:
                  * public static void launchApplication(String launchName,
@@ -744,7 +838,7 @@
                 if (fxLauncherMethod.getReturnType() != java.lang.Void.TYPE) {
                     abort(null, "java.launcher.javafx.error1");
                 }
-            } catch (ClassNotFoundException | NoSuchMethodException ex) {
+            } catch (NoSuchMethodException ex) {
                 abort(ex, "java.launcher.cls.error5", ex);
             }
 
@@ -773,4 +867,97 @@
                     new Object[] {fxLaunchName, fxLaunchMode, args});
         }
     }
+
+    private static void formatCommaList(PrintStream out,
+                                        String prefix,
+                                        Collection<?> list)
+    {
+        if (list.isEmpty())
+            return;
+        out.format("%s", prefix);
+        boolean first = true;
+        for (Object ob : list) {
+            if (first) {
+                out.format(" %s", ob);
+                first = false;
+            } else {
+                out.format(", %s", ob);
+            }
+        }
+        out.format("%n");
+    }
+
+    /**
+     * Called by the launcher to list the observable modules.
+     * If called without any sub-options then the output is a simple list of
+     * the modules. If called with sub-options then the sub-options are the
+     * names of the modules to list (-listmods:java.base,java.desktop for
+     * example).
+     */
+    static void listModules(boolean printToStderr, String optionFlag)
+        throws IOException, ClassNotFoundException
+    {
+        initOutput(printToStderr);
+
+        ModuleFinder finder = jdk.internal.module.ModuleBootstrap.finder();
+
+        int colon = optionFlag.indexOf(':');
+        if (colon == -1) {
+            finder.findAll().stream()
+                .sorted(Comparator.comparing(ModuleReference::descriptor))
+                .forEach(md -> {
+                    ostream.println(midAndLocation(md.descriptor(),
+                                                   md.location()));
+                });
+        } else {
+            String[] names = optionFlag.substring(colon+1).split(",");
+            for (String name: names) {
+                ModuleReference mref = finder.find(name).orElse(null);
+                if (mref == null) {
+                    // not found
+                    continue;
+                }
+
+                ModuleDescriptor md = mref.descriptor();
+                ostream.println(midAndLocation(md, mref.location()));
+
+                for (Requires d : md.requires()) {
+                    ostream.format("  requires %s%n", d);
+                }
+                for (String s : md.uses()) {
+                    ostream.format("  uses %s%n", s);
+                }
+
+                // sorted exports
+                Set<Exports> exports = new TreeSet<>(Comparator.comparing(Exports::source));
+                exports.addAll(md.exports());
+                for (Exports e : exports) {
+                    ostream.format("  exports %s", e.source());
+                    if (e.isQualified()) {
+                        formatCommaList(ostream, " to", e.targets());
+                    } else {
+                        ostream.println();
+                    }
+                }
+
+                // concealed packages
+                new TreeSet<>(md.conceals())
+                    .forEach(p -> ostream.format("  conceals %s%n", p));
+
+                Map<String, Provides> provides = md.provides();
+                for (Provides ps : provides.values()) {
+                    for (String impl : ps.providers())
+                        ostream.format("  provides %s with %s%n", ps.service(), impl);
+                }
+            }
+        }
+    }
+
+    static String midAndLocation(ModuleDescriptor md, Optional<URI> location ) {
+        URI loc = location.orElse(null);
+        if (loc == null || loc.getScheme().equalsIgnoreCase("jrt"))
+            return md.toNameAndVersion();
+        else
+            return md.toNameAndVersion() + " (" + loc + ")";
+    }
 }
--- a/src/java.base/share/classes/sun/launcher/resources/launcher.properties	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/sun/launcher/resources/launcher.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -27,6 +27,8 @@
 java.launcher.opt.header  =   Usage: {0} [options] class [args...]\n\
 \           (to execute a class)\n   or  {0} [options] -jar jarfile [args...]\n\
 \           (to execute a jar file)\n\
+\   or  {0} [-options] -mp <modulepath> -m <modulename> | <modulename>/<mainclass>\n\
+\           (to execute the main class in a module)\n\
 where options include:\n
 
 java.launcher.opt.datamodel  =\    -d{0}\t  use a {0}-bit data model if available\n
@@ -41,6 +43,22 @@
 \    -classpath <class search path of directories and zip/jar files>\n\
 \                  A {0} separated list of directories, JAR archives,\n\
 \                  and ZIP archives to search for class files.\n\
+\    -mp <module path>\n\
+\    -modulepath <module path>...\n\
+\                  A {0} separated list of directories, each directory\n\
+\                  is a directory of modules.\n\
+\    -upgrademodulepath <module path>...\n\
+\                  A {0} separated list of directories, each directory\n\
+\                  is a directory of modules that replace upgradeable\n\
+\                  modules in the runtime image\n\
+\    -m <modulename> | <modulename>/<mainclass>\n\
+\                  the initial or main module to resolve\n\
+\    -addmods <modulename>[,<modulename>...]\n\
+\                  root modules to resolve in addition to the initial module\n\
+\    -limitmods <modulename>[,<modulename>...]\n\
+\                  limit the universe of observable modules\n\
+\    -listmods[:<modulename>[,<modulename>...]]\n\
+\                  list the observable modules and exit\n\
 \    -D<name>=<value>\n\
 \                  set a system property\n\
 \    -verbose:[class|gc|jni]\n\
@@ -76,13 +94,10 @@
 java.launcher.X.usage=\
 \    -Xmixed           mixed mode execution (default)\n\
 \    -Xint             interpreted mode execution only\n\
-\    -Xbootclasspath:<directories and zip/jar files separated by {0}>\n\
-\                      set search path for bootstrap classes and resources\n\
 \    -Xbootclasspath/a:<directories and zip/jar files separated by {0}>\n\
 \                      append to end of bootstrap class path\n\
-\    -Xbootclasspath/p:<directories and zip/jar files separated by {0}>\n\
-\                      prepend in front of bootstrap class path\n\
 \    -Xdiag            show additional diagnostic messages\n\
+\    -Xdiag:resolver   show resolver diagnostic messages\n\
 \    -Xnoclassgc       disable class garbage collection\n\
 \    -Xincgc           enable incremental garbage collection\n\
 \    -Xloggc:<file>    log GC status to a file with time stamps\n\
@@ -105,6 +120,15 @@
 \                      show all property settings and continue\n\
 \    -XshowSettings:locale\n\
 \                      show all locale related settings and continue\n\
+\    -XaddReads:<module>=<other-module>(,<other-module>)*\n\
+\                      <module> reads other modules,\n\
+\                      regardless of module declaration\n\
+\    -XaddExports:<module>/<package>=<other-module>(,<other-module>)*\n\
+\                      <module> exports <package> to other modules,\n\
+\                      regardless of module declaration\n\
+\    -Xpatch:<module>=<file>({0}<file>)*\n\
+\                      Override or augment a module with classes and resources\n\
+\                      in JAR files or directories\n\
 \    -Xdisable-@files  disable further argument file expansion\n\n\
 The -X options are non-standard and subject to change without notice.\n
 
@@ -142,3 +166,7 @@
 java.launcher.javafx.error1=\
     Error: The JavaFX launchApplication method has the wrong signature, it\n\
     must be declared static and return a value of type void
+java.launcher.module.error1=\
+    module {0} does not have a MainClass attribute, use -m <module>/<main-class>
+java.launcher.module.error2=\
+    Error: Could not find or load main class {0} in module {1}
--- a/src/java.base/share/classes/sun/misc/Launcher.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,520 +0,0 @@
-/*
- * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.misc;
-
-import java.io.File;
-import java.io.FilePermission;
-import java.io.IOException;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.net.MalformedURLException;
-import java.net.URLStreamHandler;
-import java.net.URLStreamHandlerFactory;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.security.PrivilegedExceptionAction;
-import java.security.AccessControlContext;
-import java.security.PermissionCollection;
-import java.security.Permissions;
-import java.security.Permission;
-import java.security.ProtectionDomain;
-import java.security.CodeSource;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import sun.net.www.ParseUtil;
-import sun.security.util.SecurityConstants;
-
-/**
- * This class is used by the system to launch the main application.
-Launcher */
-public class Launcher {
-
-    // ensure URLClassPath for boot loader is initialized first
-    static {
-        URLClassPath ucp = BootClassPathHolder.bcp;
-    }
-
-    private static URLStreamHandlerFactory factory = new Factory();
-    private static Launcher launcher = new Launcher();
-
-    public static Launcher getLauncher() {
-        return launcher;
-    }
-
-    private ClassLoader loader;
-
-    public Launcher() {
-        // Create the extension class loader
-        ClassLoader extcl;
-        try {
-            extcl = ExtClassLoader.getExtClassLoader();
-        } catch (IOException e) {
-            throw new InternalError(
-                "Could not create extension class loader", e);
-        }
-
-        // Now create the class loader to use to launch the application
-        try {
-            loader = AppClassLoader.getAppClassLoader(extcl);
-        } catch (IOException e) {
-            throw new InternalError(
-                "Could not create application class loader", e);
-        }
-
-        // Also set the context class loader for the primordial thread.
-        Thread.currentThread().setContextClassLoader(loader);
-
-        // Finally, install a security manager if requested
-        String s = System.getProperty("java.security.manager");
-        if (s != null) {
-            SecurityManager sm = null;
-            if ("".equals(s) || "default".equals(s)) {
-                sm = new java.lang.SecurityManager();
-            } else {
-                try {
-                    sm = (SecurityManager)loader.loadClass(s).newInstance();
-                } catch (IllegalAccessException e) {
-                } catch (InstantiationException e) {
-                } catch (ClassNotFoundException e) {
-                } catch (ClassCastException e) {
-                }
-            }
-            if (sm != null) {
-                System.setSecurityManager(sm);
-            } else {
-                throw new InternalError(
-                    "Could not create SecurityManager: " + s);
-            }
-        }
-    }
-
-    /*
-     * Returns the class loader used to launch the main application.
-     */
-    public ClassLoader getClassLoader() {
-        return loader;
-    }
-
-    /*
-     * The class loader used for loading installed extensions.
-     */
-    static class ExtClassLoader extends URLClassLoader {
-
-        static {
-            ClassLoader.registerAsParallelCapable();
-        }
-
-        /**
-         * create an ExtClassLoader. The ExtClassLoader is created
-         * within a context that limits which files it can read
-         */
-        public static ExtClassLoader getExtClassLoader() throws IOException {
-            try {
-                // Prior implementations of this doPrivileged() block supplied
-                // aa synthesized ACC via a call to the private method
-                // ExtClassLoader.getContext().
-
-                return AccessController.doPrivileged(
-                    new PrivilegedExceptionAction<ExtClassLoader>() {
-                        public ExtClassLoader run() throws IOException {
-                            // ext modules linked into image
-                            String home = System.getProperty("java.home");
-                            File dir = new File(new File(home, "lib"), "modules");
-                            File jimage = new File(dir, "extmodules.jimage");
-
-                            File jfxrt = new File(new File(home, "lib"), "jfxrt.jar");
-                            File[] files = jfxrt.exists() ? new File[] {jimage, jfxrt}
-                                                          : new File[] {jimage};
-                            return new ExtClassLoader(files);
-                        }
-                    });
-            } catch (java.security.PrivilegedActionException e) {
-                throw (IOException) e.getException();
-            }
-        }
-
-        void addExtURL(URL url) {
-            super.addURL(url);
-        }
-
-        /*
-         * Creates a new ExtClassLoader for the specified directories.
-         */
-        public ExtClassLoader(File[] files) throws IOException {
-            super(getExtURLs(files), null, factory);
-        }
-
-        private static URL[] getExtURLs(File[] files) throws IOException {
-            int len = files.length;
-            URL[] urls = new URL[len];
-            for (int i=0; i<len; i++) {
-                urls[i] = getFileURL(files[i]);
-            }
-            return urls;
-        }
-
-        private static AccessControlContext getContext(File[] dirs)
-            throws IOException
-        {
-            PathPermissions perms =
-                new PathPermissions(dirs);
-
-            ProtectionDomain domain = new ProtectionDomain(
-                new CodeSource(perms.getCodeBase(),
-                    (java.security.cert.Certificate[]) null),
-                perms);
-
-            AccessControlContext acc =
-                new AccessControlContext(new ProtectionDomain[] { domain });
-
-            return acc;
-        }
-    }
-
-    /**
-     * The class loader used for loading from java.class.path.
-     * runs in a restricted security context.
-     */
-    static class AppClassLoader extends URLClassLoader {
-
-        static {
-            ClassLoader.registerAsParallelCapable();
-        }
-
-        public static ClassLoader getAppClassLoader(final ClassLoader extcl)
-            throws IOException
-        {
-            // modules linked into image are prepended to class path
-            String home = System.getProperty("java.home");
-            File dir = new File(new File(home, "lib"), "modules");
-            String jimage = new File(dir, "appmodules.jimage").getPath();
-
-            String cp = System.getProperty("java.class.path");
-            if (cp == null) {
-                cp = jimage;
-            } else {
-                cp = jimage + File.pathSeparator + cp;
-            }
-            final File[] path = getClassPath(cp, true);
-
-            // Note: on bugid 4256530
-            // Prior implementations of this doPrivileged() block supplied
-            // a rather restrictive ACC via a call to the private method
-            // AppClassLoader.getContext(). This proved overly restrictive
-            // when loading  classes. Specifically it prevent
-            // accessClassInPackage.sun.* grants from being honored.
-            //
-            return AccessController.doPrivileged(
-                new PrivilegedAction<AppClassLoader>() {
-                    public AppClassLoader run() {
-                        URL[] urls = pathToURLs(path);
-                        return new AppClassLoader(urls, extcl);
-                }
-            });
-        }
-
-        /*
-         * Creates a new AppClassLoader
-         */
-        AppClassLoader(URL[] urls, ClassLoader parent) {
-            super(urls, parent, factory);
-        }
-
-        /**
-         * Override loadClass so we can checkPackageAccess.
-         */
-        public Class<?> loadClass(String name, boolean resolve)
-            throws ClassNotFoundException
-        {
-            int i = name.lastIndexOf('.');
-            if (i != -1) {
-                SecurityManager sm = System.getSecurityManager();
-                if (sm != null) {
-                    sm.checkPackageAccess(name.substring(0, i));
-                }
-            }
-            return (super.loadClass(name, resolve));
-        }
-
-        /**
-         * allow any classes loaded from classpath to exit the VM.
-         */
-        protected PermissionCollection getPermissions(CodeSource codesource) {
-            PermissionCollection perms = super.getPermissions(codesource);
-            perms.add(new RuntimePermission("exitVM"));
-            return perms;
-        }
-
-        /**
-         * This class loader supports dynamic additions to the class path
-         * at runtime.
-         *
-         * @see java.lang.instrument.Instrumentation#appendToSystemClassLoaderSearch
-         */
-        private void appendToClassPathForInstrumentation(String path) {
-            assert(Thread.holdsLock(this));
-
-            // addURL is a no-op if path already contains the URL
-            super.addURL( getFileURL(new File(path)) );
-        }
-
-        /**
-         * create a context that can read any directories (recursively)
-         * mentioned in the class path. In the case of a jar, it has to
-         * be the directory containing the jar, not just the jar, as jar
-         * files might refer to other jar files.
-         */
-
-        private static AccessControlContext getContext(File[] cp)
-            throws java.net.MalformedURLException
-        {
-            PathPermissions perms =
-                new PathPermissions(cp);
-
-            ProtectionDomain domain =
-                new ProtectionDomain(new CodeSource(perms.getCodeBase(),
-                    (java.security.cert.Certificate[]) null),
-                perms);
-
-            AccessControlContext acc =
-                new AccessControlContext(new ProtectionDomain[] { domain });
-
-            return acc;
-        }
-    }
-
-    private static class BootClassPathHolder {
-        static final URLClassPath bcp;
-        static {
-            URL[] urls = AccessController.doPrivileged(
-                    new PrivilegedAction<URL[]>() {
-                        public URL[] run() {
-                            String bootClassPath = System.getProperty("sun.boot.class.path");
-                            if (bootClassPath == null)
-                                return new URL[0];
-                            // Skip empty path in boot class path i.e. not default to use CWD
-                            return pathToURLs(getClassPath(bootClassPath, false));
-                        }
-                    }
-                );
-            bcp = new URLClassPath(urls, factory);
-        }
-    }
-
-    public static URLClassPath getBootstrapClassPath() {
-        return BootClassPathHolder.bcp;
-    }
-
-    private static URL[] pathToURLs(File[] path) {
-        URL[] urls = new URL[path.length];
-        for (int i = 0; i < path.length; i++) {
-            urls[i] = getFileURL(path[i]);
-        }
-        // DEBUG
-        //for (int i = 0; i < urls.length; i++) {
-        //  System.out.println("urls[" + i + "] = " + '"' + urls[i] + '"');
-        //}
-        return urls;
-    }
-
-    private static File[] getClassPath(String cp, boolean defaultToCwd) {
-        File[] path;
-        if (cp != null) {
-            int count = 0, maxCount = 1;
-            int pos = 0, lastPos = 0;
-            // Count the number of separators first
-            while ((pos = cp.indexOf(File.pathSeparator, lastPos)) != -1) {
-                maxCount++;
-                lastPos = pos + 1;
-            }
-            path = new File[maxCount];
-            lastPos = pos = 0;
-            // Now scan for each path component
-            while ((pos = cp.indexOf(File.pathSeparator, lastPos)) != -1) {
-                if (pos > lastPos) {
-                    path[count++] = new File(cp.substring(lastPos, pos));
-                } else if (defaultToCwd) {
-                    // empty path component translates to "."
-                    path[count++] = new File(".");
-                }
-                lastPos = pos + 1;
-            }
-            // Make sure we include the last path component
-            if (lastPos < cp.length()) {
-                path[count++] = new File(cp.substring(lastPos));
-            } else if (defaultToCwd) {
-                path[count++] = new File(".");
-            }
-            // Trim array to correct size
-            if (count != maxCount) {
-                File[] tmp = new File[count];
-                System.arraycopy(path, 0, tmp, 0, count);
-                path = tmp;
-            }
-        } else {
-            path = new File[0];
-        }
-        // DEBUG
-        //for (int i = 0; i < path.length; i++) {
-        //  System.out.println("path[" + i + "] = " + '"' + path[i] + '"');
-        //}
-        return path;
-    }
-
-    private static URLStreamHandler fileHandler;
-
-    static URL getFileURL(File file) {
-        try {
-            file = file.getCanonicalFile();
-        } catch (IOException e) {}
-
-        try {
-            return ParseUtil.fileToEncodedURL(file);
-        } catch (MalformedURLException e) {
-            // Should never happen since we specify the protocol...
-            throw new InternalError(e);
-        }
-    }
-
-    /*
-     * The stream handler factory for loading system protocol handlers.
-     */
-    private static class Factory implements URLStreamHandlerFactory {
-        private static String PREFIX = "sun.net.www.protocol";
-
-        public URLStreamHandler createURLStreamHandler(String protocol) {
-            String name = PREFIX + "." + protocol + ".Handler";
-            try {
-                Class<?> c = Class.forName(name);
-                return (URLStreamHandler)c.newInstance();
-            } catch (ReflectiveOperationException e) {
-                throw new InternalError("could not load " + protocol +
-                                        "system protocol handler", e);
-            }
-        }
-    }
-}
-
-class PathPermissions extends PermissionCollection {
-    // use serialVersionUID from JDK 1.2.2 for interoperability
-    private static final long serialVersionUID = 8133287259134945693L;
-
-    private File path[];
-    private Permissions perms;
-
-    URL codeBase;
-
-    PathPermissions(File path[])
-    {
-        this.path = path;
-        this.perms = null;
-        this.codeBase = null;
-    }
-
-    URL getCodeBase()
-    {
-        return codeBase;
-    }
-
-    public void add(java.security.Permission permission) {
-        throw new SecurityException("attempt to add a permission");
-    }
-
-    private synchronized void init()
-    {
-        if (perms != null)
-            return;
-
-        perms = new Permissions();
-
-        // this is needed to be able to create the classloader itself!
-        perms.add(SecurityConstants.CREATE_CLASSLOADER_PERMISSION);
-
-        // add permission to read any "java.*" property
-        perms.add(new java.util.PropertyPermission("java.*",
-            SecurityConstants.PROPERTY_READ_ACTION));
-
-        AccessController.doPrivileged(new PrivilegedAction<Void>() {
-            public Void run() {
-                for (int i=0; i < path.length; i++) {
-                    File f = path[i];
-                    String path;
-                    try {
-                        path = f.getCanonicalPath();
-                    } catch (IOException ioe) {
-                        path = f.getAbsolutePath();
-                    }
-                    if (i == 0) {
-                        codeBase = Launcher.getFileURL(new File(path));
-                    }
-                    if (f.isDirectory()) {
-                        if (path.endsWith(File.separator)) {
-                            perms.add(new FilePermission(path+"-",
-                                SecurityConstants.FILE_READ_ACTION));
-                        } else {
-                            perms.add(new FilePermission(
-                                path + File.separator+"-",
-                                SecurityConstants.FILE_READ_ACTION));
-                        }
-                    } else {
-                        int endIndex = path.lastIndexOf(File.separatorChar);
-                        if (endIndex != -1) {
-                            path = path.substring(0, endIndex+1) + "-";
-                            perms.add(new FilePermission(path,
-                                SecurityConstants.FILE_READ_ACTION));
-                        } else {
-                            // XXX?
-                        }
-                    }
-                }
-                return null;
-            }
-        });
-    }
-
-    public boolean implies(java.security.Permission permission) {
-        if (perms == null)
-            init();
-        return perms.implies(permission);
-    }
-
-    public java.util.Enumeration<Permission> elements() {
-        if (perms == null)
-            init();
-        synchronized (perms) {
-            return perms.elements();
-        }
-    }
-
-    public String toString() {
-        if (perms == null)
-            init();
-        return perms.toString();
-    }
-}
--- a/src/java.base/share/classes/sun/misc/URLClassPath.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/sun/misc/URLClassPath.java	Thu Mar 17 19:04:16 2016 +0000
@@ -25,7 +25,6 @@
 
 package sun.misc;
 
-import java.io.ByteArrayInputStream;
 import java.io.Closeable;
 import java.io.File;
 import java.io.FileInputStream;
@@ -56,7 +55,6 @@
 import java.util.Set;
 import java.util.Stack;
 import java.util.StringTokenizer;
-import java.util.concurrent.atomic.AtomicInteger;
 import java.util.jar.JarFile;
 import java.util.zip.ZipEntry;
 import java.util.jar.JarEntry;
@@ -65,14 +63,10 @@
 import java.util.jar.Attributes.Name;
 import java.util.zip.ZipFile;
 
-import jdk.internal.jimage.ImageLocation;
-import jdk.internal.jimage.ImageReader;
 import jdk.internal.misc.JavaUtilZipFileAccess;
 import jdk.internal.misc.SharedSecrets;
-
 import sun.net.util.URLUtil;
 import sun.net.www.ParseUtil;
-import sun.net.www.protocol.jrt.JavaRuntimeURLConnection;
 
 /**
  * This class is used to maintain a search path of URLs for loading classes
@@ -387,10 +381,6 @@
                             return new Loader(url);
                         }
                     } else {
-                        if (file != null && "file".equals(url.getProtocol())) {
-                            if (file.endsWith(".jimage"))
-                                return new JImageLoader(url);
-                        }
                         return new JarLoader(url, jarHandler, lmap);
                     }
                 }
@@ -446,13 +436,14 @@
      * Return null on security check failure.
      * Called by java.net.URLClassLoader.
      */
-    public URL checkURL(URL url) {
-        try {
-            check(url);
-        } catch (Exception e) {
-            return null;
+    public static URL checkURL(URL url) {
+        if (url != null) {
+            try {
+                check(url);
+            } catch (Exception e) {
+                return null;
+            }
         }
-
         return url;
     }
 
@@ -461,7 +452,7 @@
      * Throw exception on failure.
      * Called internally within this file.
      */
-    static void check(URL url) throws IOException {
+    public static void check(URL url) throws IOException {
         SecurityManager security = System.getSecurityManager();
         if (security != null) {
             URLConnection urlConnection = url.openConnection();
@@ -1086,132 +1077,4 @@
             return null;
         }
     }
-
-    /**
-     * A Loader of classes and resources from a jimage file located in the
-     * runtime image.
-     */
-    private static class JImageLoader
-        extends Loader implements JavaRuntimeURLConnection.ResourceFinder
-    {
-        private static final AtomicInteger NEXT_INDEX = new AtomicInteger();
-
-        private final ImageReader jimage;
-        private final int index;
-
-        JImageLoader(URL url) throws IOException {
-            super(url);
-
-            // get path to image file and check that it's in the runtime
-            String urlPath = url.getFile().replace('/', File.separatorChar);
-
-            File filePath = new File(ParseUtil.decode(urlPath));
-            File home = new File(JAVA_HOME).getCanonicalFile();
-            File parent = filePath.getParentFile();
-            while (parent != null) {
-                if (parent.equals(home))
-                    break;
-                parent = parent.getParentFile();
-            }
-            if (parent == null)
-                throw new IOException(filePath + " not in runtime image");
-
-            this.jimage = ImageReader.open(filePath.toString());
-            this.index = NEXT_INDEX.getAndIncrement();
-
-            // register with the jimage protocol handler
-            JavaRuntimeURLConnection.register(this);
-        }
-
-        /**
-         * Maps the given resource name to a module.
-         */
-        private String nameToModule(String name) {
-            int pos = name.lastIndexOf('/');
-            if (pos > 0) {
-                String pkg = name.substring(0, pos);
-                String module = jimage.getModule(pkg);
-                if (module != null)
-                    return module;
-            }
-            // cannot map to module
-            return "UNNAMED" + index;
-        }
-
-        /**
-         * Constructs a URL for the resource name.
-         */
-        private URL toURL(String name) {
-            String module = nameToModule(name);
-            String encodedName = ParseUtil.encodePath(name, false);
-            try {
-                return new URL("jrt:/" + module + "/" + encodedName);
-            } catch (MalformedURLException e) {
-                throw new InternalError(e);
-            }
-        }
-
-        @Override
-        URL findResource(String name, boolean check) {
-            ImageLocation location = jimage.findLocation(name);
-            if (location == null)
-                return null;
-            URL url = toURL(name);
-            if (check) {
-                try {
-                    URLClassPath.check(url);
-                } catch (IOException | SecurityException e) {
-                    return null;
-                }
-            }
-            return url;
-        }
-
-        @Override
-        Resource getResource(String name, boolean check) {
-            ImageLocation location = jimage.findLocation(name);
-            if (location == null)
-                return null;
-            URL url = toURL(name);
-            if (check) {
-                try {
-                    URLClassPath.check(url);
-                } catch (IOException | SecurityException e) {
-                    return null;
-                }
-            }
-            return new Resource() {
-                @Override
-                public String getName() { return name; }
-                @Override
-                public URL getURL() { return url; }
-                @Override
-                public URL getCodeSourceURL() {
-                    try {
-                        return new URL("jrt:/" + nameToModule(name));
-                    } catch (MalformedURLException e) {
-                        throw new InternalError(e);
-                    }
-                }
-                @Override
-                public InputStream getInputStream() throws IOException {
-                    byte[] resource = jimage.getResource(location);
-                    return new ByteArrayInputStream(resource);
-                }
-                public int getContentLength() {
-                    long size = location.getUncompressedSize();
-                    return (size > Integer.MAX_VALUE) ? -1 : (int)size;
-                }
-            };
-        }
-
-        @Override
-        public Resource find(String module, String name) throws IOException {
-            String m = nameToModule(name);
-            if (!m.equals(module))
-                return null;
-            // URLConnection will do the permission check
-            return getResource(name, false);
-        }
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/net/www/protocol/jmod/Handler.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.net.www.protocol.jmod;
+
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLStreamHandler;
+import java.net.MalformedURLException;
+import java.io.IOException;
+
+/**
+ * Placeholder protocol handler for the jmod protocol.
+ */
+
+public class Handler extends URLStreamHandler {
+    public Handler() { }
+
+    @Override
+    protected URLConnection openConnection(URL url) throws IOException {
+        String s = url.toString();
+        int index = s.indexOf("!/");
+        if (index == -1)
+            throw new MalformedURLException("no !/ found in url spec:" + s);
+
+        throw new IOException("Can't connect to jmod URL");
+    }
+}
--- a/src/java.base/share/classes/sun/net/www/protocol/jrt/JavaRuntimeURLConnection.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/sun/net/www/protocol/jrt/JavaRuntimeURLConnection.java	Thu Mar 17 19:04:16 2016 +0000
@@ -25,6 +25,7 @@
 
 package sun.net.www.protocol.jrt;
 
+import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.FilePermission;
 import java.io.IOException;
@@ -35,8 +36,12 @@
 import java.security.Permission;
 import java.security.PrivilegedAction;
 import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
 
+import jdk.internal.jimage.ImageLocation;
+import jdk.internal.jimage.ImageReader;
+import jdk.internal.jimage.ImageReaderFactory;
+
+import sun.misc.URLClassPath;
 import sun.misc.Resource;
 import sun.net.www.ParseUtil;
 import sun.net.www.URLConnection;
@@ -47,33 +52,8 @@
  */
 public class JavaRuntimeURLConnection extends URLConnection {
 
-    /**
-     * Finds resource {@code name} in module {@code module}.
-     */
-    public interface ResourceFinder {
-        Resource find(String module, String name) throws IOException;
-    }
-
-    /**
-     * The list of resource finders for jimages in the runtime image.
-     */
-    private static final List<ResourceFinder> finders = new CopyOnWriteArrayList<>();
-
-    /**
-     * Called on behalf of the boot, extension and system class loaders to
-     * register a resource finder.
-     */
-    public static void register(ResourceFinder finder) {
-        finders.add(finder);
-    }
-
-    private static Resource find(String module, String name) throws IOException {
-        for (ResourceFinder finder: finders) {
-            Resource r = finder.find(module, name);
-            if (r != null) return r;
-        }
-        return null;
-    }
+    // ImageReader to access resources in jimage
+    private static final ImageReader reader = ImageReaderFactory.getImageReader();
 
     // the module and resource name in the URL
     private final String module;
@@ -105,6 +85,44 @@
         }
     }
 
+    /**
+     * Finds a resource in a module, returning {@code null} if the resource
+     * is not found.
+     */
+    private static Resource findResource(String module, String name) {
+        if (reader != null) {
+            URL url = toJrtURL(module, name);
+            ImageLocation location = reader.findLocation(module, name);
+            if (location != null && URLClassPath.checkURL(url) != null) {
+                return new Resource() {
+                    @Override
+                    public String getName() {
+                        return name;
+                    }
+                    @Override
+                    public URL getURL() {
+                        return url;
+                    }
+                    @Override
+                    public URL getCodeSourceURL() {
+                        return toJrtURL(module);
+                    }
+                    @Override
+                    public InputStream getInputStream() throws IOException {
+                        byte[] resource = reader.getResource(location);
+                        return new ByteArrayInputStream(resource);
+                    }
+                    @Override
+                    public int getContentLength() {
+                        long size = location.getUncompressedSize();
+                        return (size > Integer.MAX_VALUE) ? -1 : (int) size;
+                    }
+                };
+            }
+        }
+        return null;
+    }
+
     @Override
     public synchronized void connect() throws IOException {
         if (!connected) {
@@ -112,7 +130,7 @@
                 String s = (module == null) ? "" : module;
                 throw new IOException("cannot connect to jrt:/" + s);
             }
-            resource = find(module, name);
+            resource = findResource(module, name);
             if (resource == null)
                 throw new IOException(module + "/" + name + " not found");
             connected = true;
@@ -155,4 +173,26 @@
         }
         return p;
     }
+
+    /**
+     * Returns a jrt URL for the given module and resource name.
+     */
+    private static URL toJrtURL(String module, String name) {
+        try {
+            return new URL("jrt:/" + module + "/" + name);
+        } catch (MalformedURLException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    /**
+     * Returns a jrt URL for the given module.
+     */
+    private static URL toJrtURL(String module) {
+        try {
+            return new URL("jrt:/" + module);
+        } catch (MalformedURLException e) {
+            throw new InternalError(e);
+        }
+    }
 }
--- a/src/java.base/share/classes/sun/reflect/Reflection.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/sun/reflect/Reflection.java	Thu Mar 17 19:04:16 2016 +0000
@@ -25,9 +25,13 @@
 
 package sun.reflect;
 
+
 import java.lang.reflect.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Objects;
 import jdk.internal.HotSpotIntrinsicCandidate;
 import jdk.internal.misc.VM;
 
@@ -80,13 +84,6 @@
     @HotSpotIntrinsicCandidate
     public static native int getClassAccessFlags(Class<?> c);
 
-    /** A quick "fast-path" check to try to avoid getCallerClass()
-        calls. */
-    public static boolean quickCheckMemberAccess(Class<?> memberClass,
-                                                 int modifiers)
-    {
-        return Modifier.isPublic(getClassAccessFlags(memberClass) & modifiers);
-    }
 
     public static void ensureMemberAccess(Class<?> currentClass,
                                           Class<?> memberClass,
@@ -99,12 +96,7 @@
         }
 
         if (!verifyMemberAccess(currentClass, memberClass, target, modifiers)) {
-            throw new IllegalAccessException("Class " + currentClass.getName() +
-                                             " can not access a member of class " +
-                                             memberClass.getName() +
-                                             " with modifiers \"" +
-                                             Modifier.toString(modifiers) +
-                                             "\"");
+            throwIllegalAccessException(currentClass, memberClass, target, modifiers);
         }
     }
 
@@ -128,6 +120,10 @@
             return true;
         }
 
+        if (!verifyModuleAccess(currentClass, memberClass)) {
+            return false;
+        }
+
         if (!Modifier.isPublic(getClassAccessFlags(memberClass))) {
             isSameClassPackage = isSameClassPackage(currentClass, memberClass);
             gotIsSameClassPackage = true;
@@ -186,59 +182,45 @@
         return true;
     }
 
-    private static boolean isSameClassPackage(Class<?> c1, Class<?> c2) {
-        return isSameClassPackage(c1.getClassLoader(), c1.getName(),
-                                  c2.getClassLoader(), c2.getName());
+    /**
+     * Returns {@code true} if memberClass's's module exports memberClass's
+     * package to currentClass's module.
+     */
+    public static boolean verifyModuleAccess(Class<?> currentClass,
+                                             Class<?> memberClass) {
+        return verifyModuleAccess(currentClass.getModule(), memberClass);
     }
 
-    /** Returns true if two classes are in the same package; classloader
-        and classname information is enough to determine a class's package */
-    private static boolean isSameClassPackage(ClassLoader loader1, String name1,
-                                              ClassLoader loader2, String name2)
-    {
-        if (loader1 != loader2) {
-            return false;
-        } else {
-            int lastDot1 = name1.lastIndexOf('.');
-            int lastDot2 = name2.lastIndexOf('.');
-            if ((lastDot1 == -1) || (lastDot2 == -1)) {
-                // One of the two doesn't have a package.  Only return true
-                // if the other one also doesn't have a package.
-                return (lastDot1 == lastDot2);
-            } else {
-                int idx1 = 0;
-                int idx2 = 0;
+    public static boolean verifyModuleAccess(Module currentModule, Class<?> memberClass) {
+        Module memberModule = memberClass.getModule();
+
+        // module may be null during startup (initLevel 0)
+        if (currentModule == memberModule)
+           return true;  // same module (named or unnamed)
+
+        // memberClass may be primitive or array class
+        Class<?> c = memberClass;
+        while (c.isArray()) {
+            c = c.getComponentType();
+        }
+        if (c.isPrimitive())
+            return true;
 
-                // Skip over '['s
-                if (name1.charAt(idx1) == '[') {
-                    do {
-                        idx1++;
-                    } while (name1.charAt(idx1) == '[');
-                    if (name1.charAt(idx1) != 'L') {
-                        // Something is terribly wrong.  Shouldn't be here.
-                        throw new InternalError("Illegal class name " + name1);
-                    }
-                }
-                if (name2.charAt(idx2) == '[') {
-                    do {
-                        idx2++;
-                    } while (name2.charAt(idx2) == '[');
-                    if (name2.charAt(idx2) != 'L') {
-                        // Something is terribly wrong.  Shouldn't be here.
-                        throw new InternalError("Illegal class name " + name2);
-                    }
-                }
+        // check that memberModule exports the package to currentModule
+        return memberModule.isExported(c.getPackageName(), currentModule);
+    }
 
-                // Check that package part is identical
-                int length1 = lastDot1 - idx1;
-                int length2 = lastDot2 - idx2;
-
-                if (length1 != length2) {
-                    return false;
-                }
-                return name1.regionMatches(false, idx1, name2, idx2, length1);
-            }
-        }
+    /**
+     * Returns true if two classes in the same package.
+     */
+    private static boolean isSameClassPackage(Class<?> c1, Class<?> c2) {
+        if (c1.getClassLoader() != c2.getClassLoader())
+            return false;
+        while (c1.isArray())
+            c1 = c1.getComponentType();
+        while (c2.isArray())
+            c2 = c2.getComponentType();
+        return Objects.equals(c1.getPackageName(), c2.getPackageName());
     }
 
     static boolean isSubclassOf(Class<?> queryClass,
@@ -332,7 +314,7 @@
 
     /**
      * Tests if the given method is caller-sensitive and the declaring class
-     * is defined by either the bootstrap class loader or extension class loader.
+     * is defined by either the bootstrap class loader or platform class loader.
      */
     public static boolean isCallerSensitive(Method m) {
         final ClassLoader loader = m.getDeclaringClass().getClassLoader();
@@ -352,4 +334,92 @@
         }
         return false;
     }
+
+
+    // true to print a stack trace when IAE is thrown
+    private static volatile boolean printStackWhenAccessFails;
+
+    // true if printStackWhenAccessFails has been initialized
+    private static volatile boolean printStackWhenAccessFailsSet;
+
+    private static void printStackTraceIfNeeded(Throwable e) {
+        if (!printStackWhenAccessFailsSet && VM.initLevel() >= 1) {
+            // can't use method reference here, might be too early in startup
+            PrivilegedAction<Boolean> pa = new PrivilegedAction<Boolean>() {
+                public Boolean run() {
+                    String s;
+                    s = System.getProperty("sun.reflect.debugModuleAccessChecks");
+                    return (s != null && !s.equalsIgnoreCase("false"));
+                }
+            };
+            printStackWhenAccessFails = AccessController.doPrivileged(pa);
+            printStackWhenAccessFailsSet = true;
+        }
+        if (printStackWhenAccessFails) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * Throws IllegalAccessException with the an exception message based on
+     * the access that is denied.
+     */
+    private static void throwIllegalAccessException(Class<?> currentClass,
+                                                    Class<?> memberClass,
+                                                    Object target,
+                                                    int modifiers)
+        throws IllegalAccessException
+    {
+        String currentSuffix = "";
+        String memberSuffix = "";
+        Module m1 = currentClass.getModule();
+        if (m1.isNamed())
+            currentSuffix = " (in " + m1 + ")";
+        Module m2 = memberClass.getModule();
+        if (m2.isNamed())
+            memberSuffix = " (in " + m2 + ")";
+
+        Class<?> c = memberClass;
+        while (c.isArray()) {
+            c = c.getComponentType();
+        }
+        String memberPackageName = c.getPackageName();
+
+        String msg = currentClass + currentSuffix + " cannot access ";
+        if (m2.isExported(memberPackageName, m1)) {
+
+            // module access okay so include the modifiers in the message
+            msg += "a member of " + memberClass + memberSuffix +
+                    " with modifiers \"" + Modifier.toString(modifiers) + "\"";
+
+        } else {
+            // module access failed
+            msg += memberClass + memberSuffix+ " because "
+                   + m2 + " does not export " + memberPackageName;
+            if (m2.isNamed()) msg += " to " + m1;
+        }
+
+        throwIllegalAccessException(msg);
+    }
+
+    /**
+     * Throws IllegalAccessException with the given exception message.
+     */
+    public static void throwIllegalAccessException(String msg)
+        throws IllegalAccessException
+    {
+        IllegalAccessException e = new IllegalAccessException(msg);
+        printStackTraceIfNeeded(e);
+        throw e;
+    }
+
+    /**
+     * Throws InaccessibleObjectException with the given exception message.
+     */
+    public static void throwInaccessibleObjectException(String msg) {
+        InaccessibleObjectException e = new InaccessibleObjectException(msg);
+        printStackTraceIfNeeded(e);
+        throw e;
+    }
+
 }
--- a/src/java.base/share/classes/sun/reflect/misc/MethodUtil.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/sun/reflect/misc/MethodUtil.java	Thu Mar 17 19:04:16 2016 +0000
@@ -25,6 +25,7 @@
 
 package sun.reflect.misc;
 
+import java.lang.reflect.Module;
 import java.io.EOFException;
 import java.security.AllPermission;
 import java.security.AccessController;
@@ -39,7 +40,6 @@
 import java.net.URLConnection;
 import java.lang.reflect.Method;
 import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.AccessibleObject;
 import java.lang.reflect.Modifier;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -329,24 +329,26 @@
             throw new ClassNotFoundException(name);
         }
         String path = name.replace('.', '/').concat(".class");
-        URL res = getResource(path);
-        if (res != null) {
-            try {
-                return defineClass(name, res);
-            } catch (IOException e) {
-                throw new ClassNotFoundException(name, e);
+        try {
+            InputStream in = Object.class.getModule().getResourceAsStream(path);
+            if (in != null) {
+                try (in) {
+                    byte[] b = in.readAllBytes();
+                    return defineClass(name, b);
+                }
             }
-        } else {
-            throw new ClassNotFoundException(name);
+        } catch (IOException e) {
+            throw new ClassNotFoundException(name, e);
         }
+
+        throw new ClassNotFoundException(name);
     }
 
 
     /*
      * Define the proxy classes
      */
-    private Class<?> defineClass(String name, URL url) throws IOException {
-        byte[] b = getBytes(url);
+    private Class<?> defineClass(String name, byte[] b) throws IOException {
         CodeSource cs = new CodeSource(null, (java.security.cert.Certificate[])null);
         if (!name.equals(TRAMPOLINE)) {
             throw new IOException("MethodUtil: bad name " + name);
@@ -354,29 +356,6 @@
         return defineClass(name, b, 0, b.length, cs);
     }
 
-
-    /*
-     * Returns the contents of the specified URL as an array of bytes.
-     */
-    private static byte[] getBytes(URL url) throws IOException {
-        URLConnection uc = url.openConnection();
-        if (uc instanceof java.net.HttpURLConnection) {
-            java.net.HttpURLConnection huc = (java.net.HttpURLConnection) uc;
-            int code = huc.getResponseCode();
-            if (code >= java.net.HttpURLConnection.HTTP_BAD_REQUEST) {
-                throw new IOException("open HTTP connection failed.");
-            }
-        }
-        int len = uc.getContentLength();
-        try (InputStream in = new BufferedInputStream(uc.getInputStream())) {
-            byte[] b = in.readAllBytes();
-            if (len != -1 && b.length != len)
-                throw new EOFException("Expected:" + len + ", read:" + b.length);
-            return b;
-        }
-    }
-
-
     protected PermissionCollection getPermissions(CodeSource codesource)
     {
         PermissionCollection perms = super.getPermissions(codesource);
--- a/src/java.base/share/classes/sun/reflect/misc/ReflectUtil.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/sun/reflect/misc/ReflectUtil.java	Thu Mar 17 19:04:16 2016 +0000
@@ -30,7 +30,6 @@
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.Proxy;
-import java.util.Arrays;
 import sun.reflect.Reflection;
 import sun.security.util.SecurityConstants;
 
@@ -45,12 +44,6 @@
         return Class.forName(name);
     }
 
-    public static Object newInstance(Class<?> cls)
-        throws InstantiationException, IllegalAccessException {
-        checkPackageAccess(cls);
-        return cls.newInstance();
-    }
-
     /*
      * Reflection.ensureMemberAccess is overly-restrictive
      * due to a bug. We awkwardly work around it for now.
@@ -286,7 +279,7 @@
         String name = cls.getName();
         int i = name.lastIndexOf('.');
         String pkg = (i != -1) ? name.substring(0, i) : "";
-        return Proxy.isProxyClass(cls) && !pkg.equals(PROXY_PACKAGE);
+        return Proxy.isProxyClass(cls) && !pkg.startsWith(PROXY_PACKAGE);
     }
 
     /**
--- a/src/java.base/share/classes/sun/security/jca/ProviderList.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/sun/security/jca/ProviderList.java	Thu Mar 17 19:04:16 2016 +0000
@@ -36,8 +36,10 @@
 /**
  * List of Providers. Used to represent the provider preferences.
  *
- * The system starts out with a ProviderList that only has the classNames
- * of the Providers. Providers are loaded on demand only when needed.
+ * The system starts out with a ProviderList that only has the names
+ * of the Providers.
+ * When using ServiceLoader to load the providers, Providers are created
+ * semi-eagerly as we iterate through them looking for a match.
  *
  * For compatibility reasons, Providers that could not be loaded are ignored
  * and internally presented as the instance EMPTY_PROVIDER. However, those
--- a/src/java.base/share/classes/sun/security/jca/Providers.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/sun/security/jca/Providers.java	Thu Mar 17 19:04:16 2016 +0000
@@ -86,10 +86,7 @@
         "SunRsaSign",
         // Note: when SunEC is in a signed JAR file, it's not signed
         // by EC algorithms. So it's still safe to be listed here.
-        // Need to use class name here, otherwise it cannot be loaded for
-        // jar verification. Only those providers in java.base are created
-        // directly by ProviderConfig class.
-        "sun.security.ec.SunEC",
+        "SunEC",
     };
 
     // Return Sun provider.
--- a/src/java.base/share/classes/sun/security/provider/PolicyFile.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/sun/security/provider/PolicyFile.java	Thu Mar 17 19:04:16 2016 +0000
@@ -275,7 +275,6 @@
 
     // contains the policy grant entries, PD cache, and alias mapping
     private AtomicReference<PolicyInfo> policyInfo = new AtomicReference<>();
-    private boolean constructed = false;
 
     private boolean expandProperties = true;
     private boolean allowSystemProperties = true;
@@ -910,9 +909,8 @@
                NoSuchMethodException,
                InvocationTargetException
     {
-        //XXX we might want to keep a hash of created factories...
         Class<?> pc = Class.forName(type, false, null);
-        Permission answer = getKnownInstance(pc, name, actions);
+        Permission answer = getKnownPermission(pc, name, actions);
         if (answer != null) {
             return answer;
         }
@@ -955,12 +953,12 @@
     }
 
     /**
-     * Creates one of the well-known permissions directly instead of
-     * via reflection. Keep list short to not penalize non-JDK-defined
-     * permissions.
+     * Creates one of the well-known permissions in the java.base module
+     * directly instead of via reflection. Keep list short to not penalize
+     * permissions from other modules.
      */
-    private static final Permission getKnownInstance(Class<?> claz,
-        String name, String actions) {
+    private static Permission getKnownPermission(Class<?> claz, String name,
+                                                 String actions) {
         if (claz.equals(FilePermission.class)) {
             return new FilePermission(name, actions);
         } else if (claz.equals(SocketPermission.class)) {
@@ -973,6 +971,21 @@
             return new NetPermission(name, actions);
         } else if (claz.equals(AllPermission.class)) {
             return SecurityConstants.ALL_PERMISSION;
+        } else if (claz.equals(SecurityPermission.class)) {
+            return new SecurityPermission(name, actions);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Creates one of the well-known principals in the java.base module
+     * directly instead of via reflection. Keep list short to not penalize
+     * principals from other modules.
+     */
+    private static Principal getKnownPrincipal(Class<?> claz, String name) {
+        if (claz.equals(X500Principal.class)) {
+            return new X500Principal(name);
         } else {
             return null;
         }
@@ -1305,16 +1318,20 @@
             try {
                 ClassLoader cl = Thread.currentThread().getContextClassLoader();
                 Class<?> pClass = Class.forName(pppe.principalClass, false, cl);
-                if (!Principal.class.isAssignableFrom(pClass)) {
-                    // not the right subtype
-                    throw new ClassCastException(pppe.principalClass +
-                                                 " is not a Principal");
+                Principal p = getKnownPrincipal(pClass, pppe.principalName);
+                if (p == null) {
+                    if (!Principal.class.isAssignableFrom(pClass)) {
+                        // not the right subtype
+                        throw new ClassCastException(pppe.principalClass +
+                                                     " is not a Principal");
+                    }
+
+                    Constructor<?> c = pClass.getConstructor(PARAMS1);
+                    p = (Principal)c.newInstance(new Object[] {
+                                                 pppe.principalName });
+
                 }
 
-                Constructor<?> c = pClass.getConstructor(PARAMS1);
-                Principal p = (Principal)c.newInstance(new Object[] {
-                                                       pppe.principalName });
-
                 if (debug != null) {
                     debug.println("found Principal " + p.getClass().getName());
                 }
--- a/src/java.base/share/classes/sun/security/util/SecurityConstants.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/sun/security/util/SecurityConstants.java	Thu Mar 17 19:04:16 2016 +0000
@@ -98,7 +98,7 @@
     public static final NetPermission GET_RESPONSECACHE_PERMISSION =
        new NetPermission("getResponseCache");
 
-    // java.lang.SecurityManager, sun.applet.AppletPanel, sun.misc.Launcher
+    // java.lang.SecurityManager, sun.applet.AppletPanel
     public static final RuntimePermission CREATE_CLASSLOADER_PERMISSION =
         new RuntimePermission("createClassLoader");
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/text/resources/BreakIteratorInfoProvider.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.text.resources;
+
+import java.util.spi.ResourceBundleProvider;
+
+/**
+ * An interface for the internal locale data provider for which {@code ResourceBundle}
+ * searches.
+ */
+public interface BreakIteratorInfoProvider extends ResourceBundleProvider {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/text/resources/BreakIteratorRulesProvider.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.text.resources;
+
+import java.util.spi.ResourceBundleProvider;
+
+/**
+ * An interface for the internal locale data provider for which {@code ResourceBundle}
+ * searches.
+ */
+public interface BreakIteratorRulesProvider extends ResourceBundleProvider {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/text/resources/CollationDataProvider.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.text.resources;
+
+import java.util.spi.ResourceBundleProvider;
+
+/**
+ * An interface for the internal locale data provider for which {@code ResourceBundle}
+ * searches.
+ */
+public interface CollationDataProvider extends ResourceBundleProvider {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/text/resources/FormatDataProvider.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.text.resources;
+
+import java.util.spi.ResourceBundleProvider;
+
+/**
+ * An interface for the internal locale data provider for which {@code ResourceBundle}
+ * searches.
+ */
+public interface FormatDataProvider extends ResourceBundleProvider {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/text/resources/JavaTimeSupplementaryProvider.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.text.resources;
+
+import java.util.spi.ResourceBundleProvider;
+
+/**
+ * An interface for the internal locale data provider for which {@code ResourceBundle}
+ * searches.
+ */
+public interface JavaTimeSupplementaryProvider extends ResourceBundleProvider {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/text/resources/cldr/FormatDataProvider.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.text.resources.cldr;
+
+import java.util.spi.ResourceBundleProvider;
+
+/**
+ * An interface for the internal locale data provider for which {@code ResourceBundle}
+ * searches.
+ */
+public interface FormatDataProvider extends ResourceBundleProvider {
+}
--- a/src/java.base/share/classes/sun/util/CoreResourceBundleControl-XLocales.java.template	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,114 +0,0 @@
-/*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#warn This file is preprocessed before being compiled
-
-package sun.util;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.ResourceBundle;
-import java.util.ResourceBundle.Control;
-
-/**
- * This is a convenient class for loading some of internal resources faster
- * if they are built with Resources.gmk defined in J2SE workspace. Also,
- * they have to be in class file format.
- *
- * "LOCALE_LIST" will be replaced at built time by a list of locales we
- * defined in Defs.gmk. We want to exclude these locales from search to
- * gain better performance. For example, since we know if the resource
- * is built with Resources.gmk, they are not going to provide basename_en.class
- * & basename_en_US.class resources, in that case, continuing searching them
- * is expensive. By excluding them from the candidate locale list, these
- * resources won't be searched.
- *
- * @since 1.6.
- */
-public class CoreResourceBundleControl extends ResourceBundle.Control {
-    /* the candidate locale list to search */
-    private final Collection<Locale> excludedJDKLocales;
-    /* singlton instance of the resource bundle control. */
-    private static CoreResourceBundleControl resourceBundleControlInstance =
-        new CoreResourceBundleControl();
-
-    protected CoreResourceBundleControl() {
-        excludedJDKLocales = Arrays.asList(#LOCALE_LIST#);
-    }
-
-    /**
-     * This method is to provide a customized ResourceBundle.Control to speed
-     * up the search of resources in JDK.
-     *
-     * @return the instance of resource bundle control.
-     */
-    public static CoreResourceBundleControl getRBControlInstance() {
-        return resourceBundleControlInstance;
-    }
-
-    /**
-     * This method is to provide a customized ResourceBundle.Control to speed
-     * up the search of resources in JDK, with the bundle's package name check.
-     *
-     * @param bundleName bundle name to check
-     * @return the instance of resource bundle control if the bundle is JDK's,
-     *    otherwise returns null.
-     */
-    public static CoreResourceBundleControl getRBControlInstance(String bundleName) {
-        if (bundleName.startsWith("com.sun.") ||
-            bundleName.startsWith("java.") ||
-            bundleName.startsWith("javax.") ||
-            bundleName.startsWith("sun.")) {
-            return resourceBundleControlInstance;
-        } else {
-            return null;
-        }
-    }
-
-    /**
-     * @return a list of candidate locales to search from.
-     * @exception NullPointerException if baseName or locale is null.
-     */
-    @Override
-    public List<Locale> getCandidateLocales(String baseName, Locale locale) {
-        List<Locale> candidates = super.getCandidateLocales(baseName, locale);
-        candidates.removeAll(excludedJDKLocales);
-        return candidates;
-    }
-
-    /**
-     * @ returns TTL_DONT_CACHE so that ResourceBundle instance won't be cached.
-     * User of this CoreResourceBundleControl should probably maintain a hard reference
-     * to the ResourceBundle object themselves.
-     */
-    @Override
-    public long getTimeToLive(String baseName, Locale locale) {
-        return ResourceBundle.Control.TTL_DONT_CACHE;
-    }
-}
--- a/src/java.base/share/classes/sun/util/locale/provider/BreakDictionary.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/sun/util/locale/provider/BreakDictionary.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -40,7 +40,9 @@
 package sun.util.locale.provider;
 
 import java.io.BufferedInputStream;
+import java.io.InputStream;
 import java.io.IOException;
+import java.lang.reflect.Module;
 import java.security.AccessController;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
@@ -135,25 +137,29 @@
     // deserialization
     //=========================================================================
 
-    BreakDictionary(String dictionaryName)
+    BreakDictionary(Module module, String dictionaryName)
         throws IOException, MissingResourceException {
 
-        readDictionaryFile(dictionaryName);
+        readDictionaryFile(module, dictionaryName);
     }
 
-    private void readDictionaryFile(final String dictionaryName)
+    private void readDictionaryFile(final Module module, final String dictionaryName)
         throws IOException, MissingResourceException {
 
         BufferedInputStream in;
         try {
-            in = AccessController.doPrivileged(
-                new PrivilegedExceptionAction<BufferedInputStream>() {
-                    @Override
-                    public BufferedInputStream run() throws Exception {
-                        return new BufferedInputStream(getClass().getResourceAsStream("/sun/text/resources/" + dictionaryName));
-                    }
+            PrivilegedExceptionAction<BufferedInputStream> pa = () -> {
+                InputStream is = module.getResourceAsStream("sun/text/resources/" + dictionaryName);
+                if (is == null) {
+                    // Try to load the file with "java.base" module instance. Assumption
+                    // here is that the fall back data files to be read should reside in
+                    // java.base.
+                    is = BreakDictionary.class.getModule().getResourceAsStream("sun/text/resources/" + dictionaryName);
                 }
-            );
+
+                return new BufferedInputStream(is);
+            };
+            in = AccessController.doPrivileged(pa);
         }
         catch (PrivilegedActionException e) {
             throw new InternalError(e.toString(), e);
--- a/src/java.base/share/classes/sun/util/locale/provider/BreakIteratorProviderImpl.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/sun/util/locale/provider/BreakIteratorProviderImpl.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,6 +30,7 @@
 import java.text.spi.BreakIteratorProvider;
 import java.util.Locale;
 import java.util.MissingResourceException;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -155,9 +156,7 @@
                                                   int type,
                                                   String dataName,
                                                   String dictionaryName) {
-        if (locale == null) {
-            throw new NullPointerException();
-        }
+        Objects.requireNonNull(locale);
 
         LocaleResources lr = LocaleProviderAdapter.forJRE().getLocaleResources(locale);
         String[] classNames = (String[]) lr.getBreakIteratorInfo("BreakIteratorClasses");
@@ -166,10 +165,12 @@
         try {
             switch (classNames[type]) {
             case "RuleBasedBreakIterator":
-                return new RuleBasedBreakIterator(dataFile);
+                return new RuleBasedBreakIterator(
+                    lr.getBreakIteratorDataModule(), dataFile);
             case "DictionaryBasedBreakIterator":
                 String dictionaryFile = (String) lr.getBreakIteratorInfo(dictionaryName);
-                return new DictionaryBasedBreakIterator(dataFile, dictionaryFile);
+                return new DictionaryBasedBreakIterator(
+                    lr.getBreakIteratorDataModule(), dataFile, dictionaryFile);
             default:
                 throw new IllegalArgumentException("Invalid break iterator class \"" +
                                 classNames[type] + "\"");
@@ -187,5 +188,5 @@
     @Override
     public boolean isSupportedLocale(Locale locale) {
         return LocaleProviderAdapter.forType(type).isSupportedProviderLocale(locale, langtags);
+    }
 }
-}
--- a/src/java.base/share/classes/sun/util/locale/provider/DictionaryBasedBreakIterator.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/sun/util/locale/provider/DictionaryBasedBreakIterator.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -41,6 +41,7 @@
 package sun.util.locale.provider;
 
 import java.io.IOException;
+import java.lang.reflect.Module;
 import java.text.CharacterIterator;
 import java.util.ArrayList;
 import java.util.List;
@@ -108,20 +109,18 @@
 
     /**
      * Constructs a DictionaryBasedBreakIterator.
-     * @param description Same as the description parameter on RuleBasedBreakIterator,
-     * except for the special meaning of "<dictionary>".  This parameter is just
-     * passed through to RuleBasedBreakIterator's constructor.
+     * @param module The module where the dictionary file resides
      * @param dictionaryFilename The filename of the dictionary file to use
      */
-    DictionaryBasedBreakIterator(String dataFile, String dictionaryFile)
+    DictionaryBasedBreakIterator(Module module, String dataFile, String dictionaryFile)
                                         throws IOException {
-        super(dataFile);
+        super(module, dataFile);
         byte[] tmp = super.getAdditionalData();
         if (tmp != null) {
             prepareCategoryFlags(tmp);
             super.setAdditionalData(null);
         }
-        dictionary = new BreakDictionary(dictionaryFile);
+        dictionary = new BreakDictionary(module, dictionaryFile);
     }
 
     private void prepareCategoryFlags(byte[] data) {
--- a/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java	Thu Mar 17 19:04:16 2016 +0000
@@ -431,25 +431,21 @@
 
         // Use ServiceLoader to dynamically acquire installed locales' tags.
         try {
-            String nonBaseTags = AccessController.doPrivileged(new PrivilegedExceptionAction<String>() {
-                @Override
-                public String run() {
-                    String tags = null;
-                    for (LocaleDataMetaInfo ldmi :
-                         ServiceLoader.loadInstalled(LocaleDataMetaInfo.class)) {
-                        if (ldmi.getType() == LocaleProviderAdapter.Type.JRE) {
-                            String t = ldmi.availableLanguageTags(category);
-                            if (t != null) {
-                                if (tags == null) {
-                                    tags = t;
-                                } else {
-                                    tags += " " + t;
-                                }
+            String nonBaseTags = AccessController.doPrivileged((PrivilegedExceptionAction<String>) () -> {
+                StringBuilder tags = new StringBuilder();
+                for (LocaleDataMetaInfo ldmi :
+                        ServiceLoader.loadInstalled(LocaleDataMetaInfo.class)) {
+                    if (ldmi.getType() == LocaleProviderAdapter.Type.JRE) {
+                        String t = ldmi.availableLanguageTags(category);
+                        if (t != null) {
+                            if (tags.length() > 0) {
+                                tags.append(' ');
                             }
+                            tags.append(t);
                         }
                     }
-                    return tags;
                 }
+                return tags.toString();
             });
 
             if (nonBaseTags != null) {
--- a/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java	Thu Mar 17 19:04:16 2016 +0000
@@ -42,6 +42,7 @@
 
 import java.lang.ref.ReferenceQueue;
 import java.lang.ref.SoftReference;
+import java.lang.reflect.Module;
 import java.text.MessageFormat;
 import java.util.Calendar;
 import java.util.LinkedHashSet;
@@ -117,6 +118,10 @@
        return biInfo;
     }
 
+    Module getBreakIteratorDataModule() {
+       return localeData.getBreakIteratorInfo(locale).getClass().getModule();
+    }
+
     int getCalendarData(String key) {
         Integer caldata;
         String cacheKey = CALENDAR_DATA  + key;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/util/locale/provider/ResourceBundleProviderSupport.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.util.locale.provider;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Module;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.PropertyResourceBundle;
+import java.util.ResourceBundle;
+
+/**
+ * ResourceBundleProviderSupport provides convenience methods for loading
+ * resource bundles.
+ */
+public class ResourceBundleProviderSupport {
+    /**
+     * Loads a {@code ResourceBundle} of the given {@code bundleName} local to
+     * the given {@code module}.
+     *
+     * @apiNote
+     * {@link Class#forName(Module, String)} does a stack-based permission check.
+     * Caller of this method is responsible for doing an appropriate permission
+     * on behalf of the caller before calling this method.
+     *
+     * @param module     the module from which the {@code ResourceBundle} is loaded
+     * @param bundleName the bundle name for the {@code ResourceBundle} class,
+     *                   such as "com.example.app.MyResources_fr"
+     * @return the {@code ResourceBundle}, or null if no {@code ResourceBundle} is found
+     * @throws SecurityException
+     *         if a security manager exists, it denies loading the class given by
+     *         {@code bundleName} from the given {@code module}.
+     *         If the given module is "java.base", this method will not do security check.
+     * @throws NullPointerException
+     *         if {@code module} or {@code bundleName) is null
+     * @see Class#forName(Module, String)
+     */
+    public static ResourceBundle loadResourceBundle(Module module, String bundleName)
+    {
+        Class<?> c = Class.forName(module, bundleName);
+        if (c != null && ResourceBundle.class.isAssignableFrom(c)) {
+            try {
+                @SuppressWarnings("unchecked")
+                Class<ResourceBundle> bundleClass = (Class<ResourceBundle>) c;
+                Constructor<ResourceBundle> ctor = bundleClass.getConstructor();
+                if (!Modifier.isPublic(ctor.getModifiers())) {
+                    return null;
+                }
+                // java.base may not be able to read the bundleClass's module.
+                PrivilegedAction<Void> pa1 = () -> { ctor.setAccessible(true); return null; };
+                AccessController.doPrivileged(pa1);
+                try {
+                    return ctor.newInstance((Object[]) null);
+                } catch (InvocationTargetException e) {
+                    uncheckedThrow(e);
+                } catch (InstantiationException | IllegalAccessException e) {
+                    throw new InternalError(e);
+                }
+            } catch (NoSuchMethodException e) {
+            }
+        }
+        return null;
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <T extends Throwable> void uncheckedThrow(Throwable t) throws T {
+       if (t != null)
+            throw (T)t;
+       else
+            throw new Error("Unknown Exception");
+    }
+
+    /**
+     * Loads properties of the given {@code bundleName} local to the given
+     * {@code module} and returns a {@code ResourceBundle} produced from the
+     * loaded properties.
+     *
+     * @apiNote This method is intended for internal use.  Need to refactor.
+     *
+     * @param module     the module from which the properties are loaded
+     * @param bundleName the bundle name of the properties,
+     *                   such as "com.example.app.MyResources_de"
+     * @return the {@code ResourceBundle} produced from the loaded properties,
+     *         or null if no properties are found
+     * @see PropertyResourceBundle
+     */
+    public static ResourceBundle loadPropertyResourceBundle(Module module, String bundleName)
+            throws IOException
+    {
+        String resourceName = toResourceName(bundleName, "properties");
+        if (resourceName == null) {
+            return null;
+        }
+
+        PrivilegedAction<InputStream> pa = () -> {
+            try {
+                return module.getResourceAsStream(resourceName);
+            } catch (IOException e) {
+                throw new UncheckedIOException(e);
+            }
+        };
+        try (InputStream stream = AccessController.doPrivileged(pa)) {
+            if (stream != null) {
+                return new PropertyResourceBundle(stream);
+            } else {
+                return null;
+            }
+        } catch (UncheckedIOException e) {
+            throw e.getCause();
+        }
+    }
+
+    private static String toResourceName(String bundleName, String suffix) {
+        if (bundleName.contains("://")) {
+            return null;
+        }
+        StringBuilder sb = new StringBuilder(bundleName.length() + 1 + suffix.length());
+        sb.append(bundleName.replace('.', '/')).append('.').append(suffix);
+        return sb.toString();
+    }
+}
--- a/src/java.base/share/classes/sun/util/locale/provider/RuleBasedBreakIterator.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/sun/util/locale/provider/RuleBasedBreakIterator.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -41,7 +41,9 @@
 package sun.util.locale.provider;
 
 import java.io.BufferedInputStream;
+import java.io.InputStream;
 import java.io.IOException;
+import java.lang.reflect.Module;
 import java.security.AccessController;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
@@ -313,12 +315,12 @@
     //=======================================================================
 
     /**
-     * Constructs a RuleBasedBreakIterator according to the datafile
+     * Constructs a RuleBasedBreakIterator according to the module and the datafile
      * provided.
      */
-    RuleBasedBreakIterator(String datafile)
+    RuleBasedBreakIterator(Module module, String datafile)
         throws IOException, MissingResourceException {
-        readTables(datafile);
+        readTables(module, datafile);
     }
 
     /**
@@ -369,10 +371,10 @@
      *   }
      * </pre>
      */
-    protected final void readTables(String datafile)
+    protected final void readTables(Module module, String datafile)
         throws IOException, MissingResourceException {
 
-        byte[] buffer = readFile(datafile);
+        byte[] buffer = readFile(module, datafile);
 
         /* Read header_info. */
         int stateTableLength = getInt(buffer, 0);
@@ -436,21 +438,24 @@
         numCategories = stateTable.length / endStates.length;
     }
 
-    protected byte[] readFile(final String datafile)
+    protected byte[] readFile(final Module module, final String datafile)
         throws IOException, MissingResourceException {
 
         BufferedInputStream is;
         try {
-            is = AccessController.doPrivileged(
-                new PrivilegedExceptionAction<BufferedInputStream>() {
-                    @Override
-                    public BufferedInputStream run() throws Exception {
-                        return new BufferedInputStream(getClass().getResourceAsStream("/sun/text/resources/" + datafile));
-                    }
+            PrivilegedExceptionAction<BufferedInputStream> pa = () -> {
+                InputStream in = module.getResourceAsStream("sun/text/resources/" + datafile);
+                if (in == null) {
+                    // Try to load the file with "java.base" module instance. Assumption
+                    // here is that the fall back data files to be read should reside in
+                    // java.base.
+                    in = RuleBasedBreakIterator.class.getModule().getResourceAsStream("sun/text/resources/" + datafile);
                 }
-            );
-        }
-        catch (PrivilegedActionException e) {
+
+                return new BufferedInputStream(in);
+            };
+            is = AccessController.doPrivileged(pa);
+        } catch (PrivilegedActionException e) {
             throw new InternalError(e.toString(), e);
         }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/util/resources/Bundles.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,530 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - 1999 - All Rights Reserved
+ *
+ * The original version of this source code and documentation
+ * is copyrighted and owned by Taligent, Inc., a wholly-owned
+ * subsidiary of IBM. These materials are provided under terms
+ * of a License Agreement between Taligent and Sun. This technology
+ * is protected by multiple US and International patents.
+ *
+ * This notice and attribution to Taligent may not be removed.
+ * Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package sun.util.resources;
+
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.SoftReference;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.Objects;
+import java.util.ResourceBundle;
+import java.util.ServiceConfigurationError;
+import java.util.ServiceLoader;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.spi.ResourceBundleProvider;
+import jdk.internal.misc.JavaUtilResourceBundleAccess;
+import jdk.internal.misc.SharedSecrets;
+import sun.util.locale.provider.ResourceBundleProviderSupport;
+
+
+/**
+ */
+public abstract class Bundles {
+
+    /** initial size of the bundle cache */
+    private static final int INITIAL_CACHE_SIZE = 32;
+
+    /** constant indicating that no resource bundle exists */
+    private static final ResourceBundle NONEXISTENT_BUNDLE = new ResourceBundle() {
+            @Override
+            public Enumeration<String> getKeys() { return null; }
+            @Override
+            protected Object handleGetObject(String key) { return null; }
+            @Override
+            public String toString() { return "NONEXISTENT_BUNDLE"; }
+        };
+
+    private static final JavaUtilResourceBundleAccess bundleAccess
+                            = SharedSecrets.getJavaUtilResourceBundleAccess();
+
+    /**
+     * The cache is a map from cache keys (with bundle base name, locale, and
+     * class loader) to either a resource bundle or NONEXISTENT_BUNDLE wrapped by a
+     * BundleReference.
+     *
+     * The cache is a ConcurrentMap, allowing the cache to be searched
+     * concurrently by multiple threads.  This will also allow the cache keys
+     * to be reclaimed along with the ClassLoaders they reference.
+     *
+     * This variable would be better named "cache", but we keep the old
+     * name for compatibility with some workarounds for bug 4212439.
+     */
+    private static final ConcurrentMap<CacheKey, BundleReference> cacheList
+                            = new ConcurrentHashMap<>(INITIAL_CACHE_SIZE);
+
+    /**
+     * Queue for reference objects referring to class loaders or bundles.
+     */
+    private static final ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
+
+    private Bundles() {
+    }
+
+    public static ResourceBundle of(String baseName, Locale locale, Strategy strategy) {
+        return loadBundleOf(baseName, locale, strategy);
+    }
+
+    private static ResourceBundle loadBundleOf(String baseName,
+                                               Locale targetLocale,
+                                               Strategy strategy) {
+        Objects.requireNonNull(baseName);
+        Objects.requireNonNull(targetLocale);
+        Objects.requireNonNull(strategy);
+
+        CacheKey cacheKey = new CacheKey(baseName, targetLocale);
+
+        ResourceBundle bundle = null;
+
+        // Quick lookup of the cache.
+        BundleReference bundleRef = cacheList.get(cacheKey);
+        if (bundleRef != null) {
+            bundle = bundleRef.get();
+        }
+
+        // If this bundle and all of its parents are valid,
+        // then return this bundle.
+        if (isValidBundle(bundle)) {
+            return bundle;
+        }
+
+        // Get the providers for loading the "leaf" bundle (i.e., bundle for
+        // targetLocale). If no providers are required for the bundle,
+        // none of its parents will require providers.
+        Class<? extends ResourceBundleProvider> type
+                = strategy.getResourceBundleProviderType(baseName, targetLocale);
+        if (type != null) {
+            @SuppressWarnings("unchecked")
+            ServiceLoader<ResourceBundleProvider> providers
+                = (ServiceLoader<ResourceBundleProvider>) ServiceLoader.loadInstalled(type);
+            cacheKey.setProviders(providers);
+        }
+
+        List<Locale> candidateLocales = strategy.getCandidateLocales(baseName, targetLocale);
+        bundle = findBundleOf(cacheKey, strategy, baseName, candidateLocales, 0);
+        if (bundle == null) {
+            throwMissingResourceException(baseName, targetLocale, cacheKey.getCause());
+        }
+        return bundle;
+    }
+
+    private static ResourceBundle findBundleOf(CacheKey cacheKey,
+                                               Strategy strategy,
+                                               String baseName,
+                                               List<Locale> candidateLocales,
+                                               int index) {
+        ResourceBundle parent = null;
+        Locale targetLocale = candidateLocales.get(index);
+        if (index != candidateLocales.size() - 1) {
+            parent = findBundleOf(cacheKey, strategy, baseName, candidateLocales, index + 1);
+        }
+
+        // Before we do the real loading work, see whether we need to
+        // do some housekeeping: If resource bundles have been nulled out,
+        // remove all related information from the cache.
+        cleanupCache();
+
+        // find an individual ResourceBundle in the cache
+        cacheKey.setLocale(targetLocale);
+        ResourceBundle bundle = findBundleInCache(cacheKey);
+        if (bundle != null) {
+            if (bundle == NONEXISTENT_BUNDLE) {
+                return parent;
+            }
+            if (bundleAccess.getParent(bundle) == parent) {
+                return bundle;
+            }
+            // Remove bundle from the cache.
+            BundleReference bundleRef = cacheList.get(cacheKey);
+            if (bundleRef != null && bundleRef.get() == bundle) {
+                cacheList.remove(cacheKey, bundleRef);
+            }
+        }
+
+        // Determine if providers should be used for loading the bundle.
+        // An assumption here is that if the leaf bundle of a look-up path is
+        // in java.base, all bundles of the path are in java.base.
+        // (e.g., en_US of path en_US -> en -> root is in java.base and the rest
+        // are in java.base as well)
+        // This assumption isn't valid for general bundle loading.
+        ServiceLoader<ResourceBundleProvider> providers = cacheKey.getProviders();
+        if (providers != null) {
+            if (strategy.getResourceBundleProviderType(baseName, targetLocale) == null) {
+                providers = null;
+            }
+        }
+
+        CacheKey constKey = (CacheKey) cacheKey.clone();
+        try {
+            if (providers != null) {
+                bundle = loadBundleFromProviders(baseName, targetLocale, providers, cacheKey);
+            } else {
+                try {
+                    bundle = ResourceBundleProviderSupport
+                                 .loadResourceBundle(Bundles.class.getModule(),
+                                      strategy.toBundleName(baseName, targetLocale));
+                } catch (Exception e) {
+                    cacheKey.setCause(e);
+                }
+            }
+        } finally {
+            if (constKey.getCause() instanceof InterruptedException) {
+                Thread.currentThread().interrupt();
+            }
+        }
+
+        if (bundle == null) {
+            // Put NONEXISTENT_BUNDLE in the cache as a mark that there's no bundle
+            // instance for the locale.
+            putBundleInCache(cacheKey, NONEXISTENT_BUNDLE);
+            return parent;
+        }
+
+        if (parent != null && bundleAccess.getParent(bundle) == null) {
+            bundleAccess.setParent(bundle, parent);
+        }
+        bundleAccess.setLocale(bundle, targetLocale);
+        bundleAccess.setName(bundle, baseName);
+        bundle = putBundleInCache(cacheKey, bundle);
+        return bundle;
+    }
+
+    private static void cleanupCache() {
+        Object ref;
+        while ((ref = referenceQueue.poll()) != null) {
+            cacheList.remove(((CacheKeyReference)ref).getCacheKey());
+        }
+    }
+
+    /**
+     * Loads ResourceBundle from service providers.
+     */
+    private static ResourceBundle loadBundleFromProviders(String baseName,
+                                                          Locale locale,
+                                                          ServiceLoader<ResourceBundleProvider> providers,
+                                                          CacheKey cacheKey)
+    {
+        return AccessController.doPrivileged(
+                new PrivilegedAction<>() {
+                    public ResourceBundle run() {
+                        for (Iterator<ResourceBundleProvider> itr = providers.iterator(); itr.hasNext(); ) {
+                            try {
+                                ResourceBundleProvider provider = itr.next();
+                                ResourceBundle bundle = provider.getBundle(baseName, locale);
+                                if (bundle != null) {
+                                    return bundle;
+                                }
+                            } catch (ServiceConfigurationError | SecurityException e) {
+                                if (cacheKey != null) {
+                                    cacheKey.setCause(e);
+                                }
+                            }
+                        }
+                        return null;
+                    }
+                });
+
+    }
+
+    private static boolean isValidBundle(ResourceBundle bundle) {
+        return bundle != null && bundle != NONEXISTENT_BUNDLE;
+    }
+
+    /**
+     * Throw a MissingResourceException with proper message
+     */
+    private static void throwMissingResourceException(String baseName,
+                                                      Locale locale,
+                                                      Throwable cause) {
+        // If the cause is a MissingResourceException, avoid creating
+        // a long chain. (6355009)
+        if (cause instanceof MissingResourceException) {
+            cause = null;
+        }
+        MissingResourceException e;
+        e = new MissingResourceException("Can't find bundle for base name "
+                                         + baseName + ", locale " + locale,
+                                         baseName + "_" + locale, // className
+                                         "");
+        e.initCause(cause);
+        throw e;
+    }
+
+    /**
+     * Finds a bundle in the cache.
+     *
+     * @param cacheKey the key to look up the cache
+     * @return the ResourceBundle found in the cache or null
+     */
+    private static ResourceBundle findBundleInCache(CacheKey cacheKey) {
+        BundleReference bundleRef = cacheList.get(cacheKey);
+        if (bundleRef == null) {
+            return null;
+        }
+        return bundleRef.get();
+    }
+
+    /**
+     * Put a new bundle in the cache.
+     *
+     * @param cacheKey the key for the resource bundle
+     * @param bundle the resource bundle to be put in the cache
+     * @return the ResourceBundle for the cacheKey; if someone has put
+     * the bundle before this call, the one found in the cache is
+     * returned.
+     */
+    private static ResourceBundle putBundleInCache(CacheKey cacheKey,
+                                                   ResourceBundle bundle) {
+        CacheKey key = (CacheKey) cacheKey.clone();
+        BundleReference bundleRef = new BundleReference(bundle, referenceQueue, key);
+
+        // Put the bundle in the cache if it's not been in the cache.
+        BundleReference result = cacheList.putIfAbsent(key, bundleRef);
+
+        // If someone else has put the same bundle in the cache before
+        // us, we should use the one in the cache.
+        if (result != null) {
+            ResourceBundle rb = result.get();
+            if (rb != null) {
+                // Clear the back link to the cache key
+                bundle = rb;
+                // Clear the reference in the BundleReference so that
+                // it won't be enqueued.
+                bundleRef.clear();
+            } else {
+                // Replace the invalid (garbage collected)
+                // instance with the valid one.
+                cacheList.put(key, bundleRef);
+            }
+        }
+        return bundle;
+    }
+
+
+    /**
+     * The Strategy interface defines methods that are called by Bundles.of during
+     * the resource bundle loading process.
+     */
+    public static interface Strategy {
+        /**
+         * Returns a list of locales to be looked up for bundle loading.
+         */
+        public List<Locale> getCandidateLocales(String baseName, Locale locale);
+
+        /**
+         * Returns the bundle name for the given baseName and locale.
+         */
+        public String toBundleName(String baseName, Locale locale);
+
+        /**
+         * Returns the service provider type for the given baseName
+         * and locale, or null if no service providers should be used.
+         */
+        public Class<? extends ResourceBundleProvider> getResourceBundleProviderType(String baseName,
+                                                                                     Locale locale);
+    }
+
+    /**
+     * The common interface to get a CacheKey in LoaderReference and
+     * BundleReference.
+     */
+    private static interface CacheKeyReference {
+        public CacheKey getCacheKey();
+    }
+
+    /**
+     * References to bundles are soft references so that they can be garbage
+     * collected when they have no hard references.
+     */
+    private static class BundleReference extends SoftReference<ResourceBundle>
+                                         implements CacheKeyReference {
+        private final CacheKey cacheKey;
+
+        BundleReference(ResourceBundle referent, ReferenceQueue<Object> q, CacheKey key) {
+            super(referent, q);
+            cacheKey = key;
+        }
+
+        @Override
+        public CacheKey getCacheKey() {
+            return cacheKey;
+        }
+    }
+
+    /**
+     * Key used for cached resource bundles.  The key checks the base
+     * name, the locale, and the class loader to determine if the
+     * resource is a match to the requested one. The loader may be
+     * null, but the base name and the locale must have a non-null
+     * value.
+     */
+    private static class CacheKey implements Cloneable {
+        // These two are the actual keys for lookup in Map.
+        private String name;
+        private Locale locale;
+
+        // Placeholder for an error report by a Throwable
+        private Throwable cause;
+
+        // Hash code value cache to avoid recalculating the hash code
+        // of this instance.
+        private int hashCodeCache;
+
+        // The service loader to load bundles or null if no service loader
+        // is required.
+        private ServiceLoader<ResourceBundleProvider> providers;
+
+        CacheKey(String baseName, Locale locale) {
+            this.name = baseName;
+            this.locale = locale;
+            calculateHashCode();
+        }
+
+        String getName() {
+            return name;
+        }
+
+        CacheKey setName(String baseName) {
+            if (!this.name.equals(baseName)) {
+                this.name = baseName;
+                calculateHashCode();
+            }
+            return this;
+        }
+
+        Locale getLocale() {
+            return locale;
+        }
+
+        CacheKey setLocale(Locale locale) {
+            if (!this.locale.equals(locale)) {
+                this.locale = locale;
+                calculateHashCode();
+            }
+            return this;
+        }
+
+        ServiceLoader<ResourceBundleProvider> getProviders() {
+            return providers;
+        }
+
+        void setProviders(ServiceLoader<ResourceBundleProvider> providers) {
+            this.providers = providers;
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (this == other) {
+                return true;
+            }
+            try {
+                final CacheKey otherEntry = (CacheKey)other;
+                //quick check to see if they are not equal
+                if (hashCodeCache != otherEntry.hashCodeCache) {
+                    return false;
+                }
+                return locale.equals(otherEntry.locale)
+                        && name.equals(otherEntry.name);
+            } catch (NullPointerException | ClassCastException e) {
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return hashCodeCache;
+        }
+
+        private void calculateHashCode() {
+            hashCodeCache = name.hashCode() << 3;
+            hashCodeCache ^= locale.hashCode();
+        }
+
+        @Override
+        public Object clone() {
+            try {
+                CacheKey clone = (CacheKey) super.clone();
+                // Clear the reference to a Throwable
+                clone.cause = null;
+                // Clear the reference to a ServiceLoader
+                clone.providers = null;
+                return clone;
+            } catch (CloneNotSupportedException e) {
+                //this should never happen
+                throw new InternalError(e);
+            }
+        }
+
+        private void setCause(Throwable cause) {
+            if (this.cause == null) {
+                this.cause = cause;
+            } else {
+                // Override the cause if the previous one is
+                // ClassNotFoundException.
+                if (this.cause instanceof ClassNotFoundException) {
+                    this.cause = cause;
+                }
+            }
+        }
+
+        private Throwable getCause() {
+            return cause;
+        }
+
+        @Override
+        public String toString() {
+            String l = locale.toString();
+            if (l.isEmpty()) {
+                if (!locale.getVariant().isEmpty()) {
+                    l = "__" + locale.getVariant();
+                } else {
+                    l = "\"\"";
+                }
+            }
+            return "CacheKey[" + name + ", lc=" + l + ")]";
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/util/resources/CalendarDataProvider.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.util.resources;
+
+import java.util.spi.ResourceBundleProvider;
+
+/**
+ * An interface for the internal locale data provider for which {@code ResourceBundle}
+ * searches.
+ */
+public interface CalendarDataProvider extends ResourceBundleProvider {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/util/resources/CurrencyNamesProvider.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.util.resources;
+
+import java.util.spi.ResourceBundleProvider;
+
+/**
+ * An interface for the internal locale data provider for which {@code ResourceBundle}
+ * searches.
+ */
+public interface CurrencyNamesProvider extends ResourceBundleProvider {
+}
--- a/src/java.base/share/classes/sun/util/resources/LocaleData.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/classes/sun/util/resources/LocaleData.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -46,14 +46,17 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.MissingResourceException;
 import java.util.ResourceBundle;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.spi.ResourceBundleProvider;
 import sun.util.locale.provider.JRELocaleProviderAdapter;
 import sun.util.locale.provider.LocaleProviderAdapter;
-import sun.util.locale.provider.ResourceBundleBasedAdapter;
 import static sun.util.locale.provider.LocaleProviderAdapter.Type.CLDR;
 import static sun.util.locale.provider.LocaleProviderAdapter.Type.JRE;
+import sun.util.locale.provider.ResourceBundleBasedAdapter;
 
 /**
  * Provides information about and access to resource bundles in the
@@ -65,6 +68,14 @@
  */
 
 public class LocaleData {
+    private static final ResourceBundle.Control defaultControl
+        = ResourceBundle.Control.getControl(ResourceBundle.Control.FORMAT_DEFAULT);
+
+    private static final String DOTCLDR      = ".cldr";
+
+    // Map of key (base name + locale) to candidates
+    private static final Map<String, List<Locale>> CANDIDATES_MAP = new ConcurrentHashMap<>();
+
     private final LocaleProviderAdapter.Type type;
 
     public LocaleData(LocaleProviderAdapter.Type type) {
@@ -163,8 +174,7 @@
         return AccessController.doPrivileged(new PrivilegedAction<>() {
             @Override
             public ResourceBundle run() {
-                return ResourceBundle
-                        .getBundle(baseName, locale, LocaleDataResourceBundleControl.INSTANCE);
+                return Bundles.of(baseName, locale, LocaleDataStrategy.INSTANCE);
             }
         });
     }
@@ -175,9 +185,8 @@
            public OpenListResourceBundle run() {
                OpenListResourceBundle rb = null;
                try {
-                   rb = (OpenListResourceBundle) ResourceBundle.getBundle(baseName,
-                           locale, SupplementaryResourceBundleControl.INSTANCE);
-
+                   rb = (OpenListResourceBundle) Bundles.of(baseName, locale,
+                                                            SupplementaryStrategy.INSTANCE);
                } catch (MissingResourceException e) {
                    // return null if no supplementary is available
                }
@@ -186,12 +195,51 @@
         });
     }
 
-    private static class LocaleDataResourceBundleControl extends ResourceBundle.Control {
-        /* Singlton instance of ResourceBundle.Control. */
-        private static final LocaleDataResourceBundleControl INSTANCE =
-            new LocaleDataResourceBundleControl();
+    private static abstract class LocaleDataResourceBundleProvider
+                                            implements ResourceBundleProvider {
+        abstract protected boolean isSupportedInModule(String baseName, Locale locale);
+
+        /**
+         * Changes baseName to its module dependent package name and
+         * calls the super class implementation. For example,
+         * if the baseName is "sun.text.resources.FormatData" and locale is ja_JP,
+         * the baseName is changed to "sun.text.resources.ext.FormatData". If
+         * baseName contains ".cldr", such as "sun.text.resources.cldr.FormatData",
+         * the name is changed to "sun.text.resources.cldr.ext.FormatData".
+         */
+        protected String toBundleName(String baseName, Locale locale) {
+            return LocaleDataStrategy.INSTANCE.toBundleName(baseName, locale);
+        }
+    }
 
-        private LocaleDataResourceBundleControl() {
+    /**
+     * A ResourceBundleProvider implementation for loading locale data
+     * resource bundles except for the java.time supplementary data.
+     */
+    public static abstract class CommonResourceBundleProvider extends LocaleDataResourceBundleProvider {
+        @Override
+        protected boolean isSupportedInModule(String baseName, Locale locale) {
+            return LocaleDataStrategy.INSTANCE.inJavaBaseModule(baseName, locale);
+        }
+    }
+
+    /**
+     * A ResourceBundleProvider implementation for loading supplementary
+     * resource bundles for java.time.
+     */
+    public static abstract class SupplementaryResourceBundleProvider extends LocaleDataResourceBundleProvider {
+        @Override
+        protected boolean isSupportedInModule(String baseName, Locale locale) {
+            return SupplementaryStrategy.INSTANCE.inJavaBaseModule(baseName, locale);
+        }
+    }
+
+    // Bundles.Strategy implementations
+
+    private static class LocaleDataStrategy implements Bundles.Strategy {
+        private static final LocaleDataStrategy INSTANCE = new LocaleDataStrategy();
+
+        private LocaleDataStrategy() {
         }
 
         /*
@@ -205,66 +253,49 @@
          * @exception NullPointerException if baseName or locale is null.
          */
         @Override
-         public List<Locale> getCandidateLocales(String baseName, Locale locale) {
-            LocaleProviderAdapter.Type type = baseName.contains(DOTCLDR) ? CLDR : JRE;
-            LocaleProviderAdapter adapter = LocaleProviderAdapter.forType(type);
-            List<Locale> candidates = adapter instanceof ResourceBundleBasedAdapter ?
-                ((ResourceBundleBasedAdapter)adapter).getCandidateLocales(baseName, locale) :
-                super.getCandidateLocales(baseName, locale);
+        public List<Locale> getCandidateLocales(String baseName, Locale locale) {
+            String key = baseName + '-' + locale.toLanguageTag();
+            List<Locale> candidates = CANDIDATES_MAP.get(key);
+            if (candidates == null) {
+                LocaleProviderAdapter.Type type = baseName.contains(DOTCLDR) ? CLDR : JRE;
+                LocaleProviderAdapter adapter = LocaleProviderAdapter.forType(type);
+                candidates = adapter instanceof ResourceBundleBasedAdapter ?
+                    ((ResourceBundleBasedAdapter)adapter).getCandidateLocales(baseName, locale) :
+                    defaultControl.getCandidateLocales(baseName, locale);
 
-            // Weed out Locales which are known to have no resource bundles
-            int lastDot = baseName.lastIndexOf('.');
-            String category = (lastDot >= 0) ? baseName.substring(lastDot + 1) : baseName;
-            Set<String> langtags = ((JRELocaleProviderAdapter)adapter).getLanguageTagSet(category);
-            if (!langtags.isEmpty()) {
-                for (Iterator<Locale> itr = candidates.iterator(); itr.hasNext();) {
-                    if (!adapter.isSupportedProviderLocale(itr.next(), langtags)) {
-                        itr.remove();
+                // Weed out Locales which are known to have no resource bundles
+                int lastDot = baseName.lastIndexOf('.');
+                String category = (lastDot >= 0) ? baseName.substring(lastDot + 1) : baseName;
+                Set<String> langtags = ((JRELocaleProviderAdapter)adapter).getLanguageTagSet(category);
+                if (!langtags.isEmpty()) {
+                    for (Iterator<Locale> itr = candidates.iterator(); itr.hasNext();) {
+                        if (!adapter.isSupportedProviderLocale(itr.next(), langtags)) {
+                            itr.remove();
+                        }
                     }
                 }
-            }
-
-            // Force fallback to Locale.ENGLISH for CLDR time zone names support
-            if (locale.getLanguage() != "en"
-                    && type == CLDR && category.equals("TimeZoneNames")) {
-                candidates.add(candidates.size() - 1, Locale.ENGLISH);
+                // Force fallback to Locale.ENGLISH for CLDR time zone names support
+                if (locale.getLanguage() != "en"
+                        && type == CLDR && category.equals("TimeZoneNames")) {
+                    candidates.add(candidates.size() - 1, Locale.ENGLISH);
+                }
+                CANDIDATES_MAP.putIfAbsent(key, candidates);
             }
             return candidates;
         }
 
-        /*
-         * Overrides "getFallbackLocale" to return null so
-         * that the fallback locale will be null.
-         * @param baseName the resource bundle base name.
-         *        locale   the requested locale for the resource bundle.
-         * @return null for the fallback locale.
-         * @exception NullPointerException if baseName or locale is null.
-         */
-        @Override
-        public Locale getFallbackLocale(String baseName, Locale locale) {
-            if (baseName == null || locale == null) {
-                throw new NullPointerException();
-            }
-            return null;
+        boolean inJavaBaseModule(String baseName, Locale locale) {
+            // TODO: avoid hard-coded Locales
+            return locale.equals(Locale.ROOT) ||
+                (locale.getLanguage() == "en" &&
+                    (locale.getCountry().isEmpty() ||
+                     locale.getCountry() == "US"));
         }
 
-        private static final String DOTCLDR      = ".cldr";
-
-        /**
-         * Changes baseName to its module dependent package name and
-         * calls the super class implementation. For example,
-         * if the baseName is "sun.text.resources.FormatData" and locale is ja_JP,
-         * the baseName is changed to "sun.text.resources.ext.FormatData". If
-         * baseName contains "cldr", such as "sun.text.resources.cldr.FormatData",
-         * the name is changed to "sun.text.resources.cldr.ext.FormatData".
-         */
         @Override
         public String toBundleName(String baseName, Locale locale) {
             String newBaseName = baseName;
-            String lang = locale.getLanguage();
-            String ctry = locale.getCountry();
-            if (lang.length() > 0 &&
-                (lang != "en" || (ctry.length() > 0 && ctry != "US"))) {
+            if (!inJavaBaseModule(baseName, locale)) {
                 if (baseName.startsWith(JRE.getUtilResourcesPackage())
                         || baseName.startsWith(JRE.getTextResourcesPackage())) {
                     // Assume the lengths are the same.
@@ -274,19 +305,26 @@
                     if (baseName.indexOf(DOTCLDR, index) > 0) {
                         index += DOTCLDR.length();
                     }
-                    newBaseName = baseName.substring(0, index + 1) + "ext" +
-                                      baseName.substring(index);
+                    newBaseName = baseName.substring(0, index + 1) + "ext"
+                                      + baseName.substring(index);
                 }
             }
-            return super.toBundleName(newBaseName, locale);
+            return defaultControl.toBundleName(newBaseName, locale);
+        }
+
+        @Override
+        public Class<? extends ResourceBundleProvider> getResourceBundleProviderType(String baseName,
+                                                                                     Locale locale) {
+            return inJavaBaseModule(baseName, locale) ?
+                        null : CommonResourceBundleProvider.class;
         }
     }
 
-    private static class SupplementaryResourceBundleControl extends LocaleDataResourceBundleControl {
-        private static final SupplementaryResourceBundleControl INSTANCE =
-                new SupplementaryResourceBundleControl();
+    private static class SupplementaryStrategy extends LocaleDataStrategy {
+        private static final SupplementaryStrategy INSTANCE
+                = new SupplementaryStrategy();
 
-        private SupplementaryResourceBundleControl() {
+        private SupplementaryStrategy() {
         }
 
         @Override
@@ -296,9 +334,16 @@
         }
 
         @Override
-        public long getTimeToLive(String baseName, Locale locale) {
-            assert baseName.contains("JavaTimeSupplementary");
-            return TTL_DONT_CACHE;
+        public Class<? extends ResourceBundleProvider> getResourceBundleProviderType(String baseName,
+                                                                                     Locale locale) {
+            return inJavaBaseModule(baseName, locale) ?
+                    null : SupplementaryResourceBundleProvider.class;
+        }
+
+        @Override
+        boolean inJavaBaseModule(String baseName, Locale locale) {
+            // TODO: avoid hard-coded Locales
+            return locale.equals(Locale.ROOT) || locale.getLanguage() == "en";
         }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/util/resources/LocaleDataProvider.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.util.resources;
+
+import java.util.spi.ResourceBundleProvider;
+
+/**
+ * An interface for the internal locale data provider for which {@code ResourceBundle}
+ * searches.
+ */
+public interface LocaleDataProvider extends ResourceBundleProvider {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/util/resources/LocaleNamesProvider.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.util.resources;
+
+import java.util.spi.ResourceBundleProvider;
+
+/**
+ * An interface for the internal locale data provider for which {@code ResourceBundle}
+ * searches.
+ */
+public interface LocaleNamesProvider extends ResourceBundleProvider {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/util/resources/TimeZoneNamesProvider.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.util.resources;
+
+import java.util.spi.ResourceBundleProvider;
+
+/**
+ * An interface for the internal locale data provider for which {@code ResourceBundle}
+ * searches.
+ */
+public interface TimeZoneNamesProvider extends ResourceBundleProvider {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/util/resources/cldr/CalendarDataProvider.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.util.resources.cldr;
+
+import java.util.spi.ResourceBundleProvider;
+
+/**
+ * An interface for the internal locale data provider for which {@code ResourceBundle}
+ * searches.
+ */
+public interface CalendarDataProvider extends ResourceBundleProvider {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/util/resources/cldr/CurrencyNamesProvider.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.util.resources.cldr;
+
+import java.util.spi.ResourceBundleProvider;
+
+/**
+ * An interface for the internal locale data provider for which {@code ResourceBundle}
+ * searches.
+ */
+public interface CurrencyNamesProvider extends ResourceBundleProvider {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/util/resources/cldr/LocaleNamesProvider.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.util.resources.cldr;
+
+import java.util.spi.ResourceBundleProvider;
+
+/**
+ * An interface for the internal locale data provider for which {@code ResourceBundle}
+ * searches.
+ */
+public interface LocaleNamesProvider extends ResourceBundleProvider {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/util/resources/cldr/TimeZoneNamesProvider.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.util.resources.cldr;
+
+import java.util.spi.ResourceBundleProvider;
+
+/**
+ * An interface for the internal locale data provider for which {@code ResourceBundle}
+ * searches.
+ */
+public interface TimeZoneNamesProvider extends ResourceBundleProvider {
+}
--- a/src/java.base/share/conf/security/java.policy	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/conf/security/java.policy	Thu Mar 17 19:04:16 2016 +0000
@@ -1,37 +1,10 @@
 // permissions required by each component
-grant codeBase "jrt:/java.corba" {
+
+grant codeBase "jrt:/java.activation" {
         permission java.security.AllPermission;
 };
 
-grant codeBase "jrt:/jdk.zipfs" {
-        permission java.io.FilePermission "<<ALL FILES>>", "read,write,delete";
-        permission java.lang.RuntimePermission "fileSystemProvider";
-        permission java.util.PropertyPermission "*", "read";
-};
-
-grant codeBase "jrt:/jdk.localedata" {
-        permission java.lang.RuntimePermission "accessClassInPackage.sun.text.*";
-        permission java.lang.RuntimePermission "accessClassInPackage.sun.util.*";
-        permission java.util.PropertyPermission "*", "read";
-};
-
-grant codeBase "jrt:/jdk.naming.dns" {
-        permission java.security.AllPermission;
-};
-
-grant codeBase "jrt:/jdk.dynalink" {
-        permission java.security.AllPermission;
-};
-
-grant codeBase "jrt:/jdk.scripting.nashorn" {
-        permission java.security.AllPermission;
-};
-
-grant codeBase "jrt:/jdk.scripting.nashorn.shell" {
-        permission java.security.AllPermission;
-};
-
-grant codeBase "jrt:/jdk.internal.le" {
+grant codeBase "jrt:/java.corba" {
         permission java.security.AllPermission;
 };
 
@@ -72,16 +45,36 @@
         permission java.io.FilePermission "<<ALL FILES>>", "read";
 };
 
-grant codeBase "jrt:/java.xml.ws" {
-        permission java.lang.RuntimePermission "accessClassInPackage.com.sun.xml.internal.*";
-        permission java.lang.RuntimePermission "accessClassInPackage.com.sun.istack.internal";
-        permission java.lang.RuntimePermission "accessClassInPackage.com.sun.istack.internal.*";
-        permission java.lang.RuntimePermission "accessClassInPackage.com.sun.org.apache.xerces.internal.*";
-        permission java.lang.RuntimePermission "accessDeclaredMembers";
-        permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
+grant codeBase "jrt:/jdk.dynalink" {
+        permission java.security.AllPermission;
+};
+
+grant codeBase "jrt:/jdk.internal.le" {
+        permission java.security.AllPermission;
+};
+
+grant codeBase "jrt:/jdk.jsobject" {
+        permission java.security.AllPermission;
+};
+
+grant codeBase "jrt:/jdk.localedata" {
+        permission java.lang.RuntimePermission "accessClassInPackage.sun.text.*";
+        permission java.lang.RuntimePermission "accessClassInPackage.sun.util.*";
         permission java.util.PropertyPermission "*", "read";
 };
 
+grant codeBase "jrt:/jdk.naming.dns" {
+        permission java.security.AllPermission;
+};
+
+grant codeBase "jrt:/jdk.scripting.nashorn" {
+        permission java.security.AllPermission;
+};
+
+grant codeBase "jrt:/jdk.scripting.nashorn.shell" {
+        permission java.security.AllPermission;
+};
+
 grant codeBase "jrt:/java.xml.bind" {
         permission java.lang.RuntimePermission "accessClassInPackage.com.sun.xml.internal.*";
         permission java.lang.RuntimePermission "accessClassInPackage.com.sun.istack.internal";
@@ -91,8 +84,20 @@
         permission java.util.PropertyPermission "*", "read";
 };
 
-grant codeBase "jrt:/java.activation" {
-        permission java.security.AllPermission;
+grant codeBase "jrt:/java.xml.ws" {
+        permission java.lang.RuntimePermission "accessClassInPackage.com.sun.xml.internal.*";
+        permission java.lang.RuntimePermission "accessClassInPackage.com.sun.istack.internal";
+        permission java.lang.RuntimePermission "accessClassInPackage.com.sun.istack.internal.*";
+        permission java.lang.RuntimePermission "accessClassInPackage.com.sun.org.apache.xerces.internal.*";
+        permission java.lang.RuntimePermission "accessDeclaredMembers";
+        permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
+        permission java.util.PropertyPermission "*", "read";
+};
+
+grant codeBase "jrt:/jdk.zipfs" {
+        permission java.io.FilePermission "<<ALL FILES>>", "read,write,delete";
+        permission java.lang.RuntimePermission "fileSystemProvider";
+        permission java.util.PropertyPermission "*", "read";
 };
 
 // default permissions granted to all domains
--- a/src/java.base/share/conf/security/java.security	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/conf/security/java.security	Thu Mar 17 19:04:16 2016 +0000
@@ -66,28 +66,28 @@
 # List of providers and their preference orders (see above):
 #
 #ifdef solaris
-security.provider.tbd=com.oracle.security.ucrypto.UcryptoProvider
-security.provider.tbd=sun.security.pkcs11.SunPKCS11 ${java.home}/conf/security/sunpkcs11-solaris.cfg
+security.provider.tbd=OracleUcrypto
+security.provider.tbd=SunPKCS11 ${java.home}/conf/security/sunpkcs11-solaris.cfg
 #endif
-security.provider.tbd=sun.security.provider.Sun
-security.provider.tbd=sun.security.rsa.SunRsaSign
-security.provider.tbd=sun.security.ec.SunEC
-security.provider.tbd=com.sun.net.ssl.internal.ssl.Provider
-security.provider.tbd=com.sun.crypto.provider.SunJCE
-security.provider.tbd=sun.security.jgss.SunProvider
-security.provider.tbd=com.sun.security.sasl.Provider
-security.provider.tbd=org.jcp.xml.dsig.internal.dom.XMLDSigRI
-security.provider.tbd=sun.security.smartcardio.SunPCSC
-security.provider.tbd=sun.security.provider.certpath.ldap.JdkLDAP
-security.provider.tbd=com.sun.security.sasl.gsskerb.JdkSASL
+security.provider.tbd=SUN
+security.provider.tbd=SunRsaSign
+security.provider.tbd=SunEC
+security.provider.tbd=SunJSSE
+security.provider.tbd=SunJCE
+security.provider.tbd=SunJGSS
+security.provider.tbd=SunSASL
+security.provider.tbd=XMLDSig
+security.provider.tbd=SunPCSC
+security.provider.tbd=JdkLDAP
+security.provider.tbd=JdkSASL
 #ifdef windows
-security.provider.tbd=sun.security.mscapi.SunMSCAPI
+security.provider.tbd=SunMSCAPI
 #endif
 #ifdef macosx
-security.provider.tbd=apple.security.AppleProvider
+security.provider.tbd=Apple
 #endif
 #ifndef solaris
-security.provider.tbd=sun.security.pkcs11.SunPKCS11
+security.provider.tbd=SunPKCS11
 #endif
 
 #
@@ -271,6 +271,7 @@
                jdk.internal.,\
                jdk.nashorn.internal.,\
                jdk.nashorn.tools.,\
+               jdk.rmi.rmic.,\
                jdk.tools.jimage.,\
                com.sun.activation.registries.,\
                com.sun.java.accessibility.util.internal.,\
@@ -327,6 +328,7 @@
                    jdk.internal.,\
                    jdk.nashorn.internal.,\
                    jdk.nashorn.tools.,\
+                   jdk.rmi.rmic.,\
                    jdk.tools.jimage.,\
                    com.sun.activation.registries.,\
                    com.sun.java.accessibility.util.internal.,\
--- a/src/java.base/share/native/include/jni.h	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/native/include/jni.h	Thu Mar 17 19:04:16 2016 +0000
@@ -765,6 +765,17 @@
 
     jobjectRefType (JNICALL *GetObjectRefType)
         (JNIEnv* env, jobject obj);
+
+    /* Module Features */
+
+    jobject (JNICALL *GetModule)
+       (JNIEnv* env, jclass clazz);
+
+    void (JNICALL *AddModuleReads)
+        (JNIEnv* env, jobject m1, jobject m2);
+
+    jboolean (JNICALL *CanReadModule)
+        (JNIEnv* env, jobject m1, jobject m2);
 };
 
 /*
@@ -1857,6 +1868,20 @@
         return functions->GetObjectRefType(this, obj);
     }
 
+    /* Module Features */
+
+    jobject GetModule(jclass clazz) {
+        return functions->GetModule(this, clazz);
+    }
+
+    void AddModuleReads(jobject m1, jobject m2) {
+        functions->AddModuleReads(this, m1, m2);
+    }
+
+    jboolean CanReadModule(jobject m1, jobject m2) {
+        return functions->CanReadModule(this, m1, m2);
+    }
+
 #endif /* __cplusplus */
 };
 
--- a/src/java.base/share/native/include/jvm.h	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/native/include/jvm.h	Thu Mar 17 19:04:16 2016 +0000
@@ -393,6 +393,41 @@
                           const char *source);
 
 /*
+ * Module support funcions
+ */
+
+JNIEXPORT void JNICALL
+JVM_DefineModule(JNIEnv *env, jobject module, jstring version, jstring location,
+                 jobjectArray packages);
+
+JNIEXPORT void JNICALL
+JVM_SetBootLoaderUnnamedModule(JNIEnv *env, jobject module);
+
+JNIEXPORT void JNICALL
+JVM_AddReadsModule(JNIEnv *env, jobject from_module, jobject to_module);
+
+JNIEXPORT jboolean JNICALL
+JVM_CanReadModule(JNIEnv *env, jobject asking_module, jobject source_module);
+
+JNIEXPORT void JNICALL
+JVM_AddModuleExports(JNIEnv *env, jobject from_module, jstring package, jobject to_module);
+
+JNIEXPORT void JNICALL
+JVM_AddModuleExportsToAll(JNIEnv *env, jobject from_module, jstring package);
+
+JNIEXPORT void JNICALL
+JVM_AddModuleExportsToAllUnnamed(JNIEnv *env, jobject from_module, jstring package);
+
+JNIEXPORT jboolean JNICALL
+JVM_IsExportedToModule(JNIEnv *env, jobject from_module, jstring package, jobject to_module);
+
+JNIEXPORT void JNICALL
+JVM_AddModulePackage(JNIEnv* env,  jobject module, jstring package);
+
+JNIEXPORT jobject JNICALL
+JVM_GetModuleByPackageName(JNIEnv *env, jobject cl, jstring pkg);
+
+/*
  * Reflection support functions
  */
 
--- a/src/java.base/share/native/include/jvmti.h	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/native/include/jvmti.h	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,8 +23,7 @@
  * questions.
  */
 
-    /* AUTOMATICALLY GENERATED FILE - DO NOT EDIT */
-
+ /* AUTOMATICALLY GENERATED FILE - DO NOT EDIT */
 
     /* Include file for the Java(tm) Virtual Machine Tool Interface */
 
@@ -42,8 +41,9 @@
     JVMTI_VERSION_1_0 = 0x30010000,
     JVMTI_VERSION_1_1 = 0x30010100,
     JVMTI_VERSION_1_2 = 0x30010200,
-
-    JVMTI_VERSION = 0x30000000 + (1 * 0x10000) + (2 * 0x100) + 1  /* version: 1.2.1 */
+    JVMTI_VERSION_9   = 0x30090000,
+
+    JVMTI_VERSION = 0x30000000 + (9 * 0x10000) + (0 * 0x100) + 0  /* version: 9.0.0 */
 };
 
 JNIEXPORT jint JNICALL
@@ -703,7 +703,8 @@
     unsigned int can_retransform_any_class : 1;
     unsigned int can_generate_resource_exhaustion_heap_events : 1;
     unsigned int can_generate_resource_exhaustion_threads_events : 1;
-    unsigned int : 7;
+    unsigned int can_generate_early_vmstart : 1;
+    unsigned int : 6;
     unsigned int : 16;
     unsigned int : 16;
     unsigned int : 16;
@@ -1011,8 +1012,10 @@
     jthread event_thread,
      ...);
 
-  /*   3 :  RESERVED */
-  void *reserved3;
+  /*   3 : Get All Modules */
+  jvmtiError (JNICALL *GetAllModules) (jvmtiEnv* env,
+    jint* module_count_ptr,
+    jobject** modules_ptr);
 
   /*   4 : Get All Threads */
   jvmtiError (JNICALL *GetAllThreads) (jvmtiEnv* env,
@@ -1675,7 +1678,7 @@
   /*   132 : Set System Property */
   jvmtiError (JNICALL *SetSystemProperty) (jvmtiEnv* env,
     const char* property,
-    const char* value);
+    const char* value_ptr);
 
   /*   133 : Get Phase */
   jvmtiError (JNICALL *GetPhase) (jvmtiEnv* env,
@@ -2137,6 +2140,11 @@
     return functions->ClearFieldModificationWatch(this, klass, field);
   }
 
+  jvmtiError GetAllModules(jint* module_count_ptr,
+            jobject** modules_ptr) {
+    return functions->GetAllModules(this, module_count_ptr, modules_ptr);
+  }
+
   jvmtiError GetLoadedClasses(jint* class_count_ptr,
             jclass** classes_ptr) {
     return functions->GetLoadedClasses(this, class_count_ptr, classes_ptr);
@@ -2484,8 +2492,8 @@
   }
 
   jvmtiError SetSystemProperty(const char* property,
-            const char* value) {
-    return functions->SetSystemProperty(this, property, value);
+            const char* value_ptr) {
+    return functions->SetSystemProperty(this, property, value_ptr);
   }
 
   jvmtiError GetPhase(jvmtiPhase* phase_ptr) {
@@ -2531,4 +2539,3 @@
 #endif /* __cplusplus */
 
 #endif /* !_JAVA_JVMTI_H_ */
-
--- a/src/java.base/share/native/launcher/defines.h	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/native/launcher/defines.h	Thu Mar 17 19:04:16 2016 +0000
@@ -53,9 +53,10 @@
  * value of -cp option to the launcher.
  */
 #ifndef APP_CLASSPATH
-#define APP_CLASSPATH        { "/lib/tools.jar", "/classes" }
+static const char* const_appclasspath[] = { NULL };
+#else
+static const char* const_appclasspath[] = APP_CLASSPATH;
 #endif /* APP_CLASSPATH */
-static const char* const_appclasspath[] = APP_CLASSPATH;
 #else  /* !JAVA_ARGS */
 #define HAS_JAVA_ARGS JNI_FALSE
 #ifdef PROGNAME
@@ -64,7 +65,7 @@
 static char* const_progname = NULL;
 #endif
 static const char** const_jargs = NULL;
-static const char** const_appclasspath = NULL;
+static const char* const_appclasspath[] = { NULL };
 #endif /* JAVA_ARGS */
 
 #ifdef LAUNCHER_NAME
--- a/src/java.base/share/native/launcher/main.c	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/native/launcher/main.c	Thu Mar 17 19:04:16 2016 +0000
@@ -83,7 +83,7 @@
 int WINAPI
 WinMain(HINSTANCE inst, HINSTANCE previnst, LPSTR cmdline, int cmdshow)
 {
-    int margc;
+    int margc, appclassc;
     char** margv;
     const jboolean const_javaw = JNI_TRUE;
 
@@ -93,7 +93,7 @@
 int
 main(int argc, char **argv)
 {
-    int margc;
+    int margc, appclassc;
     char** margv;
     const jboolean const_javaw = JNI_FALSE;
 #endif /* JAVAW */
@@ -148,9 +148,14 @@
         margv = args->elements;
     }
 #endif /* WIN32 */
+    if (const_appclasspath[0] == NULL) {
+        appclassc = 0;
+    } else {
+        appclassc = sizeof(const_appclasspath) / sizeof(char *);
+    }
     return JLI_Launch(margc, margv,
                    sizeof(const_jargs) / sizeof(char *), const_jargs,
-                   sizeof(const_appclasspath) / sizeof(char *), const_appclasspath,
+                   appclassc, const_appclasspath,
                    VERSION_STRING,
                    DOT_VERSION,
                    (const_progname != NULL) ? const_progname : *margv,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/native/libjava/BootLoader.c	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include <stdlib.h>
+#include "jvm.h"
+#include "jni_util.h"
+#include "jdk_internal_loader_BootLoader.h"
+
+JNIEXPORT jstring JNICALL
+Java_jdk_internal_loader_BootLoader_getSystemPackageLocation(JNIEnv *env, jclass cls, jstring str)
+{
+    return JVM_GetSystemPackage(env, str);
+}
+
+JNIEXPORT jobject JNICALL
+Java_jdk_internal_loader_BootLoader_getSystemPackageNames(JNIEnv *env, jclass cls)
+{
+    return JVM_GetSystemPackages(env);
+}
+
+JNIEXPORT void JNICALL
+Java_jdk_internal_loader_BootLoader_setBootLoaderUnnamedModule0(JNIEnv *env, jclass cls, jobject module)
+{
+    JVM_SetBootLoaderUnnamedModule(env, module);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/native/libjava/Module.c	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "jni.h"
+#include "jvm.h"
+
+#include "java_lang_reflect_Module.h"
+
+JNIEXPORT void JNICALL
+Java_java_lang_reflect_Module_defineModule0(JNIEnv *env, jclass cls, jobject module,
+                                            jstring version, jstring location,
+                                            jobjectArray packages)
+{
+    JVM_DefineModule(env, module, version, location, packages);
+}
+
+JNIEXPORT void JNICALL
+Java_java_lang_reflect_Module_addReads0(JNIEnv *env, jclass cls, jobject from, jobject to)
+{
+    JVM_AddReadsModule(env, from, to);
+}
+
+JNIEXPORT void JNICALL
+Java_java_lang_reflect_Module_addExports0(JNIEnv *env, jclass cls, jobject from,
+                                          jstring pkg, jobject to)
+{
+    JVM_AddModuleExports(env, from, pkg, to);
+}
+
+JNIEXPORT void JNICALL
+Java_java_lang_reflect_Module_addExportsToAll0(JNIEnv *env, jclass cls, jobject from,
+                                               jstring pkg)
+{
+    JVM_AddModuleExportsToAll(env, from, pkg);
+}
+
+JNIEXPORT void JNICALL
+Java_java_lang_reflect_Module_addExportsToAllUnnamed0(JNIEnv *env, jclass cls,
+                                                      jobject from, jstring pkg)
+{
+    JVM_AddModuleExportsToAllUnnamed(env, from, pkg);
+}
+
+JNIEXPORT void JNICALL
+Java_java_lang_reflect_Module_addPackage0(JNIEnv *env, jclass cls, jobject m, jstring pkg)
+{
+    JVM_AddModulePackage(env, m, pkg);
+}
--- a/src/java.base/share/native/libjava/Package.c	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 1998, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#include <stdlib.h>
-#include "jvm.h"
-#include "jni_util.h"
-#include "java_lang_Package.h"
-
-JNIEXPORT jstring JNICALL
-Java_java_lang_Package_getSystemPackage0(JNIEnv *env, jclass cls, jstring str)
-{
-    return JVM_GetSystemPackage(env, str);
-}
-
-JNIEXPORT jobject JNICALL
-Java_java_lang_Package_getSystemPackages0(JNIEnv *env, jclass cls)
-{
-    return JVM_GetSystemPackages(env);
-}
--- a/src/java.base/share/native/libjava/Proxy.c	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,110 +0,0 @@
-/*
- * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#include <stdlib.h>
-
-#include "jni.h"
-#include "jni_util.h"
-
-#include "java_lang_reflect_Proxy.h"
-
-/* defined in libverify.so/verify.dll (src file common/check_format.c) */
-extern jboolean VerifyFixClassname(char *utf_name);
-
-/*
- * Class:     java_lang_reflect_Proxy
- * Method:    defineClass0
- * Signature: (Ljava/lang/ClassLoader;Ljava/lang/String;[BII)Ljava/lang/Class;
- *
- * The implementation of this native static method is a copy of that of
- * the native instance method Java_java_lang_ClassLoader_defineClass0()
- * with the implicit "this" parameter becoming the "loader" parameter.
- */
-JNIEXPORT jclass JNICALL
-Java_java_lang_reflect_Proxy_defineClass0(JNIEnv *env,
-                                          jclass ignore,
-                                          jobject loader,
-                                          jstring name,
-                                          jbyteArray data,
-                                          jint offset,
-                                          jint length)
-{
-    jbyte *body;
-    char *utfName;
-    jclass result = 0;
-    char buf[128];
-
-    if (data == NULL) {
-        JNU_ThrowNullPointerException(env, 0);
-        return 0;
-    }
-
-    /* Work around 4153825. malloc crashes on Solaris when passed a
-     * negative size.
-     */
-    if (length < 0) {
-        JNU_ThrowArrayIndexOutOfBoundsException(env, 0);
-        return 0;
-    }
-
-    body = (jbyte *)malloc(length);
-
-    if (body == 0) {
-        JNU_ThrowOutOfMemoryError(env, 0);
-        return 0;
-    }
-
-    (*env)->GetByteArrayRegion(env, data, offset, length, body);
-
-    if ((*env)->ExceptionOccurred(env))
-        goto free_body;
-
-    if (name != NULL) {
-        jsize len = (*env)->GetStringUTFLength(env, name);
-        jsize unicode_len = (*env)->GetStringLength(env, name);
-        if (len >= (jsize)sizeof(buf)) {
-            utfName = malloc(len + 1);
-            if (utfName == NULL) {
-                JNU_ThrowOutOfMemoryError(env, NULL);
-                goto free_body;
-            }
-        } else {
-            utfName = buf;
-        }
-        (*env)->GetStringUTFRegion(env, name, 0, unicode_len, utfName);
-        VerifyFixClassname(utfName);
-    } else {
-        utfName = NULL;
-    }
-
-    result = (*env)->DefineClass(env, utfName, loader, body, length);
-
-    if (utfName && utfName != buf)
-        free(utfName);
-
- free_body:
-    free(body);
-    return result;
-}
--- a/src/java.base/share/native/libjava/Reflection.c	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/native/libjava/Reflection.c	Thu Mar 17 19:04:16 2016 +0000
@@ -23,23 +23,24 @@
  * questions.
  */
 
+#include "jni.h"
 #include "jvm.h"
 #include "sun_reflect_Reflection.h"
 
-JNIEXPORT jclass JNICALL Java_sun_reflect_Reflection_getCallerClass__
-(JNIEnv *env, jclass unused)
+JNIEXPORT jclass JNICALL
+Java_sun_reflect_Reflection_getCallerClass__(JNIEnv *env, jclass unused)
 {
     return JVM_GetCallerClass(env, JVM_CALLER_DEPTH);
 }
 
-JNIEXPORT jclass JNICALL Java_sun_reflect_Reflection_getCallerClass__I
-(JNIEnv *env, jclass unused, jint depth)
+JNIEXPORT jclass JNICALL
+Java_sun_reflect_Reflection_getCallerClass__I(JNIEnv *env, jclass unused, jint depth)
 {
     return JVM_GetCallerClass(env, depth);
 }
 
-JNIEXPORT jint JNICALL Java_sun_reflect_Reflection_getClassAccessFlags
-(JNIEnv *env, jclass unused, jclass cls)
+JNIEXPORT jint JNICALL
+Java_sun_reflect_Reflection_getClassAccessFlags(JNIEnv *env, jclass unused, jclass cls)
 {
     return JVM_GetClassAccessFlags(env, cls);
 }
--- a/src/java.base/share/native/libjimage/ImageNativeSubstrate.cpp	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,661 +0,0 @@
-/*
- * Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *   - Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- *
- *   - Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- *
- *   - Neither the name of Oracle nor the names of its
- *     contributors may be used to endorse or promote products derived
- *     from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <string.h>
-
-#include "jni.h"
-#include "jni_util.h"
-
-#include "endian.hpp"
-#include "imageDecompressor.hpp"
-#include "imageFile.hpp"
-#include "inttypes.hpp"
-#include "jimage.hpp"
-#include "osSupport.hpp"
-
-#include "jdk_internal_jimage_ImageNativeSubstrate.h"
-
-extern bool MemoryMapImage;
-
-/////////////////////////////////////////////////////////////////////////////
-
-// Static function for primitive throw since libjimage is not linked with libjava
-static void JNICALL ThrowByName(JNIEnv *env, const char *name, const char *msg)
-{
-    jclass cls = (env)->FindClass(name);
-
-    if (cls != 0) /* Otherwise an exception has already been thrown */
-        (env)->ThrowNew(cls, msg);
-}
-
-// jdk.internal.jimage /////////////////////////////////////////////////////////
-
-// Java entry to open an image file for sharing.
-
-static jlong JIMAGE_Open(JNIEnv *env, const char *nativePath, jboolean big_endian) {
-    // Open image file for reading.
-    ImageFileReader* reader = ImageFileReader::open(nativePath, big_endian != JNI_FALSE);
-    // Return image ID as a jlong.
-    return ImageFileReader::readerToID(reader);
-}
-
-// Java entry for closing a shared image file.
-
-static void JIMAGE_Close(JNIEnv *env, jlong id) {
-    // Convert image ID to image reader structure.
-    ImageFileReader* reader = ImageFileReader::idToReader(id);
-    // If valid reader the close.
-    if (reader != NULL) {
-        ImageFileReader::close(reader);
-    }
-}
-
-// Java entry for accessing the base address of the image index.
-
-static jlong JIMAGE_GetIndexAddress(JNIEnv *env, jlong id) {
-    // Convert image ID to image reader structure.
-    ImageFileReader* reader = ImageFileReader::idToReader(id);
-    // If valid reader return index base address (as jlong) else zero.
-    return reader != NULL ? (jlong) reader->get_index_address() : 0L;
-}
-
-// Java entry for accessing the base address of the image data.
-
-static jlong JIMAGE_GetDataAddress(JNIEnv *env, jlong id) {
-    // Convert image ID to image reader structure.
-    ImageFileReader* reader = ImageFileReader::idToReader(id);
-    // If valid reader return data base address (as jlong) else zero.
-    return MemoryMapImage && reader != NULL ? (jlong) reader->get_data_address() : 0L;
-}
-
-// Java entry for reading an uncompressed resource from the image.
-
-static jboolean JIMAGE_Read(JNIEnv *env, jlong id, jlong offset,
-        unsigned char* uncompressedAddress, jlong uncompressed_size) {
-    // Convert image ID to image reader structure.
-    ImageFileReader* reader = ImageFileReader::idToReader(id);\
-  // If not a valid reader the fail the read.
-    if (reader == NULL) return false;
-    // Get the file offset of resource data.
-    u8 file_offset = reader->get_index_size() + offset;
-    // Check validity of arguments.
-    if (offset < 0 ||
-            uncompressed_size < 0 ||
-            file_offset > reader->file_size() - uncompressed_size) {
-        return false;
-    }
-    // Read file content into buffer.
-    return (jboolean) reader->read_at((u1*) uncompressedAddress, uncompressed_size,
-            file_offset);
-}
-
-// Java entry for reading a compressed resource from the image.
-
-static jboolean JIMAGE_ReadCompressed(JNIEnv *env,
-        jlong id, jlong offset,
-        unsigned char* compressedAddress, jlong compressed_size,
-        unsigned char* uncompressedAddress, jlong uncompressed_size) {
-    // Convert image ID to image reader structure.
-    ImageFileReader* reader = ImageFileReader::idToReader(id);
-    // If not a valid reader the fail the read.
-    if (reader == NULL) return false;
-    // Get the file offset of resource data.
-    u8 file_offset = reader->get_index_size() + offset;
-    // Check validity of arguments.
-    if (offset < 0 ||
-            compressed_size < 0 ||
-            uncompressed_size < 0 ||
-            file_offset > reader->file_size() - compressed_size) {
-        return false;
-    }
-
-    // Read file content into buffer.
-    bool is_read = reader->read_at(compressedAddress, compressed_size,
-            file_offset);
-    // If successfully read then decompress.
-    if (is_read) {
-        const ImageStrings strings = reader->get_strings();
-        ImageDecompressor::decompress_resource(compressedAddress, uncompressedAddress,
-                (u4) uncompressed_size, &strings);
-    }
-    return (jboolean) is_read;
-}
-
-// Java entry for retrieving UTF-8 bytes from image string table.
-
-static const char* JIMAGE_GetStringBytes(JNIEnv *env, jlong id, jint offset) {
-    // Convert image ID to image reader structure.
-    ImageFileReader* reader = ImageFileReader::idToReader(id);
-    // Fail if not valid reader.
-    if (reader == NULL) return NULL;
-    // Manage image string table.
-    ImageStrings strings = reader->get_strings();
-    // Retrieve string adrress from table.
-    const char* data = strings.get(offset);
-    return data;
-}
-
-// Utility function to copy location information into a jlong array.
-// WARNING: This function is experimental and temporary during JDK 9 development
-// cycle. It will not be supported in the eventual JDK 9 release.
-
-static void image_expand_location(JNIEnv *env, jlong* rawAttributes, ImageLocation& location) {
-    // Copy attributes from location.
-    for (int kind = ImageLocation::ATTRIBUTE_END + 1;
-            kind < ImageLocation::ATTRIBUTE_COUNT;
-            kind++) {
-        rawAttributes[kind] = location.get_attribute(kind);
-    }
-}
-
-// Java entry for retrieving location attributes for attribute offset.
-
-static jlong* JIMAGE_GetAttributes(JNIEnv *env, jlong* rawAttributes, jlong id, jint offset) {
-    // Convert image ID to image reader structure.
-    ImageFileReader* reader = ImageFileReader::idToReader(id);
-    // Fail if not valid reader.
-    if (reader == NULL) return NULL;
-    // Retrieve first byte address of resource's location attribute stream.
-    u1* data = reader->get_location_offset_data(offset);
-    // Fail if not valid offset.
-    if (data == NULL) return NULL;
-    // Expand stream into array.
-    ImageLocation location(data);
-    image_expand_location(env, rawAttributes, location);
-    return rawAttributes;
-}
-
-// Java entry for retrieving location attributes count for attribute offset.
-
-static jsize JIMAGE_GetAttributesCount(JNIEnv *env) {
-    return ImageLocation::ATTRIBUTE_COUNT;
-}
-
-// Java entry for retrieving location attributes for named resource.
-
-static jlong* JIMAGE_FindAttributes(JNIEnv *env, jlong* rawAttributes, jbyte* rawBytes, jsize size, jlong id) {
-    // Convert image ID to image reader structure.
-    ImageFileReader* reader = ImageFileReader::idToReader(id);
-    // Fail if not valid reader.
-    if (reader == NULL) return NULL;
-    // Convert byte array to a cstring.
-    char* path = new char[size + 1];
-    if (path == NULL) {
-        return NULL;
-    }
-    memcpy(path, rawBytes, size);
-    path[size] = '\0';
-    // Locate resource location data.
-    ImageLocation location;
-    bool found = reader->find_location(path, location);
-    delete[] path;
-    // Resource not found.
-    if (!found) return NULL;
-    // Expand stream into array.
-    image_expand_location(env, rawAttributes, location);
-    return rawAttributes;
-}
-
-// Java entry for retrieving all the attribute stream offsets from an image.
-
-static jint* JIMAGE_AttributeOffsets(JNIEnv *env, jint* rawOffsets, unsigned int length, jlong id) {
-    // Convert image ID to image reader structure.
-    ImageFileReader* reader = ImageFileReader::idToReader(id);
-    // Fail if not valid reader.
-    if (reader == NULL) return NULL;
-    // Determine endian for reader.
-    Endian* endian = reader->endian();
-    // Get base address of attribute stream offsets table.
-    u4* offsets_table = reader->offsets_table();
-    // Allocate int array result.
-    // Copy values to result (converting endian.)
-    for (u4 i = 0; i < length; i++) {
-        rawOffsets[i] = endian->get(offsets_table[i]);
-    }
-    return rawOffsets;
-}
-
-// Java entry for retrieving all the attribute stream offsets length from an image.
-
-static unsigned int JIMAGE_AttributeOffsetsLength(JNIEnv *env, jlong id) {
-    // Convert image ID to image reader structure.
-    ImageFileReader* reader = ImageFileReader::idToReader(id);
-    // Fail if not valid reader.
-    if (reader == NULL) return 0;
-    // Get perfect hash table length.
-    u4 length = reader->table_length();
-    return (jint) length;
-}
-
-JNIEXPORT jint JNICALL
-DEF_JNI_OnLoad(JavaVM *vm, void *reserved) {
-    JNIEnv *env;
-
-    if (vm->GetEnv((void**) &env, JNI_VERSION_1_2) != JNI_OK) {
-        return JNI_EVERSION; /* JNI version not supported */
-    }
-
-    return JNI_VERSION_1_2;
-}
-
-JNIEXPORT jlong JNICALL
-Java_jdk_internal_jimage_ImageNativeSubstrate_openImage(JNIEnv *env,
-        jclass cls, jstring path, jboolean big_endian) {
-    const char *nativePath;
-    jlong ret;
-
-    nativePath = env->GetStringUTFChars(path, NULL);
-    ret = JIMAGE_Open(env, nativePath, big_endian);
-    env->ReleaseStringUTFChars(path, nativePath);
-    return ret;
-}
-
-JNIEXPORT void JNICALL
-Java_jdk_internal_jimage_ImageNativeSubstrate_closeImage(JNIEnv *env,
-        jclass cls, jlong id) {
-    JIMAGE_Close(env, id);
-}
-
-JNIEXPORT jlong JNICALL
-Java_jdk_internal_jimage_ImageNativeSubstrate_getIndexAddress(JNIEnv *env,
-        jclass cls, jlong id) {
-    return JIMAGE_GetIndexAddress(env, id);
-}
-
-JNIEXPORT jlong JNICALL
-Java_jdk_internal_jimage_ImageNativeSubstrate_getDataAddress(JNIEnv *env,
-        jclass cls, jlong id) {
-    return JIMAGE_GetDataAddress(env, id);
-}
-
-JNIEXPORT jboolean JNICALL
-Java_jdk_internal_jimage_ImageNativeSubstrate_read(JNIEnv *env,
-        jclass cls, jlong id, jlong offset,
-        jobject uncompressedBuffer, jlong uncompressed_size) {
-    unsigned char* uncompressedAddress;
-
-    uncompressedAddress = (unsigned char*) env->GetDirectBufferAddress(uncompressedBuffer);
-    if (uncompressedAddress == NULL) {
-        return JNI_FALSE;
-    }
-    return JIMAGE_Read(env, id, offset, uncompressedAddress, uncompressed_size);
-}
-
-JNIEXPORT jboolean JNICALL
-Java_jdk_internal_jimage_ImageNativeSubstrate_readCompressed(JNIEnv *env,
-        jclass cls, jlong id, jlong offset,
-        jobject compressedBuffer, jlong compressed_size,
-        jobject uncompressedBuffer, jlong uncompressed_size) {
-    // Get address of read direct buffer.
-    unsigned char* compressedAddress;
-    unsigned char* uncompressedAddress;
-
-    compressedAddress = (unsigned char*) env->GetDirectBufferAddress(compressedBuffer);
-    // Get address of decompression direct buffer.
-    uncompressedAddress = (unsigned char*) env->GetDirectBufferAddress(uncompressedBuffer);
-    if (compressedAddress == NULL || uncompressedAddress == NULL) {
-        return JNI_FALSE;
-    }
-    return JIMAGE_ReadCompressed(env, id, offset, compressedAddress, compressed_size,
-            uncompressedAddress, uncompressed_size);
-}
-
-JNIEXPORT jbyteArray JNICALL
-Java_jdk_internal_jimage_ImageNativeSubstrate_getStringBytes(JNIEnv *env,
-        jclass cls, jlong id, jint offset) {
-    const char* data;
-    size_t size;
-    jbyteArray byteArray;
-    jbyte* rawBytes;
-
-    data = JIMAGE_GetStringBytes(env, id, offset);
-    // Determine String length.
-    size = strlen(data);
-    // Allocate byte array.
-    byteArray = env->NewByteArray((jsize) size);
-    if (byteArray == NULL) {
-        return NULL;
-    }
-    // Get array base address.
-    rawBytes = env->GetByteArrayElements(byteArray, NULL);
-    // Copy bytes from image string table.
-    memcpy(rawBytes, data, size);
-    // Release byte array base address.
-    env->ReleaseByteArrayElements(byteArray, rawBytes, 0);
-    return byteArray;
-}
-
-JNIEXPORT jlongArray JNICALL
-Java_jdk_internal_jimage_ImageNativeSubstrate_getAttributes(JNIEnv *env,
-        jclass cls, jlong id, jint offset) {
-    // Allocate a jlong large enough for all location attributes.
-    jlongArray attributes;
-    jlong* rawAttributes;
-    jlong* ret;
-
-    attributes = env->NewLongArray(JIMAGE_GetAttributesCount(env));
-    if (attributes == NULL) {
-        return NULL;
-    }
-    // Get base address for jlong array.
-    rawAttributes = env->GetLongArrayElements(attributes, NULL);
-    ret = JIMAGE_GetAttributes(env, rawAttributes, id, offset);
-    // Release jlong array base address.
-    env->ReleaseLongArrayElements(attributes, rawAttributes, 0);
-    return ret == NULL ? NULL : attributes;
-}
-
-JNIEXPORT jlongArray JNICALL
-Java_jdk_internal_jimage_ImageNativeSubstrate_findAttributes(JNIEnv *env,
-        jclass cls, jlong id, jbyteArray utf8) {
-    // Allocate a jlong large enough for all location attributes.
-    jsize count;
-    jlongArray attributes;
-    jlong* rawAttributes;
-    jsize size;
-    jbyte* rawBytes;
-    jlong* ret;
-
-    count = JIMAGE_GetAttributesCount(env);
-    attributes = env->NewLongArray(JIMAGE_GetAttributesCount(env));
-    if (attributes == NULL) {
-        return NULL;
-    }
-    // Get base address for jlong array.
-    rawAttributes = env->GetLongArrayElements(attributes, NULL);
-    size = env->GetArrayLength(utf8);
-    rawBytes = env->GetByteArrayElements(utf8, NULL);
-    ret = JIMAGE_FindAttributes(env, rawAttributes, rawBytes, size, id);
-    env->ReleaseByteArrayElements(utf8, rawBytes, 0);
-    // Release jlong array base address.
-    env->ReleaseLongArrayElements(attributes, rawAttributes, 0);
-    return ret == NULL ? NULL : attributes;
-
-}
-
-JNIEXPORT jintArray JNICALL
-Java_jdk_internal_jimage_ImageNativeSubstrate_attributeOffsets(JNIEnv *env,
-        jclass cls, jlong id) {
-    unsigned int length;
-    jintArray offsets;
-    jint* rawOffsets;
-    jint* ret;
-
-    length = JIMAGE_AttributeOffsetsLength(env, id);
-    offsets = env->NewIntArray(length);
-    if (offsets == NULL) {
-        return NULL;
-    }
-    // Get base address of result.
-    rawOffsets = env->GetIntArrayElements(offsets, NULL);
-    ret = JIMAGE_AttributeOffsets(env, rawOffsets, length, id);
-    if (length == 0) {
-        return NULL;
-    }
-    // Release result base address.
-    env->ReleaseIntArrayElements(offsets, rawOffsets, 0);
-    return ret == NULL ? NULL : offsets;
-}
-
-/*
- * Class:     jdk_internal_jimage_ImageNativeSubstrate
- * Method:    JIMAGE_open
- * Signature: (Ljava/lang/String;)J
- */
-JNIEXPORT jlong JNICALL Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1Open
-(JNIEnv *env, jclass, jstring path) {
-    const char *nativePath = env->GetStringUTFChars(path, NULL);
-    if (nativePath == NULL)
-        return 0; // Exception already thrown
-    jint error;
-    jlong ret = (jlong) JIMAGE_Open(nativePath, &error);
-    env->ReleaseStringUTFChars(path, nativePath);
-    return ret;
-}
-
-/*
- * Class:     jdk_internal_jimage_ImageNativeSubstrate
- * Method:    JIMAGE_Close
- * Signature: (J)J
- */
-JNIEXPORT void JNICALL Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1Close
-(JNIEnv *env, jclass, jlong jimageHandle) {
-    JIMAGE_Close((JImageFile*) jimageHandle);
-}
-
-/*
- * Class:     jdk_internal_jimage_ImageNativeSubstrate
- * Method:    JIMAGE_FindResource
- * Signature: (JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;[J)J
- */
-JNIEXPORT jlong JNICALL Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1FindResource
-(JNIEnv *env, jclass, jlong jimageHandle, jstring moduleName,
-        jstring version, jstring path, jlongArray output_size) {
-    const char *native_module = NULL;
-    const char *native_version = NULL;
-    const char *native_path = NULL;
-    jlong * native_array = NULL;
-    jlong size = 0;
-    jlong ret = 0;
-
-    if (moduleName == NULL) {
-        ThrowByName(env, "java/lang/NullPointerException", "moduleName");
-        return 0;
-    }
-    if (version == NULL) {
-        ThrowByName(env, "java/lang/NullPointerException", "version");
-        return 0;
-    }
-    if (path == NULL) {
-        ThrowByName(env, "java/lang/NullPointerException", "path");
-        return 0;
-    }
-    if (output_size == NULL) {
-        ThrowByName(env, "java/lang/NullPointerException", "size");
-        return 0;
-    }
-
-    do {
-        native_module = env->GetStringUTFChars(moduleName, NULL);
-        if (native_module == NULL)
-            break;
-        native_version = env->GetStringUTFChars(version, NULL);
-        if (native_version == NULL)
-            break;
-        native_path = env->GetStringUTFChars(path, NULL);
-        if (native_path == NULL)
-            break;
-        if (env->GetArrayLength(output_size) < 1)
-            break;
-        // Get base address for jlong array.
-        native_array = env->GetLongArrayElements(output_size, NULL);
-        if (native_array == NULL)
-            break;
-
-        ret = (jlong) JIMAGE_FindResource((JImageFile *) jimageHandle,
-                native_module, native_version, native_path, &size);
-        if (ret != 0)
-            *native_array = size;
-    } while (0);
-
-    if (native_array != NULL)
-        env->ReleaseLongArrayElements(output_size, native_array, 0);
-    if (native_path != NULL)
-        env->ReleaseStringUTFChars(path, native_path);
-    if (native_version != NULL)
-        env->ReleaseStringUTFChars(path, native_version);
-    if (native_module != NULL)
-        env->ReleaseStringUTFChars(path, native_module);
-
-    return ret;
-}
-
-/*
- * Class:     jdk_internal_jimage_ImageNativeSubstrate
- * Method:    JIMAGE_GetResource
- * Signature: (JJ[BJ)J
- */
-JNIEXPORT jlong JNICALL Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1GetResource
-(JNIEnv *env, jclass, jlong jimageHandle, jlong jlocationHandle, jbyteArray buffer, jlong size) {
-    jbyte * native_buffer = NULL;
-    jlong actual_size = 0;
-    do {
-        if (env->GetArrayLength(buffer) < size)
-            break;
-
-        native_buffer = env->GetByteArrayElements(buffer, NULL);
-        if (native_buffer == NULL)
-            break;
-
-        actual_size = JIMAGE_GetResource((JImageFile*) jimageHandle,
-                (JImageLocationRef) jlocationHandle,
-                (char *) native_buffer, size);
-    } while (0);
-    // Release byte array
-    if (native_buffer != NULL)
-        env->ReleaseByteArrayElements(buffer, native_buffer, 0);
-
-    return actual_size;
-}
-
-// Structure passed from iterator to a visitor to accumulate the results
-
-struct VisitorData {
-    JNIEnv *env;
-    int size; // current number of strings
-    int max; // Maximum number of strings
-    jobjectArray array; // String array to store the strings
-};
-
-// Visitor to accumulate fully qualified resource names
-
-static bool resourceVisitor(JImageFile* image,
-        const char* module, const char* version, const char* package,
-        const char* name, const char* extension, void* arg) {
-    struct VisitorData *vdata = (struct VisitorData *) arg;
-    JNIEnv* env = vdata->env;
-    if (vdata->size < vdata->max) {
-        // Store if there is room in the array
-        // Concatenate to get full path
-        char fullpath[IMAGE_MAX_PATH];
-        size_t moduleLen = strlen(module);
-        size_t packageLen = strlen(package);
-        size_t nameLen = strlen(name);
-        size_t extLen = strlen(extension);
-        size_t index;
-
-        if (1 + moduleLen + 1 + packageLen + 1 + nameLen + 1 + extLen + 1 > IMAGE_MAX_PATH) {
-            ThrowByName(env, "java/lang/InternalError", "concatenated name too long");
-            return true;
-        }
-
-        index = 0;
-        if (moduleLen > 0) {
-            fullpath[index++] = '/';
-            memcpy(&fullpath[index], module, moduleLen);
-            index += moduleLen;
-            fullpath[index++] = '/';
-        }
-        if (packageLen > 0) {
-            memcpy(&fullpath[index], package, packageLen);
-            index += packageLen;
-            fullpath[index++] = '/';
-        }
-        memcpy(&fullpath[index], name, nameLen);
-        index += nameLen;
-        if (extLen > 0) {
-            fullpath[index++] = '.';
-            memcpy(&fullpath[index], extension, extLen);
-            index += extLen;
-        }
-        fullpath[index++] = '\0';
-
-        jobject str = env->NewStringUTF(fullpath);
-        if (env->ExceptionCheck()) {
-            return true;
-        }
-
-        env->SetObjectArrayElement(vdata->array, vdata->size, str);
-        if (env->ExceptionCheck()) {
-            return true;
-        }
-    }
-    vdata->size++; // always count so the total size is returned
-    return true;
-}
-
-/*
- * Class:     jdk_internal_jimage_ImageNativeSubstrate
- * Method:    JIMAGE_Resources
- * Signature: (J)V
- */
-JNIEXPORT jint JNICALL Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1Resources
-(JNIEnv *env, jclass, jlong jimageHandle,
-        jobjectArray outputNames) {
-    struct VisitorData vdata;
-    vdata.env = env;
-    vdata.max = 0;
-    vdata.size = 0;
-    vdata.array = outputNames;
-
-    vdata.max = (outputNames != NULL) ? env->GetArrayLength(outputNames) : 0;
-    JIMAGE_ResourceIterator((JImageFile*) jimageHandle, &resourceVisitor, &vdata);
-    return vdata.size;
-}
-
-/*
- * Class:     jdk_internal_jimage_ImageNativeSubstrate
- * Method:    JIMAGE_PackageToModule
- * Signature: (JLjava/lang/String;)Ljava/lang/String;
- */
-JNIEXPORT jstring JNICALL Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1PackageToModule
-(JNIEnv *env, jclass, jlong jimageHandle, jstring package_name) {
-    const char *native_package = NULL;
-    const char *native_module = NULL;
-    jstring module = NULL;
-
-    native_package = env->GetStringUTFChars(package_name, NULL);
-    if (env->ExceptionCheck()) {
-        return NULL;
-    }
-
-
-    native_module = JIMAGE_PackageToModule((JImageFile*) jimageHandle, native_package);
-    if (native_module != NULL) {
-        module = env->NewStringUTF(native_module);
-    }
-    env->ReleaseStringUTFChars(package_name, native_package);
-    return module;
-}
-
-JNIEXPORT void JNICALL DEF_JNI_OnUnload(JavaVM *vm, void *reserved) {
-    ImageDecompressor::image_decompressor_close();
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/native/libjimage/NativeImageBuffer.cpp	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+
+#include "jni.h"
+#include "jni_util.h"
+
+#include "endian.hpp"
+#include "imageDecompressor.hpp"
+#include "imageFile.hpp"
+#include "inttypes.hpp"
+#include "jimage.hpp"
+#include "osSupport.hpp"
+
+#include "jdk_internal_jimage_NativeImageBuffer.h"
+
+
+JNIEXPORT jobject JNICALL
+Java_jdk_internal_jimage_NativeImageBuffer_getNativeMap(JNIEnv *env,
+        jclass cls, jstring path) {
+    const char *nativePath = env->GetStringUTFChars(path, NULL);
+    ImageFileReader* reader = ImageFileReader::find_image(nativePath);
+    env->ReleaseStringUTFChars(path, nativePath);
+
+    if (reader != NULL) {
+        return env->NewDirectByteBuffer(reader->get_index_address(), (jlong)reader->map_size());
+    }
+
+    return 0;
+}
--- a/src/java.base/share/native/libjimage/imageDecompressor.cpp	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/native/libjimage/imageDecompressor.cpp	Thu Mar 17 19:04:16 2016 +0000
@@ -111,32 +111,66 @@
     return NULL;
 }
 
+// Sparc to read unaligned content
+// u8 l = (*(u8*) ptr);
+// If ptr is not aligned, sparc will fail.
+u8 ImageDecompressor::getU8(u1* ptr, Endian *endian) {
+    u8 ret;
+    if (endian->is_big_endian()) {
+        ret = (u8)ptr[0] << 56 | (u8)ptr[1] << 48 | (u8)ptr[2]<<40 | (u8)ptr[3]<<32 |
+                ptr[4]<<24 | ptr[5]<<16 | ptr[6]<<8 | ptr[7];
+    } else {
+        ret = ptr[0] | ptr[1]<<8 | ptr[2]<<16 | ptr[3]<<24 | (u8)ptr[4]<<32 |
+                (u8)ptr[5]<<40 | (u8)ptr[6]<<48 | (u8)ptr[7]<<56;
+    }
+    return ret;
+}
+
+u4 ImageDecompressor::getU4(u1* ptr, Endian *endian) {
+    u4 ret;
+    if (endian->is_big_endian()) {
+        ret = ptr[0] << 24 | ptr[1]<<16 | (ptr[2]<<8) | ptr[3];
+    } else {
+        ret = ptr[0] | ptr[1]<<8 | (ptr[2]<<16) | ptr[3]<<24;
+    }
+    return ret;
+}
+
 /*
  * Decompression entry point. Called from ImageFileReader::get_resource.
  */
 void ImageDecompressor::decompress_resource(u1* compressed, u1* uncompressed,
-                u4 uncompressed_size, const ImageStrings* strings) {
+                u8 uncompressed_size, const ImageStrings* strings, Endian *endian) {
     bool has_header = false;
     u1* decompressed_resource = compressed;
     u1* compressed_resource = compressed;
-
     // Resource could have been transformed by a stack of decompressors.
     // Iterate and decompress resources until there is no more header.
     do {
         ResourceHeader _header;
-        memcpy(&_header, compressed_resource, sizeof (ResourceHeader));
+        u1* compressed_resource_base = compressed_resource;
+        _header._magic = getU4(compressed_resource, endian);
+        compressed_resource += 4;
+        _header._size = getU8(compressed_resource, endian);
+        compressed_resource += 8;
+        _header._uncompressed_size = getU8(compressed_resource, endian);
+        compressed_resource += 8;
+        _header._decompressor_name_offset = getU4(compressed_resource, endian);
+        compressed_resource += 4;
+        _header._decompressor_config_offset = getU4(compressed_resource, endian);
+        compressed_resource += 4;
+        _header._is_terminal = *compressed_resource;
+        compressed_resource += 1;
         has_header = _header._magic == ResourceHeader::resource_header_magic;
         if (has_header) {
             // decompressed_resource array contains the result of decompression
-            decompressed_resource = new u1[_header._uncompressed_size];
+            decompressed_resource = new u1[(size_t) _header._uncompressed_size];
             // Retrieve the decompressor name
             const char* decompressor_name = strings->get(_header._decompressor_name_offset);
             assert(decompressor_name && "image decompressor not found");
             // Retrieve the decompressor instance
             ImageDecompressor* decompressor = get_decompressor(decompressor_name);
             assert(decompressor && "image decompressor not found");
-            u1* compressed_resource_base = compressed_resource;
-            compressed_resource += ResourceHeader::resource_header_length;
             // Ask the decompressor to decompress the compressed content
             decompressor->decompress_resource(compressed_resource, decompressed_resource,
                 &_header, strings);
@@ -146,8 +180,8 @@
             compressed_resource = decompressed_resource;
         }
     } while (has_header);
-    memcpy(uncompressed, decompressed_resource, uncompressed_size);
-    delete[] decompressed_resource;
+    memcpy(uncompressed, decompressed_resource, (size_t) uncompressed_size);
+    delete decompressed_resource;
 }
 
 // Zip decompressor
@@ -299,14 +333,14 @@
             }
         }
     }
-    u4 remain = header->_size - (int)(data - data_base);
-    u4 computed = (u4)(uncompressed_resource - uncompressed_base) + remain;
+    u8 remain = header->_size - (int)(data - data_base);
+    u8 computed = (u8)(uncompressed_resource - uncompressed_base) + remain;
     if (header->_uncompressed_size != computed)
-        printf("Failure, expecting %d but getting %d\n", header->_uncompressed_size,
+        printf("Failure, expecting %llu but getting %llu\n", header->_uncompressed_size,
                 computed);
     assert(header->_uncompressed_size == computed &&
                 "Constant Pool reconstruction failed");
-    memcpy(uncompressed_resource, data, remain);
+    memcpy(uncompressed_resource, data, (size_t) remain);
 }
 
 /*
--- a/src/java.base/share/native/libjimage/imageDecompressor.hpp	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/native/libjimage/imageDecompressor.hpp	Thu Mar 17 19:04:16 2016 +0000
@@ -54,13 +54,11 @@
  *   have been used to compress the resource.
  */
 struct ResourceHeader {
-    /* Length of header, needed to retrieve content offset */
-    static const u1 resource_header_length = 21;
     /* magic bytes that identifies a compressed resource header*/
     static const u4 resource_header_magic = 0xCAFEFAFA;
     u4 _magic; // Resource header
-    u4 _size;    // Resource size
-    u4 _uncompressed_size;  // Expected uncompressed size
+    u8 _size;    // Resource size
+    u8 _uncompressed_size;  // Expected uncompressed size
     u4 _decompressor_name_offset;    // Strings table decompressor offset
     u4 _decompressor_config_offset; // Strings table config offset
     u1 _is_terminal; // Last decompressor 1, otherwise 0.
@@ -101,6 +99,8 @@
      */
     inline const char* get_name() const { return _name; }
 
+    static u8 getU8(u1* ptr, Endian *endian);
+    static u4 getU4(u1* ptr, Endian *endian);
 
 protected:
     ImageDecompressor(const char* name) : _name(name) {
@@ -113,7 +113,7 @@
     static void image_decompressor_close();
     static ImageDecompressor* get_decompressor(const char * decompressor_name) ;
     static void decompress_resource(u1* compressed, u1* uncompressed,
-        u4 uncompressed_size, const ImageStrings* strings);
+        u8 uncompressed_size, const ImageStrings* strings, Endian* _endian);
 };
 
 /**
--- a/src/java.base/share/native/libjimage/imageFile.cpp	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/native/libjimage/imageFile.cpp	Thu Mar 17 19:04:16 2016 +0000
@@ -41,7 +41,7 @@
 #include "osSupport.hpp"
 
 // Map the full jimage, only with 64 bit addressing.
-bool MemoryMapImage = sizeof(void *) == 8;
+bool ImageFileReader::memory_map_image = sizeof(void *) == 8;
 
 #ifdef WIN32
 const char FileSeparator = '\\';
@@ -144,142 +144,69 @@
 }
 
 // ImageModuleData constructor maps out sub-tables for faster access.
-ImageModuleData::ImageModuleData(const ImageFileReader* image_file,
-                const char* module_data_name) :
+ImageModuleData::ImageModuleData(const ImageFileReader* image_file) :
         _image_file(image_file),
-        _endian(image_file->endian()),
-        _strings(image_file->get_strings()) {
-    // Retrieve the resource containing the module data for the image file.
-    ImageLocation location;
-    bool found = image_file->find_location(module_data_name, location);
-    if (found) {
-        u8 data_size = location.get_attribute(ImageLocation::ATTRIBUTE_UNCOMPRESSED);
-        _data = new u1[(size_t)data_size];
-        assert(_data != NULL && "allocation failed");
-        _image_file->get_resource(location, _data);
-        // Map out the header.
-        _header = (Header*)_data;
-        // Get the package to module entry count.
-        u4 ptm_count = _header->ptm_count(_endian);
-        // Get the module to package entry count.
-        u4 mtp_count = _header->mtp_count(_endian);
-        // Compute the offset of the package to module perfect hash redirect.
-        u4 ptm_redirect_offset = sizeof(Header);
-        // Compute the offset of the package to module data.
-        u4 ptm_data_offset = ptm_redirect_offset + ptm_count * sizeof(s4);
-        // Compute the offset of the module to package perfect hash redirect.
-        u4 mtp_redirect_offset = ptm_data_offset + ptm_count * sizeof(PTMData);
-        // Compute the offset of the module to package data.
-        u4 mtp_data_offset = mtp_redirect_offset + mtp_count * sizeof(s4);
-        // Compute the offset of the module to package tables.
-        u4 mtp_packages_offset = mtp_data_offset + mtp_count * sizeof(MTPData);
-        // Compute the address of the package to module perfect hash redirect.
-        _ptm_redirect = (s4*)(_data + ptm_redirect_offset);
-        // Compute the address of the package to module data.
-        _ptm_data = (PTMData*)(_data + ptm_data_offset);
-        // Compute the address of the module to package perfect hash redirect.
-        _mtp_redirect = (s4*)(_data + mtp_redirect_offset);
-        // Compute the address of the module to package data.
-        _mtp_data = (MTPData*)(_data + mtp_data_offset);
-        // Compute the address of the module to package tables.
-        _mtp_packages = (s4*)(_data + mtp_packages_offset);
-    } else {
-        // No module data present.
-        _data = NULL;
-        _header = NULL;
-        _ptm_redirect = NULL;
-        _ptm_data = NULL;
-        _mtp_redirect = NULL;
-        _mtp_data = NULL;
-        _mtp_packages = NULL;
-    }
+        _endian(image_file->endian()) {
 }
 
 // Release module data resource.
 ImageModuleData::~ImageModuleData() {
-    if (_data) {
-        delete[] _data;
-    }
 }
 
-// Return the name of the module data resource.  Ex. "./lib/modules/file.jimage"
-// yields "file.jdata"
-void ImageModuleData::module_data_name(char* buffer, const char* image_file_name) {
-    // Locate the last slash in the file name path.
-    const char* slash = strrchr(image_file_name, FileSeparator);
-    // Trim the path to name and extension.
-    const char* name = slash ? slash + 1 : (char *)image_file_name;
-    // Locate the extension period.
-    const char* dot = strrchr(name, '.');
-    assert(dot && "missing extension on jimage name");
-    // Trim to only base name.
-    int length = (int)(dot - name);
-    strncpy(buffer, name, length);
-    buffer[length] = '\0';
-    // Append extension.
-    strcat(buffer, ".jdata");
-}
 
 // Return the module in which a package resides.    Returns NULL if not found.
 const char* ImageModuleData::package_to_module(const char* package_name) {
-    // Test files may contain no module data.
-    if (_data != NULL) {
-        // Search the package to module table.
-        s4 index = ImageStrings::find(_endian, package_name, _ptm_redirect,
-                                      _header->ptm_count(_endian));
-        // If entry is found.
-        if (index != ImageStrings::NOT_FOUND) {
-            // Retrieve the package to module entry.
-            PTMData* data = _ptm_data + index;
-            // Verify that it is the correct data.
-            if (strcmp(package_name, get_string(data->name_offset(_endian))) != 0) {
-                return NULL;
-            }
-            // Return the module name.
-            return get_string(data->module_name_offset(_endian));
-        }
+    // replace all '/' by '.'
+    char* replaced = new char[(int) strlen(package_name) + 1];
+    assert(replaced != NULL && "allocation failed");
+    int i;
+    for (i = 0; package_name[i] != '\0'; i++) {
+      replaced[i] = package_name[i] == '/' ? '.' : package_name[i];
     }
-    return NULL;
-}
+    replaced[i] = '\0';
+
+    // build path /packages/<package_name>
+    const char* radical = "/packages/";
+    char* path = new char[(int) strlen(radical) + (int) strlen(package_name) + 1];
+    assert(path != NULL && "allocation failed");
+    strcpy(path, radical);
+    strcat(path, replaced);
+    delete[] replaced;
 
-// Returns all the package names in a module in a NULL terminated array.
-// Returns NULL if module not found.
-const char** ImageModuleData::module_to_packages(const char* module_name) {
-    // Test files may contain no module data.
-    if (_data != NULL) {
-        // Search the module to package table.
-        s4 index = ImageStrings::find(_endian, module_name, _mtp_redirect,
-                                      _header->mtp_count(_endian));
-        // If entry is found.
-        if (index != ImageStrings::NOT_FOUND) {
-            // Retrieve the module to package entry.
-            MTPData* data = _mtp_data + index;
-            // Verify that it is the correct data.
-            if (strcmp(module_name, get_string(data->name_offset(_endian))) != 0) {
-                return NULL;
-            }
-            // Construct an array of all the package entries.
-            u4 count = data->package_count(_endian);
-            const char** packages = new const char*[count + 1];
-            assert(packages != NULL && "allocation failed");
-            s4 package_offset = data->package_offset(_endian);
-            for (u4 i = 0; i < count; i++) {
-                u4 package_name_offset = mtp_package(package_offset + i);
-                const char* package_name = get_string(package_name_offset);
-                packages[i] = package_name;
-            }
-            packages[count] = NULL;
-            return packages;
+    // retrieve package location
+    ImageLocation location;
+    bool found = _image_file->find_location(path, location);
+    if (!found) {
+        delete[] path;
+        return NULL;
+    }
+
+    // retrieve offsets to module name
+    int size = (int)location.get_attribute(ImageLocation::ATTRIBUTE_UNCOMPRESSED);
+    u1* content = new u1[size];
+    assert(content != NULL && "allocation failed");
+    _image_file->get_resource(location, content);
+    u1* ptr = content;
+    // sequence of sizeof(8) isEmpty|offset. Use the first module that is not empty.
+    u4 offset = 0;
+    for (i = 0; i < size; i+=8) {
+        u4 isEmpty = _endian->get(*((u4*)ptr));
+        ptr += 4;
+        if (!isEmpty) {
+            offset = _endian->get(*((u4*)ptr));
+            break;
         }
+        ptr += 4;
     }
-    return NULL;
+    delete[] content;
+    return _image_file->get_strings().get(offset);
 }
 
 // Manage a table of open image files.  This table allows multiple access points
 // to share an open image.
 ImageFileReaderTable::ImageFileReaderTable() : _count(0), _max(_growth) {
     _table = new ImageFileReader*[_max];
-    assert( _table != NULL && "allocation failed");
+    assert(_table != NULL && "allocation failed");
 }
 
 ImageFileReaderTable::~ImageFileReaderTable() {
@@ -326,26 +253,34 @@
 
 SimpleCriticalSection _reader_table_lock;
 
+// Locate an image if file already open.
+ImageFileReader* ImageFileReader::find_image(const char* name) {
+    // Lock out _reader_table.
+    SimpleCriticalSectionLock cs(&_reader_table_lock);
+    // Search for an exist image file.
+    for (u4 i = 0; i < _reader_table.count(); i++) {
+        // Retrieve table entry.
+        ImageFileReader* reader = _reader_table.get(i);
+        // If name matches, then reuse (bump up use count.)
+        assert(reader->name() != NULL && "reader->name must not be null");
+        if (strcmp(reader->name(), name) == 0) {
+            reader->inc_use();
+            return reader;
+        }
+    }
+
+    return NULL;
+}
+
 // Open an image file, reuse structure if file already open.
 ImageFileReader* ImageFileReader::open(const char* name, bool big_endian) {
-    {
-        // Lock out _reader_table.
-        SimpleCriticalSectionLock cs(&_reader_table_lock);
-        // Search for an exist image file.
-        for (u4 i = 0; i < _reader_table.count(); i++) {
-            // Retrieve table entry.
-            ImageFileReader* reader = _reader_table.get(i);
-            // If name matches, then reuse (bump up use count.)
-            assert(reader->name() != NULL && "reader->name must not be null");
-            if (strcmp(reader->name(), name) == 0) {
-                reader->inc_use();
-                return reader;
-            }
-        }
-    } // Unlock the mutex
+    ImageFileReader* reader = find_image(name);
+    if (reader != NULL) {
+        return reader;
+    }
 
     // Need a new image reader.
-    ImageFileReader* reader = new ImageFileReader(name, big_endian);
+    reader = new ImageFileReader(name, big_endian);
     if (reader == NULL || !reader->open()) {
         // Failed to open.
         delete reader;
@@ -385,21 +320,21 @@
 }
 
 // Return an id for the specifed ImageFileReader.
-u8 ImageFileReader::readerToID(ImageFileReader *reader) {
+u8 ImageFileReader::reader_to_ID(ImageFileReader *reader) {
     // ID is just the cloaked reader address.
     return (u8)reader;
 }
 
 // Validate the image id.
-bool ImageFileReader::idCheck(u8 id) {
+bool ImageFileReader::id_check(u8 id) {
     // Make sure the ID is a managed (_reader_table) reader.
     SimpleCriticalSectionLock cs(&_reader_table_lock);
     return _reader_table.contains((ImageFileReader*)id);
 }
 
 // Return an id for the specifed ImageFileReader.
-ImageFileReader* ImageFileReader::idToReader(u8 id) {
-    assert(idCheck(id) && "invalid image id");
+ImageFileReader* ImageFileReader::id_to_reader(u8 id) {
+    assert(id_check(id) && "invalid image id");
     return (ImageFileReader*)id;
 }
 
@@ -429,8 +364,6 @@
 
 // Open image file for read access.
 bool ImageFileReader::open() {
-    char buffer[IMAGE_MAX_PATH];
-
     // If file exists open for reading.
     _fd = osSupport::openReadOnly(_name);
     if (_fd == -1) {
@@ -454,19 +387,17 @@
     if (_file_size < _index_size) {
         return false;
     }
-    // Determine how much of the image is memory mapped.
-    size_t map_size = (size_t)(MemoryMapImage ? _file_size : _index_size);
     // Memory map image (minimally the index.)
-    _index_data = (u1*)osSupport::map_memory(_fd, _name, 0, map_size);
+    _index_data = (u1*)osSupport::map_memory(_fd, _name, 0, (size_t)map_size());
     assert(_index_data && "image file not memory mapped");
     // Retrieve length of index perfect hash table.
     u4 length = table_length();
     // Compute offset of the perfect hash table redirect table.
     u4 redirect_table_offset = (u4)header_size;
     // Compute offset of index attribute offsets.
-    u4 offsets_table_offset = redirect_table_offset + length * sizeof(s4);
+    u4 offsets_table_offset = redirect_table_offset + length * (u4)sizeof(s4);
     // Compute offset of index location attribute data.
-    u4 location_bytes_offset = offsets_table_offset + length * sizeof(u4);
+    u4 location_bytes_offset = offsets_table_offset + length * (u4)sizeof(u4);
     // Compute offset of index string table.
     u4 string_bytes_offset = location_bytes_offset + locations_size();
     // Compute address of the perfect hash table redirect table.
@@ -479,8 +410,7 @@
     _string_bytes = _index_data + string_bytes_offset;
 
     // Initialize the module data
-    ImageModuleData::module_data_name(buffer, _name);
-    module_data = new ImageModuleData(this, buffer);
+    module_data = new ImageModuleData(this);
     // Successful open (if memory allocation succeeded).
     return module_data != NULL;
 }
@@ -660,10 +590,10 @@
     if (compressed_size != 0) {
         u1* compressed_data;
         // If not memory mapped read in bytes.
-        if (!MemoryMapImage) {
+        if (!memory_map_image) {
             // Allocate buffer for compression.
-            compressed_data = new u1[(u4)compressed_size];
-            assert (compressed_data != NULL && "allocation failed");
+            compressed_data = new u1[(size_t)compressed_size];
+            assert(compressed_data != NULL && "allocation failed");
             // Read bytes from offset beyond the image index.
             bool is_read = read_at(compressed_data, compressed_size, _index_size + offset);
             assert(is_read && "error reading from image or short read");
@@ -673,10 +603,10 @@
         // Get image string table.
         const ImageStrings strings = get_strings();
         // Decompress resource.
-        ImageDecompressor::decompress_resource(compressed_data, uncompressed_data, (u4)uncompressed_size,
-                        &strings);
+        ImageDecompressor::decompress_resource(compressed_data, uncompressed_data, uncompressed_size,
+                        &strings, _endian);
         // If not memory mapped then release temporary buffer.
-        if (!MemoryMapImage) {
+        if (!memory_map_image) {
                 delete[] compressed_data;
         }
     } else {
--- a/src/java.base/share/native/libjimage/imageFile.hpp	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/native/libjimage/imageFile.hpp	Thu Mar 17 19:04:16 2016 +0000
@@ -303,101 +303,17 @@
 };
 
 //
-// NOTE: needs revision.
-// Each loader requires set of module meta data to identify which modules and
-// packages are managed by that loader.  Currently, there is one image file per
-// builtin loader, so only one  module meta data resource per file.
-//
-// Each element in the module meta data is a native endian 4 byte integer.  Note
-// that entries with zero offsets for string table entries should be ignored (
-// padding for hash table lookup.)
-//
-// Format:
-//      Count of package to module entries
-//      Count of module to package entries
-//      Perfect Hash redirect table[Count of package to module entries]
-//      Package to module entries[Count of package to module entries]
-//          Offset to package name in string table
-//          Offset to module name in string table
-//      Perfect Hash redirect table[Count of module to package entries]
-//      Module to package entries[Count of module to package entries]
-//          Offset to module name in string table
-//          Count of packages in module
-//          Offset to first package in packages table
-//      Packages[]
-//          Offset to package name in string table
-//
 // Manage the image module meta data.
 class ImageModuleData {
-    class Header {
-    private:
-        u4 _ptm_count;          // Count of package to module entries
-        u4 _mtp_count;          // Count of module to package entries
-    public:
-        inline u4 ptm_count(Endian* endian) const { return endian->get(_ptm_count); }
-        inline u4 mtp_count(Endian* endian) const { return endian->get(_mtp_count); }
-    };
-
-    // Hashtable entry
-    class HashData {
-    private:
-        u4 _name_offset;        // Name offset in string table
-    public:
-        inline s4 name_offset(Endian* endian) const { return endian->get(_name_offset); }
-    };
-
-    // Package to module hashtable entry
-    class PTMData : public HashData {
-    private:
-        u4 _module_name_offset; // Module name offset in string table
-    public:
-        inline s4 module_name_offset(Endian* endian) const { return endian->get(_module_name_offset); }
-    };
-
-    // Module to package hashtable entry
-    class MTPData : public HashData {
-    private:
-        u4 _package_count;       // Number of packages in module
-        u4 _package_offset;      // Offset in package list
-    public:
-        inline u4 package_count(Endian* endian)  const { return endian->get(_package_count); }
-        inline u4 package_offset(Endian* endian) const { return endian->get(_package_offset); }
-    };
-
     const ImageFileReader* _image_file; // Source image file
-    Endian* _endian;       // Endian handler
-    ImageStrings _strings; // Image file strings
-    u1* _data;             // Module data resource data
-    u8 _data_size;         // Size of resource data
-    Header* _header;       // Module data header
-    s4* _ptm_redirect;     // Package to module hashtable redirect
-    PTMData* _ptm_data;    // Package to module data
-    s4* _mtp_redirect;     // Module to packages hashtable redirect
-    MTPData* _mtp_data;    // Module to packages data
-    s4* _mtp_packages;     // Package data (name offsets)
-
-    // Return a string from the string table.
-    inline const char* get_string(u4 offset) {
-        return _strings.get(offset);
-    }
-
-    inline u4 mtp_package(u4 index) {
-        return _endian->get(_mtp_packages[index]);
-    }
+    Endian* _endian;                    // Endian handler
 
 public:
-    ImageModuleData(const ImageFileReader* image_file, const char* module_data_name);
+    ImageModuleData(const ImageFileReader* image_file);
     ~ImageModuleData();
 
-    // Return the name of the module data resource.
-    static void module_data_name(char* buffer, const char* image_file_name);
-
     // Return the module in which a package resides.    Returns NULL if not found.
     const char* package_to_module(const char* package_name);
-
-    // Returns all the package names in a module in a NULL terminated array.
-    // Returns NULL if module not found.
-    const char** module_to_packages(const char* module_name);
 };
 
 // Image file header, starting at offset 0.
@@ -491,6 +407,9 @@
     // multiple uses (ex. loader.)
     static ImageFileReaderTable _reader_table;
 
+    // true if image should be fully memory mapped.
+    static bool memory_map_image;
+
     char* _name;         // Name of image
     s4 _use;             // Use count
     int _fd;             // File descriptor
@@ -526,6 +445,9 @@
         MINOR_VERSION = 0
     };
 
+    // Locate an image if file already open.
+    static ImageFileReader* find_image(const char* name);
+
     // Open an image file, reuse structure if file already open.
     static ImageFileReader* open(const char* name, bool big_endian = Endian::is_big_endian());
 
@@ -533,13 +455,13 @@
     static void close(ImageFileReader *reader);
 
     // Return an id for the specifed ImageFileReader.
-    static u8 readerToID(ImageFileReader *reader);
+    static u8 reader_to_ID(ImageFileReader *reader);
 
     // Validate the image id.
-    static bool idCheck(u8 id);
+    static bool id_check(u8 id);
 
     // Return an id for the specifed ImageFileReader.
-    static ImageFileReader* idToReader(u8 id);
+    static ImageFileReader* id_to_reader(u8 id);
 
     // Open image file for read access.
     bool open();
@@ -562,6 +484,11 @@
         return _file_size;
     }
 
+    // Retrieve the size of the mapped image.
+    inline u8 map_size() const {
+        return (u8)(memory_map_image ? _file_size : _index_size);
+    }
+
     // Return first address of index data.
     inline u1* get_index_address() const {
         return _index_data;
--- a/src/java.base/share/native/libjimage/jimage.cpp	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/native/libjimage/jimage.cpp	Thu Mar 17 19:04:16 2016 +0000
@@ -48,7 +48,7 @@
  *
  *  Ex.
  *   jint error;
- *   JImageFile* jimage = (*JImageOpen)(JAVA_HOME "lib/modules/bootmodules.jimage", &error);
+ *   JImageFile* jimage = (*JImageOpen)(JAVA_HOME "lib/modules", &error);
  *   if (image == NULL) {
  *     tty->print_cr("JImage failed to open: %d", error);
  *     ...
--- a/src/java.base/share/native/libjimage/jimage.hpp	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/native/libjimage/jimage.hpp	Thu Mar 17 19:04:16 2016 +0000
@@ -62,7 +62,7 @@
  *
  *  Ex.
  *   jint error;
- *   JImageFile* jimage = (*JImageOpen)(JAVA_HOME "lib/modules/bootmodules.jimage", &error);
+ *   JImageFile* jimage = (*JImageOpen)(JAVA_HOME "lib/modules", &error);
  *   if (image == NULL) {
  *     tty->print_cr("JImage failed to open: %d", error);
  *     ...
--- a/src/java.base/share/native/libjli/args.c	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/native/libjli/args.c	Thu Mar 17 19:04:16 2016 +0000
@@ -105,9 +105,15 @@
     if (*arg++ == '-') {
         expectingNoDashArg = JNI_FALSE;
         if (JLI_StrCmp(arg, "cp") == 0 ||
-            JLI_StrCmp(arg, "classpath") == 0) {
+            JLI_StrCmp(arg, "classpath") == 0 ||
+            JLI_StrCmp(arg, "addmods") == 0 ||
+            JLI_StrCmp(arg, "limitmods") == 0 ||
+            JLI_StrCmp(arg, "mp") == 0 ||
+            JLI_StrCmp(arg, "modulepath") == 0 ||
+            JLI_StrCmp(arg, "upgrademodulepath") == 0) {
             expectingNoDashArg = JNI_TRUE;
-        } else if (JLI_StrCmp(arg, "jar") == 0) {
+        } else if (JLI_StrCmp(arg, "jar") == 0 ||
+                   JLI_StrCmp(arg, "m") == 0) {
             // This is tricky, we do expect NoDashArg
             // But that is considered main class to stop expansion
             expectingNoDashArg = JNI_FALSE;
--- a/src/java.base/share/native/libjli/emessages.h	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/native/libjli/emessages.h	Thu Mar 17 19:04:16 2016 +0000
@@ -41,6 +41,10 @@
 #define ARG_ERROR1      "Error: %s requires class path specification"
 #define ARG_ERROR2      "Error: %s requires jar file specification"
 #define ARG_ERROR3      "Error: The -J option should not be followed by a space."
+#define ARG_ERROR4      "Error: %s requires module path specification"
+#define ARG_ERROR5      "Error: %s requires module id"
+#define ARG_ERROR6      "Error: %s requires modules to be specified"
+#define ARG_ERROR7      "Error: %s can only be specified once"
 
 #define JVM_ERROR1      "Error: Could not create the Java Virtual Machine.\n" GEN_ERROR
 #define JVM_ERROR2      "Error: Could not detach main thread.\n" JNI_ERROR
--- a/src/java.base/share/native/libjli/java.c	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/native/libjli/java.c	Thu Mar 17 19:04:16 2016 +0000
@@ -69,10 +69,12 @@
 static jboolean printUsage = JNI_FALSE;   /* print and exit*/
 static jboolean printXUsage = JNI_FALSE;  /* print and exit*/
 static char     *showSettings = NULL;      /* print but continue */
+static char     *listModules = NULL;
 
 static const char *_program_name;
 static const char *_launcher_name;
 static jboolean _is_java_args = JNI_FALSE;
+static jboolean _have_classpath = JNI_FALSE;
 static const char *_fVersion;
 static jboolean _wc_enabled = JNI_FALSE;
 static jint _ergo_policy = DEFAULT_POLICY;
@@ -96,6 +98,14 @@
  * Prototypes for functions internal to launcher.
  */
 static void SetClassPath(const char *s);
+static void SetModulePath(const char *s);
+static void SetUpgradeModulePath(const char *s);
+static void SetMainModule(const char *s);
+static void SetAddModulesProp(const char *mods);
+static void SetLimitModulesProp(const char *mods);
+static void SetAddReadsProp(const jint n, const char *s);
+static void SetAddExportsProp(const jint n, const char *s);
+static void SetPatchProp(const jint n, const char *s);
 static void SelectVersion(int argc, char **argv, char **main_class);
 static void SetJvmEnvironment(int argc, char **argv);
 static jboolean ParseArguments(int *pargc, char ***pargv,
@@ -114,6 +124,7 @@
 static void PrintJavaVersion(JNIEnv *env, jboolean extraLF);
 static void PrintUsage(JNIEnv* env, jboolean doXUsage);
 static void ShowSettings(JNIEnv* env, char *optString);
+static void ListModules(JNIEnv* env, char *optString);
 
 static void SetPaths(int argc, char **argv);
 
@@ -193,7 +204,6 @@
 {
     int mode = LM_UNKNOWN;
     char *what = NULL;
-    char *cpath = 0;
     char *main_class = NULL;
     int ret;
     InvocationFunctions ifn;
@@ -270,11 +280,10 @@
         }
     } else {
         /* Set default CLASSPATH */
-        cpath = getenv("CLASSPATH");
-        if (cpath == NULL) {
-            cpath = ".";
+        char* cpath = getenv("CLASSPATH");
+        if (cpath != NULL) {
+            SetClassPath(cpath);
         }
-        SetClassPath(cpath);
     }
 
     /* Parse command line options; if the return value of
@@ -382,6 +391,12 @@
         CHECK_EXCEPTION_LEAVE(1);
     }
 
+    if (listModules != NULL) {
+        ListModules(env, listModules);
+        CHECK_EXCEPTION_LEAVE(1);
+        LEAVE();
+    }
+
     if (printVersion || showVersion) {
         PrintJavaVersion(env, showVersion);
         CHECK_EXCEPTION_LEAVE(0);
@@ -520,7 +535,12 @@
             }
         } else {
             if (JLI_StrCmp(arg, "-classpath") == 0 ||
-                JLI_StrCmp(arg, "-cp") == 0) {
+                JLI_StrCmp(arg, "-cp") == 0 ||
+                JLI_StrCmp(arg, "-modulepath") == 0 ||
+                JLI_StrCmp(arg, "-mp") == 0 ||
+                JLI_StrCmp(arg, "-upgrademodulepath") == 0 ||
+                JLI_StrCmp(arg, "-addmods") == 0 ||
+                JLI_StrCmp(arg, "-limitmods") == 0) {
                 newArgv[newArgvIdx++] = arg;
                 argi++;
                 if (argi < argc) {
@@ -841,6 +861,105 @@
     AddOption(def, NULL);
     if (s != orig)
         JLI_MemFree((char *) s);
+    _have_classpath = JNI_TRUE;
+}
+
+static void
+SetModulePath(const char *s)
+{
+    char *def;
+    const char *orig = s;
+    static const char format[] = "-Djdk.module.path=%s";
+    if (s == NULL)
+        return;
+    s = JLI_WildcardExpandClasspath(s);
+    def = JLI_MemAlloc(sizeof(format)
+                       - 2 /* strlen("%s") */
+                       + JLI_StrLen(s));
+    sprintf(def, format, s);
+    AddOption(def, NULL);
+    if (s != orig)
+        JLI_MemFree((char *) s);
+}
+
+static void
+SetUpgradeModulePath(const char *s)
+{
+    char *def;
+    const char *orig = s;
+    static const char format[] = "-Djdk.upgrade.module.path=%s";
+    if (s == NULL)
+        return;
+    s = JLI_WildcardExpandClasspath(s);
+    def = JLI_MemAlloc(sizeof(format)
+                       - 2 /* strlen("%s") */
+                       + JLI_StrLen(s));
+    sprintf(def, format, s);
+    AddOption(def, NULL);
+    if (s != orig)
+        JLI_MemFree((char *) s);
+}
+
+static void
+SetMainModule(const char *s)
+{
+    static const char format[] = "-Djdk.module.main=%s";
+    char* slash = JLI_StrChr(s, '/');
+    size_t s_len, def_len;
+    char *def;
+
+    /* value may be <module> or <module>/<mainclass> */
+    if (slash == NULL) {
+        s_len = JLI_StrLen(s);
+    } else {
+        s_len = (size_t) (slash - s);
+    }
+    def_len = sizeof(format)
+               - 2 /* strlen("%s") */
+               + s_len;
+    def = JLI_MemAlloc(def_len);
+    JLI_Snprintf(def, def_len, format, s);
+    AddOption(def, NULL);
+}
+
+static void
+SetAddModulesProp(const char *mods) {
+    size_t buflen = JLI_StrLen(mods) + 40;
+    char *prop = (char *)JLI_MemAlloc(buflen);
+    JLI_Snprintf(prop, buflen, "-Djdk.launcher.addmods=%s", mods);
+    AddOption(prop, NULL);
+}
+
+static void
+SetLimitModulesProp(const char *mods) {
+    size_t buflen = JLI_StrLen(mods) + 40;
+    char *prop = (char *)JLI_MemAlloc(buflen);
+    JLI_Snprintf(prop, buflen, "-Djdk.launcher.limitmods=%s", mods);
+    AddOption(prop, NULL);
+}
+
+static void
+SetAddReadsProp(const jint n, const char *s) {
+    size_t buflen = JLI_StrLen(s) + 40;
+    char *prop = (char *)JLI_MemAlloc(buflen);
+    JLI_Snprintf(prop, buflen, "-Djdk.launcher.addreads.%d=%s", n, s);
+    AddOption(prop, NULL);
+}
+
+static void
+SetAddExportsProp(const jint n, const char *s) {
+    size_t buflen = JLI_StrLen(s) + 40;
+    char *prop = (char *)JLI_MemAlloc(buflen);
+    JLI_Snprintf(prop, buflen, "-Djdk.launcher.addexports.%d=%s", n, s);
+    AddOption(prop, NULL);
+}
+
+static void
+SetPatchProp(const jint n, const char *s) {
+    size_t buflen = JLI_StrLen(s) + 40;
+    char *prop = (char *)JLI_MemAlloc(buflen);
+    JLI_Snprintf(prop, buflen, "-Djdk.launcher.patch.%d=%s", n, s);
+    AddOption(prop, NULL);
 }
 
 /*
@@ -1030,9 +1149,45 @@
             SetClassPath(*argv);
             mode = LM_CLASS;
             argv++; --argc;
+        } else if (JLI_StrCmp(arg, "-modulepath") == 0 || JLI_StrCmp(arg, "-mp") == 0) {
+            ARG_CHECK (argc, ARG_ERROR4, arg);
+            SetModulePath(*argv);
+            argv++; --argc;
+        } else if (JLI_StrCmp(arg, "-upgrademodulepath") == 0) {
+            ARG_CHECK (argc, ARG_ERROR4, arg);
+            SetUpgradeModulePath(*argv);
+            argv++; --argc;
         } else if (JLI_StrCmp(arg, "-jar") == 0) {
             ARG_CHECK (argc, ARG_ERROR2, arg);
             mode = LM_JAR;
+        } else if (JLI_StrCmp(arg, "-m") == 0) {
+            ARG_CHECK (argc, ARG_ERROR5, arg);
+            SetMainModule(*argv);
+            mode = LM_MODULE;
+        } else if (JLI_StrCmp(arg, "-addmods") == 0) {
+            ARG_CHECK (argc, ARG_ERROR6, arg);
+            SetAddModulesProp(*argv);
+            argv++; --argc;
+        } else if (JLI_StrCmp(arg, "-limitmods") == 0) {
+            ARG_CHECK (argc, ARG_ERROR6, arg);
+            SetLimitModulesProp(*argv);
+            argv++; --argc;
+        } else if (JLI_StrCmp(arg, "-listmods") == 0 ||
+                   JLI_StrCCmp(arg, "-listmods:") == 0) {
+            listModules = arg;
+            return JNI_TRUE;
+        } else if (JLI_StrCCmp(arg, "-XaddReads:") == 0) {
+            static jint n;
+            char *value = arg + 11;
+            SetAddReadsProp(n++, value);
+        } else if (JLI_StrCCmp(arg, "-XaddExports:") == 0) {
+            static jint n;
+            char *value = arg + 13;
+            SetAddExportsProp(n++, value);
+        } else if (JLI_StrCCmp(arg, "-Xpatch:") == 0) {
+            static jint n;
+            char *value = arg + 8;
+            SetPatchProp(n++, value);
         } else if (JLI_StrCmp(arg, "-help") == 0 ||
                    JLI_StrCmp(arg, "-h") == 0 ||
                    JLI_StrCmp(arg, "-?") == 0) {
@@ -1051,10 +1206,13 @@
  * In the latter case, any SUBOPT value not recognized will default to "all"
  */
         } else if (JLI_StrCmp(arg, "-XshowSettings") == 0 ||
-                JLI_StrCCmp(arg, "-XshowSettings:") == 0) {
+                   JLI_StrCCmp(arg, "-XshowSettings:") == 0) {
             showSettings = arg;
         } else if (JLI_StrCmp(arg, "-Xdiag") == 0) {
             AddOption("-Dsun.java.launcher.diag=true", NULL);
+            AddOption("-Djdk.launcher.traceResolver=true", NULL);
+        } else if (JLI_StrCmp(arg, "-Xdiag:resolver") == 0) {
+            AddOption("-Djdk.launcher.traceResolver=true", NULL);
 /*
  * The following case provide backward compatibility with old-style
  * command line options.
@@ -1099,6 +1257,10 @@
         } else if (RemovableOption(arg)) {
             ; /* Do not pass option to vm. */
         } else {
+            /* java.class.path set on the command line */
+            if (JLI_StrCCmp(arg, "-Djava.class.path=") == 0) {
+                _have_classpath = JNI_TRUE;
+            }
             AddOption(arg, NULL);
         }
     }
@@ -1110,8 +1272,11 @@
     if (*pwhat == NULL) {
         *pret = 1;
     } else if (mode == LM_UNKNOWN) {
-        /* default to LM_CLASS if -jar and -cp option are
+        /* default to LM_CLASS if -m, -jar and -cp options are
          * not specified */
+        if (!_have_classpath) {
+            SetClassPath(".");
+        }
         mode = LM_CLASS;
     }
 
@@ -1503,6 +1668,24 @@
                                  ServerClassMachine());
 }
 
+/**
+ * List modules supported by the runtime
+ */
+static void
+ListModules(JNIEnv *env, char *optString)
+{
+    jmethodID listModulesID;
+    jstring joptString;
+    jclass cls = GetLauncherHelperClass(env);
+    NULL_CHECK(cls);
+    NULL_CHECK(listModulesID = (*env)->GetStaticMethodID(env, cls,
+            "listModules", "(ZLjava/lang/String;)V"));
+    NULL_CHECK(joptString = (*env)->NewStringUTF(env, optString));
+    (*env)->CallStaticVoidMethod(env, cls, listModulesID,
+                                 USE_STDERR,
+                                 joptString);
+}
+
 /*
  * Prints default usage or the Xusage message, see sun.launcher.LauncherHelper.java
  */
--- a/src/java.base/share/native/libjli/java.h	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.base/share/native/libjli/java.h	Thu Mar 17 19:04:16 2016 +0000
@@ -223,7 +223,8 @@
 enum LaunchMode {               // cf. sun.launcher.LauncherHelper
     LM_UNKNOWN = 0,
     LM_CLASS,
-    LM_JAR
+    LM_JAR,
+    LM_MODULE
 };
 
 static const char *launchModeNames[]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/solaris/classes/module-info.java.extra	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+exports sun.nio.ch to jdk.crypto.ucrypto;
+exports sun.security.action to jdk.crypto.ucrypto;
+exports sun.security.internal.spec to jdk.crypto.ucrypto;
+exports sun.security.jca to jdk.crypto.ucrypto;
+exports sun.security.rsa to jdk.crypto.ucrypto;
+exports sun.security.util to jdk.crypto.ucrypto;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/windows/classes/module-info.java.extra	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+exports sun.security.rsa to jdk.crypto.mscapi;
+exports sun.security.internal.spec to jdk.crypto.mscapi;
+exports sun.security.util to jdk.crypto.mscapi;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.compact1/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module java.compact1 {
+    requires public java.logging;
+    requires public java.scripting;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.compact2/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module java.compact2 {
+    requires public java.compact1;
+    requires public java.rmi;
+    requires public java.sql;
+    requires public java.xml;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.compact3/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module java.compact3 {
+    requires public java.compact2;
+    requires public java.compiler;
+    requires public java.httpclient;
+    requires public java.instrument;
+    requires public java.management;
+    requires public java.naming;
+    requires public java.prefs;
+    requires public java.security.jgss;
+    requires public java.security.sasl;
+    requires public java.sql.rowset;
+    requires public java.xml.crypto;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.datatransfer/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module java.datatransfer {
+    exports java.awt.datatransfer;
+    exports sun.datatransfer to java.desktop;
+    uses sun.datatransfer.DesktopDatatransferService;
+}
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaUtils.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaUtils.java	Thu Mar 17 19:04:16 2016 +0000
@@ -37,12 +37,13 @@
 import javax.swing.border.Border;
 import javax.swing.plaf.UIResource;
 
+import jdk.internal.loader.ClassLoaders;
+
 import sun.awt.AppContext;
 
 import sun.lwawt.macosx.CImage;
 import sun.lwawt.macosx.CImage.Creator;
 import sun.lwawt.macosx.CPlatformWindow;
-import sun.misc.Launcher;
 import sun.reflect.misc.ReflectUtil;
 import sun.security.action.GetPropertyAction;
 import sun.swing.SwingUtilities2;
@@ -364,7 +365,8 @@
     // special casing naughty applications, like InstallAnywhere
     // <rdar://problem/4851533> REGR: JButton: Myst IV: the buttons of 1.0.3 updater have redraw issue
     static boolean shouldUseOpaqueButtons() {
-        final ClassLoader launcherClassLoader = Launcher.getLauncher().getClassLoader();
+        // can we use ClassLoader.getSystemClassLoader here?
+        final ClassLoader launcherClassLoader = ClassLoaders.appClassLoader();
         if (classExists(launcherClassLoader, "com.installshield.wizard.platform.macosx.MacOSXUtils")) return true;
         return false;
     }
--- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java	Thu Mar 17 19:04:16 2016 +0000
@@ -51,8 +51,6 @@
 import sun.lwawt.LWWindowPeer.PeerType;
 import sun.security.action.GetBooleanAction;
 
-import sun.util.CoreResourceBundleControl;
-
 @SuppressWarnings("serial") // JDK implementation class
 final class NamedCursor extends Cursor {
     NamedCursor(String name) {
@@ -84,9 +82,7 @@
             public ResourceBundle run() {
                 ResourceBundle platformResources = null;
                 try {
-                    platformResources =
-                            ResourceBundle.getBundle("sun.awt.resources.awtosx",
-                                    CoreResourceBundleControl.getRBControlInstance());
+                    platformResources = ResourceBundle.getBundle("sun.awt.resources.awtosx");
                 } catch (MissingResourceException e) {
                     // No resource file; defaults will be used.
                 }
--- a/src/java.desktop/share/classes/META-INF/services/java.net.ContentHandlerFactory	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-#
-# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.  Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-# Provider for content handlers
-sun.awt.www.content.MultimediaContentHandlers
--- a/src/java.desktop/share/classes/META-INF/services/javax.print.PrintServiceLookup	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-# Provider for Java Print Service
-sun.print.PrintServiceLookupProvider
--- a/src/java.desktop/share/classes/META-INF/services/javax.print.StreamPrintServiceFactory	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-# Provider for Java 2D Stream print services.
-sun.print.PSStreamPrinterFactory
--- a/src/java.desktop/share/classes/META-INF/services/javax.sound.midi.spi.MidiDeviceProvider	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-# Providers for midi devices
-com.sun.media.sound.RealTimeSequencerProvider
-com.sun.media.sound.MidiOutDeviceProvider
-com.sun.media.sound.MidiInDeviceProvider
-com.sun.media.sound.SoftProvider
--- a/src/java.desktop/share/classes/META-INF/services/javax.sound.midi.spi.MidiFileReader	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-# Providers for midi sequences
-com.sun.media.sound.StandardMidiFileReader
--- a/src/java.desktop/share/classes/META-INF/services/javax.sound.midi.spi.MidiFileWriter	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-# Providers for Midi file writing
-com.sun.media.sound.StandardMidiFileWriter
--- a/src/java.desktop/share/classes/META-INF/services/javax.sound.midi.spi.SoundbankReader	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-# Providers for Soundbanks
-com.sun.media.sound.SF2SoundbankReader
-com.sun.media.sound.DLSSoundbankReader
-com.sun.media.sound.AudioFileSoundbankReader
-com.sun.media.sound.JARSoundbankReader
--- a/src/java.desktop/share/classes/META-INF/services/javax.sound.sampled.spi.AudioFileReader	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-# Providers for audio file reading
-com.sun.media.sound.AuFileReader
-com.sun.media.sound.AiffFileReader
-com.sun.media.sound.WaveFileReader
-com.sun.media.sound.WaveFloatFileReader
-com.sun.media.sound.WaveExtensibleFileReader
-com.sun.media.sound.SoftMidiAudioFileReader
--- a/src/java.desktop/share/classes/META-INF/services/javax.sound.sampled.spi.AudioFileWriter	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-# Providers for writing audio files
-com.sun.media.sound.AuFileWriter
-com.sun.media.sound.AiffFileWriter
-com.sun.media.sound.WaveFileWriter
-com.sun.media.sound.WaveFloatFileWriter
--- a/src/java.desktop/share/classes/META-INF/services/javax.sound.sampled.spi.FormatConversionProvider	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-# Providers for FormatConversion
-com.sun.media.sound.AudioFloatFormatConverter
-com.sun.media.sound.UlawCodec
-com.sun.media.sound.AlawCodec
-com.sun.media.sound.PCMtoPCMCodec
--- a/src/java.desktop/share/classes/META-INF/services/javax.sound.sampled.spi.MixerProvider	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-# last mixer is default mixer
-com.sun.media.sound.PortMixerProvider
-com.sun.media.sound.DirectAudioDeviceProvider
--- a/src/java.desktop/share/classes/META-INF/services/sun.datatransfer.DesktopDatatransferService	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-sun.awt.datatransfer.DesktopDatatransferServiceImpl
--- a/src/java.desktop/share/classes/com/sun/beans/finder/ConstructorFinder.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.desktop/share/classes/com/sun/beans/finder/ConstructorFinder.java	Thu Mar 17 19:04:16 2016 +0000
@@ -72,6 +72,9 @@
         if (type.isInterface()) {
             throw new NoSuchMethodException("Interface does not contain constructors");
         }
+        if (!FinderUtils.isExported(type)) {
+            throw new NoSuchMethodException("Class is not accessible");
+        }
         if (Modifier.isAbstract(type.getModifiers())) {
             throw new NoSuchMethodException("Abstract class cannot be instantiated");
         }
--- a/src/java.desktop/share/classes/com/sun/beans/finder/FieldFinder.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.desktop/share/classes/com/sun/beans/finder/FieldFinder.java	Thu Mar 17 19:04:16 2016 +0000
@@ -54,6 +54,9 @@
         if (name == null) {
             throw new IllegalArgumentException("Field name is not set");
         }
+        if (!FinderUtils.isExported(type)) {
+            throw new NoSuchFieldException("Field '" + name + "' is not accessible");
+        }
         Field field = type.getField(name);
         if (!Modifier.isPublic(field.getModifiers())) {
             throw new NoSuchFieldException("Field '" + name + "' is not public");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/share/classes/com/sun/beans/finder/FinderUtils.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.sun.beans.finder;
+
+/**
+ * Defines utility methods for use by finders.
+ */
+
+final class FinderUtils {
+    private FinderUtils() { }
+
+    /**
+     * Returns true if the given class is an exported package.
+     */
+    public static boolean isExported(Class<?> c) {
+        String pn = packageName(c);
+        return c.getModule().isExported(pn);
+    }
+
+    private static String packageName(Class<?> c) {
+        if (c.isArray()) {
+            return packageName(c.getComponentType());
+        } else {
+            String name = c.getName();
+            int dot = name.lastIndexOf('.');
+            if (dot == -1) return "";
+            return name.substring(0, dot);
+        }
+    }
+}
--- a/src/java.desktop/share/classes/com/sun/beans/finder/MethodFinder.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.desktop/share/classes/com/sun/beans/finder/MethodFinder.java	Thu Mar 17 19:04:16 2016 +0000
@@ -134,6 +134,10 @@
      */
     public static Method findAccessibleMethod(Method method) throws NoSuchMethodException {
         Class<?> type = method.getDeclaringClass();
+
+        if (!FinderUtils.isExported(type)) {
+            throw new NoSuchMethodException("Method '" + method.getName() + "' is not accessible");
+        }
         if (Modifier.isPublic(type.getModifiers()) && isPackageAccessible(type)) {
             return method;
         }
--- a/src/java.desktop/share/classes/com/sun/media/sound/JARSoundbankReader.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.desktop/share/classes/com/sun/media/sound/JARSoundbankReader.java	Thu Mar 17 19:04:16 2016 +0000
@@ -88,7 +88,8 @@
                     try {
                         Class<?> c = Class.forName(line.trim(), false, ucl);
                         if (Soundbank.class.isAssignableFrom(c)) {
-                            Object o = ReflectUtil.newInstance(c);
+                            ReflectUtil.checkPackageAccess(c);
+                            Object o = c.newInstance();
                             soundbanks.add((Soundbank) o);
                         }
                     } catch (ClassNotFoundException ignored) {
--- a/src/java.desktop/share/classes/java/awt/Component.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.desktop/share/classes/java/awt/Component.java	Thu Mar 17 19:04:16 2016 +0000
@@ -8696,6 +8696,7 @@
      * the Swing package private method {@code compWriteObjectNotify}.
      */
     private void doSwingSerialization() {
+        @SuppressWarnings("deprecation")
         Package swingPackage = Package.getPackage("javax.swing");
         // For Swing serialization to correctly work Swing needs to
         // be notified before Component does it's serialization.  This
--- a/src/java.desktop/share/classes/java/awt/Toolkit.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.desktop/share/classes/java/awt/Toolkit.java	Thu Mar 17 19:04:16 2016 +0000
@@ -56,7 +56,6 @@
 import sun.awt.HeadlessToolkit;
 import sun.awt.PeerEvent;
 import sun.awt.SunToolkit;
-import sun.util.CoreResourceBundleControl;
 
 import java.security.AccessController;
 import java.security.PrivilegedAction;
@@ -464,7 +463,8 @@
      */
     private static void fallbackToLoadClassForAT(String atName) {
         try {
-            Class.forName(atName, false, ClassLoader.getSystemClassLoader()).newInstance();
+            Class<?> c = Class.forName(atName, false, ClassLoader.getSystemClassLoader());
+            c.newInstance();
         } catch (ClassNotFoundException e) {
             newAWTError(e, "Assistive Technology not found: " + atName);
         } catch (InstantiationException e) {
@@ -1373,9 +1373,7 @@
                                  new java.security.PrivilegedAction<Void>() {
             public Void run() {
                 try {
-                    resources =
-                        ResourceBundle.getBundle("sun.awt.resources.awt",
-                                                 CoreResourceBundleControl.getRBControlInstance());
+                    resources = ResourceBundle.getBundle("sun.awt.resources.awt");
                 } catch (MissingResourceException e) {
                     // No resource file; defaults will be used.
                 }
--- a/src/java.desktop/share/classes/java/awt/Window.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.desktop/share/classes/java/awt/Window.java	Thu Mar 17 19:04:16 2016 +0000
@@ -2797,7 +2797,12 @@
      */
     @Deprecated
     public void applyResourceBundle(String rbName) {
-        applyResourceBundle(ResourceBundle.getBundle(rbName));
+        // Use the unnamed module from the TCCL or system class loader.
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        if (cl == null) {
+            cl = ClassLoader.getSystemClassLoader();
+        }
+        applyResourceBundle(ResourceBundle.getBundle(rbName, cl.getUnnamedModule()));
     }
 
    /*
--- a/src/java.desktop/share/classes/javax/imageio/ImageReader.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.desktop/share/classes/javax/imageio/ImageReader.java	Thu Mar 17 19:04:16 2016 +0000
@@ -2452,31 +2452,16 @@
                 locale = Locale.getDefault();
             }
 
-            /**
-             * If an applet supplies an implementation of ImageReader and
-             * resource bundles, then the resource bundle will need to be
-             * accessed via the applet class loader. So first try the context
-             * class loader to locate the resource bundle.
-             * If that throws MissingResourceException, then try the
-             * system class loader.
+            /*
+             * Only the plugin knows the messages that are provided, so we
+             * can always locate the resource bundles from the same loader
+             * as that for the plugin code itself.
              */
-            ClassLoader loader =
-                java.security.AccessController.doPrivileged(
-                   new java.security.PrivilegedAction<ClassLoader>() {
-                      public ClassLoader run() {
-                        return Thread.currentThread().getContextClassLoader();
-                      }
-                });
-
             ResourceBundle bundle = null;
             try {
-                bundle = ResourceBundle.getBundle(baseName, locale, loader);
+                bundle = ResourceBundle.getBundle(baseName, locale, this.getClass().getModule());
             } catch (MissingResourceException mre) {
-                try {
-                    bundle = ResourceBundle.getBundle(baseName, locale);
-                } catch (MissingResourceException mre1) {
-                    throw new IllegalArgumentException("Bundle not found!");
-                }
+                throw new IllegalArgumentException("Bundle not found!");
             }
 
             String warning = null;
--- a/src/java.desktop/share/classes/javax/imageio/ImageWriter.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.desktop/share/classes/javax/imageio/ImageWriter.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1954,31 +1954,16 @@
                 locale = Locale.getDefault();
             }
 
-            /**
-             * If an applet supplies an implementation of ImageWriter and
-             * resource bundles, then the resource bundle will need to be
-             * accessed via the applet class loader. So first try the context
-             * class loader to locate the resource bundle.
-             * If that throws MissingResourceException, then try the
-             * system class loader.
+            /*
+             * Only the plugin knows the messages that are provided, so we
+             * can always locate the resource bundles from the same loader
+             * as that for the plugin code itself.
              */
-            ClassLoader loader =
-                java.security.AccessController.doPrivileged(
-                   new java.security.PrivilegedAction<ClassLoader>() {
-                      public ClassLoader run() {
-                        return Thread.currentThread().getContextClassLoader();
-                      }
-                });
-
             ResourceBundle bundle = null;
             try {
-                bundle = ResourceBundle.getBundle(baseName, locale, loader);
+                bundle = ResourceBundle.getBundle(baseName, locale, this.getClass().getModule());
             } catch (MissingResourceException mre) {
-                try {
-                    bundle = ResourceBundle.getBundle(baseName, locale);
-                } catch (MissingResourceException mre1) {
-                    throw new IllegalArgumentException("Bundle not found!");
-                }
+                throw new IllegalArgumentException("Bundle not found!");
             }
 
             String warning = null;
--- a/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadata.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadata.java	Thu Mar 17 19:04:16 2016 +0000
@@ -26,7 +26,11 @@
 package javax.imageio.metadata;
 
 import org.w3c.dom.Node;
+
 import java.lang.reflect.Method;
+import java.lang.reflect.Module;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 
 /**
  * An abstract class to be extended by objects that represent metadata
@@ -395,45 +399,11 @@
             throw new IllegalArgumentException("Unsupported format name");
         }
         try {
-            Class<?> cls = null;
-            final Object o = this;
-
-            // firstly we try to use classloader used for loading
-            // the IIOMetadata implemantation for this plugin.
-            ClassLoader loader =
-                java.security.AccessController.doPrivileged(
-                    new java.security.PrivilegedAction<ClassLoader>() {
-                            public ClassLoader run() {
-                                return o.getClass().getClassLoader();
-                            }
-                        });
-
-            try {
-                cls = Class.forName(formatClassName, true,
-                                    loader);
-            } catch (ClassNotFoundException e) {
-                // we failed to load IIOMetadataFormat class by
-                // using IIOMetadata classloader.Next try is to
-                // use thread context classloader.
-                loader =
-                    java.security.AccessController.doPrivileged(
-                        new java.security.PrivilegedAction<ClassLoader>() {
-                                public ClassLoader run() {
-                                    return Thread.currentThread().getContextClassLoader();
-                                }
-                        });
-                try {
-                    cls = Class.forName(formatClassName, true,
-                                        loader);
-                } catch (ClassNotFoundException e1) {
-                    // finally we try to use system classloader in case
-                    // if we failed to load IIOMetadataFormat implementation
-                    // class above.
-                    cls = Class.forName(formatClassName, true,
-                                        ClassLoader.getSystemClassLoader());
-                }
-            }
-
+            final String className = formatClassName;
+            // Try to load from the module of the IIOMetadata implementation
+            // for this plugin since the IIOMetadataImpl is part of the plugin
+            PrivilegedAction<Class<?>> pa = () -> { return getMetadataFormatClass(className); };
+            Class<?> cls = AccessController.doPrivileged(pa);
             Method meth = cls.getMethod("getInstance");
             return (IIOMetadataFormat) meth.invoke(null);
         } catch (Exception e) {
@@ -442,7 +412,24 @@
             ex.initCause(e);
             throw ex;
         }
+    }
 
+    private Class<?> getMetadataFormatClass(String formatClassName) {
+        Module thisModule = IIOMetadata.class.getModule();
+        Module targetModule = this.getClass().getModule();
+        Class<?> c = Class.forName(targetModule, formatClassName);
+        if (thisModule.equals(targetModule) || c == null) {
+            return c;
+        }
+        if (thisModule.isNamed()) {
+            int i = formatClassName.lastIndexOf(".");
+            String pn = i > 0 ? formatClassName.substring(0, i) : "";
+            if (!targetModule.isExported(pn, thisModule)) {
+                throw new IllegalStateException("Class " + formatClassName +
+                   " in named module must be exported to java.desktop module.");
+            }
+        }
+        return c;
     }
 
     /**
--- a/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataFormat.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataFormat.java	Thu Mar 17 19:04:16 2016 +0000
@@ -43,6 +43,12 @@
  * returns an instance of the class.  Commonly, an implementation will
  * construct only a single instance and cache it for future
  * invocations of {@code getInstance}.
+ * <p> In the event that the plugin is provided as part of a named module,
+ * that module must export the package containing the implementation class
+ * to the <pre>java.desktop</pre> module via a qualified export.
+ * An unqualified export is not recommended unless also needed for
+ * some other reason. Failing to export the package will result in
+ * access failure at runtime.
  *
  * <p> The structures that may be described by this class are a subset
  * of those expressible using XML document type definitions (DTDs),
--- a/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataFormatImpl.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataFormatImpl.java	Thu Mar 17 19:04:16 2016 +0000
@@ -956,34 +956,17 @@
         }
 
         /**
-         * If an applet supplies an implementation of IIOMetadataFormat and
-         * resource bundles, then the resource bundle will need to be
-         * accessed via the applet class loader. So first try the context
-         * class loader to locate the resource bundle.
-         * If that throws MissingResourceException, then try the
-         * system class loader.
+         * Per the class documentation, resource bundles, including localized ones
+         * are intended to be delivered by the subclasser - ie supplier of the
+         * metadataformat. For the standard format and all standard plugins that
+         * is the JDK. For 3rd party plugins that they will supply their own.
+         * This includes plugins bundled with applets/applications.
+         * In all cases this means it is sufficient to search for those resource
+         * in the module that is providing the MetadataFormatImpl subclass.
          */
-        ClassLoader loader =
-            java.security.AccessController.doPrivileged(
-                new java.security.PrivilegedAction<ClassLoader>() {
-                   public ClassLoader run() {
-                       return Thread.currentThread().getContextClassLoader();
-                   }
-            });
-
-        ResourceBundle bundle = null;
         try {
-            bundle = ResourceBundle.getBundle(resourceBaseName,
-                                              locale, loader);
-        } catch (MissingResourceException mre) {
-            try {
-                bundle = ResourceBundle.getBundle(resourceBaseName, locale);
-            } catch (MissingResourceException mre1) {
-                return null;
-            }
-        }
-
-        try {
+            ResourceBundle bundle = ResourceBundle.getBundle(resourceBaseName, locale,
+                                                            this.getClass().getModule());
             return bundle.getString(key);
         } catch (MissingResourceException e) {
             return null;
--- a/src/java.desktop/share/classes/javax/imageio/spi/ImageReaderWriterSpi.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.desktop/share/classes/javax/imageio/spi/ImageReaderWriterSpi.java	Thu Mar 17 19:04:16 2016 +0000
@@ -28,6 +28,9 @@
 import java.io.IOException;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
+import java.lang.reflect.Module;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.util.Arrays;
 import java.util.Iterator;
 import javax.imageio.ImageReader;
@@ -587,8 +590,10 @@
             throw new IllegalArgumentException("Unsupported format name");
         }
         try {
-            Class<?> cls = Class.forName(formatClassName, true,
-                                      ClassLoader.getSystemClassLoader());
+            // Try to load from the same location as the module of the SPI
+            final String className = formatClassName;
+            PrivilegedAction<Class<?>> pa = () -> { return getMetadataFormatClass(className); };
+            Class<?> cls = AccessController.doPrivileged(pa);
             Method meth = cls.getMethod("getInstance");
             return (IIOMetadataFormat) meth.invoke(null);
         } catch (Exception e) {
@@ -598,4 +603,22 @@
             throw ex;
         }
     }
+
+    private Class<?> getMetadataFormatClass(String formatClassName) {
+        Module thisModule = ImageReaderWriterSpi.class.getModule();
+        Module targetModule = this.getClass().getModule();
+        Class<?> c = Class.forName(targetModule, formatClassName);
+        if (thisModule.equals(targetModule) || c == null) {
+            return c;
+        }
+        if (thisModule.isNamed()) {
+            int i = formatClassName.lastIndexOf(".");
+            String pn = i > 0 ? formatClassName.substring(0, i) : "";
+            if (!targetModule.isExported(pn, thisModule)) {
+                throw new IllegalStateException("Class " +  formatClassName +
+                  " in named module must be exported to java.desktop module.");
+            }
+        }
+        return c;
+    }
 }
--- a/src/java.desktop/share/classes/javax/swing/UIDefaults.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.desktop/share/classes/javax/swing/UIDefaults.java	Thu Mar 17 19:04:16 2016 +0000
@@ -30,13 +30,15 @@
 import javax.swing.border.*;
 import javax.swing.event.SwingPropertyChangeSupport;
 
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
 import java.lang.reflect.*;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Enumeration;
 import java.util.Hashtable;
 import java.util.ResourceBundle;
-import java.util.ResourceBundle.Control;
 import java.util.Locale;
 import java.util.Vector;
 import java.util.MissingResourceException;
@@ -52,7 +54,6 @@
 import sun.reflect.misc.MethodUtil;
 import sun.reflect.misc.ReflectUtil;
 import sun.swing.SwingUtilities2;
-import sun.util.CoreResourceBundleControl;
 
 /**
  * A table of defaults for Swing components.  Applications can set/get
@@ -302,12 +303,12 @@
             for (int i=resourceBundles.size()-1; i >= 0; i--) {
                 String bundleName = resourceBundles.get(i);
                 try {
-                    Control c = CoreResourceBundleControl.getRBControlInstance(bundleName);
                     ResourceBundle b;
-                    if (c != null) {
-                        b = ResourceBundle.getBundle(bundleName, l, c);
+                    if (isDesktopResourceBundle(bundleName)) {
+                        // load resource bundle from java.desktop module
+                        b = ResourceBundle.getBundle(bundleName, l, UIDefaults.class.getModule());
                     } else {
-                        b = ResourceBundle.getBundle(bundleName, l);
+                        b = ResourceBundle.getBundle(bundleName, l, ClassLoader.getSystemClassLoader());
                     }
                     Enumeration<String> keys = b.getKeys();
 
@@ -329,6 +330,30 @@
         return values;
     }
 
+    /*
+     * Test if the specified baseName of the ROOT locale is in java.desktop module.
+     * JDK always defines the resource bundle of the ROOT locale.
+     */
+    private static boolean isDesktopResourceBundle(String baseName) {
+        Module thisModule = UIDefaults.class.getModule();
+        return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
+            @Override
+            public Boolean run() {
+                Class<?> c = Class.forName(thisModule, baseName);
+                if (c != null) {
+                    return true;
+                } else {
+                    String resourceName = baseName.replace('.', '/') + ".properties";
+                    try (InputStream in = thisModule.getResourceAsStream(resourceName)) {
+                        return in != null;
+                    } catch (IOException e) {
+                        throw new UncheckedIOException(e);
+                    }
+                }
+            }
+        });
+    }
+
     /**
      * Sets the value of <code>key</code> to <code>value</code> for all locales.
      * If <code>key</code> is a string and the new value isn't
@@ -767,7 +792,13 @@
                     m = uiClass.getMethod("createUI", new Class<?>[]{JComponent.class});
                     put(uiClass, m);
                 }
-                uiObject = MethodUtil.invoke(m, null, new Object[]{target});
+
+                if (uiClass.getModule() == ComponentUI.class.getModule()) {
+                    // uiClass is a system LAF if it's in java.desktop module
+                    uiObject = m.invoke(null, new Object[]{target});
+                } else {
+                    uiObject = MethodUtil.invoke(m, null, new Object[]{target});
+                }
             }
             catch (NoSuchMethodException e) {
                 getUIError("static createUI() method not found in " + uiClass);
--- a/src/java.desktop/share/classes/javax/swing/text/DefaultFormatter.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.desktop/share/classes/javax/swing/text/DefaultFormatter.java	Thu Mar 17 19:04:16 2016 +0000
@@ -31,7 +31,6 @@
 import java.lang.reflect.*;
 import java.text.ParseException;
 import javax.swing.*;
-import javax.swing.text.*;
 
 /**
  * <code>DefaultFormatter</code> formats arbitrary objects. Formatting is done
--- a/src/java.desktop/share/classes/javax/swing/text/html/ObjectView.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.desktop/share/classes/javax/swing/text/html/ObjectView.java	Thu Mar 17 19:04:16 2016 +0000
@@ -24,7 +24,6 @@
  */
 package javax.swing.text.html;
 
-import java.util.Enumeration;
 import java.awt.*;
 import javax.swing.*;
 import javax.swing.text.*;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module java.desktop {
+    requires public java.datatransfer;
+    requires public java.xml;
+    requires java.prefs;
+
+    exports java.applet;
+    exports java.awt;
+    exports java.awt.color;
+    exports java.awt.dnd;
+    exports java.awt.event;
+    exports java.awt.font;
+    exports java.awt.geom;
+    exports java.awt.im;
+    exports java.awt.im.spi;
+    exports java.awt.image;
+    exports java.awt.image.renderable;
+    exports java.awt.print;
+    exports java.beans;
+    exports java.beans.beancontext;
+    exports javax.accessibility;
+    exports javax.imageio;
+    exports javax.imageio.event;
+    exports javax.imageio.metadata;
+    exports javax.imageio.plugins.bmp;
+    exports javax.imageio.plugins.jpeg;
+    exports javax.imageio.plugins.tiff;
+    exports javax.imageio.spi;
+    exports javax.imageio.stream;
+    exports javax.print;
+    exports javax.print.attribute;
+    exports javax.print.attribute.standard;
+    exports javax.print.event;
+    exports javax.sound.midi;
+    exports javax.sound.midi.spi;
+    exports javax.sound.sampled;
+    exports javax.sound.sampled.spi;
+    exports javax.swing;
+    exports javax.swing.border;
+    exports javax.swing.colorchooser;
+    exports javax.swing.event;
+    exports javax.swing.filechooser;
+    exports javax.swing.plaf;
+    exports javax.swing.plaf.basic;
+    exports javax.swing.plaf.metal;
+    exports javax.swing.plaf.multi;
+    exports javax.swing.plaf.nimbus;
+    exports javax.swing.plaf.synth;
+    exports javax.swing.table;
+    exports javax.swing.text;
+    exports javax.swing.text.html;
+    exports javax.swing.text.html.parser;
+    exports javax.swing.text.rtf;
+    exports javax.swing.tree;
+    exports javax.swing.undo;
+
+    // qualified exports may be inserted at build time
+    // see make/GensrcModuleInfo.gmk
+    exports sun.awt to
+        jdk.accessibility;
+
+    uses java.awt.im.spi.InputMethodDescriptor;
+    uses javax.accessibility.AccessibilityProvider;
+    uses javax.imageio.spi.ImageInputStreamSpi;
+    uses javax.imageio.spi.ImageOutputStreamSpi;
+    uses javax.imageio.spi.ImageReaderSpi;
+    uses javax.imageio.spi.ImageTranscoderSpi;
+    uses javax.imageio.spi.ImageWriterSpi;
+    uses javax.print.PrintServiceLookup;
+    uses javax.print.StreamPrintServiceFactory;
+    uses javax.sound.midi.spi.MidiDeviceProvider;
+    uses javax.sound.midi.spi.MidiFileReader;
+    uses javax.sound.midi.spi.MidiFileWriter;
+    uses javax.sound.midi.spi.SoundbankReader;
+    uses javax.sound.sampled.spi.AudioFileReader;
+    uses javax.sound.sampled.spi.AudioFileWriter;
+    uses javax.sound.sampled.spi.FormatConversionProvider;
+    uses javax.sound.sampled.spi.MixerProvider;
+
+    provides sun.datatransfer.DesktopDatatransferService with sun.awt.datatransfer.DesktopDatatransferServiceImpl;
+    provides java.net.ContentHandlerFactory with sun.awt.www.content.MultimediaContentHandlers;
+    provides javax.print.PrintServiceLookup with sun.print.PrintServiceLookupProvider;
+    provides javax.print.StreamPrintServiceFactory with sun.print.PSStreamPrinterFactory;
+    provides javax.sound.midi.spi.MidiDeviceProvider with com.sun.media.sound.MidiInDeviceProvider;
+    provides javax.sound.midi.spi.MidiDeviceProvider with com.sun.media.sound.MidiOutDeviceProvider;
+    provides javax.sound.midi.spi.MidiDeviceProvider with com.sun.media.sound.RealTimeSequencerProvider;
+    provides javax.sound.midi.spi.MidiDeviceProvider with com.sun.media.sound.SoftProvider;
+    provides javax.sound.midi.spi.MidiFileReader with com.sun.media.sound.StandardMidiFileReader;
+    provides javax.sound.midi.spi.MidiFileWriter with com.sun.media.sound.StandardMidiFileWriter;
+    provides javax.sound.midi.spi.SoundbankReader with com.sun.media.sound.AudioFileSoundbankReader;
+    provides javax.sound.midi.spi.SoundbankReader with com.sun.media.sound.DLSSoundbankReader;
+    provides javax.sound.midi.spi.SoundbankReader with com.sun.media.sound.JARSoundbankReader;
+    provides javax.sound.midi.spi.SoundbankReader with com.sun.media.sound.SF2SoundbankReader;
+    provides javax.sound.sampled.spi.AudioFileReader with com.sun.media.sound.AiffFileReader;
+    provides javax.sound.sampled.spi.AudioFileReader with com.sun.media.sound.AuFileReader;
+    provides javax.sound.sampled.spi.AudioFileReader with com.sun.media.sound.SoftMidiAudioFileReader;
+    provides javax.sound.sampled.spi.AudioFileReader with com.sun.media.sound.WaveFileReader;
+    provides javax.sound.sampled.spi.AudioFileReader with com.sun.media.sound.WaveFloatFileReader;
+    provides javax.sound.sampled.spi.AudioFileReader with com.sun.media.sound.WaveExtensibleFileReader;
+    provides javax.sound.sampled.spi.AudioFileWriter with com.sun.media.sound.AiffFileWriter;
+    provides javax.sound.sampled.spi.AudioFileWriter with com.sun.media.sound.AuFileWriter;
+    provides javax.sound.sampled.spi.AudioFileWriter with com.sun.media.sound.WaveFileWriter;
+    provides javax.sound.sampled.spi.AudioFileWriter with com.sun.media.sound.WaveFloatFileWriter;
+    provides javax.sound.sampled.spi.FormatConversionProvider with com.sun.media.sound.AlawCodec;
+    provides javax.sound.sampled.spi.FormatConversionProvider with com.sun.media.sound.AudioFloatFormatConverter;
+    provides javax.sound.sampled.spi.FormatConversionProvider with com.sun.media.sound.PCMtoPCMCodec;
+    provides javax.sound.sampled.spi.FormatConversionProvider with com.sun.media.sound.UlawCodec;
+    provides javax.sound.sampled.spi.MixerProvider with com.sun.media.sound.DirectAudioDeviceProvider;
+    provides javax.sound.sampled.spi.MixerProvider with com.sun.media.sound.PortMixerProvider;
+}
+
--- a/src/java.desktop/share/classes/sun/applet/AppletSecurity.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.desktop/share/classes/sun/applet/AppletSecurity.java	Thu Mar 17 19:04:16 2016 +0000
@@ -43,7 +43,6 @@
 import sun.awt.AWTSecurityManager;
 import sun.awt.AppContext;
 import sun.awt.AWTPermissions;
-import sun.security.provider.*;
 import sun.security.util.SecurityConstants;
 
 
--- a/src/java.desktop/share/classes/sun/awt/datatransfer/TransferableProxy.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.desktop/share/classes/sun/awt/datatransfer/TransferableProxy.java	Thu Mar 17 19:04:16 2016 +0000
@@ -208,9 +208,11 @@
             classObjs[i] = cl;
         }
         try {
-            return Proxy.getProxyClass(hasNonPublicInterface ?
-                                       nonPublicLoader : classLoader,
-                                       classObjs);
+            @SuppressWarnings("deprecation")
+            Class<?> proxyClass = Proxy.getProxyClass(hasNonPublicInterface ?
+                                                          nonPublicLoader : classLoader,
+                                                      classObjs);
+            return proxyClass;
         } catch (IllegalArgumentException e) {
             throw new ClassNotFoundException(null, e);
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.httpclient/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module java.httpclient {
+    requires java.base;
+    exports java.net.http;
+}
+
--- a/src/java.instrument/share/classes/java/lang/instrument/ClassFileTransformer.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.instrument/share/classes/java/lang/instrument/ClassFileTransformer.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,141 +25,155 @@
 
 package java.lang.instrument;
 
-import  java.security.ProtectionDomain;
+import java.lang.reflect.Module;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
 
 /*
  * Copyright 2003 Wily Technology, Inc.
  */
 
 /**
- * An agent provides an implementation of this interface in order
- * to transform class files.
- * The transformation occurs before the class is defined by the JVM.
+ * A transformer of class files. An agent registers an implementation of this
+ * interface using the {@link Instrumentation#addTransformer addTransformer}
+ * method so that the transformer's {@link
+ * ClassFileTransformer#transform(Module,String,Class,ProtectionDomain,byte[])
+ * transform} method is invoked when classes are loaded,
+ * {@link Instrumentation#redefineClasses redefined}, or
+ * {@link Instrumentation#retransformClasses retransformed}. The implementation
+ * should override one of the {@code transform} methods defined here.
+ * Transformers are invoked before the class is defined by the Java virtual
+ * machine.
+ *
+ * <P>
+ * There are two kinds of transformers, determined by the <code>canRetransform</code>
+ * parameter of
+ * {@link java.lang.instrument.Instrumentation#addTransformer(ClassFileTransformer,boolean)}:
+ *  <ul>
+ *    <li><i>retransformation capable</i> transformers that were added with
+ *        <code>canRetransform</code> as true
+ *    </li>
+ *    <li><i>retransformation incapable</i> transformers that were added with
+ *        <code>canRetransform</code> as false or where added with
+ *        {@link java.lang.instrument.Instrumentation#addTransformer(ClassFileTransformer)}
+ *    </li>
+ *  </ul>
+ *
+ * <P>
+ * Once a transformer has been registered with
+ * {@link java.lang.instrument.Instrumentation#addTransformer(ClassFileTransformer,boolean)
+ * addTransformer},
+ * the transformer will be called for every new class definition and every class redefinition.
+ * Retransformation capable transformers will also be called on every class retransformation.
+ * The request for a new class definition is made with
+ * {@link java.lang.ClassLoader#defineClass ClassLoader.defineClass}
+ * or its native equivalents.
+ * The request for a class redefinition is made with
+ * {@link java.lang.instrument.Instrumentation#redefineClasses Instrumentation.redefineClasses}
+ * or its native equivalents.
+ * The request for a class retransformation is made with
+ * {@link java.lang.instrument.Instrumentation#retransformClasses Instrumentation.retransformClasses}
+ * or its native equivalents.
+ * The transformer is called during the processing of the request, before the class file bytes
+ * have been verified or applied.
+ * When there are multiple transformers, transformations are composed by chaining the
+ * <code>transform</code> calls.
+ * That is, the byte array returned by one call to <code>transform</code> becomes the input
+ * (via the <code>classfileBuffer</code> parameter) to the next call.
+ *
+ * <P>
+ * Transformations are applied in the following order:
+ *  <ul>
+ *    <li>Retransformation incapable transformers
+ *    </li>
+ *    <li>Retransformation incapable native transformers
+ *    </li>
+ *    <li>Retransformation capable transformers
+ *    </li>
+ *    <li>Retransformation capable native transformers
+ *    </li>
+ *  </ul>
+ *
+ * <P>
+ * For retransformations, the retransformation incapable transformers are not
+ * called, instead the result of the previous transformation is reused.
+ * In all other cases, this method is called.
+ * Within each of these groupings, transformers are called in the order registered.
+ * Native transformers are provided by the <code>ClassFileLoadHook</code> event
+ * in the Java Virtual Machine Tool Interface).
+ *
+ * <P>
+ * The input (via the <code>classfileBuffer</code> parameter) to the first
+ * transformer is:
+ *  <ul>
+ *    <li>for new class definition,
+ *        the bytes passed to <code>ClassLoader.defineClass</code>
+ *    </li>
+ *    <li>for class redefinition,
+ *        <code>definitions.getDefinitionClassFile()</code> where
+ *        <code>definitions</code> is the parameter to
+ *        {@link java.lang.instrument.Instrumentation#redefineClasses
+ *         Instrumentation.redefineClasses}
+ *    </li>
+ *    <li>for class retransformation,
+ *         the bytes passed to the new class definition or, if redefined,
+ *         the last redefinition, with all transformations made by retransformation
+ *         incapable transformers reapplied automatically and unaltered;
+ *         for details see
+ *         {@link java.lang.instrument.Instrumentation#retransformClasses
+ *          Instrumentation.retransformClasses}
+ *    </li>
+ *  </ul>
+ *
+ * <P>
+ * If the implementing method determines that no transformations are needed,
+ * it should return <code>null</code>.
+ * Otherwise, it should create a new <code>byte[]</code> array,
+ * copy the input <code>classfileBuffer</code> into it,
+ * along with all desired transformations, and return the new array.
+ * The input <code>classfileBuffer</code> must not be modified.
+ *
+ * <P>
+ * In the retransform and redefine cases,
+ * the transformer must support the redefinition semantics:
+ * if a class that the transformer changed during initial definition is later
+ * retransformed or redefined, the
+ * transformer must insure that the second class output class file is a legal
+ * redefinition of the first output class file.
+ *
+ * <P>
+ * If the transformer throws an exception (which it doesn't catch),
+ * subsequent transformers will still be called and the load, redefine
+ * or retransform will still be attempted.
+ * Thus, throwing an exception has the same effect as returning <code>null</code>.
+ * To prevent unexpected behavior when unchecked exceptions are generated
+ * in transformer code, a transformer can catch <code>Throwable</code>.
+ * If the transformer believes the <code>classFileBuffer</code> does not
+ * represent a validly formatted class file, it should throw
+ * an <code>IllegalClassFormatException</code>;
+ * while this has the same effect as returning null. it facilitates the
+ * logging or debugging of format corruptions.
+ *
  * <P>
  * Note the term <i>class file</i> is used as defined in section 3.1 of
- * <cite>The Java&trade; Virtual Machine Specification</cite>,
- * to mean a sequence
- * of bytes in class file format, whether or not they reside in a file.
+ * <cite>The Java&trade; Virtual Machine Specification</cite>, to mean a
+ * sequence of bytes in class file format, whether or not they reside in a
+ * file.
  *
  * @see     java.lang.instrument.Instrumentation
- * @see     java.lang.instrument.Instrumentation#addTransformer
- * @see     java.lang.instrument.Instrumentation#removeTransformer
  * @since   1.5
  */
 
 public interface ClassFileTransformer {
+
     /**
-     * The implementation of this method may transform the supplied class file and
-     * return a new replacement class file.
-     *
-     * <P>
-     * There are two kinds of transformers, determined by the <code>canRetransform</code>
-     * parameter of
-     * {@link java.lang.instrument.Instrumentation#addTransformer(ClassFileTransformer,boolean)}:
-     *  <ul>
-     *    <li><i>retransformation capable</i> transformers that were added with
-     *        <code>canRetransform</code> as true
-     *    </li>
-     *    <li><i>retransformation incapable</i> transformers that were added with
-     *        <code>canRetransform</code> as false or where added with
-     *        {@link java.lang.instrument.Instrumentation#addTransformer(ClassFileTransformer)}
-     *    </li>
-     *  </ul>
-     *
-     * <P>
-     * Once a transformer has been registered with
-     * {@link java.lang.instrument.Instrumentation#addTransformer(ClassFileTransformer,boolean)
-     * addTransformer},
-     * the transformer will be called for every new class definition and every class redefinition.
-     * Retransformation capable transformers will also be called on every class retransformation.
-     * The request for a new class definition is made with
-     * {@link java.lang.ClassLoader#defineClass ClassLoader.defineClass}
-     * or its native equivalents.
-     * The request for a class redefinition is made with
-     * {@link java.lang.instrument.Instrumentation#redefineClasses Instrumentation.redefineClasses}
-     * or its native equivalents.
-     * The request for a class retransformation is made with
-     * {@link java.lang.instrument.Instrumentation#retransformClasses Instrumentation.retransformClasses}
-     * or its native equivalents.
-     * The transformer is called during the processing of the request, before the class file bytes
-     * have been verified or applied.
-     * When there are multiple transformers, transformations are composed by chaining the
-     * <code>transform</code> calls.
-     * That is, the byte array returned by one call to <code>transform</code> becomes the input
-     * (via the <code>classfileBuffer</code> parameter) to the next call.
-     *
-     * <P>
-     * Transformations are applied in the following order:
-     *  <ul>
-     *    <li>Retransformation incapable transformers
-     *    </li>
-     *    <li>Retransformation incapable native transformers
-     *    </li>
-     *    <li>Retransformation capable transformers
-     *    </li>
-     *    <li>Retransformation capable native transformers
-     *    </li>
-     *  </ul>
+     * Transforms the given class file and returns a new replacement class file.
+     * This method is invoked when the {@link Module Module} bearing {@link
+     * ClassFileTransformer#transform(Module,String,Class,ProtectionDomain,byte[])
+     * transform} is not overridden.
      *
-     * <P>
-     * For retransformations, the retransformation incapable transformers are not
-     * called, instead the result of the previous transformation is reused.
-     * In all other cases, this method is called.
-     * Within each of these groupings, transformers are called in the order registered.
-     * Native transformers are provided by the <code>ClassFileLoadHook</code> event
-     * in the Java Virtual Machine Tool Interface).
-     *
-     * <P>
-     * The input (via the <code>classfileBuffer</code> parameter) to the first
-     * transformer is:
-     *  <ul>
-     *    <li>for new class definition,
-     *        the bytes passed to <code>ClassLoader.defineClass</code>
-     *    </li>
-     *    <li>for class redefinition,
-     *        <code>definitions.getDefinitionClassFile()</code> where
-     *        <code>definitions</code> is the parameter to
-     *        {@link java.lang.instrument.Instrumentation#redefineClasses
-     *         Instrumentation.redefineClasses}
-     *    </li>
-     *    <li>for class retransformation,
-     *         the bytes passed to the new class definition or, if redefined,
-     *         the last redefinition, with all transformations made by retransformation
-     *         incapable transformers reapplied automatically and unaltered;
-     *         for details see
-     *         {@link java.lang.instrument.Instrumentation#retransformClasses
-     *          Instrumentation.retransformClasses}
-     *    </li>
-     *  </ul>
-     *
-     * <P>
-     * If the implementing method determines that no transformations are needed,
-     * it should return <code>null</code>.
-     * Otherwise, it should create a new <code>byte[]</code> array,
-     * copy the input <code>classfileBuffer</code> into it,
-     * along with all desired transformations, and return the new array.
-     * The input <code>classfileBuffer</code> must not be modified.
-     *
-     * <P>
-     * In the retransform and redefine cases,
-     * the transformer must support the redefinition semantics:
-     * if a class that the transformer changed during initial definition is later
-     * retransformed or redefined, the
-     * transformer must insure that the second class output class file is a legal
-     * redefinition of the first output class file.
-     *
-     * <P>
-     * If the transformer throws an exception (which it doesn't catch),
-     * subsequent transformers will still be called and the load, redefine
-     * or retransform will still be attempted.
-     * Thus, throwing an exception has the same effect as returning <code>null</code>.
-     * To prevent unexpected behavior when unchecked exceptions are generated
-     * in transformer code, a transformer can catch <code>Throwable</code>.
-     * If the transformer believes the <code>classFileBuffer</code> does not
-     * represent a validly formatted class file, it should throw
-     * an <code>IllegalClassFormatException</code>;
-     * while this has the same effect as returning null. it facilitates the
-     * logging or debugging of format corruptions.
+     * @implSpec The default implementation returns null.
      *
      * @param loader                the defining loader of the class to be transformed,
      *                              may be <code>null</code> if the bootstrap loader
@@ -169,20 +183,67 @@
      *                              For example, <code>"java/util/List"</code>.
      * @param classBeingRedefined   if this is triggered by a redefine or retransform,
      *                              the class being redefined or retransformed;
-     *                              if this is a class load, <code>null</code>
+     *                              if this is a class load, {@code null}
      * @param protectionDomain      the protection domain of the class being defined or redefined
      * @param classfileBuffer       the input byte buffer in class file format - must not be modified
      *
-     * @throws IllegalClassFormatException if the input does not represent a well-formed class file
-     * @return  a well-formed class file buffer (the result of the transform),
-                or <code>null</code> if no transform is performed.
-     * @see Instrumentation#redefineClasses
+     * @throws IllegalClassFormatException
+     *         if the input does not represent a well-formed class file
+     * @return a well-formed class file buffer (the result of the transform),
+     *         or {@code null} if no transform is performed
      */
-    byte[]
+    default byte[]
     transform(  ClassLoader         loader,
                 String              className,
                 Class<?>            classBeingRedefined,
                 ProtectionDomain    protectionDomain,
                 byte[]              classfileBuffer)
-        throws IllegalClassFormatException;
+        throws IllegalClassFormatException {
+        return null;
+    }
+
+
+    /**
+     * Transforms the given class file and returns a new replacement class file.
+     *
+     * @implSpec The default implementation of this method invokes the
+     * {@link #transform(ClassLoader,String,Class,ProtectionDomain,byte[]) transform}
+     * method with the {@link Module#getClassLoader() ClassLoader} for the module.
+     *
+     * @param module                the module of the class to be transformed
+     * @param className             the name of the class in the internal form of fully
+     *                              qualified class and interface names as defined in
+     *                              <i>The Java Virtual Machine Specification</i>.
+     *                              For example, <code>"java/util/List"</code>.
+     * @param classBeingRedefined   if this is triggered by a redefine or retransform,
+     *                              the class being redefined or retransformed;
+     *                              if this is a class load, {@code null}
+     * @param protectionDomain      the protection domain of the class being defined or redefined
+     * @param classfileBuffer       the input byte buffer in class file format - must not be modified
+     *
+     * @throws IllegalClassFormatException
+     *         if the input does not represent a well-formed class file
+     * @return a well-formed class file buffer (the result of the transform),
+     *         or {@code null} if no transform is performed
+     *
+     * @since  9
+     */
+    default byte[]
+    transform(  Module              module,
+                String              className,
+                Class<?>            classBeingRedefined,
+                ProtectionDomain    protectionDomain,
+                byte[]              classfileBuffer)
+        throws IllegalClassFormatException {
+
+        PrivilegedAction<ClassLoader> pa = module::getClassLoader;
+        ClassLoader loader = AccessController.doPrivileged(pa);
+
+        // invoke the legacy transform method
+        return transform(loader,
+                         className,
+                         classBeingRedefined,
+                         protectionDomain,
+                         classfileBuffer);
+    }
 }
--- a/src/java.instrument/share/classes/java/lang/instrument/Instrumentation.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.instrument/share/classes/java/lang/instrument/Instrumentation.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,9 +25,9 @@
 
 package java.lang.instrument;
 
-import  java.io.File;
-import  java.io.IOException;
-import  java.util.jar.JarFile;
+import java.lang.reflect.Module;
+import java.security.ProtectionDomain;
+import java.util.jar.JarFile;
 
 /*
  * Copyright 2003 Wily Technology, Inc.
@@ -74,9 +74,8 @@
      * The transformer is called when classes are loaded, when they are
      * {@linkplain #redefineClasses redefined}. and if <code>canRetransform</code> is true,
      * when they are {@linkplain #retransformClasses retransformed}.
-     * See {@link java.lang.instrument.ClassFileTransformer#transform
-     * ClassFileTransformer.transform} for the order
-     * of transform calls.
+     * {@link ClassFileTransformer} defines the order of transform calls.
+     *
      * If a transformer throws
      * an exception during execution, the JVM will still call the other registered
      * transformers in order. The same transformer may be added more than once,
@@ -163,18 +162,16 @@
      *    </li>
      *    <li>for each transformer that was added with <code>canRetransform</code>
      *      false, the bytes returned by
-     *      {@link java.lang.instrument.ClassFileTransformer#transform transform}
-     *      during the last class load or redefine are
+     *      {@link ClassFileTransformer#transform(Module,String,Class,ProtectionDomain,byte[])
+     *      transform} during the last class load or redefine are
      *      reused as the output of the transformation; note that this is
      *      equivalent to reapplying the previous transformation, unaltered;
-     *      except that
-     *      {@link java.lang.instrument.ClassFileTransformer#transform transform}
-     *      is not called
+     *      except that {@code transform} method is not called.
      *    </li>
      *    <li>for each transformer that was added with <code>canRetransform</code>
      *      true, the
-     *      {@link java.lang.instrument.ClassFileTransformer#transform transform}
-     *      method is called in these transformers
+     *      {@link ClassFileTransformer#transform(Module,String,Class,ProtectionDomain,byte[])
+     *      transform} method is called in these transformers
      *    </li>
      *    <li>the transformed class file bytes are installed as the new
      *      definition of the class
@@ -182,10 +179,9 @@
      *  </ul>
      * <P>
      *
-     * The order of transformation is described in the
-     * {@link java.lang.instrument.ClassFileTransformer#transform transform} method.
-     * This same order is used in the automatic reapplication of retransformation
-     * incapable transforms.
+     * The order of transformation is described in {@link ClassFileTransformer}.
+     * This same order is used in the automatic reapplication of
+     * retransformation incapable transforms.
      * <P>
      *
      * The initial class file bytes represent the bytes passed to
@@ -662,4 +658,21 @@
      */
     void
     setNativeMethodPrefix(ClassFileTransformer transformer, String prefix);
+
+    /**
+     * Updates a module to read another module.
+     *
+     * Agents that instrument code in named modules may need to arrange for the
+     * modules to read other modules. This method is equivalent to code in {@code
+     * module} calling {@link Module#addReads(Module) addReads} to read {@code
+     * other}.
+     *
+     * @param module the module to update
+     * @param other the module to read
+     * @throws NullPointerException if either module is {@code null}
+     *
+     * @since 9
+     * @see Module#canRead(Module)
+     */
+    void addModuleReads(Module module, Module other);
 }
--- a/src/java.instrument/share/classes/java/lang/instrument/package.html	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.instrument/share/classes/java/lang/instrument/package.html	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 <!--
- Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 
  This code is free software; you can redistribute it and/or modify it
@@ -267,6 +267,24 @@
 the <code>Agent-Class</code> attribute specifies the name of the agent class
 (the value of <code>Premain-Class</code> attribute is ignored).
 
+
+<h3>Instrumenting code in modules</h3>
+
+Agents that instrument code in named modules may need to arrange for the
+modules to read other modules. If code is instrumented to invoke a method
+in a support class in another module, then the module of the instrumented
+code should read the module of the supporting class. Furthermore, the
+supporting class will only be accessible to the instrumented code if
+it is <code>public</code> and in a package that is exported by its module.
+Agents can use {@link Instrumentation#addModuleReads addModuleReads} to update
+a module to read another.
+<p>
+As an aid to agents that deploy supporting classes on the search path of the
+bootstrap class loader, or the search path of the class loader that loads
+the main agent class, the Java virtual machine arranges for the module of
+transformed classes to read the unnamed module of both class loaders.
+
+
 <h2>Related Documentation</h2>
 
 For tool documentation, please see:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.instrument/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module java.instrument {
+    exports java.lang.instrument;
+}
+
--- a/src/java.instrument/share/classes/sun/instrument/InstrumentationImpl.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.instrument/share/classes/sun/instrument/InstrumentationImpl.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,7 @@
 package sun.instrument;
 
 import java.lang.reflect.Method;
+import java.lang.reflect.Module;
 import java.lang.reflect.AccessibleObject;
 
 import java.lang.instrument.ClassFileTransformer;
@@ -37,6 +38,7 @@
 import java.security.PrivilegedAction;
 import java.security.ProtectionDomain;
 
+import java.util.Objects;
 import java.util.jar.JarFile;
 
 /*
@@ -225,6 +227,14 @@
         setNativeMethodPrefixes(mNativeAgent, prefixes, mgr.isRetransformable());
     }
 
+    @Override
+    public void addModuleReads(Module module, Module other) {
+        Objects.requireNonNull(module);
+        Objects.requireNonNull(other);
+        jdk.internal.module.Modules.addReads(module, other);
+    }
+
+
     private TransformerManager
     findTransformerManager(ClassFileTransformer transformer) {
         if (mTransformerManager.includesTransformer(transformer)) {
@@ -387,9 +397,6 @@
         } else {
             m.invoke(null, new Object[] { optionsString });
         }
-
-        // don't let others access a non-public premain method
-        setAccessible(m, false);
     }
 
     // WARNING: the native code knows the name & signature of this method
@@ -414,6 +421,7 @@
     // WARNING: the native code knows the name & signature of this method
     private byte[]
     transform(  ClassLoader         loader,
+                Module              module,
                 String              classname,
                 Class<?>            classBeingRedefined,
                 ProtectionDomain    protectionDomain,
@@ -422,10 +430,19 @@
         TransformerManager mgr = isRetransformer?
                                         mRetransfomableTransformerManager :
                                         mTransformerManager;
+        // module is null when not a class load or when loading a class in an
+        // unnamed module and this is the first type to be loaded in the package.
+        if (module == null) {
+            if (classBeingRedefined != null) {
+                module = classBeingRedefined.getModule();
+            } else {
+                module = loader.getUnnamedModule();
+            }
+        }
         if (mgr == null) {
             return null; // no manager, no transform
         } else {
-            return mgr.transform(   loader,
+            return mgr.transform(   module,
                                     classname,
                                     classBeingRedefined,
                                     protectionDomain,
--- a/src/java.instrument/share/classes/sun/instrument/TransformerManager.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.instrument/share/classes/sun/instrument/TransformerManager.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,6 +28,7 @@
 
 import java.lang.instrument.Instrumentation;
 import java.lang.instrument.ClassFileTransformer;
+import java.lang.reflect.Module;
 import java.security.ProtectionDomain;
 
 /*
@@ -167,7 +168,7 @@
     }
 
     public byte[]
-    transform(  ClassLoader         loader,
+    transform(  Module              module,
                 String              classname,
                 Class<?>            classBeingRedefined,
                 ProtectionDomain    protectionDomain,
@@ -185,7 +186,7 @@
             byte[]                  transformedBytes = null;
 
             try {
-                transformedBytes = transformer.transform(   loader,
+                transformedBytes = transformer.transform(   module,
                                                             classname,
                                                             classBeingRedefined,
                                                             protectionDomain,
--- a/src/java.instrument/share/native/libinstrument/JPLISAgent.c	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.instrument/share/native/libinstrument/JPLISAgent.c	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,6 +28,7 @@
  */
 
 #include    <jni.h>
+#include    <jvm.h>
 #include    <jvmti.h>
 #include    <stdlib.h>
 #include    <string.h>
@@ -769,6 +770,36 @@
     }
 }
 
+static jobject
+getModuleObject(JNIEnv *                jnienv,
+                jobject                 loaderObject,
+                const char*             cname) {
+    jboolean errorOutstanding = JNI_FALSE;
+    jobject moduleObject = NULL;
+    jstring package = NULL;
+
+    /* find last slash in the class name */
+    char* last_slash = (cname == NULL) ? NULL : strrchr(cname, '/');
+    int len = (last_slash == NULL) ? 0 : (int)(last_slash - cname);
+    char* pkg_name_buf = (char*)malloc(len + 1);
+
+    jplis_assert_msg(pkg_name_buf != NULL, "OOM error in native tmp buffer allocation");
+    if (last_slash != NULL) {
+        strncpy(pkg_name_buf, cname, len);
+    }
+    pkg_name_buf[len] = '\0';
+
+    package = (*jnienv)->NewStringUTF(jnienv, pkg_name_buf);
+    jplis_assert_msg(package != NULL, "OOM error in NewStringUTF");
+
+    moduleObject = JVM_GetModuleByPackageName(jnienv, loaderObject, package);
+
+    errorOutstanding = checkForAndClearThrowable(jnienv);
+    jplis_assert_msg(!errorOutstanding,
+                     "error in lookup of a module of the class being instrumented");
+    free((void*)pkg_name_buf);
+    return moduleObject;
+}
 
 /*
  *  Support for the JVMTI callbacks
@@ -810,7 +841,7 @@
             classFileBufferObject = (*jnienv)->NewByteArray(jnienv,
                                                             class_data_len);
             errorOutstanding = checkForAndClearThrowable(jnienv);
-            jplis_assert_msg(!errorOutstanding, "can't create byte arrau");
+            jplis_assert_msg(!errorOutstanding, "can't create byte array");
         }
 
         if ( !errorOutstanding ) {
@@ -828,6 +859,14 @@
         /*  now call the JPL agents to do the transforming */
         /*  potential future optimization: may want to skip this if there are none */
         if ( !errorOutstanding ) {
+            jobject moduleObject = NULL;
+
+            if (classBeingRedefined == NULL) {
+                moduleObject = getModuleObject(jnienv, loaderObject, name);
+            } else {
+                // Redefine or retransform, InstrumentationImpl.transform() will use
+                // classBeingRedefined.getModule() to get the module.
+            }
             jplis_assert(agent->mInstrumentationImpl != NULL);
             jplis_assert(agent->mTransform != NULL);
             transformedBufferObject = (*jnienv)->CallObjectMethod(
@@ -835,6 +874,7 @@
                                                 agent->mInstrumentationImpl,
                                                 agent->mTransform,
                                                 loaderObject,
+                                                moduleObject,
                                                 classNameStringObject,
                                                 classBeingRedefined,
                                                 protectionDomain,
--- a/src/java.instrument/share/native/libinstrument/JPLISAgent.h	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.instrument/share/native/libinstrument/JPLISAgent.h	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -66,7 +66,7 @@
 #define JPLIS_INSTRUMENTIMPL_AGENTMAININVOKER_METHODSIGNATURE "(Ljava/lang/String;Ljava/lang/String;)V"
 #define JPLIS_INSTRUMENTIMPL_TRANSFORM_METHODNAME           "transform"
 #define JPLIS_INSTRUMENTIMPL_TRANSFORM_METHODSIGNATURE      \
-    "(Ljava/lang/ClassLoader;Ljava/lang/String;Ljava/lang/Class;Ljava/security/ProtectionDomain;[BZ)[B"
+    "(Ljava/lang/ClassLoader;Ljava/lang/reflect/Module;Ljava/lang/String;Ljava/lang/Class;Ljava/security/ProtectionDomain;[BZ)[B"
 
 
 /*
--- a/src/java.logging/share/classes/META-INF/services/jdk.internal.logger.DefaultLoggerFinder	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-sun.util.logging.internal.LoggingProviderImpl
--- a/src/java.logging/share/classes/java/util/logging/Level.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.logging/share/classes/java/util/logging/Level.java	Thu Mar 17 19:04:16 2016 +0000
@@ -24,6 +24,7 @@
  */
 
 package java.util.logging;
+import java.lang.reflect.Module;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -262,9 +263,13 @@
     }
 
     private String computeLocalizedLevelName(Locale newLocale) {
-        ResourceBundle rb = ResourceBundle.getBundle(resourceBundleName, newLocale);
+        // Resource bundle should be loaded from the defining module
+        // or its defining class loader, if it's unnamed module,
+        // of this Level instance that can be a custom Level subclass;
+        Module module = this.getClass().getModule();
+        ResourceBundle rb = ResourceBundle.getBundle(resourceBundleName, newLocale, module);
+
         final String localizedName = rb.getString(name);
-
         final boolean isDefaultBundle = defaultBundle.equals(resourceBundleName);
         if (!isDefaultBundle) return localizedName;
 
--- a/src/java.logging/share/classes/java/util/logging/Logger.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.logging/share/classes/java/util/logging/Logger.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,7 @@
 package java.util.logging;
 
 import java.lang.ref.WeakReference;
+import java.lang.reflect.Module;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.ArrayList;
@@ -254,6 +255,9 @@
     private static final LoggerBundle NO_RESOURCE_BUNDLE =
             new LoggerBundle(null, null);
 
+    private static final RuntimePermission GET_CLASS_LOADER_PERMISSION =
+            new RuntimePermission("getClassLoader");
+
     private volatile LogManager manager;
     private String name;
     private final CopyOnWriteArrayList<Handler> handlers =
@@ -277,7 +281,7 @@
     private ArrayList<LogManager.LoggerWeakRef> kids;   // WeakReferences to loggers that have us as parent
     private volatile Level levelObject;
     private volatile int levelValue;  // current effective level value
-    private WeakReference<ClassLoader> callersClassLoaderRef;
+    private WeakReference<Module> callerModuleRef;
     private final boolean isSystemLogger;
 
     /**
@@ -383,18 +387,18 @@
         levelValue = Level.INFO.intValue();
     }
 
-    private void setCallersClassLoaderRef(Class<?> caller) {
-        ClassLoader callersClassLoader = ((caller != null)
-                                         ? caller.getClassLoader()
-                                         : null);
-        if (callersClassLoader != null) {
-            this.callersClassLoaderRef = new WeakReference<>(callersClassLoader);
+    private void setCallerModuleRef(Class<?> caller) {
+        Module callerModule = ((caller != null)
+                                        ? caller.getModule()
+                                        : null);
+        if (callerModule != null) {
+            this.callerModuleRef = new WeakReference<>(callerModule);
         }
     }
 
-    private ClassLoader getCallersClassLoader() {
-        return (callersClassLoaderRef != null)
-                ? callersClassLoaderRef.get()
+    private Module getCallerModule() {
+        return (callerModuleRef != null)
+                ? callerModuleRef.get()
                 : null;
     }
 
@@ -522,6 +526,7 @@
      * Find or create a logger for a named subsystem.  If a logger has
      * already been created with the given name it is returned.  Otherwise
      * a new logger is created.
+     *
      * <p>
      * If a new logger is created its log level will be configured
      * based on the LogManager and it will configured to also send logging
@@ -539,7 +544,7 @@
      * <p>
      * If the named Logger already exists and does not yet have a
      * localization resource bundle then the given resource bundle
-     * name is used.  If the named Logger already exists and has
+     * name is used. If the named Logger already exists and has
      * a different resource bundle name then an IllegalArgumentException
      * is thrown.
      *
@@ -1919,22 +1924,6 @@
         return useParentHandlers;
     }
 
-    private static ResourceBundle findSystemResourceBundle(final Locale locale) {
-        // the resource bundle is in a restricted package
-        return AccessController.doPrivileged(new PrivilegedAction<ResourceBundle>() {
-            @Override
-            public ResourceBundle run() {
-                try {
-                    return ResourceBundle.getBundle(SYSTEM_LOGGER_RB_NAME,
-                                                    locale,
-                                                    ClassLoader.getSystemClassLoader());
-                } catch (MissingResourceException e) {
-                    throw new InternalError(e.toString());
-                }
-            }
-        });
-    }
-
     /**
      * Private utility method to map a resource bundle name to an
      * actual resource bundle, using a simple one-entry cache.
@@ -1943,17 +1932,29 @@
      * there is no suitable previous cached value.
      *
      * @param name the ResourceBundle to locate
-     * @param userCallersClassLoader if true search using the caller's ClassLoader
+     * @param useCallersModule if true search using the caller's module.
      * @return ResourceBundle specified by name or null if not found
      */
     private synchronized ResourceBundle findResourceBundle(String name,
-                                                           boolean useCallersClassLoader) {
-        // For all lookups, we first check the thread context class loader
-        // if it is set.  If not, we use the system classloader.  If we
-        // still haven't found it we use the callersClassLoaderRef if it
-        // is set and useCallersClassLoader is true.  We set
-        // callersClassLoaderRef initially upon creating the logger with a
-        // non-null resource bundle name.
+                                                           boolean useCallersModule) {
+        // When this method is called from logrb, useCallersModule==false, and
+        // the resource bundle 'name' is the argument provided to logrb.
+        // It may, or may not be, equal to lb.resourceBundleName.
+        // Otherwise, useCallersModule==true, and name is the resource bundle
+        // name that is set (or will be set) in this logger.
+        //
+        // When useCallersModule is false, or when the caller's module is
+        // null, or when the caller's module is an unnamed module, we look
+        // first in the TCCL (or the System ClassLoader if the TCCL is null)
+        // to locate the resource bundle.
+        //
+        // Otherwise, if useCallersModule is true, and the caller's module is not
+        // null, and the caller's module is named, we look in the caller's module
+        // to locate the resource bundle.
+        //
+        // Finally, if the caller's module is not null and is unnamed, and
+        // useCallersModule is true, we look in the caller's module class loader
+        // (unless we already looked there in step 1).
 
         // Return a null bundle for a null name.
         if (name == null) {
@@ -1972,59 +1973,87 @@
             return catalog;
         }
 
-        if (name.equals(SYSTEM_LOGGER_RB_NAME)) {
-            catalog = findSystemResourceBundle(currentLocale);
-            catalogName = name;
-            catalogLocale = currentLocale;
-            return catalog;
-        }
-
         // Use the thread's context ClassLoader.  If there isn't one, use the
         // {@linkplain java.lang.ClassLoader#getSystemClassLoader() system ClassLoader}.
         ClassLoader cl = Thread.currentThread().getContextClassLoader();
         if (cl == null) {
             cl = ClassLoader.getSystemClassLoader();
         }
-        try {
-            catalog = ResourceBundle.getBundle(name, currentLocale, cl);
-            catalogName = name;
-            catalogLocale = currentLocale;
-            return catalog;
-        } catch (MissingResourceException ex) {
-            // We can't find the ResourceBundle in the default
-            // ClassLoader.  Drop through.
-        }
+
+        final Module callerModule = getCallerModule();
 
-        if (useCallersClassLoader) {
-            // Try with the caller's ClassLoader
-            ClassLoader callersClassLoader = getCallersClassLoader();
+        // If useCallersModule is false, we are called by logrb, with a name
+        // that is provided by the user. In that case we will look in the TCCL.
+        // We also look in the TCCL if callerModule is null or unnamed.
+        if (!useCallersModule || callerModule == null || !callerModule.isNamed()) {
+            try {
+                Module mod = cl.getUnnamedModule();
+                PrivilegedAction<ResourceBundle> pa = () ->
+                    ResourceBundle.getBundle(name, currentLocale, mod);
+                catalog = AccessController.doPrivileged(pa, null, GET_CLASS_LOADER_PERMISSION);
+                catalogName = name;
+                catalogLocale = currentLocale;
+                return catalog;
+            } catch (MissingResourceException ex) {
+                // We can't find the ResourceBundle in the default
+                // ClassLoader.  Drop through.
+                if (useCallersModule && callerModule != null) {
+                    try {
+                        // We are called by an unnamed module: try with the
+                        // unnamed module class loader:
+                        PrivilegedAction<ClassLoader> getModuleClassLoader =
+                                () -> callerModule.getClassLoader();
+                        ClassLoader moduleCL =
+                                AccessController.doPrivileged(getModuleClassLoader);
+                        // moduleCL can be null if the logger is created by a class
+                        // appended to the bootclasspath.
+                        // If moduleCL is null we would use cl, but we already tried
+                        // that above (we first looked in the TCCL for unnamed
+                        // caller modules) - so there no point in trying again: we
+                        // won't find anything more this second time.
+                        // In this case just return null.
+                        if (moduleCL == cl || moduleCL == null) return null;
 
-            if (callersClassLoader == null || callersClassLoader == cl) {
-                return null;
+                        // we already tried the TCCL and found nothing - so try
+                        // with the module's loader this time.
+                        catalog = ResourceBundle.getBundle(name, currentLocale,
+                                                           moduleCL);
+                        catalogName = name;
+                        catalogLocale = currentLocale;
+                        return catalog;
+                    } catch (MissingResourceException x) {
+                        return null; // no luck
+                    }
+                } else {
+                    return null;
+                }
             }
-
+        } else {
+            // we should have:
+            //  useCallersModule && callerModule != null && callerModule.isNamed();
+            // Try with the caller's module
             try {
-                catalog = ResourceBundle.getBundle(name, currentLocale,
-                                                   callersClassLoader);
+                // Use the caller's module
+                PrivilegedAction<ResourceBundle> pa = () ->
+                    ResourceBundle.getBundle(name, currentLocale, callerModule);
+                catalog = AccessController.doPrivileged(pa, null, GET_CLASS_LOADER_PERMISSION);
                 catalogName = name;
                 catalogLocale = currentLocale;
                 return catalog;
             } catch (MissingResourceException ex) {
                 return null; // no luck
             }
-        } else {
-            return null;
         }
     }
 
     // Private utility method to initialize our one entry
-    // resource bundle name cache and the callers ClassLoader
+    // resource bundle name cache and the callers Module
     // Note: for consistency reasons, we are careful to check
     // that a suitable ResourceBundle exists before setting the
     // resourceBundleName field.
     // Synchronized to prevent races in setting the fields.
     private synchronized void setupResourceInfo(String name,
-                                                Class<?> callersClass) {
+                                                Class<?> callerClass) {
         final LoggerBundle lb = loggerBundle;
         if (lb.resourceBundleName != null) {
             // this Logger already has a ResourceBundle
@@ -2043,22 +2072,26 @@
             return;
         }
 
-        setCallersClassLoaderRef(callersClass);
-        if (isSystemLogger && getCallersClassLoader() != null) {
+        setCallerModuleRef(callerClass);
+        if (isSystemLogger && (callerClass != null && callerClass.getClassLoader() != null)) {
             checkPermission();
         }
-        if (findResourceBundle(name, true) == null) {
-            // We've failed to find an expected ResourceBundle.
-            // unset the caller's ClassLoader since we were unable to find the
-            // the bundle using it
-            this.callersClassLoaderRef = null;
-            throw new MissingResourceException("Can't find " + name + " bundle",
-                                                name, "");
+
+        if (name.equals(SYSTEM_LOGGER_RB_NAME)) {
+            loggerBundle = SYSTEM_BUNDLE;
+        } else {
+            ResourceBundle bundle = findResourceBundle(name, true);
+            if (bundle == null) {
+                // We've failed to find an expected ResourceBundle.
+                // unset the caller's module since we were unable to find the
+                // the bundle using it
+                this.callerModuleRef = null;
+                throw new MissingResourceException("Can't find " + name + " bundle from ",
+                        name, "");
+            }
+
+            loggerBundle = LoggerBundle.get(name, null);
         }
-
-        // if lb.userBundle is not null we won't reach this line.
-        assert lb.userBundle == null;
-        loggerBundle = LoggerBundle.get(name, null);
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.logging/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module java.logging {
+    exports java.util.logging;
+    provides jdk.internal.logger.DefaultLoggerFinder with
+        sun.util.logging.internal.LoggingProviderImpl;
+}
+
--- a/src/java.management/share/classes/javax/management/remote/rmi/RMIConnector.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.management/share/classes/javax/management/remote/rmi/RMIConnector.java	Thu Mar 17 19:04:16 2016 +0000
@@ -43,6 +43,7 @@
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Module;
 import java.lang.reflect.Proxy;
 import java.net.MalformedURLException;
 import java.rmi.MarshalledObject;
@@ -100,6 +101,7 @@
 import javax.naming.NamingException;
 import javax.rmi.ssl.SslRMIClientSocketFactory;
 import javax.security.auth.Subject;
+import jdk.internal.module.Modules;
 import sun.reflect.misc.ReflectUtil;
 import sun.rmi.server.UnicastRef2;
 import sun.rmi.transport.LiveRef;
@@ -1956,21 +1958,22 @@
             RMIConnection.class.getName() + "Impl_Stub";
     private static final Class<?> rmiConnectionImplStubClass;
     private static final String pRefClassName =
-        "com.sun.jmx.remote.internal.PRef";
+        "jdk.jmx.remote.internal.PRef";
     private static final Constructor<?> proxyRefConstructor;
     static {
         final String pRefByteCodeString =
-                "\312\376\272\276\0\0\0.\0\27\12\0\5\0\15\11\0\4\0\16\13\0\17\0"+
-                "\20\7\0\21\7\0\22\1\0\6<init>\1\0\36(Ljava/rmi/server/RemoteRef;"+
-                ")V\1\0\4Code\1\0\6invoke\1\0S(Ljava/rmi/Remote;Ljava/lang/reflec"+
-                "t/Method;[Ljava/lang/Object;J)Ljava/lang/Object;\1\0\12Exception"+
-                "s\7\0\23\14\0\6\0\7\14\0\24\0\25\7\0\26\14\0\11\0\12\1\0\40com/"+
-                "sun/jmx/remote/internal/PRef\1\0$com/sun/jmx/remote/internal/Pr"+
-                "oxyRef\1\0\23java/lang/Exception\1\0\3ref\1\0\33Ljava/rmi/serve"+
-                "r/RemoteRef;\1\0\31java/rmi/server/RemoteRef\0!\0\4\0\5\0\0\0\0"+
-                "\0\2\0\1\0\6\0\7\0\1\0\10\0\0\0\22\0\2\0\2\0\0\0\6*+\267\0\1\261"+
-                "\0\0\0\0\0\1\0\11\0\12\0\2\0\10\0\0\0\33\0\6\0\6\0\0\0\17*\264\0"+
-                "\2+,-\26\4\271\0\3\6\0\260\0\0\0\0\0\13\0\0\0\4\0\1\0\14\0\0";
+                "\312\376\272\276\0\0\0\60\0\27\12\0\5\0\15\11\0\4\0\16\13\0\17"+
+                "\0\20\7\0\21\7\0\22\1\0\6<init>\1\0\36(Ljava/rmi/server/Remote"+
+                "Ref;)V\1\0\4Code\1\0\6invoke\1\0S(Ljava/rmi/Remote;Ljava/lang/"+
+                "reflect/Method;[Ljava/lang/Object;J)Ljava/lang/Object;\1\0\12E"+
+                "xceptions\7\0\23\14\0\6\0\7\14\0\24\0\25\7\0\26\14\0\11\0\12\1"+
+                "\0\34jdk/jmx/remote/internal/PRef\1\0$com/sun/jmx/remote/inter"+
+                "nal/ProxyRef\1\0\23java/lang/Exception\1\0\3ref\1\0\33Ljava/rm"+
+                "i/server/RemoteRef;\1\0\31java/rmi/server/RemoteRef\0!\0\4\0\5"+
+                "\0\0\0\0\0\2\0\1\0\6\0\7\0\1\0\10\0\0\0\22\0\2\0\2\0\0\0\6*+\267"+
+                "\0\1\261\0\0\0\0\0\1\0\11\0\12\0\2\0\10\0\0\0\33\0\6\0\6\0\0\0"+
+                "\17*\264\0\2+,-\26\4\271\0\3\6\0\260\0\0\0\0\0\13\0\0\0\4\0\1\0"+
+                "\14\0\0";
         final byte[] pRefByteCode =
                 NoCallStackClassLoader.stringToBytes(pRefByteCodeString);
         PrivilegedExceptionAction<Constructor<?>> action =
@@ -1980,13 +1983,34 @@
                 ClassLoader thisLoader = thisClass.getClassLoader();
                 ProtectionDomain thisProtectionDomain =
                         thisClass.getProtectionDomain();
-                String[] otherClassNames = {ProxyRef.class.getName()};
+
+                String proxyRefCName = ProxyRef.class.getName();
                 ClassLoader cl =
                         new NoCallStackClassLoader(pRefClassName,
                         pRefByteCode,
-                        otherClassNames,
+                        new String[] { proxyRefCName },
                         thisLoader,
                         thisProtectionDomain);
+
+                Module jmxModule = ProxyRef.class.getModule();
+                Module rmiModule = RemoteRef.class.getModule();
+
+                String pkg = packageOf(pRefClassName);
+                assert pkg != null && pkg.length() > 0 && !pkg.equals(packageOf(proxyRefCName));
+                Module m = Modules.defineModule(cl, "jdk.remoteref", Collections.singleton(pkg));
+
+                // jdk.remoteref needs to read to java.base and jmxModule
+                Modules.addReads(m, Object.class.getModule());
+                Modules.addReads(m, jmxModule);
+                Modules.addReads(m, rmiModule);
+
+                // jdk.remoteref needs access to ProxyRef class
+                Modules.addExports(jmxModule, packageOf(proxyRefCName), m);
+
+                // java.management needs to instantiate the fabricated RemoteRef class
+                Modules.addReads(jmxModule, m);
+                Modules.addExports(m, pkg, jmxModule);
+
                 Class<?> c = cl.loadClass(pRefClassName);
                 return c.getConstructor(RemoteRef.class);
             }
@@ -2021,6 +2045,11 @@
         proxyRefConstructor = constr;
     }
 
+    private static String packageOf(String cn) {
+        int i = cn.lastIndexOf('.');
+        return i > 0 ? cn.substring(0, i) : "";
+    }
+
     private static RMIConnection shadowJrmpStub(RemoteObject stub)
     throws InstantiationException, IllegalAccessException,
             InvocationTargetException, ClassNotFoundException,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.management/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module java.management {
+    requires public java.rmi;
+    requires java.logging;
+    requires java.naming;
+
+    exports java.lang.management;
+    exports javax.management;
+    exports javax.management.loading;
+    exports javax.management.modelmbean;
+    exports javax.management.monitor;
+    exports javax.management.openmbean;
+    exports javax.management.relation;
+    exports javax.management.remote;
+    exports javax.management.remote.rmi;
+    exports javax.management.timer;
+    exports sun.management to jdk.jconsole, jdk.management;
+    exports sun.management.spi to jdk.management;
+
+    uses javax.management.remote.JMXConnectorProvider;
+    uses javax.management.remote.JMXConnectorServerProvider;
+    uses sun.management.spi.PlatformMBeanProvider;
+
+    provides javax.security.auth.spi.LoginModule
+        with com.sun.jmx.remote.security.FileLoginModule;
+}
+
--- a/src/java.management/share/classes/sun/management/RuntimeImpl.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.management/share/classes/sun/management/RuntimeImpl.java	Thu Mar 17 19:04:16 2016 +0000
@@ -96,12 +96,8 @@
     }
 
     public String getBootClassPath() {
-        if (!isBootClassPathSupported()) {
-            throw new UnsupportedOperationException(
-                "Boot class path mechanism is not supported");
-        }
-        Util.checkMonitorAccess();
-        return jvm.getBootClassPath();
+        throw new UnsupportedOperationException(
+            "Boot class path mechanism is not supported");
     }
 
     public List<String> getInputArguments() {
@@ -118,7 +114,7 @@
     }
 
     public boolean isBootClassPathSupported() {
-        return jvm.isBootClassPathSupported();
+        return false;
     }
 
     public Map<String,String> getSystemProperties() {
--- a/src/java.management/share/classes/sun/management/StackTraceElementCompositeData.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.management/share/classes/sun/management/StackTraceElementCompositeData.java	Thu Mar 17 19:04:16 2016 +0000
@@ -25,6 +25,9 @@
 
 package sun.management;
 
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Predicate;
 import javax.management.openmbean.CompositeType;
 import javax.management.openmbean.CompositeData;
 import javax.management.openmbean.CompositeDataSupport;
@@ -49,10 +52,19 @@
     public static StackTraceElement from(CompositeData cd) {
         validateCompositeData(cd);
 
-        return new StackTraceElement(getString(cd, CLASS_NAME),
-                                     getString(cd, METHOD_NAME),
-                                     getString(cd, FILE_NAME),
-                                     getInt(cd, LINE_NUMBER));
+        if (stackTraceElementV6CompositeType.equals(cd.getCompositeType())) {
+            return new StackTraceElement(getString(cd, CLASS_NAME),
+                                         getString(cd, METHOD_NAME),
+                                         getString(cd, FILE_NAME),
+                                         getInt(cd, LINE_NUMBER));
+        } else {
+            return new StackTraceElement(getString(cd, MODULE_NAME),
+                                         getString(cd, MODULE_VERSION),
+                                         getString(cd, CLASS_NAME),
+                                         getString(cd, METHOD_NAME),
+                                         getString(cd, FILE_NAME),
+                                         getInt(cd, LINE_NUMBER));
+        }
     }
 
     public static CompositeData toCompositeData(StackTraceElement ste) {
@@ -69,6 +81,8 @@
             ste.getFileName(),
             ste.getLineNumber(),
             ste.isNativeMethod(),
+            ste.getModuleName(),
+            ste.getModuleVersion(),
         };
         try {
             return new CompositeDataSupport(stackTraceElementCompositeType,
@@ -80,23 +94,14 @@
         }
     }
 
-    private static final CompositeType stackTraceElementCompositeType;
-    static {
-        try {
-            stackTraceElementCompositeType = (CompositeType)
-                MappedMXBeanType.toOpenType(StackTraceElement.class);
-        } catch (OpenDataException e) {
-            // Should never reach here
-            throw new AssertionError(e);
-        }
-    }
-
     // Attribute names
     private static final String CLASS_NAME      = "className";
     private static final String METHOD_NAME     = "methodName";
     private static final String FILE_NAME       = "fileName";
     private static final String LINE_NUMBER     = "lineNumber";
     private static final String NATIVE_METHOD   = "nativeMethod";
+    private static final String MODULE_NAME     = "moduleName";
+    private static final String MODULE_VERSION  = "moduleVersion";
 
     private static final String[] stackTraceElementItemNames = {
         CLASS_NAME,
@@ -104,8 +109,32 @@
         FILE_NAME,
         LINE_NUMBER,
         NATIVE_METHOD,
+        MODULE_NAME,
+        MODULE_VERSION,
     };
 
+    private static final String[] stackTraceElementV9ItemNames = {
+        MODULE_NAME,
+        MODULE_VERSION,
+    };
+
+    private static final CompositeType stackTraceElementCompositeType;
+    private static final CompositeType stackTraceElementV6CompositeType;
+    static {
+        try {
+            stackTraceElementCompositeType = (CompositeType)
+                MappedMXBeanType.toOpenType(StackTraceElement.class);
+            stackTraceElementV6CompositeType =
+                TypeVersionMapper.getInstance().getVersionedCompositeType(
+                    stackTraceElementCompositeType,
+                    TypeVersionMapper.V6
+                );
+        } catch (OpenDataException e) {
+            // Should never reach here
+            throw new AssertionError(e);
+        }
+    }
+
     /** Validate if the input CompositeData has the expected
      * CompositeType (i.e. contain all attributes with expected
      * names and types).
@@ -115,11 +144,23 @@
             throw new NullPointerException("Null CompositeData");
         }
 
-        if (!isTypeMatched(stackTraceElementCompositeType, cd.getCompositeType())) {
-            throw new IllegalArgumentException(
-                "Unexpected composite type for StackTraceElement");
+        CompositeType ct = cd.getCompositeType();
+        if (!isTypeMatched(stackTraceElementCompositeType, ct)) {
+            if (!isTypeMatched(stackTraceElementV6CompositeType, ct)) {
+                throw new IllegalArgumentException(
+                    "Unexpected composite type for StackTraceElement");
+            }
         }
     }
 
+    static boolean isV6Attribute(String name) {
+        for(String attrName : stackTraceElementV9ItemNames) {
+            if (name.equals(attrName)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     private static final long serialVersionUID = -2704607706598396827L;
 }
--- a/src/java.management/share/classes/sun/management/ThreadInfoCompositeData.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.management/share/classes/sun/management/ThreadInfoCompositeData.java	Thu Mar 17 19:04:16 2016 +0000
@@ -32,7 +32,6 @@
 import javax.management.openmbean.CompositeData;
 import javax.management.openmbean.CompositeDataSupport;
 import javax.management.openmbean.OpenDataException;
-import javax.management.openmbean.OpenType;
 
 /**
  * A CompositeData for ThreadInfo for the local management support.
@@ -210,54 +209,16 @@
             threadInfoCompositeType = (CompositeType)
                 MappedMXBeanType.toOpenType(ThreadInfo.class);
             // Form a CompositeType for JDK 5.0 ThreadInfo version
-            String[] itemNames =
-                threadInfoCompositeType.keySet().toArray(new String[0]);
-            int numV5Attributes = threadInfoItemNames.length -
-                threadInfoV6Attributes.length - threadInfoV9Attributes.length;
-            String[] v5ItemNames = new String[numV5Attributes];
-            String[] v5ItemDescs = new String[numV5Attributes];
-            OpenType<?>[] v5ItemTypes = new OpenType<?>[numV5Attributes];
-            int i = 0;
-            for (String n : itemNames) {
-                if (isV5Attribute(n)) {
-                    v5ItemNames[i] = n;
-                    v5ItemDescs[i] = threadInfoCompositeType.getDescription(n);
-                    v5ItemTypes[i] = threadInfoCompositeType.getType(n);
-                    i++;
-                }
-            }
 
             threadInfoV5CompositeType =
-                new CompositeType("java.lang.management.ThreadInfo",
-                                  "J2SE 5.0 java.lang.management.ThreadInfo",
-                                  v5ItemNames,
-                                  v5ItemDescs,
-                                  v5ItemTypes);
-
-
-            // Form a CompositeType for JDK 6.0 ThreadInfo version
-            int numV6Attributes = threadInfoItemNames.length -
-                                      threadInfoV9Attributes.length;
-            String[] v6ItemNames = new String[numV6Attributes];
-            String[] v6ItemDescs = new String[numV6Attributes];
-            OpenType<?>[] v6ItemTypes = new OpenType<?>[numV6Attributes];
-            i = 0;
-            for (String n : itemNames) {
-                if (isV5Attribute(n) || isV6Attribute(n)) {
-                    v6ItemNames[i] = n;
-                    v6ItemDescs[i] = threadInfoCompositeType.getDescription(n);
-                    v6ItemTypes[i] = threadInfoCompositeType.getType(n);
-                    i++;
-                }
-            }
+                TypeVersionMapper.getInstance().getVersionedCompositeType(
+                    threadInfoCompositeType, TypeVersionMapper.V5
+                );
 
             threadInfoV6CompositeType =
-                new CompositeType("java.lang.management.ThreadInfo",
-                                  "Java SE 6 java.lang.management.ThreadInfo",
-                                  v6ItemNames,
-                                  v6ItemDescs,
-                                  v6ItemTypes);
-
+                TypeVersionMapper.getInstance().getVersionedCompositeType(
+                    threadInfoCompositeType, TypeVersionMapper.V6
+                );
         } catch (OpenDataException e) {
             // Should never reach here
             throw new AssertionError(e);
@@ -275,7 +236,7 @@
         lockInfoCompositeType = cd.getCompositeType();
     }
 
-    private static boolean isV5Attribute(String itemName) {
+    static boolean isV5Attribute(String itemName) {
         for (String n : threadInfoV6Attributes) {
             if (itemName.equals(n)) {
                 return false;
@@ -289,7 +250,7 @@
         return true;
     }
 
-    private static boolean isV6Attribute(String itemName) {
+    static boolean isV6Attribute(String itemName) {
         for (String n : threadInfoV9Attributes) {
             if (itemName.equals(n)) {
                 return false;
@@ -446,8 +407,8 @@
             // check if cd is an older version
             if (!isTypeMatched(threadInfoV5CompositeType, type) &&
                 !isTypeMatched(threadInfoV6CompositeType, type)) {
-              throw new IllegalArgumentException(
-                  "Unexpected composite type for ThreadInfo");
+                throw new IllegalArgumentException(
+                    "Unexpected composite type for ThreadInfo");
             }
         }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.management/share/classes/sun/management/TypeVersionMapper.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package sun.management;
+
+import java.lang.management.ThreadInfo;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Predicate;
+import javax.management.openmbean.ArrayType;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenDataException;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+import javax.management.openmbean.TabularType;
+import static sun.management.Util.toStringArray;
+
+/**
+ * Provides simplistic support for versioning of {@linkplain CompositeType} instances
+ * based on the latest version and filtering out certain items.
+ */
+final class TypeVersionMapper {
+    private static final class Singleton {
+        private final static TypeVersionMapper INSTANCE = new TypeVersionMapper();
+    }
+
+    final static String V5 = "J2SE 5.0";
+    final static String V6 = "Java SE 6";
+
+    private final Map<String, Map<String, Predicate<String>>> filterMap;
+
+    private TypeVersionMapper() {
+        filterMap = new HashMap<>();
+        setupStackTraceElement();
+        setupThreadInfo();
+    }
+
+    public static TypeVersionMapper getInstance() {
+        return Singleton.INSTANCE;
+    }
+
+    private void setupStackTraceElement() {
+        Map<String, Predicate<String>> filter = new HashMap<>();
+        filterMap.put(StackTraceElement.class.getName(), filter);
+        filter.put(V5, StackTraceElementCompositeData::isV6Attribute);
+        filter.put(V6, StackTraceElementCompositeData::isV6Attribute);
+    }
+
+    private void setupThreadInfo() {
+        Map<String, Predicate<String>> filter = new HashMap<>();
+        filterMap.put(ThreadInfo.class.getName(), filter);
+        filter.put(V5, ThreadInfoCompositeData::isV5Attribute);
+        filter.put(V6, ThreadInfoCompositeData::isV6Attribute);
+    }
+
+    /**
+     * Retrieves the specified version of a {@linkplain CompositeType} instance.
+     * @param type The current (latest) version of {@linkplain CompositeType}
+     * @param version The version identifier (eg. {@linkplain TypeVersionMapper#V5})
+     * @return Returns the {@linkplain CompositeType} corresponding to the requested
+     *         version.
+     * @throws OpenDataException
+     */
+    CompositeType getVersionedCompositeType(CompositeType type, String version)
+        throws OpenDataException
+    {
+        Predicate<String> filter = getFilter(type.getTypeName(), version);
+        if (filter == null) {
+            return type;
+        }
+
+        List<String> itemNames = new ArrayList<>();
+        List<String> itemDesc = new ArrayList<>();
+        List<OpenType<?>> itemTypes = new ArrayList<>();
+
+        for(String item : type.keySet()) {
+            if (filter.test(item)) {
+                itemNames.add(item);
+                itemDesc.add(type.getDescription(item));
+                itemTypes.add(getVersionedType(
+                    type.getType(item),
+                    version
+                ));
+            }
+        }
+        return new CompositeType(
+            type.getTypeName(),
+            version != null ? version + " " + type.getDescription() : type.getDescription(),
+            itemNames.toArray(new String[itemNames.size()]),
+            itemDesc.toArray(new String[itemDesc.size()]),
+            itemTypes.toArray(new OpenType<?>[itemTypes.size()])
+        );
+    }
+
+    private OpenType<?> getVersionedType(OpenType<?> type, String version)
+        throws OpenDataException
+    {
+        if (type instanceof ArrayType) {
+            return getVersionedArrayType((ArrayType)type, version);
+        }
+        if (type instanceof CompositeType) {
+            return getVersionedCompositeType((CompositeType)type, version);
+        }
+        if (type instanceof TabularType) {
+            return getVersionedTabularType((TabularType)type, version);
+        }
+        return type;
+    }
+
+    private ArrayType<?> getVersionedArrayType(ArrayType<?> type, String version)
+        throws OpenDataException
+    {
+        if (type.isPrimitiveArray()) {
+            return type;
+        }
+        OpenType<?> ot = getVersionedType(
+            type.getElementOpenType(),
+            version
+        );
+        if (ot instanceof SimpleType) {
+            return new ArrayType<>((SimpleType<?>)ot, type.isPrimitiveArray());
+        } else {
+            return new ArrayType<>(type.getDimension(), ot);
+        }
+    }
+
+    private TabularType getVersionedTabularType(TabularType type, String version)
+        throws OpenDataException
+    {
+        CompositeType ct = getVersionedCompositeType(
+            type.getRowType(),
+            version
+        );
+
+        if (ct != null) {
+            return new TabularType(
+                type.getTypeName(), type.getDescription(), ct,
+                toStringArray(type.getIndexNames()));
+        }
+        return null;
+    }
+
+    private Predicate<String> getFilter(String type, String version) {
+        Map<String, Predicate<String>> versionMap = filterMap.get(type);
+        if (versionMap == null) {
+            return null;
+        }
+
+        return versionMap.get(version);
+    }
+}
--- a/src/java.management/share/classes/sun/management/VMManagementImpl.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.management/share/classes/sun/management/VMManagementImpl.java	Thu Mar 17 19:04:16 2016 +0000
@@ -51,7 +51,6 @@
     private static boolean threadContentionMonitoringSupport;
     private static boolean currentThreadCpuTimeSupport;
     private static boolean otherThreadCpuTimeSupport;
-    private static boolean bootClassPathSupport;
     private static boolean objectMonitorUsageSupport;
     private static boolean synchronizerUsageSupport;
     private static boolean threadAllocatedMemorySupport;
@@ -87,7 +86,7 @@
     }
 
     public boolean isBootClassPathSupported() {
-        return bootClassPathSupport;
+        return false;
     }
 
     public boolean isObjectMonitorUsageSupported() {
@@ -172,8 +171,8 @@
     }
 
     public String   getBootClassPath( ) {
-        return AccessController.doPrivileged(
-            (PrivilegedAction<String>) () -> System.getProperty("sun.boot.class.path"));
+        throw new UnsupportedOperationException(
+            "Boot class path mechanism is not supported");
     }
 
     public long getUptime() {
--- a/src/java.management/share/native/include/jmm.h	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.management/share/native/include/jmm.h	Thu Mar 17 19:04:16 2016 +0000
@@ -59,7 +59,6 @@
   unsigned int isThreadContentionMonitoringSupported : 1;
   unsigned int isCurrentThreadCpuTimeSupported : 1;
   unsigned int isOtherThreadCpuTimeSupported : 1;
-  unsigned int isBootClassPathSupported : 1;
   unsigned int isObjectMonitorUsageSupported : 1;
   unsigned int isSynchronizerUsageSupported : 1;
   unsigned int isThreadAllocatedMemorySupported : 1;
--- a/src/java.management/share/native/libmanagement/VMManagementImpl.c	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.management/share/native/libmanagement/VMManagementImpl.c	Thu Mar 17 19:04:16 2016 +0000
@@ -80,9 +80,6 @@
     value = mos.isOtherThreadCpuTimeSupported;
     setStaticBooleanField(env, cls, "otherThreadCpuTimeSupport", value);
 
-    value = mos.isBootClassPathSupported;
-    setStaticBooleanField(env, cls, "bootClassPathSupport", value);
-
     if (jmm_version >= JMM_VERSION_1_1) {
         value = mos.isObjectMonitorUsageSupported;
         setStaticBooleanField(env, cls, "objectMonitorUsageSupport", value);
--- a/src/java.naming/share/classes/com/sun/jndi/ldap/Obj.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.naming/share/classes/com/sun/jndi/ldap/Obj.java	Thu Mar 17 19:04:16 2016 +0000
@@ -643,8 +643,10 @@
                  classObjs[i] = cl;
              }
              try {
-                 return Proxy.getProxyClass(hasNonPublicInterface ?
+                 @SuppressWarnings("deprecation")
+                 Class<?> proxyClass = Proxy.getProxyClass(hasNonPublicInterface ?
                         nonPublicLoader : classLoader, classObjs);
+                 return proxyClass;
              } catch (IllegalArgumentException e) {
                  throw new ClassNotFoundException(null, e);
              }
--- a/src/java.naming/share/classes/com/sun/naming/internal/VersionHelper.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.naming/share/classes/com/sun/naming/internal/VersionHelper.java	Thu Mar 17 19:04:16 2016 +0000
@@ -149,12 +149,39 @@
         return jProps;
     }
 
+    private static String resolveName(Class<?> c, String name) {
+        if (name == null) {
+            return name;
+        }
+        if (!name.startsWith("/")) {
+            while (c.isArray()) {
+                c = c.getComponentType();
+            }
+            String baseName = c.getName();
+            int index = baseName.lastIndexOf('.');
+            if (index != -1) {
+                name = baseName.substring(0, index).replace('.', '/')
+                    +"/"+name;
+            }
+        } else {
+            name = name.substring(1);
+        }
+        return name;
+    }
+
     /*
      * Returns the resource of a given name associated with a particular
      * class (never null), or null if none can be found.
      */
     InputStream getResourceAsStream(Class<?> c, String name) {
-        PrivilegedAction<InputStream> act = () -> c.getResourceAsStream(name);
+        PrivilegedAction<InputStream> act = () -> {
+            try {
+                java.lang.reflect.Module m = c.getModule();
+                return c.getModule().getResourceAsStream(resolveName(c,name));
+             } catch (IOException x) {
+                 return null;
+             }
+        };
         return AccessController.doPrivileged(act);
     }
 
--- a/src/java.naming/share/classes/javax/naming/ldap/ControlFactory.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.naming/share/classes/javax/naming/ldap/ControlFactory.java	Thu Mar 17 19:04:16 2016 +0000
@@ -112,8 +112,11 @@
       *    exception is passed up to the caller.
       *</ul>
       * <p>
-      * Note that a control factory
-      * must be public and must have a public constructor that accepts no arguments.
+      * Note that a control factory must be public and must have a public
+      * constructor that accepts no arguments.
+      * In cases where the factory is in a named module then it must be in a
+      * package which is exported by that module to the {@code java.naming}
+      * module.
       *
       * @param ctl The non-null control object containing the OID and BER data.
       * @param ctx The possibly null context in which the control is being created.
--- a/src/java.naming/share/classes/javax/naming/spi/NamingManager.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.naming/share/classes/javax/naming/spi/NamingManager.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,8 +25,9 @@
 
 package javax.naming.spi;
 
+import java.net.MalformedURLException;
 import java.util.*;
-import java.net.MalformedURLException;
+
 
 import javax.naming.*;
 import com.sun.naming.internal.VersionHelper;
@@ -243,6 +244,9 @@
      * Note that an object factory (an object that implements the ObjectFactory
      * interface) must be public and must have a public constructor that
      * accepts no arguments.
+     * In cases where the factory is in a named module then it must be in a
+     * package which is exported by that module to the {@code java.naming}
+     * module.
      * <p>
      * The {@code name} and {@code nameCtx} parameters may
      * optionally be used to specify the name of the object being created.
@@ -525,6 +529,9 @@
      * Note that an object factory (an object that implements the ObjectFactory
      * interface) must be public and must have a public constructor that
      * accepts no arguments.
+     * In cases where the factory is in a named module then it must be in a
+     * package which is exported by that module to the {@code java.naming}
+     * module.
      *
      * @param scheme    The non-null scheme-id of the URLs supported by the context.
      * @param environment The possibly null environment properties to be
@@ -641,7 +648,10 @@
      *         <br>
      *         (Note that an initial context factory (an object that implements
      *         the InitialContextFactory interface) must be public and must have
-     *         a public constructor that accepts no arguments)</li>
+     *         a public constructor that accepts no arguments.
+     *         In cases where the factory is in a named module then it must
+     *         be in a package which is exported by that module to the
+     *         {@code java.naming} module.)</li>
      *     </ul>
      * </li>
      * </ul>
@@ -847,6 +857,9 @@
      * (an object that implements the StateFactory
      * interface) must be public and must have a public constructor that
      * accepts no arguments.
+     * In cases where the factory is in a named module then it must be in a
+     * package which is exported by that module to the {@code java.naming}
+     * module.
      * <p>
      * The {@code name} and {@code nameCtx} parameters may
      * optionally be used to specify the name of the object being created.
--- a/src/java.naming/share/classes/javax/naming/spi/ObjectFactory.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.naming/share/classes/javax/naming/spi/ObjectFactory.java	Thu Mar 17 19:04:16 2016 +0000
@@ -46,6 +46,9 @@
   * An object factory must implement the {@code ObjectFactory} interface.
   * In addition, the factory class must be public and must have a
   * public constructor that accepts no parameters.
+  * Note that in cases where the factory is in a named module then it must be
+  * in a package which is exported by that module to the {@code java.naming}
+  * module.
   *<p>
   * The {@code getObjectInstance()} method of an object factory may
   * be invoked multiple times, possibly using different parameters.
--- a/src/java.naming/share/classes/javax/naming/spi/StateFactory.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.naming/share/classes/javax/naming/spi/StateFactory.java	Thu Mar 17 19:04:16 2016 +0000
@@ -58,6 +58,9 @@
   * A state factory must implement the {@code StateFactory} interface.
   * In addition, the factory class must be public and must have a
   * public constructor that accepts no parameters.
+  * Note that in cases where the factory is in a named module then it must be
+  * in a package which is exported by that module to the {@code java.naming}
+  * module.
   *<p>
   * The {@code getStateToBind()} method of a state factory may
   * be invoked multiple times, possibly using different parameters.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.naming/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module java.naming {
+    requires java.security.sasl;
+
+    exports javax.naming;
+    exports javax.naming.directory;
+    exports javax.naming.event;
+    exports javax.naming.ldap;
+    exports javax.naming.spi;
+    exports com.sun.jndi.toolkit.ctx to
+        jdk.naming.dns;
+    exports com.sun.jndi.toolkit.url to
+        java.corba,
+        jdk.naming.dns,
+        jdk.naming.rmi;
+    uses javax.naming.ldap.StartTlsResponse;
+    uses javax.naming.spi.InitialContextFactory;
+    provides java.security.Provider with sun.security.provider.certpath.ldap.JdkLDAP;
+}
+
--- a/src/java.naming/share/classes/sun/security/provider/certpath/ldap/LDAPCertStoreImpl.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.naming/share/classes/sun/security/provider/certpath/ldap/LDAPCertStoreImpl.java	Thu Mar 17 19:04:16 2016 +0000
@@ -48,7 +48,6 @@
 import sun.security.provider.certpath.X509CertificatePair;
 import sun.security.util.Cache;
 import sun.security.util.Debug;
-import sun.security.x509.X500Name;
 
 /**
  * Core implementation of a LDAP Cert Store.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.prefs/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module java.prefs {
+    requires java.xml;
+
+    exports java.util.prefs;
+    uses java.util.prefs.PreferencesFactory;
+}
+
--- a/src/java.rmi/share/classes/java/rmi/activation/ActivationID.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.rmi/share/classes/java/rmi/activation/ActivationID.java	Thu Mar 17 19:04:16 2016 +0000
@@ -275,10 +275,9 @@
             RemoteRef ref = refClass.newInstance();
             ref.readExternal(in);
             activator = (Activator)
-                Proxy.newProxyInstance(null,
+                Proxy.newProxyInstance(Activator.class.getClassLoader(),
                                        new Class<?>[] { Activator.class },
                                        new RemoteObjectInvocationHandler(ref));
-
         } catch (InstantiationException e) {
             throw (IOException)
                 new InvalidObjectException(
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.rmi/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module java.rmi {
+    requires java.logging;
+
+    exports java.rmi;
+    exports java.rmi.activation;
+    exports java.rmi.dgc;
+    exports java.rmi.registry;
+    exports java.rmi.server;
+    exports javax.rmi.ssl;
+    // com.sun.rmi.rmid contains permissions classes that must be
+    // accessible to the security manager at initialization time
+    exports com.sun.rmi.rmid to java.base;
+    exports sun.rmi.registry to
+        java.management;
+    exports sun.rmi.server to
+        java.management,
+        jdk.jconsole;
+    exports sun.rmi.transport to
+        java.management,
+        jdk.jconsole;
+    uses java.rmi.server.RMIClassLoaderSpi;
+}
+
--- a/src/java.scripting/share/classes/com/sun/tools/script/shell/Main.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.scripting/share/classes/com/sun/tools/script/shell/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -433,8 +433,11 @@
         InputStream sysIn = null;
         ClassLoader cl = Thread.currentThread().getContextClassLoader();
         for (String ext : exts) {
-            sysIn = cl.getResourceAsStream("com/sun/tools/script/shell/init." +
-                    ext);
+            try {
+                sysIn = Main.class.getModule().getResourceAsStream("com/sun/tools/script/shell/init." + ext);
+            } catch (IOException ioe) {
+                throw new RuntimeException(ioe);
+            }
             if (sysIn != null) break;
         }
         if (sysIn != null) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.scripting/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module java.scripting {
+    exports javax.script;
+    uses javax.script.ScriptEngineFactory;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.se.ee/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module java.se.ee {
+
+    requires public java.se;
+
+    // Upgradeable modules for Java EE technologies
+    requires public java.activation;
+    requires public java.annotations.common;
+    requires public java.corba;
+    requires public java.transaction;
+    requires public java.xml.bind;
+    requires public java.xml.ws;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.se/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module java.se {
+    requires public java.compact3;
+    requires public java.datatransfer;
+    requires public java.desktop;
+}
--- a/src/java.security.jgss/share/classes/META-INF/services/sun.security.ssl.ClientKeyExchangeService	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-sun.security.krb5.internal.ssl.Krb5KeyExchangeService
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.security.jgss/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module java.security.jgss {
+    requires java.naming;
+    exports javax.security.auth.kerberos;
+    exports org.ietf.jgss;
+    exports sun.security.jgss to
+        jdk.security.jgss;
+    exports sun.security.jgss.krb5 to
+        jdk.security.auth;
+    exports sun.security.krb5 to
+        jdk.security.auth;
+    exports sun.security.krb5.internal to
+        jdk.security.jgss;
+    exports sun.security.krb5.internal.ktab to
+        jdk.security.auth;
+    provides java.security.Provider with sun.security.jgss.SunProvider;
+    provides sun.security.ssl.ClientKeyExchangeService
+        with sun.security.krb5.internal.ssl.Krb5KeyExchangeService;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.security.sasl/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module java.security.sasl {
+    requires java.logging;
+
+    exports javax.security.sasl;
+    exports com.sun.security.sasl.util to
+        jdk.security.jgss;
+    provides java.security.Provider with com.sun.security.sasl.Provider;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.smartcardio/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module java.smartcardio {
+    exports javax.smartcardio;
+    provides java.security.Provider with sun.security.smartcardio.SunPCSC;
+}
+
--- a/src/java.sql.rowset/share/classes/com/sun/rowset/CachedRowSetImpl.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.sql.rowset/share/classes/com/sun/rowset/CachedRowSetImpl.java	Thu Mar 17 19:04:16 2016 +0000
@@ -2961,7 +2961,8 @@
                 // create new instance of the class
                 SQLData obj = null;
                 try {
-                    obj = (SQLData) ReflectUtil.newInstance(c);
+                    ReflectUtil.checkPackageAccess(c);
+                    obj = (SQLData) c.newInstance();
                 } catch(Exception ex) {
                     throw new SQLException("Unable to Instantiate: ", ex);
                 }
@@ -5708,7 +5709,8 @@
                 // create new instance of the class
                 SQLData obj = null;
                 try {
-                    obj = (SQLData) ReflectUtil.newInstance(c);
+                    ReflectUtil.checkPackageAccess(c);
+                    obj = (SQLData) c.newInstance();
                 } catch(Exception ex) {
                     throw new SQLException("Unable to Instantiate: ", ex);
                 }
--- a/src/java.sql.rowset/share/classes/com/sun/rowset/JdbcRowSetResourceBundle.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.sql.rowset/share/classes/com/sun/rowset/JdbcRowSetResourceBundle.java	Thu Mar 17 19:04:16 2016 +0000
@@ -102,8 +102,8 @@
         Locale locale = Locale.getDefault();
 
         // Load appropriate bundle according to locale
-         propResBundle = (PropertyResourceBundle) ResourceBundle.getBundle(PATH,
-                           locale, Thread.currentThread().getContextClassLoader());
+        propResBundle = (PropertyResourceBundle) ResourceBundle.getBundle(PATH,
+                           locale, JdbcRowSetResourceBundle.class.getModule());
 
    }
 
--- a/src/java.sql.rowset/share/classes/com/sun/rowset/internal/CachedRowSetWriter.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.sql.rowset/share/classes/com/sun/rowset/internal/CachedRowSetWriter.java	Thu Mar 17 19:04:16 2016 +0000
@@ -573,7 +573,8 @@
                         // create new instance of the class
                         SQLData obj = null;
                         try {
-                            obj = (SQLData)ReflectUtil.newInstance(c);
+                            ReflectUtil.checkPackageAccess(c);
+                            obj = (SQLData)c.newInstance();
                         } catch (Exception ex) {
                             throw new SQLException("Unable to Instantiate: ", ex);
                         }
@@ -1467,4 +1468,5 @@
 
         return isValid;
     }
+
 }
--- a/src/java.sql.rowset/share/classes/javax/sql/rowset/RowSetProvider.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.sql.rowset/share/classes/javax/sql/rowset/RowSetProvider.java	Thu Mar 17 19:04:16 2016 +0000
@@ -31,7 +31,6 @@
 import java.util.PropertyPermission;
 import java.util.ServiceConfigurationError;
 import java.util.ServiceLoader;
-import javax.sql.rowset.spi.SyncFactoryException;
 import sun.reflect.misc.ReflectUtil;
 
 /**
@@ -132,9 +131,15 @@
             factoryClassName = getSystemProperty(ROWSET_FACTORY_NAME);
             if (factoryClassName != null) {
                 trace("Found system property, value=" + factoryClassName);
-                factory = (RowSetFactory) ReflectUtil.newInstance(getFactoryClass(factoryClassName, null, true));
+                if (factoryClassName.equals(ROWSET_FACTORY_IMPL)) {
+                    return defaultRowSetFactory();
+                }
+                // getFactoryClass takes care of adding the read edge if
+                // necessary
+                Class<?> c = getFactoryClass(factoryClassName, null, false);
+                factory = (RowSetFactory) c.newInstance();
             }
-        }  catch (Exception e) {
+        } catch (Exception e) {
             throw new SQLException( "RowSetFactory: " + factoryClassName +
                     " could not be instantiated: ", e);
         }
@@ -145,10 +150,12 @@
             // look it up via the ServiceLoader API and if not found, use the
             // Java SE default.
             factory = loadViaServiceLoader();
-            factory =
-                    factory == null ? newFactory(ROWSET_FACTORY_IMPL, null) : factory;
         }
-        return (factory);
+        return  factory == null ? defaultRowSetFactory() : factory;
+    }
+
+    private static RowSetFactory defaultRowSetFactory() {
+        return new com.sun.rowset.RowSetFactoryImpl();
     }
 
     /**
@@ -192,6 +199,8 @@
         }
 
         try {
+            // getFactoryClass takes care of adding the read edge if
+            // necessary
             Class<?> providerClass = getFactoryClass(factoryClassName, cl, false);
             RowSetFactory instance = (RowSetFactory) providerClass.newInstance();
             if (debug) {
@@ -242,25 +251,30 @@
      */
     static private Class<?> getFactoryClass(String factoryClassName, ClassLoader cl,
             boolean doFallback) throws ClassNotFoundException {
+        Class<?> factoryClass = null;
+
         try {
             if (cl == null) {
                 cl = getContextClassLoader();
                 if (cl == null) {
                     throw new ClassNotFoundException();
                 } else {
-                    return cl.loadClass(factoryClassName);
+                    factoryClass = cl.loadClass(factoryClassName);
                 }
             } else {
-                return cl.loadClass(factoryClassName);
+                factoryClass = cl.loadClass(factoryClassName);
             }
         } catch (ClassNotFoundException e) {
             if (doFallback) {
                 // Use current class loader
-                return Class.forName(factoryClassName, true, RowSetFactory.class.getClassLoader());
+                factoryClass = Class.forName(factoryClassName, true, RowSetFactory.class.getClassLoader());
             } else {
                 throw e;
             }
         }
+
+        ReflectUtil.checkPackageAccess(factoryClass);
+        return factoryClass;
     }
 
     /**
--- a/src/java.sql.rowset/share/classes/javax/sql/rowset/serial/SQLInputImpl.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.sql.rowset/share/classes/javax/sql/rowset/serial/SQLInputImpl.java	Thu Mar 17 19:04:16 2016 +0000
@@ -477,7 +477,8 @@
                 // create new instance of the class
                 SQLData obj = null;
                 try {
-                    obj = (SQLData)ReflectUtil.newInstance(c);
+                    ReflectUtil.checkPackageAccess(c);
+                    obj = (SQLData)c.newInstance();
                 } catch (Exception ex) {
                     throw new SQLException("Unable to Instantiate: ", ex);
                 }
--- a/src/java.sql.rowset/share/classes/javax/sql/rowset/spi/SyncFactory.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/java.sql.rowset/share/classes/javax/sql/rowset/spi/SyncFactory.java	Thu Mar 17 19:04:16 2016 +0000
@@ -383,17 +383,14 @@
                         strFileSep + "rowset" + strFileSep +
                         "rowset.properties";
 
-                ClassLoader cl = Thread.currentThread().getContextClassLoader();
-
                 try {
                     AccessController.doPrivileged((PrivilegedExceptionAction<Void>) () -> {
-                        try (InputStream stream = (cl == null) ?
-                                ClassLoader.getSystemResourceAsStream(ROWSET_PROPERTIES)
-                                : cl.getResourceAsStream(ROWSET_PROPERTIES)) {
-                            if (stream == null) {
-                                throw new SyncFactoryException("Resource " + ROWSET_PROPERTIES + " not found");
-                            }
-                            properties.load(stream);
+                        InputStream in = SyncFactory.class.getModule().getResourceAsStream(ROWSET_PROPERTIES);
+                        if (in == null) {
+                            throw new SyncFactoryException("Resource " + ROWSET_PROPERTIES + " not found");
+                        }
+                        try (in) {
+                            properties.load(in);
                         }
                         return null;
                     });
@@ -585,12 +582,7 @@
              * there.
              **/
             c = Class.forName(providerID, true, cl);
-
-            if (c != null) {
-                return (SyncProvider) c.newInstance();
-            } else {
-                return new com.sun.rowset.providers.RIOptimisticProvider();
-            }
+            return (SyncProvider) c.newInstance();
 
         } catch (IllegalAccessException e) {
             throw new SyncFactoryException("IllegalAccessException: " + e.getMessage());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.sql.rowset/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module java.sql.rowset {
+    requires public java.logging;
+    requires public java.naming;
+    requires public java.sql;
+
+    exports javax.sql.rowset;
+    exports javax.sql.rowset.serial;
+    exports javax.sql.rowset.spi;
+    uses javax.sql.rowset.RowSetFactory;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.sql/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module java.sql {
+    requires public java.logging;
+    requires public java.xml;
+
+    exports java.sql;
+    exports javax.sql;
+    exports javax.transaction.xa;
+    uses java.sql.Driver;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.transaction/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module java.transaction {
+    requires public java.rmi;
+    exports javax.transaction;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.xml.crypto/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module java.xml.crypto {
+    requires public java.xml;
+    requires java.logging;
+
+    exports javax.xml.crypto;
+    exports javax.xml.crypto.dom;
+    exports javax.xml.crypto.dsig;
+    exports javax.xml.crypto.dsig.dom;
+    exports javax.xml.crypto.dsig.keyinfo;
+    exports javax.xml.crypto.dsig.spec;
+    provides java.security.Provider with org.jcp.xml.dsig.internal.dom.XMLDSigRI;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.accessibility/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.accessibility {
+    requires public java.desktop;
+    exports com.sun.java.accessibility.util;
+}
+
--- a/src/jdk.accessibility/windows/classes/META-INF/services/javax.accessibility.AccessibilityProvider	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.  Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-
-
-com.sun.java.accessibility.internal.ProviderImpl
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.accessibility/windows/classes/module-info.java.extra	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+provides javax.accessibility.AccessibilityProvider with com.sun.java.accessibility.internal.ProviderImpl;
--- a/src/jdk.attach/share/classes/META-INF/services/com.sun.tools.attach.spi.AttachProvider	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-#
-# Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.  Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-sun.tools.attach.AttachProviderImpl
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.attach/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.attach {
+    requires jdk.jvmstat;
+
+    exports com.sun.tools.attach;
+    exports com.sun.tools.attach.spi;
+    exports sun.tools.attach to
+        jdk.jcmd;
+    uses com.sun.tools.attach.spi.AttachProvider;
+    provides com.sun.tools.attach.spi.AttachProvider with sun.tools.attach.AttachProviderImpl;
+}
+
--- a/src/jdk.charsets/share/classes/META-INF/services/java.nio.charset.spi.CharsetProvider	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-# NIO charset SPI extended charset provider
-sun.nio.cs.ext.ExtendedCharsets
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.charsets/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.charsets {
+    provides java.nio.charset.spi.CharsetProvider
+        with sun.nio.cs.ext.ExtendedCharsets;
+}
+
--- a/src/jdk.compiler/share/classes/sun/tools/serialver/SerialVer.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/jdk.compiler/share/classes/sun/tools/serialver/SerialVer.java	Thu Mar 17 19:04:16 2016 +0000
@@ -27,15 +27,13 @@
 
 import java.io.*;
 import java.io.ObjectStreamClass;
-import java.util.Properties;
+import java.nio.file.Paths;
 import java.text.MessageFormat;
 import java.util.ResourceBundle;
 import java.util.MissingResourceException;
 import java.net.URLClassLoader;
 import java.net.URL;
 import java.net.MalformedURLException;
-import java.util.StringTokenizer;
-import sun.net.www.ParseUtil;
 
 /**
  * Supporting class for the serialver tool.
@@ -52,15 +50,12 @@
      * Create a URL class loader that will load classes from the
      * specified classpath.
      */
-    static void initializeLoader(String cp)
-                                throws MalformedURLException, IOException {
-        URL[] urls;
-        StringTokenizer st = new StringTokenizer(cp, File.pathSeparator);
-        int count = st.countTokens();
-        urls = new URL[count];
+    static void initializeLoader(String cp) throws IOException {
+        String[] paths = cp.split(File.pathSeparator);
+        int count = paths.length;
+        URL[] urls = new URL[count];
         for (int i = 0; i < count; i++) {
-            urls[i] = ParseUtil.fileToEncodedURL(
-                new File(new File(st.nextToken()).getCanonicalPath()));
+            urls[i] = Paths.get(paths[i]).toUri().toURL();
         }
         loader = new URLClassLoader(urls);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.crypto.ec/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.crypto.ec {
+    provides java.security.Provider with sun.security.ec.SunEC;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.crypto.mscapi/windows/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.crypto.mscapi {
+    provides java.security.Provider with sun.security.mscapi.SunMSCAPI;
+}
+
--- a/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/RSAKeyPairGenerator.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/RSAKeyPairGenerator.java	Thu Mar 17 19:04:16 2016 +0000
@@ -30,7 +30,6 @@
 import java.security.spec.AlgorithmParameterSpec;
 import java.security.spec.RSAKeyGenParameterSpec;
 
-import sun.security.jca.JCAUtil;
 import sun.security.rsa.RSAKeyFactory;
 
 /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.crypto.pkcs11/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.crypto.pkcs11 {
+    // Depends on SunEC provider for EC related functionality
+    requires jdk.crypto.ec;
+    provides java.security.Provider with sun.security.pkcs11.SunPKCS11;
+}
+
--- a/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/SunPKCS11.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/SunPKCS11.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1439,10 +1439,17 @@
                                    (defaultHandler,
                                    true,
                                    Thread.currentThread().getContextClassLoader());
+                        if (!javax.security.auth.callback.CallbackHandler.class.isAssignableFrom(c)) {
+                            // not the right subtype
+                            if (debug != null) {
+                                debug.println("default handler " + defaultHandler +
+                                              " is not a CallbackHandler");
+                            }
+                            return null;
+                        }
                         return (CallbackHandler)c.newInstance();
                     }
                 });
-
                 // save it
                 pHandler = myHandler;
                 return myHandler;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.crypto.ucrypto/solaris/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.crypto.ucrypto {
+    provides java.security.Provider with com.oracle.security.ucrypto.UcryptoProvider;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.deploy.osx/macosx/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.deploy.osx {
+    requires java.desktop;
+    requires java.scripting;
+}
+
--- a/src/jdk.dev/share/classes/jdk/tools/jimage/ExtractedImage.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,222 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.tools.jimage;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.PrintWriter;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.function.Consumer;
-import java.util.stream.Stream;
-import jdk.internal.jimage.Archive;
-import jdk.internal.jimage.ImageFileCreator;
-import jdk.internal.jimage.ImageModuleData;
-import jdk.internal.jimage.ImageModuleDataWriter;
-
-/**
- *
- * Support for extracted image.
- */
-public final class ExtractedImage {
-
-    /**
-     * An Archive backed by a directory.
-     */
-    public class DirArchive implements Archive {
-
-        /**
-         * A File located in a Directory.
-         */
-        private class FileEntry extends Archive.Entry {
-
-            private final long size;
-            private final Path path;
-
-            FileEntry(Path path, String name) {
-                super(DirArchive.this, getPathName(path), name,
-                        Archive.Entry.EntryType.CLASS_OR_RESOURCE);
-                this.path = path;
-                try {
-                    size = Files.size(path);
-                } catch (IOException ex) {
-                    throw new RuntimeException(ex);
-                }
-            }
-
-            /**
-             * Returns the number of bytes of this file.
-             */
-            @Override
-            public long size() {
-                return size;
-            }
-
-            @Override
-            public InputStream stream() throws IOException {
-                InputStream stream = Files.newInputStream(path);
-                open.add(stream);
-                return stream;
-            }
-        }
-
-        private final Path dirPath;
-        private final String moduleName;
-        private final List<InputStream> open = new ArrayList<>();
-        private final int chop;
-
-        protected DirArchive(Path dirPath) throws IOException {
-            if (!Files.isDirectory(dirPath)) {
-                throw new IOException("Not a directory");
-            }
-            chop = dirPath.toString().length() + 1;
-            this.moduleName = dirPath.getFileName().toString();
-            this.dirPath = dirPath;
-        }
-
-        @Override
-        public String moduleName() {
-            return moduleName;
-        }
-
-        @Override
-        public Stream<Entry> entries() {
-            try {
-                return Files.walk(dirPath).map(this::toEntry).filter(n -> n != null);
-            } catch(IOException ex) {
-                throw new RuntimeException(ex);
-            }
-        }
-
-        private Archive.Entry toEntry(Path p) {
-            if (Files.isDirectory(p)) {
-                return null;
-            }
-            String name = getPathName(p).substring(chop);
-            if (name.startsWith("_")) {
-                return null;
-            }
-            if (verbose) {
-                String verboseName = moduleName + "/" + name;
-                log.println(verboseName);
-            }
-
-            return new FileEntry(p, name);
-        }
-
-        @Override
-        public void close() throws IOException {
-            IOException e = null;
-            for (InputStream stream : open) {
-                try {
-                    stream.close();
-                } catch (IOException ex) {
-                    if (e == null) {
-                        e = ex;
-                    } else {
-                        e.addSuppressed(ex);
-                    }
-                }
-            }
-            if (e != null) {
-                throw e;
-            }
-        }
-
-        @Override
-        public void open() throws IOException {
-            // NOOP
-        }
-    }
-    private Map<String, Set<String>> modulePackages = new LinkedHashMap<>();
-    private Set<Archive> archives = new HashSet<>();
-    private final PrintWriter log;
-    private final boolean verbose;
-    private final String jdataName;
-    ExtractedImage(Path dirPath, PrintWriter log,
-            boolean verbose) throws IOException {
-        if (!Files.isDirectory(dirPath)) {
-            throw new IOException("Not a directory");
-        }
-        List<String> jdataNameHolder = new ArrayList<>();
-        Files.walk(dirPath, 1).forEach((p) -> {
-            try {
-                if (!dirPath.equals(p)) {
-                    String name = getPathName(p);
-                    if (name.endsWith(ImageModuleData.META_DATA_EXTENSION)) {
-                        jdataNameHolder.add(p.getFileName().toString());
-                        List<String> lines = Files.readAllLines(p);
-                        for (Entry<String, List<String>> entry
-                                : ImageModuleDataWriter.toModulePackages(lines).entrySet()) {
-                            Set<String> pkgs = new HashSet<>();
-                            pkgs.addAll(entry.getValue());
-                            modulePackages.put(entry.getKey(), pkgs);
-                        }
-                        modulePackages = Collections.unmodifiableMap(modulePackages);
-                    } else {
-                        if (Files.isDirectory(p)) {
-                            Archive a = new DirArchive(p);
-                            archives.add(a);
-                        }
-                    }
-                }
-            } catch (IOException ex) {
-                throw new RuntimeException(ex);
-            }
-        });
-        archives = Collections.unmodifiableSet(archives);
-        this.log = log;
-        this.verbose = verbose;
-        if (jdataNameHolder.size() != 1) {
-            throw new IOException("Wrong module information");
-        }
-        // The name of the metadata resource must be reused in the recreated jimage
-        String name = jdataNameHolder.get(0);
-        // Extension will be added when recreating the jimage
-        if (name.endsWith(ImageModuleData.META_DATA_EXTENSION)) {
-            name = name.substring(0, name.length()
-                    - ImageModuleData.META_DATA_EXTENSION.length());
-        }
-        jdataName = name;
-    }
-
-    void recreateJImage(Path path) throws IOException {
-
-        ImageFileCreator.recreateJimage(path, jdataName, archives, modulePackages);
-    }
-
-    private static String getPathName(Path path) {
-        return path.toString().replace(File.separatorChar, '/');
-    }
-}
--- a/src/jdk.dev/share/classes/jdk/tools/jimage/JImageTask.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,416 +0,0 @@
-/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.tools.jimage;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.channels.FileChannel;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import static java.nio.file.StandardOpenOption.READ;
-import static java.nio.file.StandardOpenOption.WRITE;
-import java.util.LinkedList;
-import java.util.List;
-import jdk.internal.jimage.BasicImageReader;
-import jdk.internal.jimage.ImageHeader;
-import static jdk.internal.jimage.ImageHeader.MAGIC;
-import static jdk.internal.jimage.ImageHeader.MAJOR_VERSION;
-import static jdk.internal.jimage.ImageHeader.MINOR_VERSION;
-import jdk.internal.jimage.ImageLocation;
-import jdk.internal.jimage.ImageModuleData;
-import jdk.internal.jimage.ImageResourcesTree;
-import jdk.tools.jimage.TaskHelper.BadArgs;
-import jdk.tools.jimage.TaskHelper.HiddenOption;
-import jdk.tools.jimage.TaskHelper.Option;
-import jdk.tools.jimage.TaskHelper.OptionsHelper;
-
-class JImageTask {
-
-    static final Option<?>[] recognizedOptions = {
-        new Option<JImageTask>(true, "--dir") {
-            @Override
-            protected void process(JImageTask task, String opt, String arg) throws BadArgs {
-                 task.options.directory = arg;
-            }
-        },
-        new HiddenOption<JImageTask>(false, "--fullversion") {
-            @Override
-            protected void process(JImageTask task, String opt, String arg) {
-                task.options.fullVersion = true;
-            }
-        },
-        new Option<JImageTask>(false, "--help") {
-            @Override
-            protected void process(JImageTask task, String opt, String arg) {
-                task.options.help = true;
-            }
-        },
-
-        new Option<JImageTask>(true, "--flags") {
-            @Override
-            protected void process(JImageTask task, String opt, String arg) {
-                task.options.flags = arg;
-            }
-        },
-
-        new Option<JImageTask>(false, "--verbose") {
-            @Override
-            protected void process(JImageTask task, String opt, String arg) throws BadArgs {
-                 task.options.verbose = true;
-            }
-        },
-        new Option<JImageTask>(false, "--version") {
-            @Override
-            protected void process(JImageTask task, String opt, String arg) {
-                task.options.version = true;
-            }
-        },
-    };
-    private static final TaskHelper taskHelper
-            = new TaskHelper("jdk.tools.jimage.resources.jimage");
-    private static final OptionsHelper<JImageTask> optionsHelper
-            = taskHelper.newOptionsHelper(JImageTask.class, recognizedOptions);
-
-    static class OptionsValues {
-        Task task = Task.LIST;
-        String directory = ".";
-        boolean fullVersion;
-        boolean help;
-        String flags;
-        boolean verbose;
-        boolean version;
-        List<File> jimages = new LinkedList<>();
-    }
-
-    private static final String PROGNAME = "jimage";
-    private final OptionsValues options = new OptionsValues();
-
-    enum Task {
-        EXTRACT,
-        INFO,
-        LIST,
-        RECREATE,
-        SET,
-        VERIFY
-    };
-
-    private String pad(String string, int width, boolean justifyRight) {
-        int length = string.length();
-
-        if (length == width) {
-            return string;
-        }
-
-        if (length > width) {
-            return string.substring(0, width);
-        }
-
-        int padding = width - length;
-
-        StringBuilder sb = new StringBuilder(width);
-        if (justifyRight) {
-            for (int i = 0; i < padding; i++) {
-                sb.append(' ');
-            }
-        }
-
-        sb.append(string);
-
-        if (!justifyRight) {
-            for (int i = 0; i < padding; i++) {
-                sb.append(' ');
-            }
-        }
-
-        return sb.toString();
-    }
-
-    private String pad(String string, int width) {
-        return pad(string, width, false);
-    }
-
-    private String pad(long value, int width) {
-        return pad(Long.toString(value), width, true);
-    }
-
-    private static final int EXIT_OK = 0;        // No errors.
-    private static final int EXIT_ERROR = 1;     // Completed but reported errors.
-    private static final int EXIT_CMDERR = 2;    // Bad command-line arguments and/or switches.
-    private static final int EXIT_SYSERR = 3;    // System error or resource exhaustion.
-    private static final int EXIT_ABNORMAL = 4;  // Terminated abnormally.
-
-    int run(String[] args) {
-        if (log == null) {
-            setLog(new PrintWriter(System.out));
-        }
-
-        try {
-            List<String> unhandled = optionsHelper.handleOptions(this, args);
-            if(!unhandled.isEmpty()) {
-                options.task = Enum.valueOf(Task.class, unhandled.get(0).toUpperCase());
-                for(int i = 1; i < unhandled.size(); i++) {
-                    options.jimages.add(new File(unhandled.get(i)));
-                }
-            }
-            if (options.help) {
-                optionsHelper.showHelp(PROGNAME, "recreate only options:");
-            }
-            if (options.version || options.fullVersion) {
-                taskHelper.showVersion(options.fullVersion);
-            }
-            boolean ok = run();
-            return ok ? EXIT_OK : EXIT_ERROR;
-        } catch (BadArgs e) {
-            taskHelper.reportError(e.key, e.args);
-            if (e.showUsage) {
-                log.println(taskHelper.getMessage("main.usage.summary", PROGNAME));
-            }
-            return EXIT_CMDERR;
-        } catch (Exception x) {
-            x.printStackTrace();
-            return EXIT_ABNORMAL;
-        } finally {
-            log.flush();
-        }
-    }
-
-    private void recreate() throws IOException, BadArgs {
-        File directory = new File(options.directory);
-        if (!directory.isDirectory()) {
-            throw taskHelper.newBadArgs("err.not.a.dir", directory.getAbsolutePath());
-        }
-        Path dirPath = directory.toPath();
-        if (options.jimages.isEmpty()) {
-            throw taskHelper.newBadArgs("err.jimage.not.specified");
-        } else if (options.jimages.size() != 1) {
-            throw taskHelper.newBadArgs("err.only.one.jimage");
-        }
-
-        Path jimage = options.jimages.get(0).toPath();
-
-        if (jimage.toFile().createNewFile()) {
-            ExtractedImage img = new ExtractedImage(dirPath, log, options.verbose);
-            img.recreateJImage(jimage);
-        } else {
-            throw taskHelper.newBadArgs("err.jimage.already.exists", jimage.getFileName());
-        }
-    }
-
-    private void title(File file, BasicImageReader reader) {
-        log.println("jimage: " + file.getName());
-    }
-
-    private void listTitle(File file, BasicImageReader reader) {
-        title(file, reader);
-
-        if (options.verbose) {
-            log.print(pad("Offset", OFFSET_WIDTH + 1));
-            log.print(pad("Size", SIZE_WIDTH + 1));
-            log.print(pad("Compressed", COMPRESSEDSIZE_WIDTH + 1));
-            log.println(" Entry");
-        }
-    }
-
-    private interface JImageAction {
-        public void apply(File file, BasicImageReader reader) throws IOException, BadArgs;
-    }
-
-    private interface ResourceAction {
-        public void apply(BasicImageReader reader, String name,
-                ImageLocation location) throws IOException, BadArgs;
-    }
-
-    private void extract(BasicImageReader reader, String name,
-            ImageLocation location) throws IOException, BadArgs {
-        File directory = new File(options.directory);
-        byte[] bytes = reader.getResource(location);
-        File resource =  new File(directory, name);
-        File parent = resource.getParentFile();
-
-        if (parent.exists()) {
-            if (!parent.isDirectory()) {
-                throw taskHelper.newBadArgs("err.cannot.create.dir", parent.getAbsolutePath());
-            }
-        } else if (!parent.mkdirs()) {
-            throw taskHelper.newBadArgs("err.cannot.create.dir", parent.getAbsolutePath());
-        }
-
-        if (name.endsWith(ImageModuleData.META_DATA_EXTENSION)) {
-            ImageModuleData imageModuleData = new ImageModuleData(reader, bytes);
-            List<String> lines = imageModuleData.fromModulePackages();
-            Files.write(resource.toPath(), lines);
-        } else {
-            if (!ImageResourcesTree.isTreeInfoResource(name)) {
-                Files.write(resource.toPath(), bytes);
-            }
-        }
-    }
-
-    private static final int NUMBER_WIDTH = 12;
-    private static final int OFFSET_WIDTH = NUMBER_WIDTH;
-    private static final int SIZE_WIDTH = NUMBER_WIDTH;
-    private static final int COMPRESSEDSIZE_WIDTH = NUMBER_WIDTH;
-
-    private void print(String entry, ImageLocation location) {
-        log.print(pad(location.getContentOffset(), OFFSET_WIDTH) + " ");
-        log.print(pad(location.getUncompressedSize(), SIZE_WIDTH) + " ");
-        log.print(pad(location.getCompressedSize(), COMPRESSEDSIZE_WIDTH) + " ");
-        log.println(entry);
-    }
-
-    private void print(BasicImageReader reader, String entry) {
-        if (options.verbose) {
-            print(entry, reader.findLocation(entry));
-        } else {
-            log.println(entry);
-        }
-    }
-
-    private void info(File file, BasicImageReader reader) throws IOException {
-        ImageHeader header = reader.getHeader();
-
-        log.println(" Major Version:  " + header.getMajorVersion());
-        log.println(" Minor Version:  " + header.getMinorVersion());
-        log.println(" Flags:          " + Integer.toHexString(header.getMinorVersion()));
-        log.println(" Resource Count: " + header.getResourceCount());
-        log.println(" Table Length:   " + header.getTableLength());
-        log.println(" Offsets Size:   " + header.getOffsetsSize());
-        log.println(" Redirects Size: " + header.getRedirectSize());
-        log.println(" Locations Size: " + header.getLocationsSize());
-        log.println(" Strings Size:   " + header.getStringsSize());
-        log.println(" Index Size:     " + header.getIndexSize());
-    }
-
-    private void list(BasicImageReader reader, String name, ImageLocation location) {
-        print(reader, name);
-    }
-
-    void set(File file, BasicImageReader reader) throws BadArgs {
-        try {
-            ImageHeader oldHeader = reader.getHeader();
-
-            int value = 0;
-            try {
-                value = Integer.valueOf(options.flags);
-            } catch (NumberFormatException ex) {
-                throw taskHelper.newBadArgs("err.flags.not.int", options.flags);
-            }
-
-            ImageHeader newHeader = new ImageHeader(MAGIC, MAJOR_VERSION, MINOR_VERSION,
-                    value,
-                    oldHeader.getResourceCount(), oldHeader.getTableLength(),
-                    oldHeader.getLocationsSize(), oldHeader.getStringsSize());
-
-            ByteBuffer buffer = ByteBuffer.allocate(ImageHeader.getHeaderSize());
-            buffer.order(ByteOrder.nativeOrder());
-            newHeader.writeTo(buffer);
-            buffer.rewind();
-
-            try (FileChannel channel = FileChannel.open(file.toPath(), READ, WRITE)) {
-                channel.write(buffer, 0);
-            }
-        } catch (IOException ex) {
-            throw taskHelper.newBadArgs("err.cannot.update.file", file.getName());
-        }
-    }
-
-     void verify(BasicImageReader reader, String name, ImageLocation location) {
-        if (name.endsWith(".class")) {
-            byte[] bytes = reader.getResource(location);
-
-            if (bytes == null || bytes.length <= 4 ||
-                (bytes[0] & 0xFF) != 0xCA ||
-                (bytes[1] & 0xFF) != 0xFE ||
-                (bytes[2] & 0xFF) != 0xBA ||
-                (bytes[3] & 0xFF) != 0xBE) {
-                log.print(" NOT A CLASS: ");
-                print(reader, name);
-            }
-        }
-    }
-
-    private void iterate(JImageAction jimageAction,
-            ResourceAction resourceAction) throws IOException, BadArgs {
-        for (File file : options.jimages) {
-            if (!file.exists() || !file.isFile()) {
-                throw taskHelper.newBadArgs("err.not.a.jimage", file.getName());
-            }
-
-            String path = file.getCanonicalPath();
-            BasicImageReader reader = BasicImageReader.open(path);
-
-            if (jimageAction != null) {
-                jimageAction.apply(file, reader);
-            }
-
-            if (resourceAction != null) {
-                String[] entryNames = reader.getEntryNames();
-
-                for (String name : entryNames) {
-                    if (!ImageResourcesTree.isTreeInfoResource(name)) {
-                        ImageLocation location = reader.findLocation(name);
-                        resourceAction.apply(reader, name, location);
-                    }
-                }
-            }
-       }
-    }
-
-    private boolean run() throws IOException, BadArgs {
-        switch (options.task) {
-            case EXTRACT:
-                iterate(null, this::extract);
-                break;
-            case INFO:
-                iterate(this::info, null);
-                break;
-            case LIST:
-                iterate(this::listTitle, this::list);
-                break;
-            case RECREATE:
-                recreate();
-                break;
-            case SET:
-                iterate(this::set, null);
-                break;
-            case VERIFY:
-                iterate(this::title, this::verify);
-                break;
-            default:
-                throw taskHelper.newBadArgs("err.invalid.task", options.task.name()).showUsage(true);
-        }
-        return true;
-    }
-
-    private PrintWriter log;
-    void setLog(PrintWriter out) {
-        log = out;
-        taskHelper.setLog(log);
-    }
-}
--- a/src/jdk.dev/share/classes/jdk/tools/jimage/Main.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.tools.jimage;
-
-import java.io.PrintWriter;
-
-
-public class Main {
-    public static void main(String[] args) throws Exception {
-        JImageTask t = new JImageTask();
-        int rc = t.run(args);
-        System.exit(rc);
-    }
-
-    /**
-     * Entry point that does <i>not</i> call System.exit.
-     *
-     * @param args command line arguments
-     * @param out output stream
-     * @return an exit code. 0 means success, non-zero means an error occurred.
-     */
-    public static int run(String[] args, PrintWriter out) {
-        JImageTask t = new JImageTask();
-        t.setLog(out);
-        return t.run(args);
-    }
-}
--- a/src/jdk.dev/share/classes/jdk/tools/jimage/TaskHelper.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,231 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.tools.jimage;
-
-import java.io.PrintWriter;
-import java.text.MessageFormat;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-import java.util.MissingResourceException;
-import java.util.ResourceBundle;
-
-/**
- *
- * JImage tools shared helper.
- */
-public final class TaskHelper {
-
-    public class BadArgs extends Exception {
-
-        static final long serialVersionUID = 8765093759964640721L;
-
-        private BadArgs(String key, Object... args) {
-            super(bundleHelper.getMessage(key, args));
-            this.key = key;
-            this.args = args;
-        }
-
-        public BadArgs showUsage(boolean b) {
-            showUsage = b;
-            return this;
-        }
-        public final String key;
-        public final Object[] args;
-        public boolean showUsage;
-    }
-
-    public static abstract class Option<T> {
-
-        final boolean hasArg;
-        final String[] aliases;
-
-        public Option(boolean hasArg, String... aliases) {
-            this.hasArg = hasArg;
-            this.aliases = aliases;
-        }
-
-        public boolean isHidden() {
-            return false;
-        }
-
-        public boolean matches(String opt) {
-            for (String a : aliases) {
-                if (a.equals(opt)) {
-                    return true;
-                } else if (opt.startsWith("--") && hasArg && opt.startsWith(a + "=")) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        public boolean ignoreRest() {
-            return false;
-        }
-
-        protected abstract void process(T task, String opt, String arg) throws BadArgs;
-    }
-
-    public static abstract class HiddenOption<T> extends Option<T> {
-
-        public HiddenOption(boolean hasArg, String... aliases) {
-            super(hasArg, aliases);
-        }
-
-        @Override
-        public boolean isHidden() {
-            return true;
-        }
-    }
-
-    private class ResourceBundleHelper {
-
-        private final ResourceBundle bundle;
-
-        ResourceBundleHelper(String path) {
-            Locale locale = Locale.getDefault();
-            try {
-                bundle = ResourceBundle.getBundle(path, locale);
-            } catch (MissingResourceException e) {
-                throw new InternalError("Cannot find resource bundle for locale " + locale);
-            }
-        }
-
-        String getMessage(String key, Object... args) {
-            String val = bundle.getString(key);
-            return MessageFormat.format(val, args);
-        }
-
-    }
-
-    public class OptionsHelper<T> {
-
-        private final List<Option<T>> options;
-
-        OptionsHelper(List<Option<T>> options) {
-            this.options = options;
-        }
-
-        public List<String> handleOptions(T task, String[] args) throws BadArgs {
-            List<String> rest = new ArrayList<>();
-            // process options
-            for (int i = 0; i < args.length; i++) {
-                if (args[i].charAt(0) == '-') {
-                    String name = args[i];
-                    Option<T> option = getOption(name);
-                    if (option == null) {
-                        throw new BadArgs("err.unknown.option", name).showUsage(true);
-                    }
-                    String param = null;
-                    if (option.hasArg) {
-                        if (name.startsWith("--") && name.indexOf('=') > 0) {
-                            param = name.substring(name.indexOf('=') + 1, name.length());
-                        } else if (i + 1 < args.length) {
-                            param = args[++i];
-                        }
-                        if (param == null || param.isEmpty() || param.charAt(0) == '-') {
-                            throw new BadArgs("err.missing.arg", name).showUsage(true);
-                        }
-                    }
-                    option.process(task, name, param);
-                    if (option.ignoreRest()) {
-                        i = args.length;
-                    }
-                } else {
-                    rest.add(args[i]);
-                }
-            }
-            return rest;
-        }
-
-        private Option<T> getOption(String name) throws BadArgs {
-            for (Option<T> o : options) {
-                if (o.matches(name)) {
-                    return o;
-                }
-            }
-            return null;
-        }
-
-        public void showHelp(String progName, String pluginsHeader) {
-            log.println(bundleHelper.getMessage("main.usage", progName));
-            for (Option<?> o : options) {
-                String name = o.aliases[0].substring(1); // there must always be at least one name
-                name = name.charAt(0) == '-' ? name.substring(1) : name;
-                if (o.isHidden() || name.equals("h")) {
-                    continue;
-                }
-                log.println(bundleHelper.getMessage("main.opt." + name));
-            }
-        }
-    }
-
-    private PrintWriter log;
-    private final ResourceBundleHelper bundleHelper;
-
-    public TaskHelper(String path) {
-        this.bundleHelper = new ResourceBundleHelper(path);
-    }
-
-    public <T> OptionsHelper<T> newOptionsHelper(Class<T> clazz, Option<?>[] options) {
-        List<Option<T>> optionsList = new ArrayList<>();
-        for (Option<?> o : options) {
-            @SuppressWarnings("unchecked")
-            Option<T> opt = (Option<T>) o;
-            optionsList.add(opt);
-        }
-        return new OptionsHelper<>(optionsList);
-    }
-
-    public BadArgs newBadArgs(String key, Object... args) {
-        return new BadArgs(key, args);
-    }
-
-    public String getMessage(String key, Object... args) {
-        return bundleHelper.getMessage(key, args);
-    }
-
-    public void setLog(PrintWriter log) {
-        this.log = log;
-    }
-
-    public void reportError(String key, Object... args) {
-        log.println(bundleHelper.getMessage("error.prefix") + " " + bundleHelper.getMessage(key, args));
-    }
-
-    public void warning(String key, Object... args) {
-        log.println(bundleHelper.getMessage("warn.prefix") + " " + bundleHelper.getMessage(key, args));
-    }
-
-    public void showVersion(boolean full) {
-        log.println(version(full ? "full" : "release"));
-    }
-
-    public String version(String key) {
-        return System.getProperty("java.version");
-    }
-
-}
--- a/src/jdk.dev/share/classes/jdk/tools/jimage/resources/jimage.properties	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-main.usage.summary=\
-Usage: {0} <extract|info|list|recreate|set|verify> <options> jimage...\n\
-use --help for a list of possible options
-
-main.usage=\
-Usage: {0} <extract|info|list|recreate|set|verify> <options> jimage...\n\
-\n\
-\  extract  - Extract all jimage entries into separate files into the directory\n\
-\             specified by --dir=<directory> (default='.')\n\
-\  info     - Prints information specified in the jimage header.\n\
-\  list     - Prints the names of all the entries in the jimage.  When used with\n\
-\             --verbose will also print entry attributes ex. size and offset.\n\
-\  recreate - Reconstructs a jimage from an extracted directory (--dir)\n\
-\  set      - sets the value of specific jimage header entries\n\
-\  verify   - Reports errors on any .class entries that don't verify as classes.\n\
-\n\
-Possible options include:
-
-error.prefix=Error:
-warn.prefix=Warning:
-
-main.opt.dir=\
-\  --dir                                Target directory for extract/recreate
-
-main.opt.flags=\
-\  --flags=value                        Set the jimage flags to value
-
-main.opt.help=\
-\  --help                               Print this usage message
-
-main.opt.verbose=\
-\  --verbose                            Verbose listing
-
-main.opt.version=\
-\  --version                            Version information
-
-err.cannot.create.dir=cannot create directory: {0}
-err.cannot.read.file=cannot read file: {0}
-err.cannot.update.file=cannot update file: {0}
-err.flags.not.int=--flags value not integer: {0}
-err.internal.error=internal error: {0} {1} {2}
-err.invalid.arg.for.option=invalid argument for option: {0}
-err.invalid.task=task must be extract|recreate|info|list|verify: {0}
-err.jimage.already.exists=jimage already exists: {0}
-err.jimage.not.specified=no jimage specified
-err.missing.arg=no value given for {0}
-err.not.a.dir=not a directory: {0}
-err.not.a.jimage=not a jimage file: {0}
-err.only.one.jimage=only one jimage should be specified
-err.option.unsupported={0} not supported: {1}
-err.unknown.option=unknown option: {0}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.httpserver/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.httpserver {
+    requires java.logging;
+    exports com.sun.net.httpserver;
+    exports com.sun.net.httpserver.spi;
+    uses com.sun.net.httpserver.spi.HttpServerProvider;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.internal.le {
+    exports jdk.internal.jline to
+        jdk.scripting.nashorn.shell,
+        jdk.jshell;
+    exports jdk.internal.jline.console to
+        jdk.scripting.nashorn.shell,
+        jdk.jshell;
+    exports jdk.internal.jline.console.completer to
+        jdk.scripting.nashorn.shell,
+        jdk.jshell;
+    exports jdk.internal.jline.console.history to
+        jdk.scripting.nashorn.shell,
+        jdk.jshell;
+    exports jdk.internal.jline.internal to
+        jdk.scripting.nashorn.shell,
+        jdk.jshell;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.opt/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.internal.opt {
+    exports jdk.internal.joptsimple to jdk.jlink;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jartool/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.jartool {
+    exports com.sun.jarsigner;
+    exports jdk.security.jarsigner;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.tools.jar;
+
+import java.io.File;
+import java.io.PrintStream;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleDescriptor.Version;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+/**
+ * Parser for GNU Style Options.
+ */
+class GNUStyleOptions {
+
+    static class BadArgs extends Exception {
+        static final long serialVersionUID = 0L;
+
+        boolean showUsage;
+
+        BadArgs(String key, String arg) { super(Main.formatMsg(key, arg)); }
+        BadArgs(String key) { super(Main.getMsg(key)); }
+
+        BadArgs showUsage(boolean b) {
+            showUsage = b;
+            return this;
+        }
+    }
+
+    static Option[] recognizedOptions = {
+            // Main operations
+            new Option(false, OptionType.MAIN_OPERATION, "--create", "-c") {
+                void process(Main tool, String opt, String arg) throws BadArgs {
+                    if (tool.iflag || tool.tflag || tool.uflag || tool.xflag || tool.printModuleDescriptor)
+                        throw new BadArgs("error.multiple.main.operations").showUsage(true);
+                    tool.cflag = true;
+                }
+            },
+            new Option(true, OptionType.MAIN_OPERATION, "--generate-index", "-i") {
+                void process(Main tool, String opt, String arg) throws BadArgs {
+                    if (tool.cflag || tool.tflag || tool.uflag || tool.xflag || tool.printModuleDescriptor)
+                        throw new BadArgs("error.multiple.main.operations").showUsage(true);
+                    tool.iflag = true;
+                    tool.rootjar = arg;
+                }
+            },
+            new Option(false, OptionType.MAIN_OPERATION, "--list", "-t") {
+                void process(Main tool, String opt, String arg) throws BadArgs {
+                    if (tool.cflag || tool.iflag || tool.uflag || tool.xflag || tool.printModuleDescriptor)
+                        throw new BadArgs("error.multiple.main.operations").showUsage(true);
+                    tool.tflag = true;
+                }
+            },
+            new Option(false, OptionType.MAIN_OPERATION, "--update", "-u") {
+                void process(Main tool, String opt, String arg) throws BadArgs {
+                    if (tool.cflag || tool.iflag || tool.tflag || tool.xflag || tool.printModuleDescriptor)
+                        throw new BadArgs("error.multiple.main.operations").showUsage(true);
+                    tool.uflag = true;
+                }
+            },
+            new Option(false, OptionType.MAIN_OPERATION, "--extract", "-x") {
+                void process(Main tool, String opt, String arg) throws BadArgs {
+                    if (tool.cflag || tool.iflag  || tool.tflag || tool.uflag || tool.printModuleDescriptor)
+                        throw new BadArgs("error.multiple.main.operations").showUsage(true);
+                    tool.xflag = true;
+                }
+            },
+            new Option(false, OptionType.MAIN_OPERATION, "--print-module-descriptor", "-p") {
+                void process(Main tool, String opt, String arg) throws BadArgs {
+                    if (tool.cflag || tool.iflag  || tool.tflag || tool.uflag || tool.xflag)
+                        throw new BadArgs("error.multiple.main.operations").showUsage(true);
+                    tool.printModuleDescriptor = true;
+                }
+            },
+
+            // Additional options
+            new Option(true, OptionType.ANY, "--file", "-f") {
+                void process(Main jartool, String opt, String arg) {
+                    jartool.fname = arg;
+                }
+            },
+            new Option(false, OptionType.ANY, "--verbose", "-v") {
+                void process(Main jartool, String opt, String arg) {
+                    jartool.vflag = true;
+                }
+            },
+            new Option(false, OptionType.CREATE, "--normalize", "-n") {
+                void process(Main jartool, String opt, String arg) {
+                    jartool.nflag = true;
+                }
+                boolean isHidden() { return true; }
+            },
+            new Option(true, OptionType.CREATE_UPDATE, "--main-class", "-e") {
+                void process(Main jartool, String opt, String arg) {
+                    jartool.ename = arg;
+                }
+            },
+            new Option(true, OptionType.CREATE_UPDATE, "--manifest", "-m") {
+                void process(Main jartool, String opt, String arg) {
+                    jartool.mname = arg;
+                }
+            },
+            new Option(false, OptionType.CREATE_UPDATE, "--no-manifest", "-M") {
+                void process(Main jartool, String opt, String arg) {
+                    jartool.Mflag = true;
+                }
+            },
+            new Option(true, OptionType.CREATE_UPDATE, "--module-version") {
+                void process(Main jartool, String opt, String arg) {
+                    jartool.moduleVersion = Version.parse(arg);
+                }
+            },
+            new Option(true, OptionType.CREATE_UPDATE, "--hash-dependencies") {
+                void process(Main jartool, String opt, String arg) throws BadArgs {
+                    try {
+                        jartool.dependenciesToHash = Pattern.compile(arg);
+                    } catch (PatternSyntaxException e) {
+                        throw new BadArgs("err.badpattern", arg).showUsage(true);
+                    }
+                }
+            },
+            new Option(true, OptionType.CREATE_UPDATE, "--modulepath", "--mp") {
+                void process(Main jartool, String opt, String arg) {
+                    String[] dirs = arg.split(File.pathSeparator);
+                    Path[] paths = new Path[dirs.length];
+                    int i = 0;
+                    for (String dir : dirs) {
+                        paths[i++] = Paths.get(dir);
+                    }
+                    jartool.moduleFinder = ModuleFinder.compose(jartool.moduleFinder,
+                                                                ModuleFinder.of(paths));
+                }
+            },
+            new Option(false, OptionType.CREATE_UPDATE_INDEX, "--no-compress", "-0") {
+                void process(Main jartool, String opt, String arg) {
+                    jartool.flag0 = true;
+                }
+            },
+
+            // Hidden options
+            new Option(false, OptionType.OTHER, "-P") {
+                void process(Main jartool, String opt, String arg) {
+                    jartool.pflag = true;
+                }
+                boolean isHidden() { return true; }
+            },
+
+            // Other options
+            new Option(true, true, OptionType.OTHER, "--help", "-h") {
+                void process(Main jartool, String opt, String arg) throws BadArgs {
+                    if (jartool.info == null) {
+                        if (arg == null) {
+                            jartool.info = Main.Info.HELP;
+                            return;
+                        }
+
+                        if (!arg.equals("compat"))
+                            throw new BadArgs("error.illegal.option", arg).showUsage(true);
+
+                        jartool.info = Main.Info.COMPAT_HELP;
+                    }
+                }
+            },
+            new Option(false, OptionType.OTHER, "--version") {
+                void process(Main jartool, String opt, String arg) {
+                    if (jartool.info == null)
+                        jartool.info = Main.Info.VERSION;
+                }
+            }
+    };
+
+    enum OptionType {
+        MAIN_OPERATION("main"),
+        ANY("any"),
+        CREATE("create"),
+        CREATE_UPDATE("create.update"),
+        CREATE_UPDATE_INDEX("create.update.index"),
+        OTHER("other");
+
+        /** Resource lookup section prefix. */
+        final String name;
+
+        OptionType(String name) { this.name = name; }
+    }
+
+    static abstract class Option {
+        final boolean hasArg;
+        final boolean argIsOptional;
+        final String[] aliases;
+        final OptionType type;
+
+        Option(boolean hasArg, OptionType type, String... aliases) {
+            this(hasArg, false, type, aliases);
+        }
+
+        Option(boolean hasArg, boolean argIsOptional, OptionType type, String... aliases) {
+            this.hasArg = hasArg;
+            this.argIsOptional = argIsOptional;
+            this.type = type;
+            this.aliases = aliases;
+        }
+
+        boolean isHidden() { return false; }
+
+        boolean matches(String opt) {
+            for (String a : aliases) {
+                if (a.equals(opt)) {
+                    return true;
+                } else if (opt.startsWith("--") && hasArg && opt.startsWith(a + "=")) {
+                    return true;
+                } else if (opt.startsWith("--help") && opt.startsWith(a + ":")) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        abstract void process(Main jartool, String opt, String arg) throws BadArgs;
+    }
+
+    static int parseOptions(Main jartool, String[] args) throws BadArgs {
+        int count = 0;
+        if (args.length == 0) {
+            jartool.info = Main.Info.USAGE_SUMMARY;
+            return 0;
+        }
+
+        // process options
+        for (; count < args.length; count++) {
+            if (args[count].charAt(0) != '-' || args[count].equals("-C"))
+                break;
+
+            String name = args[count];
+            Option option = getOption(name);
+            String param = null;
+            if (option.hasArg) {
+                if (name.startsWith("--help")) {  // "special" optional separator
+                    if (name.indexOf(':') > 0) {
+                        param = name.substring(name.indexOf(':') + 1, name.length());
+                    }
+                } else if (name.startsWith("--") && name.indexOf('=') > 0) {
+                    param = name.substring(name.indexOf('=') + 1, name.length());
+                } else if (count + 1 < args.length) {
+                    param = args[++count];
+                }
+                if (!option.argIsOptional &&
+                    (param == null || param.isEmpty() || param.charAt(0) == '-')) {
+                    throw new BadArgs("error.missing.arg", name).showUsage(true);
+                }
+            }
+            option.process(jartool, name, param);
+        }
+
+        return count;
+    }
+
+    private static Option getOption(String name) throws BadArgs {
+        for (Option o : recognizedOptions) {
+            if (o.matches(name)) {
+                return o;
+            }
+        }
+        throw new BadArgs("error.unrecognized.option", name).showUsage(true);
+    }
+
+    static void printHelp(PrintStream out) {
+        out.format("%s%n", Main.getMsg("main.help.preopt"));
+        for (OptionType type : OptionType.values()) {
+            boolean typeHeadingWritten = false;
+
+            for (Option o : recognizedOptions) {
+                if (!o.type.equals(type))
+                    continue;
+                String name = o.aliases[0].substring(1); // there must always be at least one name
+                name = name.charAt(0) == '-' ? name.substring(1) : name;
+                if (o.isHidden() || name.equals("h")) {
+                    continue;
+                }
+                if (!typeHeadingWritten) {
+                    out.format("%n%s%n", Main.getMsg("main.help.opt." + type.name));
+                    typeHeadingWritten = true;
+                }
+                out.format("%s%n", Main.getMsg("main.help.opt." + type.name + "." + name));
+            }
+        }
+        out.format("%n%s%n%n", Main.getMsg("main.help.postopt"));
+    }
+
+    static void printCompatHelp(PrintStream out) {
+        out.format("%s%n", Main.getMsg("usage.compat"));
+    }
+
+    static void printUsageSummary(PrintStream out) {
+        out.format("%s%n", Main.getMsg("main.usage.summary"));
+        out.format("%s%n", Main.getMsg("main.usage.summary.try"));
+    }
+
+    static void printVersion(PrintStream out) {
+        out.format("%s %s%n", "jar", System.getProperty("java.version"));
+    }
+}
--- a/src/jdk.jartool/share/classes/sun/tools/jar/Main.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/jdk.jartool/share/classes/sun/tools/jar/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,17 +26,35 @@
 package sun.tools.jar;
 
 import java.io.*;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Exports;
+import java.lang.module.ModuleDescriptor.Provides;
+import java.lang.module.ModuleDescriptor.Requires;
+import java.lang.module.ModuleDescriptor.Version;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReference;
+import java.lang.reflect.Method;
+import java.net.URI;
 import java.nio.file.Path;
 import java.nio.file.Files;
+import java.nio.file.Paths;
 import java.util.*;
+import java.util.function.Consumer;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 import java.util.zip.*;
 import java.util.jar.*;
 import java.util.jar.Pack200.*;
 import java.util.jar.Manifest;
 import java.text.MessageFormat;
+
+import jdk.internal.module.Hasher;
+import jdk.internal.module.ModuleInfoExtender;
 import sun.misc.JarIndex;
 import static sun.misc.JarIndex.INDEX_NAME;
 import static java.util.jar.JarFile.MANIFEST_NAME;
+import static java.util.stream.Collectors.joining;
 import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
 
 /**
@@ -60,6 +78,11 @@
 
     // All files need to be added/updated.
     Set<File> entries = new LinkedHashSet<File>();
+    // All packages.
+    Set<String> packages = new HashSet<>();
+    // All actual entries added, or existing, in the jar file ( excl manifest
+    // and module-info.class ). Populated during create or update.
+    Set<String> jarEntries = new HashSet<>();
 
     // Directories specified by "-C" operation.
     Set<String> paths = new HashSet<String>();
@@ -78,6 +101,30 @@
      */
     boolean cflag, uflag, xflag, tflag, vflag, flag0, Mflag, iflag, nflag, pflag;
 
+    /* To support additional GNU Style informational options */
+    enum Info {
+        HELP(GNUStyleOptions::printHelp),
+        COMPAT_HELP(GNUStyleOptions::printCompatHelp),
+        USAGE_SUMMARY(GNUStyleOptions::printUsageSummary),
+        VERSION(GNUStyleOptions::printVersion);
+
+        private Consumer<PrintStream> printFunction;
+        Info(Consumer<PrintStream> f) { this.printFunction = f; }
+        void print(PrintStream out) { printFunction.accept(out); }
+    };
+    Info info;
+
+    /* Modular jar related options */
+    boolean printModuleDescriptor;
+    Version moduleVersion;
+    Pattern dependenciesToHash;
+    ModuleFinder moduleFinder = ModuleFinder.empty();
+
+    private static final String MODULE_INFO = "module-info.class";
+
+    Path moduleInfo;
+    private boolean isModularJar() { return moduleInfo != null; }
+
     static final String MANIFEST_DIR = "META-INF/";
     static final String VERSION = "1.0";
 
@@ -102,7 +149,7 @@
         }
     }
 
-    private String getMsg(String key) {
+    static String getMsg(String key) {
         try {
             return (rsrc.getString(key));
         } catch (MissingResourceException e) {
@@ -110,14 +157,14 @@
         }
     }
 
-    private String formatMsg(String key, String arg) {
+    static String formatMsg(String key, String arg) {
         String msg = getMsg(key);
         String[] args = new String[1];
         args[0] = arg;
         return MessageFormat.format(msg, (Object[]) args);
     }
 
-    private String formatMsg2(String key, String arg, String arg1) {
+    static String formatMsg2(String key, String arg, String arg1) {
         String msg = getMsg(key);
         String[] args = new String[2];
         args[0] = arg;
@@ -189,6 +236,16 @@
                     }
                 }
                 expand(null, files, false);
+
+                byte[] moduleInfoBytes = null;
+                if (isModularJar()) {
+                    moduleInfoBytes = addExtendedModuleAttributes(
+                            readModuleInfo(moduleInfo));
+                } else if (moduleVersion != null || dependenciesToHash != null) {
+                    error(getMsg("error.module.options.without.info"));
+                    return false;
+                }
+
                 OutputStream out;
                 if (fname != null) {
                     out = new FileOutputStream(fname);
@@ -210,7 +267,14 @@
                     tmpfile = createTemporaryFile(tmpbase, ".jar");
                     out = new FileOutputStream(tmpfile);
                 }
-                create(new BufferedOutputStream(out, 4096), manifest);
+                create(new BufferedOutputStream(out, 4096), manifest, moduleInfoBytes);
+
+                // Consistency checks for modular jars.
+                if (isModularJar()) {
+                    if (!checkServices(moduleInfoBytes))
+                        return false;
+                }
+
                 if (in != null) {
                     in.close();
                 }
@@ -267,8 +331,21 @@
                 InputStream manifest = (!Mflag && (mname != null)) ?
                     (new FileInputStream(mname)) : null;
                 expand(null, files, true);
+
+                byte[] moduleInfoBytes = null;
+                if (isModularJar()) {
+                    moduleInfoBytes = readModuleInfo(moduleInfo);
+                }
+
                 boolean updateOk = update(in, new BufferedOutputStream(out),
-                                          manifest, null);
+                                          manifest, moduleInfoBytes, null);
+
+                // Consistency checks for modular jars.
+                if (isModularJar()) {
+                    if(!checkServices(moduleInfoBytes))
+                        return false;
+                }
+
                 if (ok) {
                     ok = updateOk;
                 }
@@ -328,6 +405,17 @@
                 }
             } else if (iflag) {
                 genIndex(rootjar, files);
+            } else if (printModuleDescriptor) {
+                boolean found;
+                if (fname != null) {
+                    found = printModuleDescriptor(new ZipFile(fname));
+                } else {
+                    try (FileInputStream fin = new FileInputStream(FileDescriptor.in)) {
+                        found = printModuleDescriptor(fin);
+                    }
+                }
+                if (!found)
+                    error(getMsg("error.module.descriptor.not.found"));
             }
         } catch (IOException e) {
             fatalError(e);
@@ -362,84 +450,111 @@
         int count = 1;
         try {
             String flags = args[0];
-            if (flags.startsWith("-")) {
-                flags = flags.substring(1);
-            }
-            for (int i = 0; i < flags.length(); i++) {
-                switch (flags.charAt(i)) {
-                case 'c':
-                    if (xflag || tflag || uflag || iflag) {
-                        usageError();
-                        return false;
-                    }
-                    cflag = true;
-                    break;
-                case 'u':
-                    if (cflag || xflag || tflag || iflag) {
-                        usageError();
-                        return false;
-                    }
-                    uflag = true;
-                    break;
-                case 'x':
-                    if (cflag || uflag || tflag || iflag) {
-                        usageError();
-                        return false;
-                    }
-                    xflag = true;
-                    break;
-                case 't':
-                    if (cflag || uflag || xflag || iflag) {
-                        usageError();
-                        return false;
+
+            // Note: flags.length == 2 can be treated as the short version of
+            // the GNU option since the there cannot be any other options,
+            // excluding -C, as per the old way.
+            if (flags.startsWith("--")
+                || (flags.startsWith("-") && flags.length() == 2)) {
+                try {
+                    count = GNUStyleOptions.parseOptions(this, args);
+                } catch (GNUStyleOptions.BadArgs x) {
+                    if (info != null) {
+                        info.print(out);
+                        return true;
                     }
-                    tflag = true;
-                    break;
-                case 'M':
-                    Mflag = true;
-                    break;
-                case 'v':
-                    vflag = true;
-                    break;
-                case 'f':
-                    fname = args[count++];
-                    break;
-                case 'm':
-                    mname = args[count++];
-                    break;
-                case '0':
-                    flag0 = true;
-                    break;
-                case 'i':
-                    if (cflag || uflag || xflag || tflag) {
-                        usageError();
-                        return false;
+                    error(x.getMessage());
+                    if (x.showUsage)
+                        Info.USAGE_SUMMARY.print(err);
+                    return false;
+                }
+            } else {
+                // Legacy/compatibility options
+                if (flags.startsWith("-")) {
+                    flags = flags.substring(1);
+                }
+                for (int i = 0; i < flags.length(); i++) {
+                    switch (flags.charAt(i)) {
+                        case 'c':
+                            if (xflag || tflag || uflag || iflag) {
+                                usageError();
+                                return false;
+                            }
+                            cflag = true;
+                            break;
+                        case 'u':
+                            if (cflag || xflag || tflag || iflag) {
+                                usageError();
+                                return false;
+                            }
+                            uflag = true;
+                            break;
+                        case 'x':
+                            if (cflag || uflag || tflag || iflag) {
+                                usageError();
+                                return false;
+                            }
+                            xflag = true;
+                            break;
+                        case 't':
+                            if (cflag || uflag || xflag || iflag) {
+                                usageError();
+                                return false;
+                            }
+                            tflag = true;
+                            break;
+                        case 'M':
+                            Mflag = true;
+                            break;
+                        case 'v':
+                            vflag = true;
+                            break;
+                        case 'f':
+                            fname = args[count++];
+                            break;
+                        case 'm':
+                            mname = args[count++];
+                            break;
+                        case '0':
+                            flag0 = true;
+                            break;
+                        case 'i':
+                            if (cflag || uflag || xflag || tflag) {
+                                usageError();
+                                return false;
+                            }
+                            // do not increase the counter, files will contain rootjar
+                            rootjar = args[count++];
+                            iflag = true;
+                            break;
+                        case 'n':
+                            nflag = true;
+                            break;
+                        case 'e':
+                            ename = args[count++];
+                            break;
+                        case 'P':
+                            pflag = true;
+                            break;
+                        default:
+                            error(formatMsg("error.illegal.option",
+                                    String.valueOf(flags.charAt(i))));
+                            usageError();
+                            return false;
                     }
-                    // do not increase the counter, files will contain rootjar
-                    rootjar = args[count++];
-                    iflag = true;
-                    break;
-                case 'n':
-                    nflag = true;
-                    break;
-                case 'e':
-                     ename = args[count++];
-                     break;
-                case 'P':
-                     pflag = true;
-                     break;
-                default:
-                    error(formatMsg("error.illegal.option",
-                                String.valueOf(flags.charAt(i))));
-                    usageError();
-                    return false;
                 }
             }
         } catch (ArrayIndexOutOfBoundsException e) {
             usageError();
             return false;
         }
-        if (!cflag && !tflag && !xflag && !uflag && !iflag) {
+
+        if (info != null) {
+            info.print(out);
+            return true;
+        }
+
+        if (!cflag && !tflag && !xflag && !uflag && !iflag && !printModuleDescriptor) {
             error(getMsg("error.bad.option"));
             usageError();
             return false;
@@ -489,23 +604,56 @@
         return true;
     }
 
+    private static Set<String> findPackages(ZipFile zf) {
+        return zf.stream()
+                 .filter(e -> e.getName().endsWith(".class"))
+                 .map(e -> toPackageName(e))
+                 .filter(pkg -> pkg.length() > 0)
+                 .distinct()
+                 .collect(Collectors.toSet());
+    }
+
+    private static String toPackageName(ZipEntry entry) {
+        return toPackageName(entry.getName());
+    }
+
+    private static String toPackageName(String path) {
+        assert path.endsWith(".class");
+        int index = path.lastIndexOf('/');
+        if (index != -1) {
+            return path.substring(0, index).replace('/', '.');
+        } else {
+            return "";
+        }
+    }
+
     /**
      * Expands list of files to process into full list of all files that
      * can be found by recursively descending directories.
      */
-    void expand(File dir, String[] files, boolean isUpdate) {
-        if (files == null) {
+    void expand(File dir, String[] files, boolean isUpdate) throws IOException {
+        if (files == null)
             return;
-        }
+
         for (int i = 0; i < files.length; i++) {
             File f;
-            if (dir == null) {
+            if (dir == null)
                 f = new File(files[i]);
-            } else {
+            else
                 f = new File(dir, files[i]);
-            }
+
             if (f.isFile()) {
-                if (entries.add(f)) {
+                String path = f.getPath();
+                if (entryName(path).equals(MODULE_INFO)) {
+                    if (moduleInfo != null && vflag)
+                        output(formatMsg("error.unexpected.module-info", path));
+                    moduleInfo = f.toPath();
+                    if (isUpdate)
+                        entryMap.put(entryName(path), f);
+                } else if (entries.add(f)) {
+                    jarEntries.add(entryName(path));
+                    if (path.endsWith(".class"))
+                        packages.add(toPackageName(entryName(path)));
                     if (isUpdate)
                         entryMap.put(entryName(f.getPath()), f);
                 }
@@ -529,13 +677,14 @@
     /**
      * Creates a new JAR file.
      */
-    void create(OutputStream out, Manifest manifest)
+    void create(OutputStream out, Manifest manifest, byte[] moduleInfoBytes)
         throws IOException
     {
         ZipOutputStream zos = new JarOutputStream(out);
         if (flag0) {
             zos.setMethod(ZipOutputStream.STORED);
         }
+        // TODO: check module-info attributes against manifest ??
         if (manifest != null) {
             if (vflag) {
                 output(getMsg("out.added.manifest"));
@@ -554,6 +703,20 @@
             manifest.write(zos);
             zos.closeEntry();
         }
+        if (moduleInfoBytes != null) {
+            if (vflag) {
+                output(getMsg("out.added.module-info"));
+            }
+            ZipEntry e = new ZipEntry(MODULE_INFO);
+            e.setTime(System.currentTimeMillis());
+            if (flag0) {
+                crc32ModuleInfo(e, moduleInfoBytes);
+            }
+            zos.putNextEntry(e);
+            ByteArrayInputStream in = new ByteArrayInputStream(moduleInfoBytes);
+            in.transferTo(zos);
+            zos.closeEntry();
+        }
         for (File file: entries) {
             addFile(zos, file);
         }
@@ -589,12 +752,14 @@
      */
     boolean update(InputStream in, OutputStream out,
                    InputStream newManifest,
+                   byte[] newModuleInfoBytes,
                    JarIndex jarIndex) throws IOException
     {
         ZipInputStream zis = new ZipInputStream(in);
         ZipOutputStream zos = new JarOutputStream(out);
         ZipEntry e = null;
         boolean foundManifest = false;
+        boolean foundModuleInfo = false;
         boolean updateOk = true;
 
         if (jarIndex != null) {
@@ -606,6 +771,7 @@
             String name = e.getName();
 
             boolean isManifestEntry = equalsIgnoreCase(name, MANIFEST_NAME);
+            boolean isModuleInfoEntry = name.equals(MODULE_INFO);
 
             if ((jarIndex != null && equalsIgnoreCase(name, INDEX_NAME))
                 || (Mflag && isManifestEntry)) {
@@ -633,6 +799,13 @@
                 if (!updateManifest(old, zos)) {
                     return false;
                 }
+            } else if (isModuleInfoEntry
+                       && ((newModuleInfoBytes != null) || (ename != null)
+                           || moduleVersion != null || dependenciesToHash != null)) {
+                if (newModuleInfoBytes == null) {
+                    // Update existing module-info.class
+                    newModuleInfoBytes = readModuleInfo(zis);
+                }
             } else {
                 if (!entryMap.containsKey(name)) { // copy the old stuff
                     // do our own compression
@@ -653,6 +826,10 @@
                     entryMap.remove(name);
                     entries.remove(f);
                 }
+
+                jarEntries.add(name);
+                if (name.endsWith(".class"))
+                    packages.add(toPackageName(name));
             }
         }
 
@@ -675,6 +852,20 @@
                 }
             }
         }
+
+        // write the module-info.class
+        if (newModuleInfoBytes != null) {
+            newModuleInfoBytes = addExtendedModuleAttributes(newModuleInfoBytes);
+
+            // TODO: check manifest main classes, etc
+            if (!updateModuleInfo(newModuleInfoBytes, zos)) {
+                updateOk = false;
+            }
+        } else if (moduleVersion != null || dependenciesToHash != null) {
+            error(getMsg("error.module.options.without.info"));
+            updateOk = false;
+        }
+
         zis.close();
         zos.close();
         return updateOk;
@@ -696,6 +887,22 @@
         zos.closeEntry();
     }
 
+    private boolean updateModuleInfo(byte[] moduleInfoBytes, ZipOutputStream zos)
+        throws IOException
+    {
+        ZipEntry e = new ZipEntry(MODULE_INFO);
+        e.setTime(System.currentTimeMillis());
+        if (flag0) {
+            crc32ModuleInfo(e, moduleInfoBytes);
+        }
+        zos.putNextEntry(e);
+        zos.write(moduleInfoBytes);
+        if (vflag) {
+            output(getMsg("out.update.module-info"));
+        }
+        return true;
+    }
+
     private boolean updateManifest(Manifest m, ZipOutputStream zos)
         throws IOException
     {
@@ -833,6 +1040,8 @@
                 output(formatMsg("out.ignore.entry", name));
             }
             return;
+        } else if (name.equals(MODULE_INFO)) {
+            throw new Error("Unexpected module info: " + name);
         }
 
         long size = isDir ? 0 : file.length();
@@ -928,6 +1137,17 @@
     }
 
     /**
+     * Computes the crc32 of a module-info.class.  This is necessary when the
+     * ZipOutputStream is in STORED mode.
+     */
+    private void crc32ModuleInfo(ZipEntry e, byte[] bytes) throws IOException {
+        CRC32OutputStream os = new CRC32OutputStream();
+        ByteArrayInputStream in = new ByteArrayInputStream(bytes);
+        in.transferTo(os);
+        os.updateEntry(e);
+    }
+
+    /**
      * Computes the crc32 of a Manifest.  This is necessary when the
      * ZipOutputStream is in STORED mode.
      */
@@ -1151,7 +1371,7 @@
         try {
             if (update(Files.newInputStream(jarPath),
                        Files.newOutputStream(tmpPath),
-                       null, index)) {
+                       null, null, index)) {
                 try {
                     Files.move(tmpPath, jarPath, REPLACE_EXISTING);
                 } catch (IOException e) {
@@ -1268,7 +1488,7 @@
      * Prints usage message.
      */
     void usageError() {
-        error(getMsg("usage"));
+        Info.USAGE_SUMMARY.print(err);
     }
 
     /**
@@ -1369,4 +1589,235 @@
         }
         return tmpfile;
     }
+
+    private static byte[] readModuleInfo(InputStream zis) throws IOException {
+        return zis.readAllBytes();
+    }
+
+    private static byte[] readModuleInfo(Path path) throws IOException {
+        try (InputStream is = Files.newInputStream(path)) {
+            return is.readAllBytes();
+        }
+    }
+
+    // Modular jar support
+
+    static <T> String toString(Set<T> set,
+                               CharSequence prefix,
+                               CharSequence suffix ) {
+        if (set.isEmpty())
+            return "";
+
+        return set.stream().map(e -> e.toString())
+                           .collect(joining(", ", prefix, suffix));
+    }
+
+    private boolean printModuleDescriptor(ZipFile zipFile)
+        throws IOException
+    {
+        ZipEntry entry = zipFile.getEntry(MODULE_INFO);
+        if (entry ==  null)
+            return false;
+
+        try (InputStream is = zipFile.getInputStream(entry)) {
+            printModuleDescriptor(is);
+        }
+        return true;
+    }
+
+    private boolean printModuleDescriptor(FileInputStream fis)
+        throws IOException
+    {
+        try (BufferedInputStream bis = new BufferedInputStream(fis);
+             ZipInputStream zis = new ZipInputStream(bis)) {
+
+            ZipEntry e;
+            while ((e = zis.getNextEntry()) != null) {
+                if (e.getName().equals(MODULE_INFO)) {
+                    printModuleDescriptor(zis);
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    @SuppressWarnings("unchecked")
+    private void printModuleDescriptor(InputStream entryInputStream)
+        throws IOException
+    {
+        ModuleDescriptor md = ModuleDescriptor.read(entryInputStream);
+        StringBuilder sb = new StringBuilder();
+        sb.append("\nName:\n  " + md.toNameAndVersion());
+
+        Set<Requires> requires = md.requires();
+        if (!requires.isEmpty()) {
+            sb.append("\nRequires:");
+            requires.forEach(r ->
+                    sb.append("\n  ").append(r.name())
+                            .append(toString(r.modifiers(), " [ ", " ]")));
+        }
+
+        Set<String> s = md.uses();
+        if (!s.isEmpty()) {
+            sb.append("\nUses: ");
+            s.forEach(sv -> sb.append("\n  ").append(sv));
+        }
+
+        Set<Exports> exports = md.exports();
+        if (!exports.isEmpty()) {
+            sb.append("\nExports:");
+            exports.forEach(sv -> sb.append("\n  ").append(sv));
+        }
+
+        Map<String,Provides> provides = md.provides();
+        if (!provides.isEmpty()) {
+            sb.append("\nProvides: ");
+            provides.values().forEach(p ->
+                    sb.append("\n  ").append(p.service())
+                      .append(" with ")
+                      .append(toString(p.providers(), "", "")));
+        }
+
+        Optional<String> mc = md.mainClass();
+        if (mc.isPresent())
+            sb.append("\nMain class:\n  " + mc.get());
+
+        s = md.conceals();
+        if (!s.isEmpty()) {
+            sb.append("\nConceals:");
+            s.forEach(p -> sb.append("\n  ").append(p));
+        }
+
+        try {
+            Method m = ModuleDescriptor.class.getDeclaredMethod("hashes");
+            m.setAccessible(true);
+            Optional<Hasher.DependencyHashes> optHashes =
+                    (Optional<Hasher.DependencyHashes>) m.invoke(md);
+
+            if (optHashes.isPresent()) {
+                Hasher.DependencyHashes hashes = optHashes.get();
+                sb.append("\nHashes:");
+                sb.append("\n  Algorithm: " + hashes.algorithm());
+                hashes.names().stream().forEach(mod ->
+                        sb.append("\n  ").append(mod)
+                          .append(": ").append(hashes.hashFor(mod)));
+            }
+        } catch (ReflectiveOperationException x) {
+            throw new InternalError(x);
+        }
+        output(sb.toString());
+    }
+
+    private static String toBinaryName(String classname) {
+        return (classname.replace('.', '/')) + ".class";
+    }
+
+    private boolean checkServices(byte[] moduleInfoBytes)
+        throws IOException
+    {
+        ModuleDescriptor md;
+        try (InputStream in = new ByteArrayInputStream(moduleInfoBytes)) {
+            md = ModuleDescriptor.read(in);
+        }
+        Set<String> missing = md.provides()
+                                .values()
+                                .stream()
+                                .map(Provides::providers)
+                                .flatMap(Set::stream)
+                                .filter(p -> !jarEntries.contains(toBinaryName(p)))
+                                .collect(Collectors.toSet());
+        if (missing.size() > 0) {
+            missing.stream().forEach(s -> fatalError(formatMsg("error.missing.provider", s)));
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Returns a byte array containing the module-info.class.
+     *
+     * If --module-version, --main-class, or other options were provided
+     * then the corresponding class file attributes are added to the
+     * module-info here.
+     */
+    private byte[] addExtendedModuleAttributes(byte[] moduleInfoBytes)
+        throws IOException
+    {
+        assert isModularJar();
+
+        ModuleDescriptor md;
+        try (InputStream in = new ByteArrayInputStream(moduleInfoBytes)) {
+            md = ModuleDescriptor.read(in);
+        }
+        String name = md.name();
+        Set<ModuleDescriptor.Requires> dependences = md.requires();
+        Set<String> exported = md.exports()
+                                 .stream()
+                                 .map(ModuleDescriptor.Exports::source)
+                                 .collect(Collectors.toSet());
+
+        // copy the module-info.class into the jmod with the additional
+        // attributes for the version, main class and other meta data
+        try (InputStream in = new ByteArrayInputStream(moduleInfoBytes);
+             ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
+            ModuleInfoExtender extender = ModuleInfoExtender.newExtender(in);
+
+            // Add (or replace) the ConcealedPackages attribute
+            Set<String> conceals = packages.stream()
+                                            .filter(p -> !exported.contains(p))
+                                            .collect(Collectors.toSet());
+
+            extender.conceals(conceals);
+
+            // --main-class
+            if (ename != null)
+                extender.mainClass(ename);
+
+            // --module-version
+            if (moduleVersion != null)
+                extender.version(moduleVersion);
+
+            // --hash-dependencies
+            if (dependenciesToHash != null)
+                extender.hashes(hashDependences(name, dependences));
+
+            extender.write(baos);
+            return baos.toByteArray();
+        }
+    }
+
+    /**
+     * Examines the module dependences of the given module and computes the
+     * hash of any module that matches the pattern {@code dependenciesToHash}.
+     */
+    private Hasher.DependencyHashes
+    hashDependences(String name,
+                    Set<ModuleDescriptor.Requires> moduleDependences)
+        throws IOException
+    {
+        Map<String, Path> map = new HashMap<>();
+        Matcher matcher = dependenciesToHash.matcher("");
+        for (ModuleDescriptor.Requires md: moduleDependences) {
+            String dn = md.name();
+            if (matcher.reset(dn).find()) {
+                Optional<ModuleReference> omref = moduleFinder.find(dn);
+                if (!omref.isPresent()) {
+                    throw new IOException(formatMsg2("error.hash.dep", name , dn));
+                }
+                map.put(dn, modRefToPath(omref.get()));
+            }
+        }
+
+        if (map.size() == 0) {
+            return null;
+        } else {
+            return Hasher.generate(map, "SHA-256");
+        }
+    }
+
+    private static Path modRefToPath(ModuleReference mref) {
+        URI location = mref.location().get();
+        return Paths.get(location);
+    }
 }
--- a/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -23,10 +23,18 @@
 # questions.
 #
 
+error.multiple.main.operations=\
+     You may not specify more than one '-cuxti' options
 error.cant.open=\
-     can''t open: {0} 
+     can''t open: {0}
 error.illegal.option=\
         Illegal option: {0}
+error.unrecognized.option=\
+    unrecognized option : {0}
+error.missing.arg=\
+     option {0} requires an argument
+error.bad.file.arg=\
+     Error parsing file arguments
 error.bad.option=\
         One of options -{ctxu} must be specified.
 error.bad.cflag=\
@@ -46,10 +54,24 @@
         incorrect length while processing: {0}
 error.create.tempfile=\
         Could not create a temporary file
+error.hash.dep=\
+        Hashing module {0} dependences, unable to find module {1} on module path
+error.module.options.without.info=\
+        One of --module-version or --hash-dependencies without module-info.class
+error.unexpected.module-info=\
+        Unexpected module descriptor {0}
+error.module.descriptor.not.found=\
+        Module descriptor not found
+error.missing.provider=\
+        Service provider not found: {0}
 out.added.manifest=\
         added manifest
+out.added.module-info=\
+        added module-info.class
 out.update.manifest=\
         updated manifest
+out.update.module-info=\
+        updated module-info.class
 out.ignore.entry=\
         ignoring entry {0}
 out.adding=\
@@ -67,7 +89,9 @@
 out.size=\
         (in = {0}) (out= {1})
 
-usage=\
+usage.compat=\
+\Compatibility Interface:\
+\n\
 Usage: jar {ctxui}[vfmn0PMe] [jar-file] [manifest-file] [entry-point] [-C dir] files ...\n\
 Options:\n\
 \ \   -c  create new archive\n\
@@ -93,3 +117,91 @@
 Example 2: use an existing manifest file 'mymanifest' and archive all the\n\
 \ \          files in the foo/ directory into 'classes.jar': \n\
 \ \      jar cvfm classes.jar mymanifest -C foo/ .\n
+
+main.usage.summary=\
+jar: You must specify one of -ctxui options.
+main.usage.summary.try=\
+Try `jar --help' for more information.
+
+main.help.preopt=\
+Usage: jar [OPTION...] [-C dir] files ...\n\
+jar creates an archive for classes and resources, and can manipulate or\n\
+restore individual classes or resources from an archive.\n\
+\n\
+\ Examples:\n\
+\ # Create an archive called classes.jar with two class files:\n\
+\ jar --create --file classes.jar Foo.class Bar.class\n\
+\ # Create an archive using an existing manifest, with all the files in foo/:\n\
+\ jar --create --file classes.jar --manifest mymanifest -C foo/ .\n\
+\ # Create a modular jar archive, where the module descriptor is located in\n\
+\ # classes/module-info.class:\n\
+\ jar --create --file foo.jar --main-class com.foo.Main --module-version 1.0\n\
+\     -C foo/ classes resources\n\
+\ # Update an existing non-modular jar to a modular jar:\n\
+\ jar --update --file foo.jar --main-class com.foo.Main --module-version 1.0\n\
+\     -C foo/ module-info.class
+main.help.opt.main=\
+\ Main operation mode:\n
+main.help.opt.main.create=\
+\  -c, --create               Create the archive
+main.help.opt.main.generate-index=\
+\  -i, --generate-index=FILE  Generate index information for the specified jar\n\
+\                             archives
+main.help.opt.main.list=\
+\  -t, --list                 List the table of contents for the archive
+main.help.opt.main.update=\
+\  -u, --update               Update an existing jar archive
+main.help.opt.main.extract=\
+\  -x, --extract              Extract named (or all) files from the archive
+main.help.opt.main.print-module-descriptor=\
+\  -p, --print-module-descriptor  Print the module descriptor
+main.help.opt.any=\
+\ Operation modifiers valid in any mode:\n\
+\n\
+\  -C DIR                     Change to the specified directory and include the\n\
+\                             following file
+main.help.opt.any.file=\
+\  -f, --file=FILE            The archive file name
+main.help.opt.any.verbose=\
+\  -v, --verbose              Generate verbose output on standard output
+main.help.opt.create.update=\
+\ Operation modifiers valid only in create and update mode:\n
+main.help.opt.create.update.main-class=\
+\  -e, --main-class=CLASSNAME The application entry point for stand-alone\n\
+\                             applications bundled into a modular, or executable,\n\
+\                             jar archive
+main.help.opt.create.update.manifest=\
+\  -m, --manifest=FILE        Include the manifest information from the given\n\
+\                             manifest file
+main.help.opt.create.update.no-manifest=\
+\  -M, --no-manifest          Do not create a manifest file for the entries
+main.help.opt.create.update.module-version=\
+\      --module-version=VERSION    The module version, when creating a modular\n\
+\                             jar, or updating a non-modular jar
+main.help.opt.create.update.hash-dependencies=\
+\      --hash-dependencies=PATTERN  Compute and record the hashes of module\n\
+\                             dependencies matched by the given pattern, when\n\
+\                             creating a modular jar, or updating a non-modular\n\
+\                             jar
+main.help.opt.create.update.modulepath=\
+\      --modulepath           Location of module dependence for generating
+\                             the hash
+main.help.opt.create.update.index=\
+\ Operation modifiers valid only in create, update, and generate-index mode:\n
+main.help.opt.create.update.index.no-compress=\
+\  -0, --no-compress          Store only; use no ZIP compression
+main.help.opt.other=\
+\ Other options:\n
+main.help.opt.other.help=\
+\  -?, --help[:compat]        Give this, or optionally the compatibility, help
+main.help.opt.other.version=\
+\      --version              Print program version
+main.help.postopt=\
+\ An archive is a modular jar if a module descriptor, 'module-info.class', is\n\
+\ located in the root of the given directories, or the root of the jar archive\n\
+\ itself. The following operations are only valid when creating a modular jar,\n\
+\ or updating an existing non-modular jar: '--module-version',\n\
+\ '--hash-dependencies', and '--modulepath'.\n\
+\n\
+\ Mandatory or optional arguments to long options are also mandatory or optional\n\
+\ for any corresponding short options.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jcmd/share/classes/jdk/internal/vm/agent/spi/ToolProvider.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.vm.agent.spi;
+
+/**
+ * Service interface for jdk.hotspot.agent to provide the tools that
+ * jstack, jmap, jinfo will invoke, if present.
+ */
+public interface ToolProvider {
+    /**
+     * Returns the name of the tool provider
+     */
+    String getName();
+
+    /**
+     * Invoke the tool provider with the given arguments
+     */
+    void run(String... arguments);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jcmd/share/classes/jdk/internal/vm/agent/spi/ToolProviderFinder.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.vm.agent.spi;
+
+import java.lang.reflect.Layer;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.ServiceLoader;
+
+public final class ToolProviderFinder {
+    private static final Map<String, ToolProvider> providers = init();
+
+    public static ToolProvider find(String name) {
+        return providers.get(name);
+    }
+
+    private static Map<String, ToolProvider> init() {
+        Map<String, ToolProvider> providers = new HashMap<>();
+        ServiceLoader.load(Layer.boot(), ToolProvider.class)
+                     .forEach(p -> providers.putIfAbsent(p.getName(), p));
+        return providers;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jcmd/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.jcmd {
+    requires jdk.attach;
+    requires jdk.jvmstat;
+
+    exports jdk.internal.vm.agent.spi to jdk.hotspot.agent;
+
+    uses jdk.internal.vm.agent.spi.ToolProvider;
+}
+
--- a/src/jdk.jcmd/share/classes/sun/tools/jinfo/JInfo.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/jdk.jcmd/share/classes/sun/tools/jinfo/JInfo.java	Thu Mar 17 19:04:16 2016 +0000
@@ -25,7 +25,6 @@
 
 package sun.tools.jinfo;
 
-import java.lang.reflect.Method;
 import java.util.Arrays;
 import java.io.IOException;
 import java.io.InputStream;
@@ -33,6 +32,8 @@
 import com.sun.tools.attach.VirtualMachine;
 
 import sun.tools.attach.HotSpotVirtualMachine;
+import jdk.internal.vm.agent.spi.ToolProvider;
+import jdk.internal.vm.agent.spi.ToolProviderFinder;
 
 /*
  * This class is the main class for the JInfo utility. It parses its arguments
@@ -40,6 +41,7 @@
  * or an SA tool.
  */
 final public class JInfo {
+    private static final String SA_JINFO_TOOL_NAME = "jinfo";
     private boolean useSA = false;
     private String[] args = null;
 
@@ -183,34 +185,11 @@
 
     // Invoke SA tool with the given arguments
     private void runTool() throws Exception {
-        String tool = "sun.jvm.hotspot.tools.JInfo";
-        // Tool not available on this platform.
-        Class<?> c = loadClass(tool);
-        if (c == null) {
+        ToolProvider tool = ToolProviderFinder.find(SA_JINFO_TOOL_NAME);
+        if (tool == null) {
             usage(1);
         }
-
-        // invoke the main method with the arguments
-        Class<?>[] argTypes = { String[].class } ;
-        Method m = c.getDeclaredMethod("main", argTypes);
-
-        Object[] invokeArgs = { args };
-        m.invoke(null, invokeArgs);
-    }
-
-    // loads the given class using the system class loader
-    private static Class<?> loadClass(String name) {
-        //
-        // We specify the system class loader so as to cater for development
-        // environments where this class is on the boot class path but sa-jdi.jar
-        // is on the system class path. Once the JDK is deployed then both
-        // tools.jar and sa-jdi.jar are on the system class path.
-        //
-        try {
-            return Class.forName(name, true,
-                                 ClassLoader.getSystemClassLoader());
-        } catch (Exception x)  { }
-        return null;
+        tool.run(args);
     }
 
     private static void flag(String pid, String option) throws IOException {
@@ -298,9 +277,7 @@
 
     // print usage message
     private static void usage(int exit) {
-
-        Class<?> c = loadClass("sun.jvm.hotspot.tools.JInfo");
-        boolean usageSA = (c != null);
+        boolean usageSA = ToolProviderFinder.find(SA_JINFO_TOOL_NAME) != null;
 
         System.err.println("Usage:");
         if (usageSA) {
--- a/src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java	Thu Mar 17 19:04:16 2016 +0000
@@ -25,7 +25,6 @@
 
 package sun.tools.jmap;
 
-import java.lang.reflect.Method;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
@@ -33,6 +32,8 @@
 import com.sun.tools.attach.VirtualMachine;
 import com.sun.tools.attach.AttachNotSupportedException;
 import sun.tools.attach.HotSpotVirtualMachine;
+import jdk.internal.vm.agent.spi.ToolProvider;
+import jdk.internal.vm.agent.spi.ToolProviderFinder;
 
 /*
  * This class is the main class for the JMap utility. It parses its arguments
@@ -149,15 +150,15 @@
     // Invoke SA tool  with the given arguments
     private static void runTool(String option, String args[]) throws Exception {
         String[][] tools = {
-            { "-pmap",          "sun.jvm.hotspot.tools.PMap"             },
-            { "-heap",          "sun.jvm.hotspot.tools.HeapSummary"      },
-            { "-heap:format=b", "sun.jvm.hotspot.tools.HeapDumper"       },
-            { "-histo",         "sun.jvm.hotspot.tools.ObjectHistogram"  },
-            { "-clstats",       "sun.jvm.hotspot.tools.ClassLoaderStats" },
-            { "-finalizerinfo", "sun.jvm.hotspot.tools.FinalizerInfo"    },
+            { "-pmap",          "pmap"             },
+            { "-heap",          "heapSummary"      },
+            { "-heap:format=b", "heapDumper"       },
+            { "-histo",         "objectHistogram"  },
+            { "-clstats",       "classLoaderStats" },
+            { "-finalizerinfo", "finalizerInfo"    },
         };
 
-        String tool = null;
+        String name = null;
 
         // -dump option needs to be handled in a special way
         if (option.startsWith(DUMP_OPTION_PREFIX)) {
@@ -168,7 +169,7 @@
             }
 
             // tool for heap dumping
-            tool = "sun.jvm.hotspot.tools.HeapDumper";
+            name = "heapDumper";
 
             // HeapDumper -f <file>
             args = prepend(fn, args);
@@ -177,43 +178,24 @@
             int i=0;
             while (i < tools.length) {
                 if (option.equals(tools[i][0])) {
-                    tool = tools[i][1];
+                    name = tools[i][1];
                     break;
                 }
                 i++;
             }
         }
-        if (tool == null) {
+        if (name == null) {
             usage(1);   // no mapping to tool
         }
 
-        // Tool not available on this  platform.
-        Class<?> c = loadClass(tool);
-        if (c == null) {
+        // Tool not available on this platform.
+        ToolProvider tool = ToolProviderFinder.find(name);
+        if (tool == null) {
             usage(1);
         }
 
         // invoke the main method with the arguments
-        Class<?>[] argTypes = { String[].class } ;
-        Method m = c.getDeclaredMethod("main", argTypes);
-
-        Object[] invokeArgs = { args };
-        m.invoke(null, invokeArgs);
-    }
-
-    // loads the given class using the system class loader
-    private static Class<?> loadClass(String name) {
-        //
-        // We specify the system clas loader so as to cater for development
-        // environments where this class is on the boot class path but sa-jdi.jar
-        // is on the system class path. Once the JDK is deployed then both
-        // tools.jar and sa-jdi.jar are on the system class path.
-        //
-        try {
-            return Class.forName(name, true,
-                                 ClassLoader.getSystemClassLoader());
-        } catch (Exception x)  { }
-        return null;
+        tool.run(args);
     }
 
     private static final String LIVE_OBJECTS_OPTION = "-live";
@@ -340,8 +322,7 @@
 
     // returns true if SA is available
     private static boolean haveSA() {
-        Class<?> c = loadClass("sun.jvm.hotspot.tools.HeapSummary");
-        return (c != null);
+        return ToolProviderFinder.find("heapSummary") != null;
     }
 
     // print usage message
--- a/src/jdk.jcmd/share/classes/sun/tools/jstack/JStack.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/jdk.jcmd/share/classes/sun/tools/jstack/JStack.java	Thu Mar 17 19:04:16 2016 +0000
@@ -25,14 +25,13 @@
 
 package sun.tools.jstack;
 
-import java.lang.reflect.Method;
-import java.lang.reflect.Constructor;
-import java.io.IOException;
 import java.io.InputStream;
 
 import com.sun.tools.attach.VirtualMachine;
 import com.sun.tools.attach.AttachNotSupportedException;
 import sun.tools.attach.HotSpotVirtualMachine;
+import jdk.internal.vm.agent.spi.ToolProvider;
+import jdk.internal.vm.agent.spi.ToolProviderFinder;
 
 /*
  * This class is the main class for the JStack utility. It parses its arguments
@@ -40,6 +39,8 @@
  * obtained the thread dump from a target process using the VM attach mechanism
  */
 public class JStack {
+    private static final String SA_JSTACK_TOOL_NAME = "jstack";
+
     public static void main(String[] args) throws Exception {
         if (args.length == 0) {
             usage(1); // no arguments
@@ -117,11 +118,14 @@
         }
     }
 
+    // SA JStack tool
+    private static boolean isAgentToolPresent() {
+        return ToolProviderFinder.find(SA_JSTACK_TOOL_NAME) != null;
+    }
 
-    // SA JStack tool
     private static void runJStackTool(boolean mixed, boolean locks, String args[]) throws Exception {
-        Class<?> cl = loadSAClass();
-        if (cl == null) {
+        ToolProvider tool = ToolProviderFinder.find(SA_JSTACK_TOOL_NAME);
+        if (tool == null) {
             usage(1);            // SA not available
         }
 
@@ -133,28 +137,9 @@
             args = prepend("-l", args);
         }
 
-        Class<?>[] argTypes = { String[].class };
-        Method m = cl.getDeclaredMethod("main", argTypes);
-
-        Object[] invokeArgs = { args };
-        m.invoke(null, invokeArgs);
+        tool.run(args);
     }
 
-    // Returns sun.jvm.hotspot.tools.JStack if available, otherwise null.
-    private static Class<?> loadSAClass() {
-        //
-        // Attempt to load JStack class - we specify the system class
-        // loader so as to cater for development environments where
-        // this class is on the boot class path but sa-jdi.jar is on
-        // the system class path. Once the JDK is deployed then both
-        // tools.jar and sa-jdi.jar are on the system class path.
-        //
-        try {
-            return Class.forName("sun.jvm.hotspot.tools.JStack", true,
-                                 ClassLoader.getSystemClassLoader());
-        } catch (Exception x)  { }
-        return null;
-    }
 
     // Attach to pid and perform a thread dump
     private static void runThreadDump(String pid, String args[]) throws Exception {
@@ -168,8 +153,7 @@
             } else {
                 x.printStackTrace();
             }
-            if ((x instanceof AttachNotSupportedException) &&
-                (loadSAClass() != null)) {
+            if ((x instanceof AttachNotSupportedException) && isAgentToolPresent()) {
                 System.err.println("The -F option can be used when the target " +
                     "process is not responding");
             }
@@ -208,7 +192,7 @@
         System.err.println("    jstack [-l] <pid>");
         System.err.println("        (to connect to running process)");
 
-        if (loadSAClass() != null) {
+        if (isAgentToolPresent()) {
             System.err.println("    jstack -F [-m] [-l] <pid>");
             System.err.println("        (to connect to a hung process)");
             System.err.println("    jstack [-m] [-l] <executable> <core>");
@@ -220,7 +204,7 @@
         System.err.println("");
         System.err.println("Options:");
 
-        if (loadSAClass() != null) {
+        if (isAgentToolPresent()) {
             System.err.println("    -F  to force a thread dump. Use when jstack <pid> does not respond" +
                 " (process is hung)");
             System.err.println("    -m  to print both java and native frames (mixed mode)");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jconsole/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.jconsole {
+    requires public java.desktop;
+    requires public java.management;
+    requires java.logging;
+    requires java.rmi;
+    requires jdk.attach;
+    requires jdk.jvmstat;
+    requires jdk.management;
+    exports com.sun.tools.jconsole;
+    uses com.sun.tools.jconsole.JConsolePlugin;
+}
+
--- a/src/jdk.jdi/share/classes/META-INF/services/com.sun.jdi.connect.Connector	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-#
-# Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.  Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-# 
-
-#
-# List all Sun provided connector providers here. If there
-# are providers that are only available on a particular OS
-# then prefix the line with #[OS] and they will automatically
-# uncommented by the build process - see make/jpda/front/Makefile.
-#
-com.sun.tools.jdi.SunCommandLineLauncher
-com.sun.tools.jdi.RawCommandLineLauncher
-com.sun.tools.jdi.SocketAttachingConnector
-com.sun.tools.jdi.SocketListeningConnector
-#[windows]com.sun.tools.jdi.SharedMemoryAttachingConnector
-#[windows]com.sun.tools.jdi.SharedMemoryListeningConnector
-com.sun.tools.jdi.ProcessAttachingConnector
--- a/src/jdk.jdi/share/classes/META-INF/services/com.sun.jdi.connect.spi.TransportService	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-#
-# Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.  Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-# 
-
-#
-# List any additional Sun provided transport services here.
-# If any transport services are OS specific then prefix the line
-# with #[OS] and they will automatically be uncommented in the
-# build process - see make/jpda/front/Makefile.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jdi/share/classes/com/sun/jdi/InvalidModuleException.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.jdi;
+
+/**
+ * Thrown to indicate that the requested module is invalid
+ * or became invalid after the module was unloaded.
+ * <p>
+ *
+ * @since  9
+ */
+public class InvalidModuleException extends RuntimeException {
+    private static final long serialVersionUID = 7907359387320658039L;
+
+    /**
+     * Constructs a {@code InvalidModuleException} with no detail message.
+     */
+    public InvalidModuleException() {
+        super();
+    }
+
+    /**
+     * Constructs a {@code InvalidModuleException} with the given detail
+     * message.
+     *
+     * @param msg
+     *        The detail message; can be {@code null}
+     */
+    public InvalidModuleException(String msg) {
+        super(msg);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jdi/share/classes/com/sun/jdi/ModuleReference.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.jdi;
+
+
+/**
+ * A module in the target VM.
+ * <p>
+ * Any method on {@code ModuleReference} which directly or
+ * indirectly takes {@code ModuleReference} as an parameter may throw
+ * {@link com.sun.jdi.VMDisconnectedException} if the target VM is
+ * disconnected and the {@link com.sun.jdi.event.VMDisconnectEvent} has been or is
+ * available to be read from the {@link com.sun.jdi.event.EventQueue}.
+ * <p>
+ * Any method on {@code ModuleReference} which directly or
+ * indirectly takes {@code ModuleReference} as an parameter may throw
+ * {@link com.sun.jdi.VMOutOfMemoryException} if the target VM has run out of memory.
+ * <p>
+ * Any method on {@code ModuleReference} or which directly or indirectly takes
+ * {@code ModuleReference} as parameter may throw
+ * {@link com.sun.jdi.InvalidModuleException} if the mirrored module
+ * has been unloaded.
+ *
+ * Not all target virtual machines support this class.
+ * Use {@link VirtualMachine#canGetModuleInfo()}
+ * to determine if the class is supported.
+ *
+ * @since  9
+ */
+public interface ModuleReference extends ObjectReference {
+
+    /**
+     * Returns the module name.
+     * This method returns {@code null}
+     * if this module is an unnamed module.
+     *
+     * @return the name of this module.
+     */
+    String name();
+
+    /**
+     * Returns the {@link ClassLoaderReference} object for this module.
+     *
+     * @return the {@link ClassLoaderReference} object for this module.
+     */
+    ClassLoaderReference classLoader();
+
+    /**
+     * Indicates if this module reads another module.
+     *
+     * @return {@code true} if this module reads {@code other},
+     *         {@code false} otherwise
+     */
+    boolean canRead(ModuleReference other);
+}
--- a/src/jdk.jdi/share/classes/com/sun/jdi/ReferenceType.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/jdk.jdi/share/classes/com/sun/jdi/ReferenceType.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -117,6 +117,30 @@
     ClassLoaderReference classLoader();
 
     /**
+     * Gets the module object which contains the class corresponding
+     * to this type.
+     *
+     * Not all target virtual machines support this operation.
+     * Use {@link VirtualMachine#canGetModuleInfo()}
+     * to determine if the operation is supported.
+     *
+     * @implSpec
+     * The default implementation throws {@code UnsupportedOperationException}.
+     *
+     * @return a {@link ModuleReference} which mirrors the module in the target VM.
+     *
+     * @throws java.lang.UnsupportedOperationException if
+     * the target virtual machine does not support this
+     * operation.
+     *
+     * @since 9
+     */
+    default ModuleReference module() {
+        throw new java.lang.UnsupportedOperationException(
+            "The method module() must be implemented");
+    }
+
+    /**
      * Gets an identifying name for the source corresponding to the
      * declaration of this type. Interpretation of this string is
      * the responsibility of the source repository mechanism.
--- a/src/jdk.jdi/share/classes/com/sun/jdi/VirtualMachine.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/jdk.jdi/share/classes/com/sun/jdi/VirtualMachine.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
 package com.sun.jdi;
 
 import com.sun.jdi.event.EventQueue;
+import com.sun.jdi.ModuleReference;
 import com.sun.jdi.request.EventRequestManager;
 
 import java.util.List;
@@ -73,6 +74,32 @@
 public interface VirtualMachine extends Mirror {
 
     /**
+     * Returns all modules. For each module in the target
+     * VM a {@link ModuleReference} will be placed in the returned list.
+     * <P>
+     *
+     * Not all target virtual machines support this operation.
+     * Use {@link VirtualMachine#canGetModuleInfo()}
+     * to determine if the operation is supported.
+     *
+     * @implSpec
+     * The default implementation throws {@code UnsupportedOperationException}.
+     *
+     * @return a list of {@link ModuleReference} objects, each mirroring
+     * a module in the target VM.
+     *
+     * @throws java.lang.UnsupportedOperationException if
+     * the target virtual machine does not support this
+     * operation.
+     *
+     * @since 9
+     */
+    default List<ModuleReference> allModules() {
+        throw new java.lang.UnsupportedOperationException(
+            "The method allModules() must be implemented");
+    }
+
+    /**
      * Returns the loaded reference types that
      * match a given name. The name must be fully qualified
      * (for example, java.lang.String). The returned list
@@ -733,6 +760,24 @@
     boolean canGetConstantPool();
 
     /**
+     * Determines if the target VM supports getting information about modules.
+     *
+     * @return {@code true} if the feature is supported, {@code false} otherwise
+     *
+     * @implSpec
+     * The default implementation returns {@code false}.
+     *
+     * @see VirtualMachine#allModules()
+     * @see ReferenceType#module()
+     * @see ModuleReference
+     *
+     * @since 9
+     */
+    default boolean canGetModuleInfo() {
+        return false;
+    }
+
+    /**
      * Set this VM's default stratum (see {@link Location} for a
      * discussion of strata).  Overrides the per-class default set
      * in the class file.
--- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/JDWPException.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/JDWPException.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -43,6 +43,8 @@
         switch (errorCode) {
             case JDWP.Error.INVALID_OBJECT:
                 return new ObjectCollectedException();
+            case JDWP.Error.INVALID_MODULE:
+                return new InvalidModuleException();
             case JDWP.Error.VM_DEAD:
                 return new VMDisconnectedException();
             case JDWP.Error.OUT_OF_MEMORY:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ModuleReferenceImpl.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.jdi;
+
+import com.sun.jdi.*;
+
+
+class ModuleReferenceImpl extends ObjectReferenceImpl implements ModuleReference {
+
+    protected ModuleReferenceImpl(VirtualMachine aVm, long aRef) {
+        super(aVm, aRef);
+    }
+
+    protected String description() {
+        return "ModuleReference " + ref();
+    }
+
+    private String name;
+    private ClassLoaderReference classLoader;
+
+    private boolean cachedName = false;
+    private boolean cachedClassLoader = false;
+
+
+    public synchronized String name() {
+        if (cachedName) {
+            return name;
+        }
+        try {
+            name = JDWP.ModuleReference.Name.process(this.vm, this).name;
+            if (name != null && name.length() == 0) {
+                // The JDWP returns empty name for unnamed modules
+                name = null;
+            }
+            cachedName = true;
+        } catch (JDWPException ex) {
+            throw ex.toJDIException();
+        }
+        return name;
+    }
+
+    public synchronized ClassLoaderReference classLoader() {
+        if (cachedClassLoader) {
+            return classLoader;
+        }
+        try {
+            classLoader = JDWP.ModuleReference.ClassLoader.
+                process(this.vm, this).classLoader;
+            cachedClassLoader = true;
+        } catch (JDWPException ex) {
+            throw ex.toJDIException();
+        }
+        return classLoader;
+    }
+
+    public synchronized boolean canRead(ModuleReference module) {
+        boolean ret;
+        try {
+            ret = JDWP.ModuleReference.CanRead.
+                process(this.vm, this, (ModuleReferenceImpl)module).canRead;
+        } catch (JDWPException ex) {
+            throw ex.toJDIException();
+        }
+        return ret;
+    }
+}
--- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/PacketStream.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/PacketStream.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -154,6 +154,10 @@
         writeID(vm.sizeofMethodRef, data);
     }
 
+    void writeModuleRef(long data) {
+        writeID(vm.sizeofModuleRef, data);
+    }
+
     void writeFieldRef(long data) {
         writeID(vm.sizeofFieldRef, data);
     }
@@ -467,6 +471,11 @@
         return vm.referenceType(ref, tag);
     }
 
+    ModuleReferenceImpl readModule() {
+        long ref = readModuleRef();
+        return vm.moduleMirror(ref);
+    }
+
     /**
      * Read method reference represented as vm specific byte sequence.
      */
@@ -475,6 +484,13 @@
     }
 
     /**
+     * Read module reference represented as vm specific byte sequence.
+     */
+    long readModuleRef() {
+        return readID(vm.sizeofModuleRef);
+    }
+
+    /**
      * Read field reference represented as vm specific byte sequence.
      */
     long readFieldRef() {
--- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -47,6 +47,7 @@
     private boolean isClassLoaderCached = false;
     private ClassLoaderReference classLoader = null;
     private ClassObjectReference classObject = null;
+    private ModuleReference module = null;
 
     private int status = 0;
     private boolean isPrepared = false;
@@ -219,6 +220,22 @@
         return classLoader;
     }
 
+    public ModuleReference module() {
+        if (module != null) {
+            return module;
+        }
+        // Does not need synchronization, since worst-case
+        // static info is fetched twice
+        try {
+            ModuleReferenceImpl m = JDWP.ReferenceType.Module.
+                process(vm, this).module;
+            module = vm.getModule(m.ref());
+        } catch (JDWPException exc) {
+            throw exc.toJDIException();
+        }
+        return module;
+    }
+
     public boolean isPublic() {
         if (modifiers == -1)
             getModifiers();
@@ -308,7 +325,8 @@
             if (vm.canGet1_5LanguageFeatures()) {
                 JDWP.ReferenceType.FieldsWithGeneric.FieldInfo[] jdwpFields;
                 try {
-                    jdwpFields = JDWP.ReferenceType.FieldsWithGeneric.process(vm, this).declared;
+                    jdwpFields = JDWP.ReferenceType.FieldsWithGeneric.
+                        process(vm, this).declared;
                 } catch (JDWPException exc) {
                     throw exc.toJDIException();
                 }
--- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/VirtualMachineImpl.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/VirtualMachineImpl.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
 package com.sun.tools.jdi;
 
 import com.sun.jdi.*;
+import com.sun.jdi.ModuleReference;
 import com.sun.jdi.connect.spi.Connection;
 import com.sun.jdi.request.EventRequestManager;
 import com.sun.jdi.request.EventRequest;
@@ -48,6 +49,7 @@
     public final int sizeofObjectRef;
     public final int sizeofClassRef;
     public final int sizeofFrameRef;
+    public final int sizeofModuleRef;
 
     final int sequenceNumber;
 
@@ -75,6 +77,8 @@
     private TreeSet<ReferenceType> typesBySignature;
     private boolean retrievedAllTypes = false;
 
+    private Map<Long, ModuleReference> modulesByID;
+
     // For other languages support
     private String defaultStratum = null;
 
@@ -204,6 +208,7 @@
         sizeofObjectRef = idSizes.objectIDSize;
         sizeofClassRef = idSizes.referenceTypeIDSize;
         sizeofFrameRef  = idSizes.frameIDSize;
+        sizeofModuleRef = idSizes.objectIDSize;
 
         /**
          * Set up requests needed by internal event handler.
@@ -265,6 +270,12 @@
         return System.identityHashCode(this);
     }
 
+    public List<ModuleReference> allModules() {
+        validateVM();
+        List<ModuleReference> modules = retrieveAllModules();
+        return Collections.unmodifiableList(modules);
+    }
+
     public List<ReferenceType> classesByName(String className) {
         validateVM();
         String signature = JNITypeParser.typeNameToSignature(className);
@@ -585,7 +596,8 @@
        } catch (JDWPException exc) {
            throw exc.toJDIException();
        }
-   }
+    }
+
     public String description() {
         validateVM();
 
@@ -674,20 +686,18 @@
             versionInfo().jdwpMinor >= 6;
     }
     public boolean canGetInstanceInfo() {
-        if (versionInfo().jdwpMajor < 1 ||
-            versionInfo().jdwpMinor < 6) {
+        if (versionInfo().jdwpMajor > 1 ||
+            versionInfo().jdwpMinor >= 6) {
+            validateVM();
+            return hasNewCapabilities() &&
+                capabilitiesNew().canGetInstanceInfo;
+        } else {
             return false;
         }
-        validateVM();
-        return hasNewCapabilities() &&
-            capabilitiesNew().canGetInstanceInfo;
     }
     public boolean canUseSourceNameFilters() {
-        if (versionInfo().jdwpMajor < 1 ||
-            versionInfo().jdwpMinor < 6) {
-            return false;
-        }
-        return true;
+        return versionInfo().jdwpMajor > 1 ||
+            versionInfo().jdwpMinor >= 6;
     }
     public boolean canForceEarlyReturn() {
         validateVM();
@@ -703,12 +713,8 @@
             capabilitiesNew().canGetSourceDebugExtension;
     }
     public boolean canGetClassFileVersion() {
-        if ( versionInfo().jdwpMajor < 1 &&
-             versionInfo().jdwpMinor  < 6) {
-            return false;
-        } else {
-            return true;
-        }
+        return versionInfo().jdwpMajor > 1 ||
+            versionInfo().jdwpMinor >= 6;
     }
     public boolean canGetConstantPool() {
         validateVM();
@@ -730,6 +736,10 @@
         return hasNewCapabilities() &&
             capabilitiesNew().canGetMonitorFrameInfo;
     }
+    public boolean canGetModuleInfo() {
+        validateVM();
+        return versionInfo().jdwpMajor >= 9;
+    }
 
     public void setDebugTraceMode(int traceFlags) {
         validateVM();
@@ -929,6 +939,48 @@
         return capabilitiesNew;
     }
 
+    private synchronized ModuleReference addModule(long id) {
+        if (modulesByID == null) {
+            modulesByID = new HashMap<Long, ModuleReference>(77);
+        }
+        ModuleReference module = new ModuleReferenceImpl(vm, id);
+        modulesByID.put(id, module);
+        return module;
+    }
+
+    ModuleReference getModule(long id) {
+        if (id == 0) {
+            return null;
+        } else {
+            ModuleReference module = null;
+            synchronized (this) {
+                if (modulesByID != null) {
+                    module = modulesByID.get(id);
+                }
+                if (module == null) {
+                    module = addModule(id);
+                }
+            }
+            return module;
+        }
+    }
+
+    private synchronized List<ModuleReference> retrieveAllModules() {
+        ModuleReferenceImpl[] reqModules;
+        try {
+            reqModules = JDWP.VirtualMachine.AllModules.process(vm).modules;
+        } catch (JDWPException exc) {
+            throw exc.toJDIException();
+        }
+        ArrayList<ModuleReference> modules = new ArrayList<>();
+        for (int i = 0; i < reqModules.length; i++) {
+            long moduleRef = reqModules[i].ref();
+            ModuleReference module = getModule(moduleRef);
+            modules.add(module);
+        }
+        return modules;
+    }
+
     private List<ReferenceType> retrieveClassesBySignature(String signature) {
         if ((vm.traceFlags & VirtualMachine.TRACE_REFTYPES) != 0) {
             vm.printTrace("Retrieving matching ReferenceTypes, sig=" + signature);
@@ -1364,6 +1416,10 @@
                                                       JDWP.Tag.CLASS_OBJECT);
     }
 
+    ModuleReferenceImpl moduleMirror(long id) {
+        return (ModuleReferenceImpl)getModule(id);
+    }
+
     /*
      * Implementation of PathSearchingVirtualMachine
      */
--- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/VirtualMachineManagerImpl.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/VirtualMachineManagerImpl.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -47,8 +47,8 @@
     private final ThreadGroup mainGroupForJDI;
     private ResourceBundle messages = null;
     private int vmSequenceNumber = 0;
-    private static final int majorVersion = 1;
-    private static final int minorVersion = 8;
+    private static final int majorVersion = 9;
+    private static final int minorVersion = 0;
 
     private static final Object lock = new Object();
     private static VirtualMachineManagerImpl vmm;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jdi/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.jdi {
+    requires jdk.attach;
+
+    exports com.sun.jdi;
+    exports com.sun.jdi.connect;
+    exports com.sun.jdi.connect.spi;
+    exports com.sun.jdi.event;
+    exports com.sun.jdi.request;
+    exports com.sun.tools.jdi to jdk.hotspot.agent;
+
+    uses com.sun.jdi.connect.Connector;
+    uses com.sun.jdi.connect.spi.TransportService;
+
+    // windows shared memory connector providers are added at build time
+    provides com.sun.jdi.connect.Connector with com.sun.tools.jdi.ProcessAttachingConnector;
+    provides com.sun.jdi.connect.Connector with com.sun.tools.jdi.RawCommandLineLauncher;
+    provides com.sun.jdi.connect.Connector with com.sun.tools.jdi.SocketAttachingConnector;
+    provides com.sun.jdi.connect.Connector with com.sun.tools.jdi.SocketListeningConnector;
+    provides com.sun.jdi.connect.Connector with com.sun.tools.jdi.SunCommandLineLauncher;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jdi/windows/classes/module-info.java.extra	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+provides com.sun.jdi.connect.Connector with com.sun.tools.jdi.SharedMemoryAttachingConnector;
+provides com.sun.jdi.connect.Connector with com.sun.tools.jdi.SharedMemoryListeningConnector;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jdwp.agent/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.jdwp.agent {
+}
+
--- a/src/jdk.jdwp.agent/share/native/libjdwp/JDWP.h	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/jdk.jdwp.agent/share/native/libjdwp/JDWP.h	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -60,7 +60,7 @@
            JDWP_InvokeOptions_INVOKE_ ## name
 #define JDWP_ERROR(name) \
            JDWP_Error_ ## name
-#define JDWP_HIGHEST_COMMAND_SET 17
+#define JDWP_HIGHEST_COMMAND_SET 18
 #define JDWP_REQUEST_NONE        -1
 
 /* This typedef helps keep the event and error types straight. */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jdwp.agent/share/native/libjdwp/ModuleReferenceImpl.c	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "util.h"
+#include "inStream.h"
+#include "outStream.h"
+#include "ModuleReferenceImpl.h"
+
+
+static jclass jlrM(JNIEnv *env) {
+    return findClass(env, "Ljava/lang/reflect/Module;");
+}
+
+static jboolean
+getName(PacketInputStream *in, PacketOutputStream *out)
+{
+    static jmethodID method = NULL;
+    JNIEnv *env = getEnv();
+    char *name = NULL;
+    jstring namestr;
+    jobject module;
+
+    if (method == NULL) {
+        method = getMethod(env, jlrM(env), "getName", "()Ljava/lang/String;");
+    }
+    module = inStream_readModuleRef(getEnv(), in);
+    if (inStream_error(in)) {
+        return JNI_TRUE;
+    }
+    namestr = (jstring)JNI_FUNC_PTR(env, CallObjectMethod) (env, module, method);
+    if (namestr != NULL) {
+        name = (char*)JNI_FUNC_PTR(env, GetStringUTFChars)(env, namestr, NULL);
+    } else {
+        // The JDWP converts null into an empty string
+    }
+    (void)outStream_writeString(out, name);
+    if (name != NULL) {
+        jvmtiDeallocate(name);
+    }
+    return JNI_TRUE;
+}
+
+static jboolean
+getClassLoader(PacketInputStream *in, PacketOutputStream *out)
+{
+    static jmethodID method = NULL;
+    JNIEnv *env = getEnv();
+    jobject loader;
+    jobject module;
+
+    if (method == NULL) {
+        method = getMethod(env, jlrM(env), "getClassLoader", "()Ljava/lang/ClassLoader;");
+    }
+    module = inStream_readModuleRef(env, in);
+    if (inStream_error(in)) {
+        return JNI_TRUE;
+    }
+    loader = JNI_FUNC_PTR(env, CallObjectMethod) (env, module, method);
+
+    (void)outStream_writeObjectRef(env, out, loader);
+    return JNI_TRUE;
+}
+
+static jboolean
+canRead(PacketInputStream *in, PacketOutputStream *out)
+{
+    static jmethodID method = NULL;
+    JNIEnv *env = getEnv();
+    jboolean can_read;
+    jobject module;
+    jobject source_module;
+
+    if (method == NULL) {
+        method = getMethod(env, jlrM(env), "canRead", "(Ljava/lang/reflect/Module;)Z");
+    }
+    module = inStream_readModuleRef(env, in);
+    if (inStream_error(in)) {
+        return JNI_TRUE;
+    }
+    source_module = inStream_readModuleRef(env, in);
+    if (inStream_error(in)) {
+        return JNI_TRUE;
+    }
+    can_read = JNI_FUNC_PTR(env, CallBooleanMethod)
+        (env, module, method, source_module);
+
+    (void)outStream_writeBoolean(out, can_read);
+    return JNI_TRUE;
+}
+
+
+void *ModuleReference_Cmds[] = { (void *)3
+    ,(void *)getName
+    ,(void *)getClassLoader
+    ,(void *)canRead
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jdwp.agent/share/native/libjdwp/ModuleReferenceImpl.h	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+extern void *ModuleReference_Cmds[];
--- a/src/jdk.jdwp.agent/share/native/libjdwp/ReferenceTypeImpl.c	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/jdk.jdwp.agent/share/native/libjdwp/ReferenceTypeImpl.c	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -109,6 +109,26 @@
 }
 
 static jboolean
+getModule(PacketInputStream *in, PacketOutputStream *out)
+{
+    jobject clazz;
+    jobject module;
+    JNIEnv *env;
+
+    env = getEnv();
+
+    clazz = inStream_readClassRef(env, in);
+    if (inStream_error(in)) {
+        return JNI_TRUE;
+    }
+
+    module = JNI_FUNC_PTR(env, GetModule)(env, clazz);
+
+    (void)outStream_writeModuleRef(env, out, module);
+    return JNI_TRUE;
+}
+
+static jboolean
 modifiers(PacketInputStream *in, PacketOutputStream *out)
 {
     jint modifiers;
@@ -605,7 +625,7 @@
     return JNI_TRUE;
 }
 
-void *ReferenceType_Cmds[] = { (void *)18
+void *ReferenceType_Cmds[] = { (void *)19
     ,(void *)signature
     ,(void *)getClassLoader
     ,(void *)modifiers
@@ -624,4 +644,5 @@
     ,(void *)instances
     ,(void *)getClassVersion
     ,(void *)getConstantPool
+    ,(void *)getModule
 };
--- a/src/jdk.jdwp.agent/share/native/libjdwp/VirtualMachineImpl.c	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/jdk.jdwp.agent/share/native/libjdwp/VirtualMachineImpl.c	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,8 +35,8 @@
 #include "FrameID.h"
 
 static char *versionName = "Java Debug Wire Protocol (Reference Implementation)";
-static int majorVersion = 1;  /* JDWP major version */
-static int minorVersion = 8;  /* JDWP minor version */
+static int majorVersion = 9;  /* JDWP major version */
+static int minorVersion = 0;  /* JDWP minor version */
 
 static jboolean
 version(PacketInputStream *in, PacketOutputStream *out)
@@ -190,6 +190,41 @@
 }
 
 static jboolean
+allModules(PacketInputStream *in, PacketOutputStream *out)
+{
+    JNIEnv *env;
+
+    if (gdata->vmDead) {
+        outStream_setError(out, JDWP_ERROR(VM_DEAD));
+        return JNI_TRUE;
+    }
+
+    env = getEnv();
+
+    WITH_LOCAL_REFS(env, 1) {
+
+        jint count = 0;
+        jint i = 0;
+        jobject* modules = NULL;
+        jvmtiError error = JVMTI_ERROR_NONE;
+
+        error = JVMTI_FUNC_PTR(gdata->jvmti, GetAllModules) (gdata->jvmti, &count, &modules);
+        if (error != JVMTI_ERROR_NONE) {
+            outStream_setError(out, map2jdwpError(error));
+        } else {
+            (void)outStream_writeInt(out, count);
+            for (i = 0; i < count; i++) {
+                (void)outStream_writeModuleRef(env, out, modules[i]);
+            }
+            jvmtiDeallocate(modules);
+        }
+
+    } END_WITH_LOCAL_REFS(env);
+
+    return JNI_TRUE;
+}
+
+static jboolean
 allClasses1(PacketInputStream *in, PacketOutputStream *out, int outputGenerics)
 {
     JNIEnv *env;
@@ -747,6 +782,7 @@
     (void)outStream_writeBoolean(out, (jboolean)caps.can_get_constant_pool);
     /* 21 Can force early return */
     (void)outStream_writeBoolean(out, (jboolean)caps.can_force_early_return);
+
     (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 22 */
     (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 23 */
     (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 24 */
@@ -823,7 +859,6 @@
 classPaths(PacketInputStream *in, PacketOutputStream *out)
 {
     char *ud;
-    char *bp;
     char *cp;
 
     ud = gdata->property_user_dir;
@@ -834,13 +869,9 @@
     if ( cp == NULL ) {
         cp = "";
     }
-    bp = gdata->property_sun_boot_class_path;
-    if ( bp == NULL ) {
-        bp = "";
-    }
     (void)outStream_writeString(out, ud);
     writePaths(out, cp);
-    writePaths(out, bp);
+    (void)outStream_writeInt(out, 0); // no bootclasspath
     return JNI_TRUE;
 }
 
@@ -890,7 +921,7 @@
     return JNI_TRUE;
 }
 
-void *VirtualMachine_Cmds[] = { (void *)21
+void *VirtualMachine_Cmds[] = { (void *)22
     ,(void *)version
     ,(void *)classesForSignature
     ,(void *)allClasses
@@ -912,4 +943,5 @@
     ,(void *)setDefaultStratum
     ,(void *)allClassesWithGeneric
     ,(void *)instanceCounts
+    ,(void *)allModules
 };
--- a/src/jdk.jdwp.agent/share/native/libjdwp/debugDispatch.c	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/jdk.jdwp.agent/share/native/libjdwp/debugDispatch.c	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,6 +33,7 @@
 #include "ArrayTypeImpl.h"
 #include "FieldImpl.h"
 #include "MethodImpl.h"
+#include "ModuleReferenceImpl.h"
 #include "ObjectReferenceImpl.h"
 #include "StringReferenceImpl.h"
 #include "ThreadReferenceImpl.h"
@@ -82,6 +83,7 @@
     l1Array[JDWP_COMMAND_SET(EventRequest)] = (void *)EventRequest_Cmds;
     l1Array[JDWP_COMMAND_SET(StackFrame)] = (void *)StackFrame_Cmds;
     l1Array[JDWP_COMMAND_SET(ClassObjectReference)] = (void *)ClassObjectReference_Cmds;
+    l1Array[JDWP_COMMAND_SET(ModuleReference)] = (void *)ModuleReference_Cmds;
 }
 
 void
--- a/src/jdk.jdwp.agent/share/native/libjdwp/inStream.c	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/jdk.jdwp.agent/share/native/libjdwp/inStream.c	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -165,6 +165,24 @@
 }
 
 /*
+ * Read a module from the stream. The ID used in the wire protocol
+ * is converted to a reference which is returned. The reference is
+ * global and strong, but it should *not* be deleted by the caller
+ * since it is freed when this stream is destroyed.
+ */
+jobject
+inStream_readModuleRef(JNIEnv *env, PacketInputStream *stream)
+{
+    jobject ref = inStream_readObjectRef(env, stream);
+    if (ref == NULL && stream->error == JDWP_ERROR(INVALID_OBJECT)) {
+        stream->error = JDWP_ERROR(INVALID_MODULE);
+        return NULL;
+    }
+
+    return ref;
+}
+
+/*
  * Read an object from the stream. The ID used in the wire protocol
  * is converted to a reference which is returned. The reference is
  * global and strong, but it should *not* be deleted by the caller
--- a/src/jdk.jdwp.agent/share/native/libjdwp/inStream.h	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/jdk.jdwp.agent/share/native/libjdwp/inStream.h	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -60,6 +60,7 @@
 jfieldID inStream_readFieldID(PacketInputStream *stream);
 jlocation inStream_readLocation(PacketInputStream *stream);
 
+jobject inStream_readModuleRef(JNIEnv *env, PacketInputStream *stream);
 jobject inStream_readObjectRef(JNIEnv *env, PacketInputStream *stream);
 jclass inStream_readClassRef(JNIEnv *env, PacketInputStream *stream);
 jthread inStream_readThreadRef(JNIEnv *env, PacketInputStream *stream);
--- a/src/jdk.jdwp.agent/share/native/libjdwp/outStream.c	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/jdk.jdwp.agent/share/native/libjdwp/outStream.c	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -197,6 +197,12 @@
 }
 
 jdwpError
+outStream_writeModuleRef(JNIEnv *env, PacketOutputStream *stream, jobject val)
+{
+    return outStream_writeObjectRef(env, stream, val);
+}
+
+jdwpError
 outStream_writeObjectRef(JNIEnv *env, PacketOutputStream *stream, jobject val)
 {
     jlong id;
--- a/src/jdk.jdwp.agent/share/native/libjdwp/outStream.h	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/jdk.jdwp.agent/share/native/libjdwp/outStream.h	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -67,6 +67,7 @@
 jdwpError outStream_writeLong(PacketOutputStream *stream, jlong val);
 jdwpError outStream_writeFloat(PacketOutputStream *stream, jfloat val);
 jdwpError outStream_writeDouble(PacketOutputStream *stream, jdouble val);
+jdwpError outStream_writeModuleRef(JNIEnv *env, PacketOutputStream *stream, jobject val);
 jdwpError outStream_writeObjectRef(JNIEnv *env, PacketOutputStream *stream, jobject val);
 jdwpError outStream_writeObjectTag(JNIEnv *env, PacketOutputStream *stream, jobject val);
 jdwpError outStream_writeFrameID(PacketOutputStream *stream, FrameID val);
--- a/src/jdk.jdwp.agent/share/native/libjdwp/util.c	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/jdk.jdwp.agent/share/native/libjdwp/util.c	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -86,7 +86,7 @@
     *pobj = NULL;
 }
 
-static jclass
+jclass
 findClass(JNIEnv *env, const char * name)
 {
     jclass x;
@@ -109,7 +109,7 @@
     return x;
 }
 
-static jmethodID
+jmethodID
 getMethod(JNIEnv *env, jclass clazz, const char * name, const char *signature)
 {
     jmethodID method;
@@ -250,8 +250,6 @@
                         = getPropertyUTF8(env, "java.vm.info");
         gdata->property_java_class_path
                         = getPropertyUTF8(env, "java.class.path");
-        gdata->property_sun_boot_class_path
-                        = getPropertyUTF8(env, "sun.boot.class.path");
         gdata->property_sun_boot_library_path
                         = getPropertyUTF8(env, "sun.boot.library.path");
         gdata->property_path_separator
--- a/src/jdk.jdwp.agent/share/native/libjdwp/util.h	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/jdk.jdwp.agent/share/native/libjdwp/util.h	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -113,7 +113,6 @@
     char* property_java_vm_name;          /* UTF8 java.vm.name */
     char* property_java_vm_info;          /* UTF8 java.vm.info */
     char* property_java_class_path;       /* UTF8 java.class.path */
-    char* property_sun_boot_class_path;   /* UTF8 sun.boot.class.path */
     char* property_sun_boot_library_path; /* UTF8 sun.boot.library.path */
     char* property_path_separator;        /* UTF8 path.separator */
     char* property_user_dir;              /* UTF8 user.dir */
@@ -194,6 +193,7 @@
 #define AGENT_ERROR_INVALID_EVENT_TYPE          _AGENT_ERROR(24)
 #define AGENT_ERROR_INVALID_OBJECT              _AGENT_ERROR(25)
 #define AGENT_ERROR_NO_MORE_FRAMES              _AGENT_ERROR(26)
+#define AGENT_ERROR_INVALID_MODULE              _AGENT_ERROR(27)
 
 /* Combined event information */
 
@@ -354,6 +354,9 @@
 
 void threadGroupInfo(jthreadGroup, jvmtiThreadGroupInfo *info);
 
+jclass findClass(JNIEnv *env, const char * name);
+jmethodID getMethod(JNIEnv *env, jclass clazz, const char * name, const char *signature);
+char *getModuleName(jclass);
 char *getClassname(jclass);
 jvmtiError classSignature(jclass, char**, char**);
 jint classStatus(jclass);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jimage/ExtractedImage.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jimage;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.function.Consumer;
+import jdk.tools.jlink.internal.ImageFileCreator;
+import jdk.tools.jlink.internal.Archive;
+import jdk.tools.jlink.internal.ImagePluginStack;
+import jdk.tools.jlink.internal.DirArchive;
+/**
+ *
+ * Support for extracted image.
+ */
+public final class ExtractedImage {
+
+    private Set<Archive> archives = new HashSet<>();
+    private final ImagePluginStack plugins;
+
+    ExtractedImage(Path dirPath, ImagePluginStack plugins, PrintWriter log,
+            boolean verbose) throws IOException {
+        if (!Files.isDirectory(dirPath)) {
+            throw new IOException("Not a directory");
+        }
+        Consumer<String> cons = (String t) -> {
+            if (verbose) {
+                log.println(t);
+            }
+        };
+        this.plugins = plugins;
+        Files.walk(dirPath, 1).forEach((p) -> {
+            if (!dirPath.equals(p)) {
+                if (Files.isDirectory(p)) {
+                    Archive a = new DirArchive(p, cons);
+                    archives.add(a);
+                }
+            }
+        });
+        archives = Collections.unmodifiableSet(archives);
+    }
+
+    void recreateJImage(Path path) throws IOException {
+        ImageFileCreator.recreateJimage(path, archives, plugins);
+    }
+
+    private static String getPathName(Path path) {
+        return path.toString().replace(File.separatorChar, '/');
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jimage/JImageTask.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,397 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jimage;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.channels.FileChannel;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import static java.nio.file.StandardOpenOption.READ;
+import static java.nio.file.StandardOpenOption.WRITE;
+import java.util.LinkedList;
+import java.util.List;
+import jdk.internal.jimage.BasicImageReader;
+import jdk.internal.jimage.ImageHeader;
+import static jdk.internal.jimage.ImageHeader.MAGIC;
+import static jdk.internal.jimage.ImageHeader.MAJOR_VERSION;
+import static jdk.internal.jimage.ImageHeader.MINOR_VERSION;
+import jdk.internal.jimage.ImageLocation;
+import jdk.tools.jlink.internal.ImageResourcesTree;
+import jdk.tools.jlink.internal.ImagePluginConfiguration;
+import jdk.tools.jlink.internal.ImagePluginStack;
+import jdk.tools.jlink.internal.TaskHelper;
+import jdk.tools.jlink.internal.TaskHelper.BadArgs;
+import static jdk.tools.jlink.internal.TaskHelper.JIMAGE_BUNDLE;
+import jdk.tools.jlink.internal.TaskHelper.Option;
+import jdk.tools.jlink.internal.TaskHelper.OptionsHelper;
+
+class JImageTask {
+
+    static final Option<?>[] recognizedOptions = {
+        new Option<JImageTask>(true, (task, opt, arg) -> {
+            task.options.directory = arg;
+        }, "--dir"),
+        new Option<JImageTask>(false, (task, opt, arg) -> {
+            task.options.fullVersion = true;
+        }, true, "--fullversion"),
+        new Option<JImageTask>(false, (task, opt, arg) -> {
+            task.options.help = true;
+        }, "--help"),
+        new Option<JImageTask>(true, (task, opt, arg) -> {
+            task.options.flags = arg;
+        }, "--flags"),
+        new Option<JImageTask>(false, (task, opt, arg) -> {
+            task.options.verbose = true;
+        }, "--verbose"),
+        new Option<JImageTask>(false, (task, opt, arg) -> {
+            task.options.version = true;
+        }, "--version")
+    };
+    private static final TaskHelper taskHelper
+            = new TaskHelper(JIMAGE_BUNDLE);
+    private static final OptionsHelper<JImageTask> optionsHelper
+            = taskHelper.newOptionsHelper(JImageTask.class, recognizedOptions);
+
+    static class OptionsValues {
+        Task task = Task.LIST;
+        String directory = ".";
+        boolean fullVersion;
+        boolean help;
+        String flags;
+        boolean verbose;
+        boolean version;
+        List<File> jimages = new LinkedList<>();
+    }
+
+    private static final String PROGNAME = "jimage";
+    private final OptionsValues options = new OptionsValues();
+
+    enum Task {
+        EXTRACT,
+        INFO,
+        LIST,
+        RECREATE,
+        SET,
+        VERIFY
+    };
+
+    private String pad(String string, int width, boolean justifyRight) {
+        int length = string.length();
+
+        if (length == width) {
+            return string;
+        }
+
+        if (length > width) {
+            return string.substring(0, width);
+        }
+
+        int padding = width - length;
+
+        StringBuilder sb = new StringBuilder(width);
+        if (justifyRight) {
+            for (int i = 0; i < padding; i++) {
+                sb.append(' ');
+            }
+        }
+
+        sb.append(string);
+
+        if (!justifyRight) {
+            for (int i = 0; i < padding; i++) {
+                sb.append(' ');
+            }
+        }
+
+        return sb.toString();
+    }
+
+    private String pad(String string, int width) {
+        return pad(string, width, false);
+    }
+
+    private String pad(long value, int width) {
+        return pad(Long.toString(value), width, true);
+    }
+
+    private static final int EXIT_OK = 0;        // No errors.
+    private static final int EXIT_ERROR = 1;     // Completed but reported errors.
+    private static final int EXIT_CMDERR = 2;    // Bad command-line arguments and/or switches.
+    private static final int EXIT_SYSERR = 3;    // System error or resource exhaustion.
+    private static final int EXIT_ABNORMAL = 4;  // Terminated abnormally.
+
+    int run(String[] args) {
+        if (log == null) {
+            setLog(new PrintWriter(System.out));
+        }
+
+        try {
+            List<String> unhandled = optionsHelper.handleOptions(this, args);
+            if(!unhandled.isEmpty()) {
+                options.task = Enum.valueOf(Task.class, unhandled.get(0).toUpperCase());
+                for(int i = 1; i < unhandled.size(); i++) {
+                    options.jimages.add(new File(unhandled.get(i)));
+                }
+            }
+            if (options.help) {
+                optionsHelper.showHelp(PROGNAME);
+            }
+            if(optionsHelper.listPlugins()) {
+                optionsHelper.listPlugins(true);
+                return EXIT_OK;
+            }
+            if (options.version || options.fullVersion) {
+                taskHelper.showVersion(options.fullVersion);
+            }
+            boolean ok = run();
+            return ok ? EXIT_OK : EXIT_ERROR;
+        } catch (BadArgs e) {
+            taskHelper.reportError(e.key, e.args);
+            if (e.showUsage) {
+                log.println(taskHelper.getMessage("main.usage.summary", PROGNAME));
+            }
+            return EXIT_CMDERR;
+        } catch (Exception x) {
+            x.printStackTrace();
+            return EXIT_ABNORMAL;
+        } finally {
+            log.flush();
+        }
+    }
+
+    private void recreate() throws Exception, BadArgs {
+        File directory = new File(options.directory);
+        if (!directory.isDirectory()) {
+            throw taskHelper.newBadArgs("err.not.a.dir", directory.getAbsolutePath());
+        }
+        Path dirPath = directory.toPath();
+        if (options.jimages.isEmpty()) {
+            throw taskHelper.newBadArgs("err.jimage.not.specified");
+        } else if (options.jimages.size() != 1) {
+            throw taskHelper.newBadArgs("err.only.one.jimage");
+        }
+
+        Path jimage = options.jimages.get(0).toPath();
+
+        if (jimage.toFile().createNewFile()) {
+            ImagePluginStack pc = ImagePluginConfiguration.parseConfiguration(taskHelper.
+                    getPluginsConfig(null, false));
+            ExtractedImage img = new ExtractedImage(dirPath, pc, log, options.verbose);
+            img.recreateJImage(jimage);
+        } else {
+            throw taskHelper.newBadArgs("err.jimage.already.exists", jimage.getFileName());
+        }
+    }
+
+    private void title(File file, BasicImageReader reader) {
+        log.println("jimage: " + file.getName());
+    }
+
+    private void listTitle(File file, BasicImageReader reader) {
+        title(file, reader);
+
+        if (options.verbose) {
+            log.print(pad("Offset", OFFSET_WIDTH + 1));
+            log.print(pad("Size", SIZE_WIDTH + 1));
+            log.print(pad("Compressed", COMPRESSEDSIZE_WIDTH + 1));
+            log.println(" Entry");
+        }
+    }
+
+    private interface JImageAction {
+        public void apply(File file, BasicImageReader reader) throws IOException, BadArgs;
+    }
+
+    private interface ResourceAction {
+        public void apply(BasicImageReader reader, String name,
+                ImageLocation location) throws IOException, BadArgs;
+    }
+
+    private void extract(BasicImageReader reader, String name,
+            ImageLocation location) throws IOException, BadArgs {
+        File directory = new File(options.directory);
+        byte[] bytes = reader.getResource(location);
+        File resource =  new File(directory, name);
+        File parent = resource.getParentFile();
+
+        if (parent.exists()) {
+            if (!parent.isDirectory()) {
+                throw taskHelper.newBadArgs("err.cannot.create.dir", parent.getAbsolutePath());
+            }
+        } else if (!parent.mkdirs()) {
+            throw taskHelper.newBadArgs("err.cannot.create.dir", parent.getAbsolutePath());
+        }
+
+        if (!ImageResourcesTree.isTreeInfoResource(name)) {
+            Files.write(resource.toPath(), bytes);
+        }
+    }
+
+    private static final int NUMBER_WIDTH = 12;
+    private static final int OFFSET_WIDTH = NUMBER_WIDTH;
+    private static final int SIZE_WIDTH = NUMBER_WIDTH;
+    private static final int COMPRESSEDSIZE_WIDTH = NUMBER_WIDTH;
+
+    private void print(String entry, ImageLocation location) {
+        log.print(pad(location.getContentOffset(), OFFSET_WIDTH) + " ");
+        log.print(pad(location.getUncompressedSize(), SIZE_WIDTH) + " ");
+        log.print(pad(location.getCompressedSize(), COMPRESSEDSIZE_WIDTH) + " ");
+        log.println(entry);
+    }
+
+    private void print(BasicImageReader reader, String entry) {
+        if (options.verbose) {
+            print(entry, reader.findLocation(entry));
+        } else {
+            log.println(entry);
+        }
+    }
+
+    private void info(File file, BasicImageReader reader) throws IOException {
+        ImageHeader header = reader.getHeader();
+
+        log.println(" Major Version:  " + header.getMajorVersion());
+        log.println(" Minor Version:  " + header.getMinorVersion());
+        log.println(" Flags:          " + Integer.toHexString(header.getMinorVersion()));
+        log.println(" Resource Count: " + header.getResourceCount());
+        log.println(" Table Length:   " + header.getTableLength());
+        log.println(" Offsets Size:   " + header.getOffsetsSize());
+        log.println(" Redirects Size: " + header.getRedirectSize());
+        log.println(" Locations Size: " + header.getLocationsSize());
+        log.println(" Strings Size:   " + header.getStringsSize());
+        log.println(" Index Size:     " + header.getIndexSize());
+    }
+
+    private void list(BasicImageReader reader, String name, ImageLocation location) {
+        print(reader, name);
+    }
+
+    void set(File file, BasicImageReader reader) throws BadArgs {
+        try {
+            ImageHeader oldHeader = reader.getHeader();
+
+            int value = 0;
+            try {
+                value = Integer.valueOf(options.flags);
+            } catch (NumberFormatException ex) {
+                throw taskHelper.newBadArgs("err.flags.not.int", options.flags);
+            }
+
+            ImageHeader newHeader = new ImageHeader(MAGIC, MAJOR_VERSION, MINOR_VERSION,
+                    value,
+                    oldHeader.getResourceCount(), oldHeader.getTableLength(),
+                    oldHeader.getLocationsSize(), oldHeader.getStringsSize());
+
+            ByteBuffer buffer = ByteBuffer.allocate(ImageHeader.getHeaderSize());
+            buffer.order(ByteOrder.nativeOrder());
+            newHeader.writeTo(buffer);
+            buffer.rewind();
+
+            try (FileChannel channel = FileChannel.open(file.toPath(), READ, WRITE)) {
+                channel.write(buffer, 0);
+            }
+        } catch (IOException ex) {
+            throw taskHelper.newBadArgs("err.cannot.update.file", file.getName());
+        }
+    }
+
+     void verify(BasicImageReader reader, String name, ImageLocation location) {
+        if (name.endsWith(".class")) {
+            byte[] bytes = reader.getResource(location);
+
+            if (bytes == null || bytes.length <= 4 ||
+                (bytes[0] & 0xFF) != 0xCA ||
+                (bytes[1] & 0xFF) != 0xFE ||
+                (bytes[2] & 0xFF) != 0xBA ||
+                (bytes[3] & 0xFF) != 0xBE) {
+                log.print(" NOT A CLASS: ");
+                print(reader, name);
+            }
+        }
+    }
+
+    private void iterate(JImageAction jimageAction,
+            ResourceAction resourceAction) throws IOException, BadArgs {
+        for (File file : options.jimages) {
+            if (!file.exists() || !file.isFile()) {
+                throw taskHelper.newBadArgs("err.not.a.jimage", file.getName());
+            }
+
+            try (BasicImageReader reader = BasicImageReader.open(file.toPath())) {
+                if (jimageAction != null) {
+                    jimageAction.apply(file, reader);
+                }
+
+                if (resourceAction != null) {
+                    String[] entryNames = reader.getEntryNames();
+
+                    for (String name : entryNames) {
+                        if (!ImageResourcesTree.isTreeInfoResource(name)) {
+                            ImageLocation location = reader.findLocation(name);
+                            resourceAction.apply(reader, name, location);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private boolean run() throws Exception, BadArgs {
+        switch (options.task) {
+            case EXTRACT:
+                iterate(null, this::extract);
+                break;
+            case INFO:
+                iterate(this::info, null);
+                break;
+            case LIST:
+                iterate(this::listTitle, this::list);
+                break;
+            case RECREATE:
+                recreate();
+                break;
+            case SET:
+                iterate(this::set, null);
+                break;
+            case VERIFY:
+                iterate(this::title, this::verify);
+                break;
+            default:
+                throw taskHelper.newBadArgs("err.invalid.task", options.task.name()).showUsage(true);
+        }
+        return true;
+    }
+
+    private PrintWriter log;
+    void setLog(PrintWriter out) {
+        log = out;
+        taskHelper.setLog(log);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jimage/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jimage;
+
+import java.io.PrintWriter;
+
+
+public class Main {
+    public static void main(String[] args) throws Exception {
+        JImageTask t = new JImageTask();
+        int rc = t.run(args);
+        System.exit(rc);
+    }
+
+    /**
+     * Entry point that does <i>not</i> call System.exit.
+     *
+     * @param args command line arguments
+     * @param out output stream
+     * @return an exit code. 0 means success, non-zero means an error occurred.
+     */
+    public static int run(String[] args, PrintWriter out) {
+        JImageTask t = new JImageTask();
+        t.setLog(out);
+        return t.run(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jimage/resources/jimage.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,64 @@
+main.usage.summary=\
+Usage: {0} <extract|info|list|recreate|set|verify> <options> jimage...\n\
+use --help for a list of possible options
+
+main.usage=\
+Usage: {0} <extract|info|list|recreate|set|verify> <options> jimage...\n\
+\n\
+\  extract  - Extract all jimage entries into separate files into the directory\n\
+\             specified by --dir=<directory> (default='.')\n\
+\  info     - Prints information specified in the jimage header.\n\
+\  list     - Prints the names of all the entries in the jimage.  When used with\n\
+\             --verbose will also print entry attributes ex. size and offset.\n\
+\  recreate - Reconstructs a jimage from an extracted directory (--dir)\n\
+\  set      - sets the value of specific jimage header entries\n\
+\  verify   - Reports errors on any .class entries that don't verify as classes.\n\
+\n\
+Possible options include:
+
+main.extended.help=\
+jimage recreate is extensible by the main of plugins. Following plugins have been discovered \
+thanks to ServiceLoader and can be used when re-creating a jimage.
+
+error.prefix=Error:
+warn.prefix=Warning:
+
+main.opt.dir=\
+\  --dir                                Target directory for extract/recreate
+
+main.opt.flags=\
+\  --flags=value                        Set the jimage flags to value
+
+main.opt.help=\
+\  --help                               Print this usage message
+
+main.opt.verbose=\
+\  --verbose                            Verbose listing
+
+main.opt.version=\
+\  --version                            Version information
+
+main.opt.configuration=\
+\  --configuration <path>               Path to properties file containing defaults\
+\ options for recreate
+
+main.command.files=\
+\  @<filename>                          Read options from file
+
+err.cannot.create.dir=cannot create directory: {0}
+err.cannot.read.file=cannot read file: {0}
+err.cannot.update.file=cannot update file: {0}
+err.file.not.found=cannot find file: {0}
+err.file.error=cannot access file: {0}
+err.flags.not.int=--flags value not integer: {0}
+err.internal.error=internal error: {0} {1} {2}
+err.invalid.arg.for.option=invalid argument for option: {0}
+err.invalid.task=task must be extract|recreate|info|list|verify: {0}
+err.jimage.already.exists=jimage already exists: {0}
+err.jimage.not.specified=no jimage specified
+err.missing.arg=no value given for {0}
+err.not.a.dir=not a directory: {0}
+err.not.a.jimage=not a jimage file: {0}
+err.only.one.jimage=only one jimage should be specified
+err.option.unsupported={0} not supported: {1}
+err.unknown.option=unknown option: {0}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/Jlink.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink;
+
+import java.lang.reflect.Layer;
+import java.nio.ByteOrder;
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import jdk.tools.jlink.internal.JlinkTask;
+import jdk.tools.jlink.plugin.Plugin;
+import jdk.tools.jlink.plugin.PluginContext;
+import jdk.tools.jlink.plugin.PluginException;
+import jdk.tools.jlink.plugin.ExecutableImage;
+import jdk.tools.jlink.builder.ImageBuilder;
+import jdk.tools.jlink.internal.PluginContextImpl;
+import jdk.tools.jlink.internal.PluginRepository;
+
+/**
+ * API to call jlink.
+ */
+public final class Jlink {
+
+    /**
+     * Create a plugin.
+     *
+     * @param name Plugin name
+     * @param configuration Plugin configuration.
+     * @param pluginsLayer Plugins Layer. null means boot layer.
+     * @return A new plugin or null if plugin is unknown.
+     */
+    public static Plugin newPlugin(String name,
+            Map<String, String> configuration, Layer pluginsLayer) {
+        Objects.requireNonNull(name);
+        Objects.requireNonNull(configuration);
+        pluginsLayer = pluginsLayer == null ? Layer.boot() : pluginsLayer;
+        return PluginRepository.newPlugin(configuration, name, pluginsLayer);
+    }
+
+    /**
+     * A complete plugin configuration. Instances of this class are used to
+     * configure jlink.
+     */
+    public static final class PluginsConfiguration {
+
+        private final List<Plugin> plugins;
+        private final ImageBuilder imageBuilder;
+        private final String lastSorterPluginName;
+        private final PluginContext pluginContext;
+
+        /**
+         * Empty plugins configuration.
+         */
+        public PluginsConfiguration() {
+            this(Collections.emptyList());
+        }
+
+        /**
+         * Plugins configuration.
+         *
+         * @param plugins List of plugins.
+         */
+        public PluginsConfiguration(List<Plugin> plugins) {
+            this(plugins, null, null, null);
+        }
+
+        /**
+         * Plugins configuration with a last sorter and an ImageBuilder. No
+         * sorting can occur after the last sorter plugin. The ImageBuilder is
+         * in charge to layout the image content on disk.
+         *
+         * @param plugins List of transformer plugins.
+         * @param imageBuilder Image builder.
+         * @param lastSorterPluginName Name of last sorter plugin, no sorting
+         * can occur after it.
+         */
+        public PluginsConfiguration(List<Plugin> plugins,
+                ImageBuilder imageBuilder, String lastSorterPluginName) {
+            this(plugins, imageBuilder, lastSorterPluginName, null);
+        }
+
+        /**
+         * Plugins configuration with a last sorter and an ImageBuilder. No
+         * sorting can occur after the last sorter plugin. The ImageBuilder is
+         * in charge to layout the image content on disk.
+         *
+         * @param plugins List of transformer plugins.
+         * @param imageBuilder Image builder.
+         * @param lastSorterPluginName Name of last sorter plugin, no sorting
+         * @param ctx the plugin context
+         * can occur after it.
+         */
+        public PluginsConfiguration(List<Plugin> plugins,
+                ImageBuilder imageBuilder, String lastSorterPluginName,
+                PluginContext ctx) {
+            this.plugins = plugins == null ? Collections.emptyList()
+                    : plugins;
+            this.imageBuilder = imageBuilder;
+            this.lastSorterPluginName = lastSorterPluginName;
+            this.pluginContext = ctx != null? ctx : new PluginContextImpl();
+        }
+
+        /**
+         * @return the plugins
+         */
+        public List<Plugin> getPlugins() {
+            return plugins;
+        }
+
+        /**
+         * @return the imageBuilder
+         */
+        public ImageBuilder getImageBuilder() {
+            return imageBuilder;
+        }
+
+        /**
+         * @return the lastSorterPluginName
+         */
+        public String getLastSorterPluginName() {
+            return lastSorterPluginName;
+        }
+
+        /**
+         * @return the pluginContext
+         */
+        public PluginContext getPluginContext() {
+            return pluginContext;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder builder = new StringBuilder();
+            builder.append("imagebuilder=").append(imageBuilder).append("\n");
+            StringBuilder pluginsBuilder = new StringBuilder();
+            for (Plugin p : plugins) {
+                pluginsBuilder.append(p).append(",");
+            }
+            builder.append("plugins=").append(pluginsBuilder).append("\n");
+            builder.append("lastsorter=").append(lastSorterPluginName).append("\n");
+
+            return builder.toString();
+        }
+    }
+
+    /**
+     * Jlink configuration. Instances of this class are used to configure jlink.
+     */
+    public static final class JlinkConfiguration {
+
+        private final List<Path> modulepaths;
+        private final Path output;
+        private final Set<String> modules;
+        private final Set<String> limitmods;
+
+        private final ByteOrder endian;
+
+        /**
+         * jlink configuration,
+         *
+         * @param output Output directory, must not exist.
+         * @param modulepaths Modules paths
+         * @param modules Root modules to resolve
+         * @param limitmods Limit the universe of observable modules
+         * @param endian Jimage byte order. Native order by default
+         */
+        public JlinkConfiguration(Path output,
+                List<Path> modulepaths,
+                Set<String> modules,
+                Set<String> limitmods,
+                ByteOrder endian) {
+            this.output = output;
+            this.modulepaths = modulepaths == null ? Collections.emptyList() : modulepaths;
+            this.modules = modules == null ? Collections.emptySet() : modules;
+            this.limitmods = limitmods == null ? Collections.emptySet() : limitmods;
+            this.endian = endian == null ? ByteOrder.nativeOrder() : endian;
+        }
+
+        /**
+         * jlink configuration,
+         *
+         * @param output Output directory, must not exist.
+         * @param modulepaths Modules paths
+         * @param modules Root modules to resolve
+         * @param limitmods Limit the universe of observable modules
+         */
+        public JlinkConfiguration(Path output,
+                List<Path> modulepaths,
+                Set<String> modules,
+                Set<String> limitmods) {
+            this(output, modulepaths, modules, limitmods,
+                    ByteOrder.nativeOrder());
+        }
+
+        /**
+         * @return the modulepaths
+         */
+        public List<Path> getModulepaths() {
+            return modulepaths;
+        }
+
+        /**
+         * @return the byte ordering
+         */
+        public ByteOrder getByteOrder() {
+            return endian;
+        }
+
+        /**
+         * @return the output
+         */
+        public Path getOutput() {
+            return output;
+        }
+
+        /**
+         * @return the modules
+         */
+        public Set<String> getModules() {
+            return modules;
+        }
+
+        /**
+         * @return the limitmods
+         */
+        public Set<String> getLimitmods() {
+            return limitmods;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder builder = new StringBuilder();
+
+            builder.append("output=").append(output).append("\n");
+            StringBuilder pathsBuilder = new StringBuilder();
+            for (Path p : modulepaths) {
+                pathsBuilder.append(p).append(",");
+            }
+            builder.append("modulepaths=").append(pathsBuilder).append("\n");
+
+            StringBuilder modsBuilder = new StringBuilder();
+            for (String p : modules) {
+                modsBuilder.append(p).append(",");
+            }
+            builder.append("modules=").append(modsBuilder).append("\n");
+
+            StringBuilder limitsBuilder = new StringBuilder();
+            for (String p : limitmods) {
+                limitsBuilder.append(p).append(",");
+            }
+            builder.append("limitmodules=").append(limitsBuilder).append("\n");
+            builder.append("endian=").append(endian).append("\n");
+            return builder.toString();
+        }
+    }
+
+    /**
+     * Jlink instance constructor, if a security manager is set, the jlink
+     * permission is checked.
+     */
+    public Jlink() {
+        if (System.getSecurityManager() != null) {
+            System.getSecurityManager().
+                    checkPermission(new JlinkPermission("jlink"));
+        }
+    }
+
+    /**
+     * Build the image.
+     *
+     * @param config Jlink config, must not be null.
+     * @throws PluginException
+     */
+    public void build(JlinkConfiguration config) {
+        build(config, null);
+    }
+
+    /**
+     * Build the image with a plugin configuration.
+     *
+     * @param config Jlink config, must not be null.
+     * @param pluginsConfig Plugins config, can be null
+     * @throws PluginException
+     */
+    public void build(JlinkConfiguration config, PluginsConfiguration pluginsConfig) {
+        Objects.requireNonNull(config);
+        try {
+            JlinkTask.createImage(config, pluginsConfig);
+        } catch (Exception ex) {
+            throw new PluginException(ex);
+        }
+    }
+
+    /**
+     * Post process the image with a plugin configuration.
+     *
+     * @param image Existing image.
+     * @param plugins Plugins cannot be null
+     */
+    public void postProcess(ExecutableImage image, List<Plugin> plugins) {
+        Objects.requireNonNull(image);
+        Objects.requireNonNull(plugins);
+        try {
+            JlinkTask.postProcessImage(image, plugins);
+        } catch (Exception ex) {
+            throw new PluginException(ex);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/JlinkPermission.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink;
+
+import java.security.BasicPermission;
+
+/**
+ * The permission required to use jlink API. The permission target_name is
+ * "jlink". e.g.: permission jdk.tools.jlink.plugins.JlinkPermission "jlink";
+ *
+ */
+public final class JlinkPermission extends BasicPermission {
+
+    private static final long serialVersionUID = -3687912306077727801L;
+
+    public JlinkPermission(String name) {
+        super(name);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/DefaultImageBuilder.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.builder;
+
+import jdk.tools.jlink.plugin.ExecutableImage;
+import jdk.tools.jlink.plugin.PluginException;
+import java.io.BufferedOutputStream;
+import java.io.BufferedWriter;
+import java.io.ByteArrayInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UncheckedIOException;
+import java.io.Writer;
+import java.lang.module.ModuleDescriptor;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import java.nio.file.attribute.PosixFileAttributeView;
+import java.nio.file.attribute.PosixFilePermission;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Properties;
+import java.util.Set;
+import jdk.tools.jlink.internal.BasicImageWriter;
+import jdk.tools.jlink.internal.plugins.FileCopierPlugin;
+import jdk.tools.jlink.internal.plugins.FileCopierPlugin.SymImageFile;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Pool.Module;
+import jdk.tools.jlink.plugin.Pool.ModuleData;
+
+/**
+ *
+ * Default Image Builder. This builder creates the default runtime image layout.
+ */
+public class DefaultImageBuilder implements ImageBuilder {
+
+    /**
+     * The default java executable Image.
+     */
+    static class DefaultExecutableImage extends ExecutableImage {
+
+        public DefaultExecutableImage(Path home, Set<String> modules) {
+            super(home, modules, createArgs(home));
+        }
+
+        private static List<String> createArgs(Path home) {
+            Objects.requireNonNull(home);
+            List<String> javaArgs = new ArrayList<>();
+            javaArgs.add(home.resolve("bin").
+                    resolve(getJavaProcessName()).toString());
+            return javaArgs;
+        }
+
+        @Override
+        public void storeLaunchArgs(List<String> args) {
+            try {
+                patchScripts(this, args);
+            } catch (IOException ex) {
+                throw new UncheckedIOException(ex);
+            }
+        }
+    }
+
+    private final Path root;
+    private final Path mdir;
+    private final boolean genBom;
+    private final Set<String> modules = new HashSet<>();
+
+    /**
+     * Default image builder constructor.
+     *
+     * @param genBom true, generates a bom file.
+     * @param root The image root directory.
+     * @throws IOException
+     */
+    public DefaultImageBuilder(boolean genBom, Path root) throws IOException {
+        Objects.requireNonNull(root);
+
+        this.genBom = genBom;
+
+        this.root = root;
+        this.mdir = root.resolve("lib");
+        Files.createDirectories(mdir);
+    }
+
+    private void storeFiles(Set<String> modules, String bom, Properties release) throws IOException {
+        if (release != null) {
+            addModules(release, modules);
+            File r = new File(root.toFile(), "release");
+            try (FileOutputStream fo = new FileOutputStream(r)) {
+                release.store(fo, null);
+            }
+        }
+        // Generate bom
+        if (genBom) {
+            File bomFile = new File(root.toFile(), "bom");
+            createUtf8File(bomFile, bom);
+        }
+    }
+
+    private void addModules(Properties release, Set<String> modules) throws IOException {
+        StringBuilder builder = new StringBuilder();
+        int i = 0;
+        for (String m : modules) {
+            builder.append(m);
+            if (i < modules.size() - 1) {
+                builder.append(",");
+            }
+            i++;
+        }
+        release.setProperty("MODULES", builder.toString());
+    }
+
+    @Override
+    public void storeFiles(Pool files, String bom, Properties release) {
+        try {
+            for (ModuleData f : files.getContent()) {
+               if (!f.getType().equals(Pool.ModuleDataType.CLASS_OR_RESOURCE)) {
+                    accept(f);
+                }
+            }
+            for (Module m : files.getModules()) {
+                // Only add modules that contain packages
+                if (!m.getAllPackages().isEmpty()) {
+                    // Skip the fake module used by FileCopierPlugin when copying files.
+                    if (m.getName().equals(FileCopierPlugin.FAKE_MODULE)) {
+                       continue;
+                    }
+                    modules.add(m.getName());
+                }
+            }
+            storeFiles(modules, bom, release);
+
+            if (Files.getFileStore(root).supportsFileAttributeView(PosixFileAttributeView.class)) {
+                // launchers in the bin directory need execute permission
+                Path bin = root.resolve("bin");
+                if (Files.isDirectory(bin)) {
+                    Files.list(bin)
+                            .filter(f -> !f.toString().endsWith(".diz"))
+                            .filter(f -> Files.isRegularFile(f))
+                            .forEach(this::setExecutable);
+                }
+
+                // jspawnhelper is in lib or lib/<arch>
+                Path lib = root.resolve("lib");
+                if (Files.isDirectory(lib)) {
+                    Files.find(lib, 2, (path, attrs) -> {
+                        return path.getFileName().toString().equals("jspawnhelper") ||
+                               path.getFileName().toString().equals("jexec");
+                    }).forEach(this::setExecutable);
+                }
+            }
+
+            prepareApplicationFiles(files, modules);
+        } catch (IOException ex) {
+            throw new PluginException(ex);
+        }
+    }
+
+    @Override
+    public void storeFiles(Pool files, String bom) {
+        storeFiles(files, bom, new Properties());
+    }
+
+    /**
+     * Generates launcher scripts.
+     * @param imageContent The image content.
+     * @param modules The set of modules that the runtime image contains.
+     * @throws IOException
+     */
+    protected void prepareApplicationFiles(Pool imageContent, Set<String> modules) throws IOException {
+        // generate launch scripts for the modules with a main class
+        for (String module : modules) {
+            String path = "/" + module + "/module-info.class";
+            ModuleData res = imageContent.get(path);
+            if (res == null) {
+                throw new IOException("module-info.class not found for " + module + " module");
+            }
+            Optional<String> mainClass;
+            ByteArrayInputStream stream = new ByteArrayInputStream(res.getBytes());
+            mainClass = ModuleDescriptor.read(stream).mainClass();
+            if (mainClass.isPresent()) {
+                Path cmd = root.resolve("bin").resolve(module);
+                if (!Files.exists(cmd)) {
+                    StringBuilder sb = new StringBuilder();
+                    sb.append("#!/bin/sh")
+                            .append("\n");
+                    sb.append("JLINK_VM_OPTIONS=")
+                            .append("\n");
+                    sb.append("DIR=`dirname $0`")
+                            .append("\n");
+                    sb.append("$DIR/java $JLINK_VM_OPTIONS -m ")
+                            .append(module).append('/')
+                            .append(mainClass.get())
+                            .append(" $@\n");
+
+                    try (BufferedWriter writer = Files.newBufferedWriter(cmd,
+                            StandardCharsets.ISO_8859_1,
+                            StandardOpenOption.CREATE_NEW)) {
+                        writer.write(sb.toString());
+                    }
+                    if (Files.getFileStore(root.resolve("bin"))
+                            .supportsFileAttributeView(PosixFileAttributeView.class)) {
+                        setExecutable(cmd);
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    public DataOutputStream getJImageOutputStream() {
+        try {
+            Path jimageFile = mdir.resolve(BasicImageWriter.MODULES_IMAGE_NAME);
+            OutputStream fos = Files.newOutputStream(jimageFile);
+            BufferedOutputStream bos = new BufferedOutputStream(fos);
+            return new DataOutputStream(bos);
+        } catch (IOException ex) {
+            throw new UncheckedIOException(ex);
+        }
+    }
+
+    private void accept(ModuleData file) throws IOException {
+        String fullPath = file.getPath();
+        String module = "/" + file.getModule()+ "/";
+        String filename = fullPath.substring(module.length());
+        // Remove radical native|config|...
+        filename = filename.substring(filename.indexOf('/') + 1);
+        try (InputStream in = file.stream()) {
+            switch (file.getType()) {
+                case NATIVE_LIB:
+                    writeEntry(in, destFile(nativeDir(filename), filename));
+                    break;
+                case NATIVE_CMD:
+                    Path path = destFile("bin", filename);
+                    writeEntry(in, path);
+                    path.toFile().setExecutable(true);
+                    break;
+                case CONFIG:
+                    writeEntry(in, destFile("conf", filename));
+                    break;
+                case OTHER:
+                    if (file instanceof SymImageFile) {
+                        SymImageFile sym = (SymImageFile) file;
+                        Path target = root.resolve(sym.getTargetPath());
+                        if (!Files.exists(target)) {
+                            throw new IOException("Sym link target " + target
+                                    + " doesn't exist");
+                        }
+                        writeSymEntry(root.resolve(filename), target);
+                    } else {
+                        writeEntry(in, root.resolve(filename));
+                    }
+                    break;
+                default:
+                    throw new InternalError("unexpected entry: " + fullPath);
+            }
+        }
+    }
+
+    private Path destFile(String dir, String filename) {
+        return root.resolve(dir).resolve(filename);
+    }
+
+    private void writeEntry(InputStream in, Path dstFile) throws IOException {
+        Objects.requireNonNull(in);
+        Objects.requireNonNull(dstFile);
+        Files.createDirectories(Objects.requireNonNull(dstFile.getParent()));
+        Files.copy(in, dstFile);
+    }
+
+    private void writeSymEntry(Path dstFile, Path target) throws IOException {
+        Objects.requireNonNull(dstFile);
+        Objects.requireNonNull(target);
+        Files.createDirectories(Objects.requireNonNull(dstFile.getParent()));
+        Files.createLink(dstFile, target);
+    }
+
+    private static String nativeDir(String filename) {
+        if (isWindows()) {
+            if (filename.endsWith(".dll") || filename.endsWith(".diz")
+                    || filename.endsWith(".pdb") || filename.endsWith(".map")) {
+                return "bin";
+            } else {
+                return "lib";
+            }
+        } else {
+            return "lib";
+        }
+    }
+
+    private static boolean isWindows() {
+        return System.getProperty("os.name").startsWith("Windows");
+    }
+
+    /**
+     * chmod ugo+x file
+     */
+    private void setExecutable(Path file) {
+        try {
+            Set<PosixFilePermission> perms = Files.getPosixFilePermissions(file);
+            perms.add(PosixFilePermission.OWNER_EXECUTE);
+            perms.add(PosixFilePermission.GROUP_EXECUTE);
+            perms.add(PosixFilePermission.OTHERS_EXECUTE);
+            Files.setPosixFilePermissions(file, perms);
+        } catch (IOException ioe) {
+            throw new UncheckedIOException(ioe);
+        }
+    }
+
+    private static void createUtf8File(File file, String content) throws IOException {
+        try (OutputStream fout = new FileOutputStream(file);
+                Writer output = new OutputStreamWriter(fout, "UTF-8")) {
+            output.write(content);
+        }
+    }
+
+    @Override
+    public ExecutableImage getExecutableImage() {
+        return new DefaultExecutableImage(root, modules);
+    }
+
+    // This is experimental, we should get rid-off the scripts in a near future
+    private static void patchScripts(ExecutableImage img, List<String> args) throws IOException {
+        Objects.requireNonNull(args);
+        if (!args.isEmpty()) {
+            Files.find(img.getHome().resolve("bin"), 2, (path, attrs) -> {
+                return img.getModules().contains(path.getFileName().toString());
+            }).forEach((p) -> {
+                try {
+                    String pattern = "JLINK_VM_OPTIONS=";
+                    byte[] content = Files.readAllBytes(p);
+                    String str = new String(content, StandardCharsets.UTF_8);
+                    int index = str.indexOf(pattern);
+                    StringBuilder builder = new StringBuilder();
+                    if (index != -1) {
+                        builder.append(str.substring(0, index)).
+                                append(pattern);
+                        for (String s : args) {
+                            builder.append(s).append(" ");
+                        }
+                        String remain = str.substring(index + pattern.length());
+                        builder.append(remain);
+                        str = builder.toString();
+                        try (BufferedWriter writer = Files.newBufferedWriter(p,
+                                StandardCharsets.ISO_8859_1,
+                                StandardOpenOption.WRITE)) {
+                            writer.write(str);
+                        }
+                    }
+                } catch (IOException ex) {
+                    throw new RuntimeException(ex);
+                }
+            });
+        }
+    }
+
+    private static String getJavaProcessName() {
+        return isWindows() ? "java.exe" : "java";
+    }
+
+    public static ExecutableImage getExecutableImage(Path root) {
+        if (Files.exists(root.resolve("bin").resolve(getJavaProcessName()))) {
+            return new DefaultImageBuilder.DefaultExecutableImage(root,
+                    retrieveModules(root));
+        }
+        return null;
+    }
+
+    private static Set<String> retrieveModules(Path root) {
+        Path releaseFile = root.resolve("release");
+        Set<String> modules = new HashSet<>();
+        if (Files.exists(releaseFile)) {
+            Properties release = new Properties();
+            try (FileInputStream fi = new FileInputStream(releaseFile.toFile())) {
+                release.load(fi);
+            } catch (IOException ex) {
+                System.err.println("Can't read release file " + ex);
+            }
+            String mods = release.getProperty("MODULES");
+            if (mods != null) {
+                String[] arr = mods.split(",");
+                for (String m : arr) {
+                    modules.add(m.trim());
+                }
+
+            }
+        }
+        return modules;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/ImageBuilder.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.builder;
+
+import java.io.DataOutputStream;
+import java.util.Properties;
+
+import jdk.tools.jlink.plugin.ExecutableImage;
+import jdk.tools.jlink.plugin.PluginException;
+import jdk.tools.jlink.plugin.Pool;
+
+/**
+ * Implement this interface to develop your own image layout. First the jimage
+ * is written onto the output stream returned by getOutputStream then storeFiles
+ * is called.
+ */
+public interface ImageBuilder {
+
+    /**
+     * Store the external files.
+     *
+     * @param content Pool of module content.
+     * @param bom The options used to build the image file.
+     * @param release the release properties
+     * @throws PluginException
+     */
+    public default void storeFiles(Pool content, String bom, Properties release) {
+        storeFiles(content, bom);
+    }
+
+    /**
+     * Store the external files.
+     *
+     * @param content Pool of module content.
+     * @param bom The options used to build the image file.
+     * @throws PluginException
+     */
+    public default void storeFiles(Pool content, String bom) {
+        throw new UnsupportedOperationException("storeFiles");
+    }
+
+    /**
+     * The OutputStream to store the jimage file.
+     *
+     * @return The output stream
+     * @throws PluginException
+     */
+    public DataOutputStream getJImageOutputStream();
+
+    /**
+     * Gets the executable image that is generated.
+     *
+     * @return The executable image.
+     * @throws PluginException
+     */
+    public ExecutableImage getExecutableImage();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Archive.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Path;
+import java.util.Objects;
+import java.util.stream.Stream;
+
+/**
+ * An Archive of all content, classes, resources, configuration files, and
+ * other, for a module.
+ */
+public interface Archive {
+
+    /**
+     * Entry is contained in an Archive
+     */
+    public abstract class Entry {
+
+        public static enum EntryType {
+
+            MODULE_NAME,
+            CLASS_OR_RESOURCE,
+            NATIVE_LIB,
+            NATIVE_CMD,
+            CONFIG,
+            SERVICE;
+        }
+
+        private final String name;
+        private final EntryType type;
+        private final Archive archive;
+        private final String path;
+
+        public Entry(Archive archive, String path, String name, EntryType type) {
+            Objects.requireNonNull(archive);
+            Objects.requireNonNull(path);
+            Objects.requireNonNull(name);
+            Objects.requireNonNull(type);
+            this.archive = archive;
+            this.path = path;
+            this.name = name;
+            this.type = type;
+        }
+
+        public Archive archive() {
+            return archive;
+        }
+
+        public String path() {
+            return path;
+        }
+
+        public EntryType type() {
+            return type;
+        }
+
+        /**
+         * Returns the name of this entry.
+         */
+        public String name() {
+            return name;
+        }
+
+        @Override
+        public String toString() {
+            return "type " + type.name() + " path " + path;
+        }
+
+        /**
+         * Returns the number of uncompressed bytes for this entry.
+         */
+        public abstract long size();
+
+        public abstract InputStream stream() throws IOException;
+    }
+
+    /**
+     * The module name.
+     */
+    String moduleName();
+
+    /**
+     * Returns the path to this module's content
+     */
+    Path getPath();
+
+    /**
+     * Stream of Entry.
+     * The stream of entries needs to be closed after use
+     * since it might cover lazy I/O based resources.
+     * So callers need to use a try-with-resources block.
+     */
+    Stream<Entry> entries();
+
+    /**
+     * Open the archive
+     */
+    void open() throws IOException;
+
+    /**
+     * Close the archive
+     */
+    void close() throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/BasicImageWriter.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+*/
+
+package jdk.tools.jlink.internal;
+
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.List;
+import jdk.internal.jimage.ImageHeader;
+import jdk.internal.jimage.ImageStream;
+import jdk.internal.jimage.ImageStringsReader;
+
+public final class BasicImageWriter {
+    public static final String MODULES_IMAGE_NAME = "modules";
+
+    private final static int RETRY_LIMIT = 1000;
+
+    private ByteOrder byteOrder;
+    private ImageStringsWriter strings;
+    private int length;
+    private int[] redirect;
+    private ImageLocationWriter[] locations;
+    private List<ImageLocationWriter> input;
+    private ImageStream headerStream;
+    private ImageStream redirectStream;
+    private ImageStream locationOffsetStream;
+    private ImageStream locationStream;
+    private ImageStream allIndexStream;
+
+    public BasicImageWriter() {
+        this(ByteOrder.nativeOrder());
+    }
+
+    public BasicImageWriter(ByteOrder byteOrder) {
+        this.byteOrder = byteOrder;
+        this.input = new ArrayList<>();
+        this.strings = new ImageStringsWriter();
+        this.headerStream = new ImageStream(byteOrder);
+        this.redirectStream = new ImageStream(byteOrder);
+        this.locationOffsetStream = new ImageStream(byteOrder);
+        this.locationStream = new ImageStream(byteOrder);
+        this.allIndexStream = new ImageStream(byteOrder);
+    }
+
+    public ByteOrder getByteOrder() {
+        return byteOrder;
+    }
+
+    public int addString(String string) {
+        return strings.add(string);
+    }
+
+    public String getString(int offset) {
+        return strings.get(offset);
+    }
+
+    public void addLocation(String fullname, long contentOffset,
+            long compressedSize, long uncompressedSize) {
+        ImageLocationWriter location =
+                ImageLocationWriter.newLocation(fullname, strings,
+                        contentOffset, compressedSize, uncompressedSize);
+        input.add(location);
+        length++;
+    }
+
+    ImageLocationWriter[] getLocations() {
+        return locations;
+    }
+
+    int getLocationsCount() {
+        return input.size();
+    }
+
+    private void generatePerfectHash() {
+        PerfectHashBuilder<ImageLocationWriter> builder =
+            new PerfectHashBuilder<>(
+                        PerfectHashBuilder.Entry.class, // PerfectHashBuilder.Entry<ImageLocationWriter>().getClass()
+                        PerfectHashBuilder.Bucket.class); // PerfectHashBuilder.Bucket<ImageLocationWriter>().getClass()
+
+        input.forEach((location) -> {
+            builder.put(location.getFullName(), location);
+        });
+
+        builder.generate();
+
+        length = builder.getCount();
+        redirect = builder.getRedirect();
+        PerfectHashBuilder.Entry<ImageLocationWriter>[] order = builder.getOrder();
+        locations = new ImageLocationWriter[length];
+
+        for (int i = 0; i < length; i++) {
+            locations[i] = order[i].getValue();
+        }
+    }
+
+    private void prepareStringBytes() {
+        strings.getStream().align(2);
+    }
+
+    private void prepareRedirectBytes() {
+        for (int i = 0; i < length; i++) {
+            redirectStream.putInt(redirect[i]);
+        }
+    }
+
+    private void prepareLocationBytes() {
+        // Reserve location offset zero for empty locations
+        locationStream.put(ImageLocationWriter.ATTRIBUTE_END << 3);
+
+        for (int i = 0; i < length; i++) {
+            ImageLocationWriter location = locations[i];
+
+            if (location != null) {
+                location.writeTo(locationStream);
+            }
+        }
+
+        locationStream.align(2);
+    }
+
+    private void prepareOffsetBytes() {
+        for (int i = 0; i < length; i++) {
+            ImageLocationWriter location = locations[i];
+            int offset = location != null ? location.getLocationOffset() : 0;
+            locationOffsetStream.putInt(offset);
+        }
+    }
+
+    private void prepareHeaderBytes() {
+        ImageHeader header = new ImageHeader(input.size(), length,
+                locationStream.getSize(), strings.getSize());
+        header.writeTo(headerStream);
+    }
+
+    private void prepareTableBytes() {
+        allIndexStream.put(headerStream);
+        allIndexStream.put(redirectStream);
+        allIndexStream.put(locationOffsetStream);
+        allIndexStream.put(locationStream);
+        allIndexStream.put(strings.getStream());
+    }
+
+    public byte[] getBytes() {
+        if (allIndexStream.getSize() == 0) {
+            generatePerfectHash();
+            prepareStringBytes();
+            prepareRedirectBytes();
+            prepareLocationBytes();
+            prepareOffsetBytes();
+            prepareHeaderBytes();
+            prepareTableBytes();
+        }
+
+        return allIndexStream.toArray();
+    }
+
+    ImageLocationWriter find(String key) {
+        int index = redirect[ImageStringsReader.hashCode(key) % length];
+
+        if (index < 0) {
+            index = -index - 1;
+        } else {
+            index = ImageStringsReader.hashCode(key, index) % length;
+        }
+
+        return locations[index];
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/DirArchive.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+
+/**
+ * An Archive backed by a directory.
+ */
+public class DirArchive implements Archive {
+
+    /**
+     * A File located in a Directory.
+     */
+    private class FileEntry extends Archive.Entry {
+
+        private final long size;
+        private final Path path;
+
+        FileEntry(Path path, String name) {
+            super(DirArchive.this, getPathName(path), name,
+                    Archive.Entry.EntryType.CLASS_OR_RESOURCE);
+            this.path = path;
+            try {
+                size = Files.size(path);
+            } catch (IOException ex) {
+                throw new RuntimeException(ex);
+            }
+        }
+
+        /**
+         * Returns the number of bytes of this file.
+         */
+        @Override
+        public long size() {
+            return size;
+        }
+
+        @Override
+        public InputStream stream() throws IOException {
+            InputStream stream = Files.newInputStream(path);
+            open.add(stream);
+            return stream;
+        }
+    }
+
+    private static final String MODULE_INFO = "module-info.class";
+
+    private final Path dirPath;
+    private final String moduleName;
+    private final List<InputStream> open = new ArrayList<>();
+    private final int chop;
+    private final Consumer<String> log;
+    private static final Consumer<String> noopConsumer = (String t) -> {
+    };
+
+    public DirArchive(Path dirPath) {
+        this(dirPath, noopConsumer);
+    }
+
+    public DirArchive(Path dirPath, Consumer<String> log) {
+        Objects.requireNonNull(dirPath);
+        if (!Files.isDirectory(dirPath)) {
+            throw new IllegalArgumentException("Not a directory");
+        }
+        chop = dirPath.toString().length() + 1;
+        this.moduleName = Objects.requireNonNull(dirPath.getFileName()).toString();
+        this.dirPath = dirPath;
+        this.log = log;
+    }
+
+    @Override
+    public String moduleName() {
+        return moduleName;
+    }
+
+    @Override
+    public Path getPath() {
+        return dirPath;
+    }
+
+    @Override
+    public Stream<Entry> entries() {
+        Stream<Entry> ret = null;
+        try {
+            ret = Files.walk(dirPath).map(this::toEntry).filter(n -> n != null);
+        } catch (IOException ex) {
+            throw new RuntimeException(ex);
+        }
+        return ret;
+    }
+
+    private Archive.Entry toEntry(Path p) {
+        if (Files.isDirectory(p)) {
+            return null;
+        }
+        String name = getPathName(p).substring(chop);
+        if (name.startsWith("_")) {
+            return null;
+        }
+        log.accept(moduleName + "/" + name);
+        if (name.equals(MODULE_INFO)) {
+            name = moduleName + "/" + MODULE_INFO;
+        }
+        return new FileEntry(p, name);
+    }
+
+    @Override
+    public void close() throws IOException {
+        IOException e = null;
+        for (InputStream stream : open) {
+            try {
+                stream.close();
+            } catch (IOException ex) {
+                if (e == null) {
+                    e = ex;
+                } else {
+                    e.addSuppressed(ex);
+                }
+            }
+        }
+        if (e != null) {
+            throw e;
+        }
+    }
+
+    @Override
+    public void open() throws IOException {
+        // NOOP
+    }
+
+    private static String getPathName(Path path) {
+        return path.toString().replace(File.separatorChar, '/');
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageFileCreator.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,370 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal;
+
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteOrder;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import jdk.tools.jlink.internal.Archive.Entry;
+import jdk.tools.jlink.internal.Archive.Entry.EntryType;
+import jdk.tools.jlink.internal.PoolImpl.CompressedModuleData;
+import jdk.tools.jlink.plugin.ExecutableImage;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.Pool.ModuleDataType;
+
+/**
+ * An image (native endian.)
+ * <pre>{@code
+ * {
+ *   u4 magic;
+ *   u2 major_version;
+ *   u2 minor_version;
+ *   u4 resource_count;
+ *   u4 table_length;
+ *   u4 location_attributes_size;
+ *   u4 strings_size;
+ *   u4 redirect[table_length];
+ *   u4 offsets[table_length];
+ *   u1 location_attributes[location_attributes_size];
+ *   u1 strings[strings_size];
+ *   u1 content[if !EOF];
+ * }
+ * }</pre>
+ */
+public final class ImageFileCreator {
+    private final Map<String, List<Entry>> entriesForModule = new HashMap<>();
+    private final ImagePluginStack plugins;
+    private ImageFileCreator(ImagePluginStack plugins) {
+        this.plugins = plugins;
+    }
+
+    public static ExecutableImage create(Set<Archive> archives,
+            ImagePluginStack plugins)
+            throws IOException {
+        return ImageFileCreator.create(archives, ByteOrder.nativeOrder(),
+                plugins);
+    }
+
+    public static ExecutableImage create(Set<Archive> archives,
+            ByteOrder byteOrder)
+            throws IOException {
+        return ImageFileCreator.create(archives, byteOrder,
+                new ImagePluginStack(null));
+    }
+
+    public static ExecutableImage create(Set<Archive> archives,
+            ByteOrder byteOrder,
+            ImagePluginStack plugins)
+            throws IOException
+    {
+        ImageFileCreator image = new ImageFileCreator(plugins);
+        try {
+            image.readAllEntries(archives);
+            // write to modular image
+            image.writeImage(archives, byteOrder);
+        } finally {
+            //Close all archives
+            for (Archive a : archives) {
+                a.close();
+            }
+        }
+
+        return plugins.getExecutableImage();
+    }
+
+    private void readAllEntries(Set<Archive> archives) {
+        archives.stream().forEach((archive) -> {
+            Map<Boolean, List<Entry>> es;
+            try (Stream<Entry> entries = archive.entries()) {
+                es = entries.collect(Collectors.partitioningBy(n -> n.type()
+                        == EntryType.CLASS_OR_RESOURCE));
+            }
+            String mn = archive.moduleName();
+            List<Entry> all = new ArrayList<>();
+            all.addAll(es.get(false));
+            all.addAll(es.get(true));
+            entriesForModule.put(mn, all);
+        });
+    }
+
+    public static boolean isClassPackage(String path) {
+        return path.endsWith(".class") && !path.endsWith("module-info.class");
+    }
+
+    public static void recreateJimage(Path jimageFile,
+            Set<Archive> archives,
+            ImagePluginStack pluginSupport)
+            throws IOException {
+        try {
+            Map<String, List<Entry>> entriesForModule
+                    = archives.stream().collect(Collectors.toMap(
+                                    Archive::moduleName,
+                                    a -> {
+                                        try (Stream<Entry> entries = a.entries()) {
+                                            return entries.collect(Collectors.toList());
+                                        }
+                                    }));
+            ByteOrder order = ByteOrder.nativeOrder();
+            BasicImageWriter writer = new BasicImageWriter(order);
+            PoolImpl pool = createPools(archives, entriesForModule, order, writer);
+            try (OutputStream fos = Files.newOutputStream(jimageFile);
+                    BufferedOutputStream bos = new BufferedOutputStream(fos);
+                    DataOutputStream out = new DataOutputStream(bos)) {
+                generateJImage(pool, writer, pluginSupport, out);
+            }
+        } finally {
+            //Close all archives
+            for (Archive a : archives) {
+                a.close();
+            }
+        }
+    }
+
+    private void writeImage(Set<Archive> archives,
+            ByteOrder byteOrder)
+            throws IOException {
+        BasicImageWriter writer = new BasicImageWriter(byteOrder);
+        PoolImpl allContent = createPools(archives,
+                entriesForModule, byteOrder, writer);
+        PoolImpl result = generateJImage(allContent,
+             writer, plugins, plugins.getJImageFileOutputStream());
+
+        //Handle files.
+        try {
+            plugins.storeFiles(allContent, result, writer);
+        } catch (Exception ex) {
+            throw new IOException(ex);
+        }
+    }
+
+    private static PoolImpl generateJImage(PoolImpl allContent,
+            BasicImageWriter writer,
+            ImagePluginStack pluginSupport,
+            DataOutputStream out
+    ) throws IOException {
+        PoolImpl resultResources;
+        try {
+            resultResources = pluginSupport.visitResources(allContent);
+        } catch (Exception ex) {
+            throw new IOException(ex);
+        }
+        Set<String> duplicates = new HashSet<>();
+        long offset = 0;
+
+        List<ModuleData> content = new ArrayList<>();
+        List<String> paths = new ArrayList<>();
+                 // the order of traversing the resources and the order of
+        // the module content being written must be the same
+        for (ModuleData res : resultResources.getContent()) {
+            if (res.getType().equals(ModuleDataType.CLASS_OR_RESOURCE)) {
+                String path = res.getPath();
+                content.add(res);
+                long uncompressedSize = res.getLength();
+                long compressedSize = 0;
+                if (res instanceof CompressedModuleData) {
+                    CompressedModuleData comp
+                            = (CompressedModuleData) res;
+                    compressedSize = res.getLength();
+                    uncompressedSize = comp.getUncompressedSize();
+                }
+                long onFileSize = res.getLength();
+
+                if (duplicates.contains(path)) {
+                    System.err.format("duplicate resource \"%s\", skipping%n",
+                            path);
+                    // TODO Need to hang bytes on resource and write
+                    // from resource not zip.
+                    // Skipping resource throws off writing from zip.
+                    offset += onFileSize;
+                    continue;
+                }
+                duplicates.add(path);
+                writer.addLocation(path, offset, compressedSize, uncompressedSize);
+                paths.add(path);
+                offset += onFileSize;
+            }
+        }
+
+        ImageResourcesTree tree = new ImageResourcesTree(offset, writer, paths);
+
+        // write header and indices
+        byte[] bytes = writer.getBytes();
+        out.write(bytes, 0, bytes.length);
+
+        // write module content
+        for (ModuleData res : content) {
+            byte[] buf = res.getBytes();
+            out.write(buf, 0, buf.length);
+        }
+
+        tree.addContent(out);
+
+        out.close();
+
+        return resultResources;
+    }
+
+    private static Pool.ModuleDataType mapImageFileType(EntryType type) {
+        switch(type) {
+            case CONFIG: {
+                return Pool.ModuleDataType.CONFIG;
+            }
+            case NATIVE_CMD: {
+                return Pool.ModuleDataType.NATIVE_CMD;
+            }
+            case NATIVE_LIB: {
+                return Pool.ModuleDataType.NATIVE_LIB;
+            }
+        }
+        return null;
+    }
+
+    private static PoolImpl createPools(Set<Archive> archives,
+            Map<String, List<Entry>> entriesForModule,
+            ByteOrder byteOrder,
+            BasicImageWriter writer) throws IOException {
+        PoolImpl resources = new PoolImpl(byteOrder, new StringTable() {
+
+            @Override
+            public int addString(String str) {
+                return writer.addString(str);
+            }
+
+            @Override
+            public String getString(int id) {
+                return writer.getString(id);
+            }
+        });
+        for (Archive archive : archives) {
+            String mn = archive.moduleName();
+            for (Entry entry : entriesForModule.get(mn)) {
+
+                if (entry.type() == EntryType.CLASS_OR_RESOURCE) {
+                    // Removal of "classes/" radical.
+                    String path = entry.name();
+                    try (InputStream stream = entry.stream()) {
+                        byte[] bytes = readAllBytes(stream);
+                        if (path.endsWith("module-info.class")) {
+                            path = "/" + path;
+                        } else {
+                            path = "/" + mn + "/" + path;
+                        }
+                        try {
+                            resources.add(Pool.newResource(path, bytes));
+                        } catch (Exception ex) {
+                            throw new IOException(ex);
+                        }
+                    }
+                } else {
+                    try {
+                        // Entry.path() contains the kind of file native, conf, bin, ...
+                        // Keep it to avoid naming conflict (eg: native/jvm.cfg and config/jvm.cfg
+                        resources.add(Pool.newImageFile(mn,
+                                "/" + mn + "/" + entry.path(), mapImageFileType(entry.type()),
+                                entry.stream(), entry.size()));
+                    } catch (Exception ex) {
+                        throw new IOException(ex);
+                    }
+                }
+            }
+        }
+        return resources;
+    }
+
+    private static final int BUF_SIZE = 8192;
+
+    private static byte[] readAllBytes(InputStream is) throws IOException {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        byte[] buf = new byte[BUF_SIZE];
+        while (true) {
+            int n = is.read(buf);
+            if (n < 0) {
+                break;
+            }
+            baos.write(buf, 0, n);
+        }
+        return baos.toByteArray();
+    }
+
+    /**
+     * Helper method that splits a Resource path onto 3 items: module, parent
+     * and resource name.
+     *
+     * @param path
+     * @return An array containing module, parent and name.
+     */
+    public static String[] splitPath(String path) {
+        Objects.requireNonNull(path);
+        String noRoot = path.substring(1);
+        int pkgStart = noRoot.indexOf("/");
+        String module = noRoot.substring(0, pkgStart);
+        List<String> result = new ArrayList<>();
+        result.add(module);
+        String pkg = noRoot.substring(pkgStart + 1);
+        String resName;
+        int pkgEnd = pkg.lastIndexOf("/");
+        if (pkgEnd == -1) { // No package.
+            resName = pkg;
+        } else {
+            resName = pkg.substring(pkgEnd + 1);
+        }
+
+        pkg = toPackage(pkg, false);
+        result.add(pkg);
+        result.add(resName);
+
+        String[] array = new String[result.size()];
+        return result.toArray(array);
+    }
+
+    private static String toPackage(String name, boolean log) {
+        int index = name.lastIndexOf('/');
+        if (index > 0) {
+            return name.substring(0, index).replace('/', '.');
+        } else {
+            // ## unnamed package
+            if (log) {
+                System.err.format("Warning: %s in unnamed package%n", name);
+            }
+            return "";
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageLocationWriter.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jlink.internal;
+
+import jdk.internal.jimage.ImageLocation;
+import jdk.internal.jimage.ImageStream;
+import jdk.internal.jimage.ImageStringsReader;
+
+public final class ImageLocationWriter extends ImageLocation {
+    private int locationOffset;
+
+    private ImageLocationWriter(ImageStringsWriter strings) {
+        super(new long[ATTRIBUTE_COUNT], strings);
+    }
+
+    void writeTo(ImageStream stream) {
+        byte[] bytes = ImageLocation.compress(attributes);
+        locationOffset = stream.getPosition();
+        stream.put(bytes, 0, bytes.length);
+    }
+
+    private ImageLocationWriter addAttribute(int kind, long value) {
+        assert ATTRIBUTE_END < kind &&
+               kind < ATTRIBUTE_COUNT : "Invalid attribute kind";
+        attributes[kind] = value;
+        return this;
+    }
+
+    private ImageLocationWriter addAttribute(int kind, String value) {
+        return addAttribute(kind, strings.add(value));
+    }
+
+    static ImageLocationWriter newLocation(String fullName,
+            ImageStringsWriter strings,
+            long contentOffset, long compressedSize, long uncompressedSize) {
+        String moduleName = "";
+        String parentName = "";
+        String baseName;
+        String extensionName = "";
+
+        int offset = fullName.indexOf('/', 1);
+        if (fullName.length() >= 2 && fullName.charAt(0) == '/' && offset != -1) {
+            moduleName = fullName.substring(1, offset);
+            fullName = fullName.substring(offset + 1);
+        }
+
+        offset = fullName.lastIndexOf('/');
+        if (1 < offset) {
+            parentName = fullName.substring(0, offset);
+            fullName = fullName.substring(offset + 1);
+        }
+
+        offset = fullName.lastIndexOf('.');
+        if (offset != -1) {
+            baseName = fullName.substring(0, offset);
+            extensionName = fullName.substring(offset + 1);
+        } else {
+            baseName = fullName;
+        }
+
+        return new ImageLocationWriter(strings)
+               .addAttribute(ATTRIBUTE_MODULE, moduleName)
+               .addAttribute(ATTRIBUTE_PARENT, parentName)
+               .addAttribute(ATTRIBUTE_BASE, baseName)
+               .addAttribute(ATTRIBUTE_EXTENSION, extensionName)
+               .addAttribute(ATTRIBUTE_OFFSET, contentOffset)
+               .addAttribute(ATTRIBUTE_COMPRESSED, compressedSize)
+               .addAttribute(ATTRIBUTE_UNCOMPRESSED, uncompressedSize);
+    }
+
+    @Override
+    public int hashCode() {
+        return hashCode(ImageStringsReader.HASH_MULTIPLIER);
+    }
+
+    int hashCode(int seed) {
+        int hash = seed;
+
+        if (getModuleOffset() != 0) {
+            hash = ImageStringsReader.hashCode("/", hash);
+            hash = ImageStringsReader.hashCode(getModule(), hash);
+            hash = ImageStringsReader.hashCode("/", hash);
+        }
+
+        if (getParentOffset() != 0) {
+            hash = ImageStringsReader.hashCode(getParent(), hash);
+            hash = ImageStringsReader.hashCode("/", hash);
+        }
+
+        hash = ImageStringsReader.hashCode(getBase(), hash);
+
+        if (getExtensionOffset() != 0) {
+            hash = ImageStringsReader.hashCode(".", hash);
+            hash = ImageStringsReader.hashCode(getExtension(), hash);
+        }
+
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (!(obj instanceof ImageLocationWriter)) {
+            return false;
+        }
+
+        ImageLocationWriter other = (ImageLocationWriter) obj;
+
+        return getModuleOffset() == other.getModuleOffset() &&
+               getParentOffset() == other.getParentOffset() &&
+               getBaseOffset() == other.getBaseOffset() &&
+               getExtensionOffset() == other.getExtensionOffset();
+    }
+
+    int getLocationOffset() {
+        return locationOffset;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginConfiguration.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal;
+
+import java.io.DataOutputStream;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Properties;
+import jdk.tools.jlink.plugin.ExecutableImage;
+import jdk.tools.jlink.builder.ImageBuilder;
+import jdk.tools.jlink.Jlink;
+import jdk.tools.jlink.plugin.Plugin;
+import jdk.tools.jlink.plugin.PluginContext;
+import jdk.tools.jlink.plugin.PluginException;
+import jdk.tools.jlink.plugin.Plugin.CATEGORY;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.PostProcessorPlugin;
+import jdk.tools.jlink.plugin.TransformerPlugin;
+
+/**
+ * Plugins configuration.
+ */
+public final class ImagePluginConfiguration {
+
+    private static final List<Plugin.CATEGORY> CATEGORIES_ORDER = new ArrayList<>();
+
+    static {
+        CATEGORIES_ORDER.add(Plugin.CATEGORY.FILTER);
+        CATEGORIES_ORDER.add(Plugin.CATEGORY.TRANSFORMER);
+        CATEGORIES_ORDER.add(Plugin.CATEGORY.MODULEINFO_TRANSFORMER);
+        CATEGORIES_ORDER.add(Plugin.CATEGORY.SORTER);
+        CATEGORIES_ORDER.add(Plugin.CATEGORY.COMPRESSOR);
+        CATEGORIES_ORDER.add(Plugin.CATEGORY.VERIFIER);
+        CATEGORIES_ORDER.add(Plugin.CATEGORY.PROCESSOR);
+        CATEGORIES_ORDER.add(Plugin.CATEGORY.PACKAGER);
+    }
+
+    private ImagePluginConfiguration() {
+    }
+
+    public static ImagePluginStack parseConfiguration(Jlink.PluginsConfiguration plugins)
+            throws Exception {
+        return parseConfiguration(plugins, null);
+    }
+
+    /*
+     * Create a stack of plugins from a a configuration.
+     *
+     */
+    public static ImagePluginStack parseConfiguration(Jlink.PluginsConfiguration pluginsConfiguration,
+            String bom)
+            throws Exception {
+        if (pluginsConfiguration == null) {
+            return new ImagePluginStack(bom);
+        }
+        Map<Plugin.CATEGORY, List<Plugin>> plugins = new LinkedHashMap<>();
+        for (Plugin.CATEGORY cat : CATEGORIES_ORDER) {
+            plugins.put(cat, new ArrayList<>());
+        }
+
+        List<String> seen = new ArrayList<>();
+        // split into categories and check for plugin with same name.
+        for (Plugin plug : pluginsConfiguration.getPlugins()) {
+            if (seen.contains(plug.getName())) {
+                throw new Exception("Plugin " + plug.getName()
+                        + " added more than once to stack ");
+            }
+            seen.add(plug.getName());
+            CATEGORY category = Utils.getCategory(plug);
+            if (category == null) {
+                throw new PluginException("Invalid category for "
+                        + plug.getName());
+            }
+            List<Plugin> lst = plugins.get(category);
+            lst.add(plug);
+        }
+
+        List<TransformerPlugin> transformerPlugins = new ArrayList<>();
+        List<PostProcessorPlugin> postProcessingPlugins = new ArrayList<>();
+        for (Entry<Plugin.CATEGORY, List<Plugin>> entry : plugins.entrySet()) {
+            // Sort according to plugin constraints
+            List<Plugin> orderedPlugins = PluginOrderingGraph.sort(entry.getValue());
+            CATEGORY category = entry.getKey();
+            for (Plugin p : orderedPlugins) {
+                if (Utils.isPostProcessor(category)) {
+                    @SuppressWarnings("unchecked")
+                    PostProcessorPlugin pp = (PostProcessorPlugin) p;
+                    postProcessingPlugins.add(pp);
+                } else {
+                    @SuppressWarnings("unchecked")
+                    TransformerPlugin trans = (TransformerPlugin) p;
+                    transformerPlugins.add(trans);
+                }
+            }
+        }
+        Plugin lastSorter = null;
+        for (Plugin plugin : transformerPlugins) {
+            if (plugin.getName().equals(pluginsConfiguration.getLastSorterPluginName())) {
+                lastSorter = plugin;
+                break;
+            }
+        }
+        if (pluginsConfiguration.getLastSorterPluginName() != null && lastSorter == null) {
+            throw new IOException("Unknown last plugin "
+                    + pluginsConfiguration.getLastSorterPluginName());
+        }
+        ImageBuilder builder = pluginsConfiguration.getImageBuilder();
+        if (builder == null) {
+            // This should be the case for jimage only creation or post-install.
+            builder = new ImageBuilder() {
+
+                @Override
+                public DataOutputStream getJImageOutputStream() {
+                    throw new PluginException("No directory setup to store files");
+                }
+
+                @Override
+                public ExecutableImage getExecutableImage() {
+                    throw new PluginException("No directory setup to store files");
+                }
+
+                @Override
+                public void storeFiles(Pool files, String bom) {
+                    throw new PluginException("No directory setup to store files");
+                }
+            };
+        }
+
+        PluginContext ctxt = pluginsConfiguration.getPluginContext();
+        return new ImagePluginStack(builder, transformerPlugins,
+                lastSorter, postProcessingPlugins, ctxt, bom);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginStack.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,488 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.lang.module.ModuleDescriptor;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Properties;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import jdk.internal.jimage.decompressor.Decompressor;
+import jdk.tools.jlink.plugin.Plugin;
+import jdk.tools.jlink.plugin.PluginContext;
+import jdk.tools.jlink.plugin.ExecutableImage;
+import jdk.tools.jlink.builder.ImageBuilder;
+import jdk.tools.jlink.plugin.TransformerPlugin;
+import jdk.tools.jlink.plugin.PluginException;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.PostProcessorPlugin;
+
+/**
+ * Plugins Stack. Plugins entry point to apply transformations onto resources
+ * and files.
+ */
+public final class ImagePluginStack {
+
+    public interface ImageProvider {
+
+        ExecutableImage retrieve(ImagePluginStack stack) throws IOException;
+    }
+
+    public static final class OrderedResourcePool extends PoolImpl {
+
+        private final List<ModuleData> orderedList = new ArrayList<>();
+
+        public OrderedResourcePool(ByteOrder order, StringTable table) {
+            super(order, table);
+        }
+
+        /**
+         * Add a resource.
+         *
+         * @param resource The Resource to add.
+         */
+        @Override
+        public void add(ModuleData resource) {
+            super.add(resource);
+            orderedList.add(resource);
+        }
+
+        List<ModuleData> getOrderedList() {
+            return Collections.unmodifiableList(orderedList);
+        }
+    }
+
+    private final static class CheckOrderResourcePool extends PoolImpl {
+
+        private final List<ModuleData> orderedList;
+        private int currentIndex;
+
+        public CheckOrderResourcePool(ByteOrder order, List<ModuleData> orderedList, StringTable table) {
+            super(order, table);
+            this.orderedList = orderedList;
+        }
+
+        /**
+         * Add a resource.
+         *
+         * @param resource The Resource to add.
+         */
+        @Override
+        public void add(ModuleData resource) {
+            ModuleData ordered = orderedList.get(currentIndex);
+            if (!resource.equals(ordered)) {
+                throw new PluginException("Resource " + resource.getPath() + " not in the right order");
+            }
+            super.add(resource);
+            currentIndex += 1;
+        }
+    }
+
+    private static final class PreVisitStrings implements StringTable {
+
+        private int currentid = 0;
+        private final Map<String, Integer> stringsUsage = new HashMap<>();
+
+        private final Map<String, Integer> stringsMap = new HashMap<>();
+        private final Map<Integer, String> reverseMap = new HashMap<>();
+
+        @Override
+        public int addString(String str) {
+            Objects.requireNonNull(str);
+            Integer count = stringsUsage.get(str);
+            if (count == null) {
+                count = 0;
+            }
+            count += 1;
+            stringsUsage.put(str, count);
+            Integer id = stringsMap.get(str);
+            if (id == null) {
+                id = currentid;
+                stringsMap.put(str, id);
+                currentid += 1;
+                reverseMap.put(id, str);
+            }
+
+            return id;
+        }
+
+        private List<String> getSortedStrings() {
+            Stream<java.util.Map.Entry<String, Integer>> stream
+                    = stringsUsage.entrySet().stream();
+            // Remove strings that have a single occurence
+            List<String> result = stream.sorted(Comparator.comparing(e -> e.getValue(),
+                    Comparator.reverseOrder())).filter((e) -> {
+                        return e.getValue() > 1;
+                    }).map(java.util.Map.Entry::getKey).
+                    collect(Collectors.toList());
+            return result;
+        }
+
+        @Override
+        public String getString(int id) {
+            return reverseMap.get(id);
+        }
+    }
+
+    private final Plugin lastSorter;
+    private final List<TransformerPlugin> contentPlugins = new ArrayList<>();
+    private final List<PostProcessorPlugin> postProcessingPlugins = new ArrayList<>();
+    private final List<ResourcePrevisitor> resourcePrevisitors = new ArrayList<>();
+
+    private final ImageBuilder imageBuilder;
+    private final Properties release;
+    private final String bom;
+
+    public ImagePluginStack(String bom) {
+        this(null, Collections.emptyList(), null,
+                Collections.emptyList(), null, bom);
+    }
+
+    public ImagePluginStack(ImageBuilder imageBuilder,
+            List<TransformerPlugin> contentPlugins,
+            Plugin lastSorter,
+            List<PostProcessorPlugin> postprocessingPlugins,
+            String bom) {
+        this(imageBuilder, contentPlugins, lastSorter,
+            postprocessingPlugins, null, bom);
+    }
+
+    public ImagePluginStack(ImageBuilder imageBuilder,
+            List<TransformerPlugin> contentPlugins,
+            Plugin lastSorter,
+            List<PostProcessorPlugin> postprocessingPlugins,
+            PluginContext ctxt,
+            String bom) {
+        Objects.requireNonNull(contentPlugins);
+        this.lastSorter = lastSorter;
+        for (TransformerPlugin p : contentPlugins) {
+            Objects.requireNonNull(p);
+            if (p instanceof ResourcePrevisitor) {
+                resourcePrevisitors.add((ResourcePrevisitor) p);
+            }
+            this.contentPlugins.add(p);
+        }
+        for (PostProcessorPlugin p : postprocessingPlugins) {
+            Objects.requireNonNull(p);
+            this.postProcessingPlugins.add(p);
+        }
+        this.imageBuilder = imageBuilder;
+        this.release = ctxt != null? ctxt.getReleaseProperties() : new Properties();
+        this.bom = bom;
+    }
+
+    public void operate(ImageProvider provider) throws Exception {
+        ExecutableImage img = provider.retrieve(this);
+        List<String> arguments = new ArrayList<>();
+        for (PostProcessorPlugin plugin : postProcessingPlugins) {
+            List<String> lst = plugin.process(img);
+            if (lst != null) {
+                arguments.addAll(lst);
+            }
+        }
+        img.storeLaunchArgs(arguments);
+    }
+
+    public DataOutputStream getJImageFileOutputStream() throws IOException {
+        return imageBuilder.getJImageOutputStream();
+    }
+
+    public ImageBuilder getImageBuilder() {
+        return imageBuilder;
+    }
+
+    /**
+     * Resource Plugins stack entry point. All resources are going through all
+     * the plugins.
+     *
+     * @param resources The set of resources to visit
+     * @return The result of the visit.
+     * @throws IOException
+     */
+    public PoolImpl visitResources(PoolImpl resources)
+            throws Exception {
+        Objects.requireNonNull(resources);
+        resources.setReadOnly();
+        if (resources.isEmpty()) {
+            return new PoolImpl(resources.getByteOrder(),
+                    resources.getStringTable());
+        }
+        PreVisitStrings previsit = new PreVisitStrings();
+        for (ResourcePrevisitor p : resourcePrevisitors) {
+            p.previsit(resources, previsit);
+        }
+
+        // Store the strings resulting from the previsit.
+        List<String> sorted = previsit.getSortedStrings();
+        for (String s : sorted) {
+            resources.getStringTable().addString(s);
+        }
+
+        PoolImpl current = resources;
+        List<Pool.ModuleData> frozenOrder = null;
+        for (TransformerPlugin p : contentPlugins) {
+            current.setReadOnly();
+            PoolImpl output = null;
+            if (p == lastSorter) {
+                if (frozenOrder != null) {
+                    throw new Exception("Order of resources is already frozen. Plugin "
+                            + p.getName() + " is badly located");
+                }
+                // Create a special Resource pool to compute the indexes.
+                output = new OrderedResourcePool(current.getByteOrder(),
+                        resources.getStringTable());
+            } else {// If we have an order, inject it
+                if (frozenOrder != null) {
+                    output = new CheckOrderResourcePool(current.getByteOrder(),
+                            frozenOrder, resources.getStringTable());
+                } else {
+                    output = new PoolImpl(current.getByteOrder(),
+                            resources.getStringTable());
+                }
+            }
+            p.visit(current, output);
+            if (output.isEmpty()) {
+                throw new Exception("Invalid resource pool for plugin " + p);
+            }
+            if (output instanceof OrderedResourcePool) {
+                frozenOrder = ((OrderedResourcePool) output).getOrderedList();
+            }
+
+            current = output;
+        }
+        current.setReadOnly();
+        return current;
+    }
+
+    /**
+     * This pool wrap the original pool and automatically uncompress moduledata
+     * if needed.
+     */
+    private class LastPool extends Pool {
+        private class LastModule implements Module {
+
+            private final Module module;
+
+            LastModule(Module module) {
+                this.module = module;
+            }
+
+            @Override
+            public String getName() {
+                return module.getName();
+            }
+
+            @Override
+            public ModuleData get(String path) {
+                ModuleData d = module.get(path);
+                return getUncompressed(d);
+            }
+
+            @Override
+            public ModuleDescriptor getDescriptor() {
+                return module.getDescriptor();
+            }
+
+            @Override
+            public void add(ModuleData data) {
+                throw new PluginException("pool is readonly");
+            }
+
+            @Override
+            public Set<String> getAllPackages() {
+                return module.getAllPackages();
+            }
+
+            @Override
+            public String toString() {
+                return getName();
+            }
+
+            @Override
+            public Collection<ModuleData> getContent() {
+                List<ModuleData> lst = new ArrayList<>();
+                for(ModuleData md : module.getContent()) {
+                    lst.add(getUncompressed(md));
+                }
+                return lst;
+            }
+        }
+        private final PoolImpl pool;
+        Decompressor decompressor = new Decompressor();
+        Collection<ModuleData> content;
+
+        LastPool(PoolImpl pool) {
+            this.pool = pool;
+        }
+
+        @Override
+        public boolean isReadOnly() {
+            return true;
+        }
+
+        @Override
+        public void add(ModuleData resource) {
+            throw new PluginException("pool is readonly");
+        }
+
+        /**
+         * Retrieves the module of the provided name.
+         *
+         * @param name The module name
+         * @return the module or null if the module doesn't exist.
+         */
+        @Override
+        public Module getModule(String name) {
+            Module module = pool.getModule(name);
+            if (module != null) {
+                module = new LastModule(module);
+            }
+            return module;
+        }
+
+        /**
+         * The collection of modules contained in this pool.
+         *
+         * @return The collection of modules.
+         */
+        @Override
+        public Collection<Module> getModules() {
+            List<Module> modules = new ArrayList<>();
+            for (Module m : pool.getModules()) {
+                modules.add(new LastModule(m));
+            }
+            return modules;
+        }
+
+        /**
+         * Get all resources contained in this pool instance.
+         *
+         * @return The collection of resources;
+         */
+        @Override
+        public Collection<ModuleData> getContent() {
+            if (content == null) {
+                content = new ArrayList<>();
+                for (ModuleData md : pool.getContent()) {
+                    content.add(getUncompressed(md));
+                }
+            }
+            return content;
+        }
+
+        /**
+         * Get the resource for the passed path.
+         *
+         * @param path A resource path
+         * @return A Resource instance or null if the resource is not found
+         */
+        @Override
+        public ModuleData get(String path) {
+            Objects.requireNonNull(path);
+            Pool.ModuleData res = pool.get(path);
+            return getUncompressed(res);
+        }
+
+        @Override
+        public boolean contains(ModuleData res) {
+            return pool.contains(res);
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return pool.isEmpty();
+        }
+
+        @Override
+        public void visit(Visitor visitor, Pool output) {
+            pool.visit(visitor, output);
+        }
+
+        @Override
+        public ByteOrder getByteOrder() {
+            return pool.getByteOrder();
+        }
+
+        private ModuleData getUncompressed(ModuleData res) {
+            if (res != null) {
+                if (res instanceof PoolImpl.CompressedModuleData) {
+                    try {
+                        byte[] bytes = decompressor.decompressResource(getByteOrder(),
+                                (int offset) -> pool.getStringTable().getString(offset),
+                                res.getBytes());
+                        res = Pool.newResource(res.getPath(),
+                                new ByteArrayInputStream(bytes),
+                                bytes.length);
+                    } catch (IOException ex) {
+                        throw new PluginException(ex);
+                    }
+                }
+            }
+            return res;
+        }
+    }
+
+    /**
+     * Make the imageBuilder to store files.
+     *
+     * @param original
+     * @param transformed
+     * @param writer
+     * @throws java.lang.Exception
+     */
+    public void storeFiles(PoolImpl original, PoolImpl transformed,
+            BasicImageWriter writer)
+            throws Exception {
+        Objects.requireNonNull(original);
+        try {
+            // fill release information available from transformed "java.base" module!
+            ModuleDescriptor desc = transformed.getModule("java.base").getDescriptor();
+            desc.osName().ifPresent(s -> release.put("OS_NAME", s));
+            desc.osVersion().ifPresent(s -> release.put("OS_VERSION", s));
+            desc.osArch().ifPresent(s -> release.put("OS_ARCH", s));
+        } catch (Exception ignored) {
+        }
+
+        imageBuilder.storeFiles(new LastPool(transformed), bom, release);
+    }
+
+    public ExecutableImage getExecutableImage() throws IOException {
+        return imageBuilder.getExecutableImage();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageResourcesTree.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,450 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+/**
+ * A class to build a sorted tree of Resource paths as a tree of ImageLocation.
+ *
+ */
+// XXX Public only due to the JImageTask / JImageTask code duplication
+public final class ImageResourcesTree {
+    public static boolean isTreeInfoResource(String path) {
+        return path.startsWith("/packages") || path.startsWith("/modules");
+    }
+
+    /**
+     * Path item tree node.
+     */
+    private static class Node {
+
+        private final String name;
+        private final Map<String, Node> children = new TreeMap<>();
+        private final Node parent;
+        private ImageLocationWriter loc;
+
+        private Node(String name, Node parent) {
+            this.name = name;
+            this.parent = parent;
+
+            if (parent != null) {
+                parent.children.put(name, this);
+            }
+        }
+
+        public String getPath() {
+            if (parent == null) {
+                return "/";
+            }
+            return buildPath(this);
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public Node getChildren(String name) {
+            Node item = children.get(name);
+            return item;
+        }
+
+        private static String buildPath(Node item) {
+            if (item == null) {
+                return null;
+            }
+            String path = buildPath(item.parent);
+            if (path == null) {
+                return item.getName();
+            } else {
+                return path + "/" + item.getName();
+            }
+        }
+    }
+
+    private static final class ResourceNode extends Node {
+
+        public ResourceNode(String name, Node parent) {
+            super(name, parent);
+        }
+    }
+
+    private static class PackageNode extends Node {
+        /**
+         * A reference to a package. Empty packages can be located inside one or
+         * more modules. A package with classes exist in only one module.
+         */
+        final static class PackageReference {
+
+            private final String name;
+            private final boolean isEmpty;
+
+            PackageReference(String name, boolean isEmpty) {
+                Objects.requireNonNull(name);
+                this.name = name;
+                this.isEmpty = isEmpty;
+            }
+
+            @Override
+            public String toString() {
+                return name + "[empty:" + isEmpty + "]";
+            }
+        }
+
+        private final Map<String, PackageReference> references = new TreeMap<>();
+
+        PackageNode(String name, Node parent) {
+            super(name, parent);
+        }
+
+        private void addReference(String name, boolean isEmpty) {
+            PackageReference ref = references.get(name);
+            if (ref == null) {
+                references.put(name, new PackageReference(name, isEmpty));
+            } else {
+                if (ref.isEmpty) { // replace with new one incase non empty.
+                    references.put(name, new PackageReference(name, isEmpty));
+                }
+            }
+        }
+
+        private void validate() {
+            boolean exists = false;
+            for (PackageReference ref : references.values()) {
+                if (!ref.isEmpty) {
+                    if (exists) {
+                        throw new RuntimeException("Multiple modules to contain package "
+                                + getName());
+                    } else {
+                        exists = true;
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Tree of nodes.
+     */
+    private static final class Tree {
+
+        private final Map<String, Node> directAccess = new HashMap<>();
+        private final List<String> paths;
+        private final Node root;
+        private Node modules;
+        private Node packages;
+
+        private Tree(List<String> paths) {
+            this.paths = paths;
+            root = new Node("", null);
+            buildTree();
+        }
+
+        private void buildTree() {
+            modules = new Node("modules", root);
+            directAccess.put(modules.getPath(), modules);
+
+            Map<String, Set<String>> moduleToPackage = new TreeMap<>();
+            Map<String, Set<String>> packageToModule = new TreeMap<>();
+
+            for (String p : paths) {
+                if (!p.startsWith("/")) {
+                    continue;
+                }
+                String[] split = p.split("/");
+                // minimum length is 3 items: /<mod>/<pkg>
+                if (split.length < 3) {
+                    System.err.println("Resources tree, invalid data structure, "
+                            + "skipping " + p);
+                    continue;
+                }
+                Node current = modules;
+                String module = null;
+                for (int i = 0; i < split.length; i++) {
+                    // When a non terminal node is marked as being a resource, something is wrong.
+                    // It has been observed some badly created jar file to contain
+                    // invalid directory entry marled as not directory (see 8131762)
+                    if (current instanceof ResourceNode) {
+                        System.err.println("Resources tree, invalid data structure, "
+                                + "skipping " + p);
+                        continue;
+                    }
+                    String s = split[i];
+                    if (!s.isEmpty()) {
+                        // First item, this is the module, simply add a new node to the
+                        // tree.
+                        if (module == null) {
+                            module = s;
+                        }
+                        Node n = current.children.get(s);
+                        if (n == null) {
+                            if (i == split.length - 1) { // Leaf
+                                n = new ResourceNode(s, current);
+                                String pkg = toPackageName(n.parent);
+                                //System.err.println("Adding a resource node. pkg " + pkg + ", name " + s);
+                                if (pkg != null && !pkg.startsWith("META-INF")) {
+                                    Set<String> pkgs = moduleToPackage.get(module);
+                                    if (pkgs == null) {
+                                        pkgs = new TreeSet<>();
+                                        moduleToPackage.put(module, pkgs);
+                                    }
+                                    pkgs.add(pkg);
+                                }
+                            } else { // put only sub trees, no leaf
+                                n = new Node(s, current);
+                                directAccess.put(n.getPath(), n);
+                                String pkg = toPackageName(n);
+                                if (pkg != null && !pkg.startsWith("META-INF")) {
+                                    Set<String> mods = packageToModule.get(pkg);
+                                    if (mods == null) {
+                                        mods = new TreeSet<>();
+                                        packageToModule.put(pkg, mods);
+                                    }
+                                    mods.add(module);
+                                }
+                            }
+                        }
+                        current = n;
+                    }
+                }
+            }
+            packages = new Node("packages", root);
+            directAccess.put(packages.getPath(), packages);
+            // The subset of package nodes that have some content.
+            // These packages exist only in a single module.
+            for (Map.Entry<String, Set<String>> entry : moduleToPackage.entrySet()) {
+                for (String pkg : entry.getValue()) {
+                    PackageNode pkgNode = new PackageNode(pkg, packages);
+                    pkgNode.addReference(entry.getKey(), false);
+                    directAccess.put(pkgNode.getPath(), pkgNode);
+                }
+            }
+
+            // All packages
+            for (Map.Entry<String, Set<String>> entry : packageToModule.entrySet()) {
+                // Do we already have a package node?
+                PackageNode pkgNode = (PackageNode) packages.getChildren(entry.getKey());
+                if (pkgNode == null) {
+                    pkgNode = new PackageNode(entry.getKey(), packages);
+                }
+                for (String module : entry.getValue()) {
+                    pkgNode.addReference(module, true);
+                }
+                directAccess.put(pkgNode.getPath(), pkgNode);
+            }
+            // Validate that the packages are well formed.
+            for (Node n : packages.children.values()) {
+                PackageNode pkg = (PackageNode) n;
+                pkg.validate();
+            }
+
+        }
+
+        public String toResourceName(Node node) {
+            if (!node.children.isEmpty()) {
+                throw new RuntimeException("Node is not a resource");
+            }
+            return removeRadical(node);
+        }
+
+        public String getModule(Node node) {
+            if (node.parent == null || node.getName().equals("modules")
+                    || node.getName().startsWith("packages")) {
+                return null;
+            }
+            String path = removeRadical(node);
+            // "/xxx/...";
+            path = path.substring(1);
+            int i = path.indexOf("/");
+            if (i == -1) {
+                return path;
+            } else {
+                return path.substring(0, i);
+            }
+        }
+
+        public String toPackageName(Node node) {
+            if (node.parent == null) {
+                return null;
+            }
+            String path = removeRadical(node.getPath(), "/modules/");
+            String module = getModule(node);
+            if (path.equals(module)) {
+                return null;
+            }
+            String pkg = removeRadical(path, module + "/");
+            return pkg.replaceAll("/", ".");
+        }
+
+        public String removeRadical(Node node) {
+            return removeRadical(node.getPath(), "/modules");
+        }
+
+        private String removeRadical(String path, String str) {
+            if (!(path.length() < str.length())) {
+                path = path.substring(str.length());
+            }
+            return path;
+        }
+
+        public Node getRoot() {
+            return root;
+        }
+
+        public Map<String, Node> getMap() {
+            return directAccess;
+        }
+    }
+
+    private static final class LocationsAdder {
+
+        private long offset;
+        private final List<byte[]> content = new ArrayList<>();
+        private final BasicImageWriter writer;
+        private final Tree tree;
+
+        LocationsAdder(Tree tree, long offset, BasicImageWriter writer) {
+            this.tree = tree;
+            this.offset = offset;
+            this.writer = writer;
+            addLocations(tree.getRoot());
+        }
+
+        private int addLocations(Node current) {
+            if (current instanceof PackageNode) {
+                PackageNode pkgNode = (PackageNode) current;
+                int size = pkgNode.references.size() * 8;
+                writer.addLocation(current.getPath(), offset, 0, size);
+                offset += size;
+            } else {
+                int[] ret = new int[current.children.size()];
+                int i = 0;
+                for (java.util.Map.Entry<String, Node> entry : current.children.entrySet()) {
+                    ret[i] = addLocations(entry.getValue());
+                    i += 1;
+                }
+                if (current != tree.getRoot() && !(current instanceof ResourceNode)) {
+                    int size = ret.length * 4;
+                    writer.addLocation(current.getPath(), offset, 0, size);
+                    offset += size;
+                }
+            }
+            return 0;
+        }
+
+        private List<byte[]> computeContent() {
+            // Map used to associate Tree item with locations offset.
+            Map<String, ImageLocationWriter> outLocations = new HashMap<>();
+            for (ImageLocationWriter wr : writer.getLocations()) {
+                outLocations.put(wr.getFullName(), wr);
+            }
+            // Attach location to node
+            for (Map.Entry<String, ImageLocationWriter> entry : outLocations.entrySet()) {
+                Node item = tree.getMap().get(entry.getKey());
+                if (item != null) {
+                    item.loc = entry.getValue();
+                }
+            }
+            computeContent(tree.getRoot(), outLocations);
+            return content;
+        }
+
+        private int computeContent(Node current, Map<String, ImageLocationWriter> outLocations) {
+            if (current instanceof PackageNode) {
+                // /packages/<pkg name>
+                PackageNode pkgNode = (PackageNode) current;
+                int size = pkgNode.references.size() * 8;
+                ByteBuffer buff = ByteBuffer.allocate(size);
+                buff.order(writer.getByteOrder());
+                for (PackageNode.PackageReference mod : pkgNode.references.values()) {
+                    buff.putInt(mod.isEmpty ? 1 : 0);
+                    buff.putInt(writer.addString(mod.name));
+                }
+                byte[] arr = buff.array();
+                content.add(arr);
+                current.loc = outLocations.get(current.getPath());
+            } else {
+                int[] ret = new int[current.children.size()];
+                int i = 0;
+                for (java.util.Map.Entry<String, Node> entry : current.children.entrySet()) {
+                    ret[i] = computeContent(entry.getValue(), outLocations);
+                    i += 1;
+                }
+                if (ret.length > 0) {
+                    int size = ret.length * 4;
+                    ByteBuffer buff = ByteBuffer.allocate(size);
+                    buff.order(writer.getByteOrder());
+                    for (int val : ret) {
+                        buff.putInt(val);
+                    }
+                    byte[] arr = buff.array();
+                    content.add(arr);
+                } else {
+                    if (current instanceof ResourceNode) {
+                        // A resource location, remove "/modules"
+                        String s = tree.toResourceName(current);
+                        current.loc = outLocations.get(s);
+                    } else {
+                        // empty "/packages" or empty "/modules" paths
+                        current.loc = outLocations.get(current.getPath());
+                    }
+                }
+                if (current.loc == null && current != tree.getRoot()) {
+                    System.err.println("Invalid path in metadata, skipping " + current.getPath());
+                }
+            }
+            return current.loc == null ? 0 : current.loc.getLocationOffset();
+        }
+    }
+
+    private final List<String> paths;
+    private final LocationsAdder adder;
+
+    public ImageResourcesTree(long offset, BasicImageWriter writer, List<String> paths) {
+        this.paths = new ArrayList<>();
+        this.paths.addAll(paths);
+        Collections.sort(this.paths);
+        Tree tree = new Tree(this.paths);
+        adder = new LocationsAdder(tree, offset, writer);
+    }
+
+    public void addContent(DataOutputStream out) throws IOException {
+        List<byte[]> content = adder.computeContent();
+        for (byte[] c : content) {
+            out.write(c, 0, c.length);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageStringsWriter.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jlink.internal;
+
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import jdk.internal.jimage.ImageStream;
+import jdk.internal.jimage.ImageStrings;
+import jdk.internal.jimage.ImageStringsReader;
+
+class ImageStringsWriter implements ImageStrings {
+    private static final int NOT_FOUND = -1;
+    static final int EMPTY_OFFSET = 0;
+
+    private final HashMap<String, Integer> stringToOffsetMap;
+    private final ImageStream stream;
+
+    ImageStringsWriter() {
+        this.stringToOffsetMap = new HashMap<>();
+        this.stream = new ImageStream();
+
+        // Reserve 0 offset for empty string.
+        int offset = addString("");
+        assert offset == 0 : "Empty string not zero offset";
+        // Reserve 1 offset for frequently used ".class".
+        addString("class");
+    }
+
+    private int addString(final String string) {
+        int offset = stream.getPosition();
+        byte[] bytes = ImageStringsReader.mutf8FromString(string);
+        stream.put(bytes, 0, bytes.length);
+        stream.put('\0');
+        stringToOffsetMap.put(string, offset);
+
+        return offset;
+    }
+
+    @Override
+    public int add(final String string) {
+        int offset = find(string);
+
+        return offset == NOT_FOUND ? addString(string) : offset;
+    }
+
+    int find(final String string) {
+        Integer offset = stringToOffsetMap.get(string);
+
+        return offset != null ? offset : NOT_FOUND;
+    }
+
+    @Override
+    public String get(int offset) {
+        ByteBuffer buffer = stream.getBuffer();
+        int capacity = buffer.capacity();
+        assert 0 <= offset && offset < capacity : "String buffer offset out of range";
+        int zero = NOT_FOUND;
+        for (int i = offset; i < capacity; i++) {
+            if (buffer.get(i) == '\0') {
+                zero = i;
+                break;
+            }
+        }
+        assert zero != NOT_FOUND;
+        int length = zero - offset;
+        byte[] bytes = new byte[length];
+        int mark = buffer.position();
+        buffer.position(offset);
+        buffer.get(bytes);
+        buffer.position(mark);
+
+        return ImageStringsReader.stringFromMUTF8(bytes);
+    }
+
+    ImageStream getStream() {
+        return stream;
+    }
+
+    int getSize() {
+        return stream.getSize();
+    }
+
+    int getCount() {
+        return stringToOffsetMap.size();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JarArchive.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jlink.internal;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
+import java.nio.file.Path;
+import java.util.Objects;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import jdk.tools.jlink.internal.Archive.Entry.EntryType;
+
+/**
+ * An Archive backed by a jar file.
+ */
+public abstract class JarArchive implements Archive {
+
+    /**
+     * An entry located in a jar file.
+     */
+    private class JarEntry extends Entry {
+
+        private final long size;
+        private final ZipEntry entry;
+        private final ZipFile file;
+
+        JarEntry(String path, String name, EntryType type, ZipFile file, ZipEntry entry) {
+            super(JarArchive.this, path, name, type);
+            this.entry = entry;
+            this.file = file;
+            size = entry.getSize();
+        }
+
+        /**
+         * Returns the number of uncompressed bytes for this entry.
+         */
+        @Override
+        public long size() {
+            return size;
+        }
+
+        @Override
+        public InputStream stream() throws IOException {
+            return file.getInputStream(entry);
+        }
+    }
+
+    private static final String MODULE_INFO = "module-info.class";
+
+    private final Path file;
+    private final String moduleName;
+    // currently processed ZipFile
+    private ZipFile zipFile;
+
+    protected JarArchive(String mn, Path file) {
+        Objects.requireNonNull(mn);
+        Objects.requireNonNull(file);
+        this.moduleName = mn;
+        this.file = file;
+    }
+
+    @Override
+    public String moduleName() {
+        return moduleName;
+    }
+
+    @Override
+    public Path getPath() {
+        return file;
+    }
+
+    @Override
+    public Stream<Entry> entries() {
+        try {
+            if (zipFile == null) {
+                open();
+            }
+        } catch (IOException ioe) {
+            throw new UncheckedIOException(ioe);
+        }
+        return zipFile.stream().map(this::toEntry).filter(n -> n != null);
+    }
+
+    abstract EntryType toEntryType(String entryName);
+
+    abstract String getFileName(String entryName);
+
+    private Entry toEntry(ZipEntry ze) {
+        String name = ze.getName();
+        String fn = getFileName(name);
+
+        if (ze.isDirectory() || fn.startsWith("_")) {
+            return null;
+        }
+
+        EntryType rt = toEntryType(name);
+
+        if (fn.equals(MODULE_INFO)) {
+            fn = moduleName + "/" + MODULE_INFO;
+        }
+        return new JarEntry(ze.getName(), fn, rt, zipFile, ze);
+    }
+
+    @Override
+    public void close() throws IOException {
+        if (zipFile != null) {
+            zipFile.close();
+        }
+    }
+
+    @Override
+    public void open() throws IOException {
+        if (zipFile != null) {
+            zipFile.close();
+        }
+        zipFile = new ZipFile(file.toFile());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,568 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.UncheckedIOException;
+import java.lang.module.Configuration;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReference;
+import java.lang.module.ResolutionException;
+import java.lang.module.ResolvedModule;
+import java.lang.reflect.InvocationTargetException;
+import java.net.URI;
+import java.nio.ByteOrder;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Date;
+import java.util.Formatter;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import jdk.internal.module.ConfigurableModuleFinder;
+import jdk.internal.module.ConfigurableModuleFinder.Phase;
+import jdk.tools.jlink.internal.TaskHelper.BadArgs;
+import static jdk.tools.jlink.internal.TaskHelper.JLINK_BUNDLE;
+import jdk.tools.jlink.internal.TaskHelper.Option;
+import jdk.tools.jlink.internal.TaskHelper.OptionsHelper;
+import jdk.tools.jlink.internal.ImagePluginStack.ImageProvider;
+import jdk.tools.jlink.plugin.ExecutableImage;
+import jdk.tools.jlink.Jlink.JlinkConfiguration;
+import jdk.tools.jlink.Jlink.PluginsConfiguration;
+import jdk.tools.jlink.plugin.PluginException;
+import jdk.tools.jlink.builder.DefaultImageBuilder;
+import jdk.tools.jlink.plugin.Plugin;
+
+/**
+ * Implementation for the jlink tool.
+ *
+ * ## Should use jdk.joptsimple some day.
+ */
+public class JlinkTask {
+
+    private static <T extends Throwable> void fail(Class<T> type,
+            String format,
+            Object... args) throws T {
+        String msg = new Formatter().format(format, args).toString();
+        try {
+            T t = type.getConstructor(String.class).newInstance(msg);
+            throw t;
+        } catch (InstantiationException |
+                InvocationTargetException |
+                NoSuchMethodException |
+                IllegalAccessException e) {
+            throw new InternalError("Unable to create an instance of " + type, e);
+        }
+    }
+
+    private static final TaskHelper taskHelper
+            = new TaskHelper(JLINK_BUNDLE);
+
+    static Option<?>[] recognizedOptions = {
+        new Option<JlinkTask>(false, (task, opt, arg) -> {
+            task.options.help = true;
+        }, "--help"),
+        new Option<JlinkTask>(true, (task, opt, arg) -> {
+            String[] dirs = arg.split(File.pathSeparator);
+            task.options.modulePath = new Path[dirs.length];
+            int i = 0;
+            for (String dir : dirs) {
+                task.options.modulePath[i++] = Paths.get(dir);
+            }
+        }, "--modulepath", "--mp"),
+        new Option<JlinkTask>(true, (task, opt, arg) -> {
+            for (String mn : arg.split(",")) {
+                if (mn.isEmpty()) {
+                    throw taskHelper.newBadArgs("err.mods.must.be.specified",
+                            "--limitmods");
+                }
+                task.options.limitMods.add(mn);
+            }
+        }, "--limitmods"),
+        new Option<JlinkTask>(true, (task, opt, arg) -> {
+            for (String mn : arg.split(",")) {
+                if (mn.isEmpty()) {
+                    throw taskHelper.newBadArgs("err.mods.must.be.specified",
+                            "--addmods");
+                }
+                task.options.addMods.add(mn);
+            }
+        }, "--addmods"),
+        new Option<JlinkTask>(true, (task, opt, arg) -> {
+            Path path = Paths.get(arg);
+            task.options.output = path;
+        }, "--output"),
+        new Option<JlinkTask>(true, (task, opt, arg) -> {
+            if ("little".equals(arg)) {
+                task.options.endian = ByteOrder.LITTLE_ENDIAN;
+            } else if ("big".equals(arg)) {
+                task.options.endian = ByteOrder.BIG_ENDIAN;
+            } else {
+                throw taskHelper.newBadArgs("err.unknown.byte.order", arg);
+            }
+        }, "--endian"),
+        new Option<JlinkTask>(false, (task, opt, arg) -> {
+            task.options.version = true;
+        }, "--version"),
+        new Option<JlinkTask>(true, (task, opt, arg) -> {
+            Path path = Paths.get(arg);
+            if (Files.exists(path)) {
+                throw taskHelper.newBadArgs("err.dir.exists", path);
+            }
+            task.options.packagedModulesPath = path;
+        }, true, "--keep-packaged-modules"),
+        new Option<JlinkTask>(false, (task, opt, arg) -> {
+            task.options.genbom = true;
+        }, true, "--genbom"),
+        new Option<JlinkTask>(true, (task, opt, arg) -> {
+            task.options.saveoptsfile = arg;
+        }, "--saveopts"),
+        new Option<JlinkTask>(false, (task, opt, arg) -> {
+            task.options.fullVersion = true;
+        }, true, "--fullversion"),};
+
+    private static final String PROGNAME = "jlink";
+    private final OptionsValues options = new OptionsValues();
+
+    private static final OptionsHelper<JlinkTask> optionsHelper
+            = taskHelper.newOptionsHelper(JlinkTask.class, recognizedOptions);
+    private PrintWriter log;
+
+    void setLog(PrintWriter out) {
+        log = out;
+        taskHelper.setLog(log);
+    }
+
+    /**
+     * Result codes.
+     */
+    static final int EXIT_OK = 0, // Completed with no errors.
+            EXIT_ERROR = 1, // Completed but reported errors.
+            EXIT_CMDERR = 2, // Bad command-line arguments
+            EXIT_SYSERR = 3, // System error or resource exhaustion.
+            EXIT_ABNORMAL = 4;// terminated abnormally
+
+    static class OptionsValues {
+        boolean help;
+        boolean genbom;
+        String  saveoptsfile;
+        boolean version;
+        boolean fullVersion;
+        Path[] modulePath;
+        Set<String> limitMods = new HashSet<>();
+        Set<String> addMods = new HashSet<>();
+        Path output;
+        Path packagedModulesPath;
+        ByteOrder endian = ByteOrder.nativeOrder();
+    }
+
+    int run(String[] args) {
+        if (log == null) {
+            setLog(new PrintWriter(System.err));
+        }
+        try {
+            optionsHelper.handleOptions(this, args);
+            if (options.help) {
+                optionsHelper.showHelp(PROGNAME);
+                return EXIT_OK;
+            }
+            if (optionsHelper.listPlugins()) {
+                optionsHelper.listPlugins(true);
+                return EXIT_OK;
+            }
+            if (options.version || options.fullVersion) {
+                taskHelper.showVersion(options.fullVersion);
+                return EXIT_OK;
+            }
+            if (taskHelper.getExistingImage() == null) {
+                if (options.modulePath == null || options.modulePath.length == 0) {
+                    throw taskHelper.newBadArgs("err.modulepath.must.be.specified").showUsage(true);
+                }
+                createImage();
+            } else {
+                postProcessOnly(taskHelper.getExistingImage());
+            }
+
+            if (options.saveoptsfile != null) {
+                Files.write(Paths.get(options.saveoptsfile), getSaveOpts().getBytes());
+            }
+
+            return EXIT_OK;
+        } catch (UncheckedIOException | PluginException | IOException | ResolutionException e) {
+            log.println(taskHelper.getMessage("error.prefix") + " " + e.getMessage());
+            log.println(taskHelper.getMessage("main.usage.summary", PROGNAME));
+            return EXIT_ERROR;
+        } catch (BadArgs e) {
+            taskHelper.reportError(e.key, e.args);
+            if (e.showUsage) {
+                log.println(taskHelper.getMessage("main.usage.summary", PROGNAME));
+            }
+            return EXIT_CMDERR;
+        } catch (Throwable x) {
+            log.println(taskHelper.getMessage("main.msg.bug"));
+            x.printStackTrace(log);
+            return EXIT_ABNORMAL;
+        } finally {
+            log.flush();
+        }
+    }
+
+    private static Map<String, Path> modulesToPath(Configuration cf) {
+        Map<String, Path> modPaths = new HashMap<>();
+        for (ResolvedModule resolvedModule : cf.modules()) {
+            ModuleReference mref = resolvedModule.reference();
+            URI uri = mref.location().get();
+            modPaths.put(mref.descriptor().name(), Paths.get(uri));
+        }
+        return modPaths;
+    }
+
+    /*
+     * Jlink API entry point.
+     */
+    public static void createImage(JlinkConfiguration config,
+            PluginsConfiguration plugins)
+            throws Exception {
+        Objects.requireNonNull(config);
+        Objects.requireNonNull(config.getOutput());
+        plugins = plugins == null ? new PluginsConfiguration() : plugins;
+
+        if (config.getModulepaths().isEmpty()) {
+            throw new Exception("Empty module paths");
+        }
+        Path[] arr = new Path[config.getModulepaths().size()];
+        arr = config.getModulepaths().toArray(arr);
+        ModuleFinder finder
+                = newModuleFinder(arr, config.getLimitmods(), config.getModules());
+
+        // First create the image provider
+        ImageProvider imageProvider
+                = createImageProvider(finder,
+                                      checkAddMods(config.getModules()),
+                                      config.getLimitmods(),
+                                      config.getByteOrder(),
+                                      null);
+
+        // Then create the Plugin Stack
+        ImagePluginStack stack = ImagePluginConfiguration.parseConfiguration(plugins,
+                genBOMContent(config, plugins));
+
+        //Ask the stack to proceed;
+        stack.operate(imageProvider);
+    }
+
+    /*
+     * Jlink API entry point.
+     */
+    public static void postProcessImage(ExecutableImage image, List<Plugin> postProcessorPlugins)
+            throws Exception {
+        Objects.requireNonNull(image);
+        Objects.requireNonNull(postProcessorPlugins);
+        PluginsConfiguration config = new PluginsConfiguration(postProcessorPlugins);
+        ImagePluginStack stack = ImagePluginConfiguration.
+                parseConfiguration(config);
+
+        stack.operate((ImagePluginStack stack1) -> image);
+    }
+
+    private void postProcessOnly(Path existingImage) throws Exception {
+        PluginsConfiguration config = taskHelper.getPluginsConfig(null, false);
+        ExecutableImage img = DefaultImageBuilder.getExecutableImage(existingImage);
+        if (img == null) {
+            throw taskHelper.newBadArgs("err.existing.image.invalid");
+        }
+        postProcessImage(img, config.getPlugins());
+    }
+
+    private void createImage() throws Exception {
+        if (options.output == null) {
+            throw taskHelper.newBadArgs("err.output.must.be.specified").showUsage(true);
+        }
+        ModuleFinder finder
+                = newModuleFinder(options.modulePath, options.limitMods, options.addMods);
+        try {
+            options.addMods = checkAddMods(options.addMods);
+        } catch (IllegalArgumentException ex) {
+            throw taskHelper.newBadArgs("err.mods.must.be.specified", "--addmods")
+                    .showUsage(true);
+        }
+        // First create the image provider
+        ImageProvider imageProvider
+                = createImageProvider(finder,
+                        options.addMods,
+                        options.limitMods,
+                        options.endian,
+                        options.packagedModulesPath);
+
+        // Then create the Plugin Stack
+        ImagePluginStack stack = ImagePluginConfiguration.
+                parseConfiguration(taskHelper.getPluginsConfig(options.output, options.genbom),
+                        genBOMContent());
+
+        //Ask the stack to proceed
+        stack.operate(imageProvider);
+    }
+
+    private static Set<String> checkAddMods(Set<String> addMods) {
+        if (addMods.isEmpty()) {
+            throw new IllegalArgumentException("no modules to add");
+        }
+        return addMods;
+    }
+
+    private static ModuleFinder newModuleFinder(Path[] paths,
+            Set<String> limitMods,
+            Set<String> addMods) {
+        ModuleFinder finder = ModuleFinder.of(paths);
+
+        // jmods are located at link-time
+        if (finder instanceof ConfigurableModuleFinder) {
+            ((ConfigurableModuleFinder) finder).configurePhase(Phase.LINK_TIME);
+        }
+
+        // if limitmods is specified then limit the universe
+        if (!limitMods.isEmpty()) {
+            finder = limitFinder(finder, limitMods, addMods);
+        }
+        return finder;
+    }
+
+    private static ImageProvider createImageProvider(ModuleFinder finder,
+                                                     Set<String> addMods,
+                                                     Set<String> limitMods,
+                                                     ByteOrder order,
+                                                     Path retainModulesPath)
+            throws IOException
+    {
+        if (addMods.isEmpty()) {
+            throw new IllegalArgumentException("empty modules and limitmods");
+        }
+
+        Configuration cf = Configuration.empty()
+                .resolveRequires(finder,
+                                 ModuleFinder.empty(),
+                                 addMods);
+
+        Map<String, Path> mods = modulesToPath(cf);
+        return new ImageHelper(cf, mods, order, retainModulesPath);
+    }
+
+    /**
+     * Returns a ModuleFinder that limits observability to the given root
+     * modules, their transitive dependences, plus a set of other modules.
+     */
+    private static ModuleFinder limitFinder(ModuleFinder finder,
+            Set<String> roots,
+            Set<String> otherMods) {
+
+        // resolve all root modules
+        Configuration cf = Configuration.empty()
+                .resolveRequires(finder,
+                                 ModuleFinder.empty(),
+                                 roots);
+
+        // module name -> reference
+        Map<String, ModuleReference> map = new HashMap<>();
+        cf.modules().forEach(m -> {
+            ModuleReference mref = m.reference();
+            map.put(mref.descriptor().name(), mref);
+        });
+
+        // set of modules that are observable
+        Set<ModuleReference> mrefs = new HashSet<>(map.values());
+
+        // add the other modules
+        for (String mod : otherMods) {
+            Optional<ModuleReference> omref = finder.find(mod);
+            if (omref.isPresent()) {
+                ModuleReference mref = omref.get();
+                map.putIfAbsent(mod, mref);
+                mrefs.add(mref);
+            } else {
+                // no need to fail
+            }
+        }
+
+        return new ModuleFinder() {
+            @Override
+            public Optional<ModuleReference> find(String name) {
+                return Optional.ofNullable(map.get(name));
+            }
+
+            @Override
+            public Set<ModuleReference> findAll() {
+                return mrefs;
+            }
+        };
+    }
+
+    private String getSaveOpts() {
+        StringBuilder sb = new StringBuilder();
+        sb.append('#').append(new Date()).append("\n");
+        for (String c : optionsHelper.getInputCommand()) {
+            sb.append(c).append(" ");
+        }
+
+        return sb.toString();
+    }
+
+    private static String getBomHeader() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("#").append(new Date()).append("\n");
+        sb.append("#Please DO NOT Modify this file").append("\n");
+        return sb.toString();
+    }
+
+    private String genBOMContent() throws IOException {
+        StringBuilder sb = new StringBuilder();
+        sb.append(getBomHeader());
+        StringBuilder command = new StringBuilder();
+        for (String c : optionsHelper.getInputCommand()) {
+            command.append(c).append(" ");
+        }
+        sb.append("command").append(" = ").append(command);
+        sb.append("\n");
+
+        return sb.toString();
+    }
+
+    private static String genBOMContent(JlinkConfiguration config,
+            PluginsConfiguration plugins)
+            throws IOException {
+        StringBuilder sb = new StringBuilder();
+        sb.append(getBomHeader());
+        sb.append(config);
+        sb.append(plugins);
+        return sb.toString();
+    }
+
+    private static class ImageHelper implements ImageProvider {
+
+        final Set<Archive> archives;
+        final ByteOrder order;
+        final Path packagedModulesPath;
+
+        ImageHelper(Configuration cf,
+                    Map<String, Path> modsPaths,
+                    ByteOrder order,
+                    Path packagedModulesPath) throws IOException {
+            archives = modsPaths.entrySet().stream()
+                                .map(e -> newArchive(e.getKey(), e.getValue()))
+                                .collect(Collectors.toSet());
+            this.order = order;
+            this.packagedModulesPath = packagedModulesPath;
+        }
+
+        private Archive newArchive(String module, Path path) {
+            if (path.toString().endsWith(".jmod")) {
+                return new JmodArchive(module, path);
+            } else if (path.toString().endsWith(".jar")) {
+                return new ModularJarArchive(module, path);
+            } else if (Files.isDirectory(path)) {
+                return new DirArchive(path);
+            } else {
+                fail(RuntimeException.class,
+                        "Selected module %s (%s) not in jmod or modular jar format",
+                        module,
+                        path);
+            }
+            return null;
+        }
+
+        @Override
+        public ExecutableImage retrieve(ImagePluginStack stack) throws IOException {
+            ExecutableImage image = ImageFileCreator.create(archives, order, stack);
+            if (packagedModulesPath != null) {
+                // copy the packaged modules to the given path
+                Files.createDirectories(packagedModulesPath);
+                for (Archive a : archives) {
+                    Path file = a.getPath();
+                    Path dest = packagedModulesPath.resolve(file.getFileName());
+                    Files.copy(file, dest);
+                }
+            }
+            return image;
+        }
+    }
+
+    private static enum Section {
+        NATIVE_LIBS("native", nativeDir()),
+        NATIVE_CMDS("bin", "bin"),
+        CLASSES("classes", "classes"),
+        CONFIG("conf", "conf"),
+        UNKNOWN("unknown", "unknown");
+
+        private static String nativeDir() {
+            if (System.getProperty("os.name").startsWith("Windows")) {
+                return "bin";
+            } else {
+                return "lib";
+            }
+        }
+
+        private final String jmodDir;
+        private final String imageDir;
+
+        Section(String jmodDir, String imageDir) {
+            this.jmodDir = jmodDir;
+            this.imageDir = imageDir;
+        }
+
+        String imageDir() {
+            return imageDir;
+        }
+
+        String jmodDir() {
+            return jmodDir;
+        }
+
+        boolean matches(String path) {
+            return path.startsWith(jmodDir);
+        }
+
+        static Section getSectionFromName(String dir) {
+            if (Section.NATIVE_LIBS.matches(dir)) {
+                return Section.NATIVE_LIBS;
+            } else if (Section.NATIVE_CMDS.matches(dir)) {
+                return Section.NATIVE_CMDS;
+            } else if (Section.CLASSES.matches(dir)) {
+                return Section.CLASSES;
+            } else if (Section.CONFIG.matches(dir)) {
+                return Section.CONFIG;
+            } else {
+                return Section.UNKNOWN;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JmodArchive.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jlink.internal;
+
+import jdk.tools.jlink.internal.JarArchive;
+import java.nio.file.Path;
+import java.util.Objects;
+import jdk.tools.jlink.internal.Archive.Entry.EntryType;
+
+/**
+ * An Archive backed by a jmod file.
+ */
+public class JmodArchive extends JarArchive {
+
+    private static final String JMOD_EXT = ".jmod";
+    private static final String MODULE_NAME = "module";
+    private static final String MODULE_INFO = "module-info.class";
+    private static final String CLASSES     = "classes";
+    private static final String NATIVE_LIBS = "native";
+    private static final String NATIVE_CMDS = "bin";
+    private static final String CONFIG      = "conf";
+
+    public JmodArchive(String mn, Path jmod) {
+        super(mn, jmod);
+        String filename = Objects.requireNonNull(jmod.getFileName()).toString();
+        if (!filename.endsWith(JMOD_EXT))
+            throw new UnsupportedOperationException("Unsupported format: " + filename);
+    }
+
+    @Override
+    EntryType toEntryType(String entryName) {
+        String section = getSection(entryName.replace('\\', '/'));
+        switch (section) {
+            case CLASSES:
+                return EntryType.CLASS_OR_RESOURCE;
+            case NATIVE_LIBS:
+                return EntryType.NATIVE_LIB;
+            case NATIVE_CMDS:
+                return EntryType.NATIVE_CMD;
+            case CONFIG:
+                return EntryType.CONFIG;
+            case MODULE_NAME:
+                return EntryType.MODULE_NAME;
+            default:
+                //throw new InternalError("unexpected entry: " + name + " " + zipfile.toString()); //TODO
+                throw new InternalError("unexpected entry: " + section);
+        }
+    }
+
+    private static String getSection(String entryName) {
+        int i = entryName.indexOf('/');
+        // Unnamed section.
+        String section = "";
+        if (i > 0) {
+            section = entryName.substring(0, entryName.indexOf('/'));
+        }
+        return section;
+    }
+
+    @Override
+    String getFileName(String entryName) {
+        entryName = entryName.replace('\\', '/');
+        return entryName.substring(entryName.indexOf('/') + 1);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jlink.internal;
+
+import java.io.*;
+
+public class Main {
+    public static void main(String... args) throws Exception {
+        JlinkTask t = new JlinkTask();
+        int rc = t.run(args);
+        System.exit(rc);
+    }
+
+
+    /**
+     * Entry point that does <i>not</i> call System.exit.
+     *
+     * @param args command line arguments
+     * @param out output stream
+     * @return an exit code. 0 means success, non-zero means an error occurred.
+     */
+    public static int run(String[] args, PrintWriter out) {
+        JlinkTask t = new JlinkTask();
+        t.setLog(out);
+        return t.run(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ModularJarArchive.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jlink.internal;
+
+import java.nio.file.Path;
+import java.util.Objects;
+import jdk.tools.jlink.internal.Archive.Entry.EntryType;
+
+/**
+ * An Archive backed by a jar file.
+ */
+public class ModularJarArchive extends JarArchive {
+
+    private static final String JAR_EXT = ".jar";
+
+    public ModularJarArchive(String mn, Path jmod) {
+        super(mn, jmod);
+        String filename = Objects.requireNonNull(jmod.getFileName()).toString();
+        if (!filename.endsWith(JAR_EXT))
+            throw new UnsupportedOperationException("Unsupported format: " + filename);
+    }
+
+    @Override
+    EntryType toEntryType(String section) {
+        return EntryType.CLASS_OR_RESOURCE;
+    }
+
+    @Override
+    String getFileName(String entryName) {
+        return entryName;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/PerfectHashBuilder.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,360 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+*/
+
+package jdk.tools.jlink.internal;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import jdk.internal.jimage.ImageStringsReader;
+
+/*
+ * The algorithm used here is outlined in Applications of Finite Automata
+ * Representing Large Vocabularies - Claudio L Lucchesi and Tomasz Kowaltowski,
+ * 1992, and A Practical Minimal Perfect Hashing Method - Fabiano C. Botelho1,
+ * Yoshiharu Kohayakawa, and Nivio Ziviani, 2005.
+ *
+ * The primary JDK use of this algorithm is managing the jimage location index.
+ *
+ * The goal of PerfectHashBuilder is to construct an automaton which maps a
+ * string key to a unique index 0..N-1, where N is the number of key-value pairs.
+ * What makes MPHM effective is that the size of the lookup table is N or very
+ * near N, and the minimum lookup is O(1) maximum lookup is O(2).
+ *
+ * The result of PerfectHashBuilder is two integer arrays, redirect and order.
+ * The redirect table provides a 1-1 mapping to the order table, using the
+ * reader algorithm described further on.  The order table provides a mapping
+ * to entries.  If entries are fixed size and can be put in a direct table, then
+ * the order table can be used to construct the direct table and then discarded.
+ *
+ * The steps for constructing the lookup tables are as follows;
+ *
+ *   - Compute an MPHM hash for each key, based on a fixed base value modulo N.
+ *     Note, the hash is based on the modified UTF-8 of the key, simplifying
+ *     computation in native code.
+ *
+ *   - Combine keys that map to the same hash code (collisions) into bucket
+ *     chains.
+ *
+ *   - Sort bucket chains by length of chains, longest first (most collisions.)
+ *     Sorting is done to pack the redirect table with the worst collision
+ *     offenders first.
+ *
+ *   - For each chain, recompute the hash of each key using a new base value.
+ *     Recomputation should give a different key distribution. A tally is kept
+ *     of where the key maps, using the order table. The tally is used to detect
+ *     new collisions. If there are further collisions, then restart
+ *     redistribution using a different hash base value.  If a chain is
+ *     successfully distributed, then the base value used to compute the hash
+ *     is recorded in the redirect table.
+ *
+ *   - Once all colliding chains are resolved (length > 1), then the chains with
+ *     only one entry are used to fill in the empty slots in the order table.
+ *     These keys are recorded in the redirect table using the twos complement
+ *     of the order index.
+ *
+ *   - It is possible that a given set of keys cannot be packed into a table of
+ *     size N.  If this situation occurs then the size of the table is
+ *     adjusted so that keys distribute differently.
+ *
+ * Readers algoritm;
+ *
+ *   - Compute the hash for the key using the fixed base value modulo N.  This
+ *     will provide an index into the redirect table. The integer value in the
+ *     redirect table will determine the next step.
+ *
+ *   - If the value in the redirect table is positive, then that value is used
+ *     to rehash the key to get the index into the order table.
+ *
+ *   - If the value in the redirect table is negative, then that value is the
+ *     twos complement of the index into the order table.
+ *
+ *   - If the value in the redirect table is zero, then there is no matching
+ *     entry.
+ *
+ *   - Note that the resulting entry needs to be validated to ensure a match.
+ *     This is typically done by comparing the key with the key in entry.
+ */
+public class PerfectHashBuilder<E> {
+    private static final int RETRY_LIMIT = 1000;
+
+    private Class<?> entryComponent;
+    private Class<?> bucketComponent;
+
+    private final Map<String, Entry<E>> map = new LinkedHashMap<>();
+    private int[] redirect;
+    private Entry<E>[] order;
+    private int count = 0;
+
+    @SuppressWarnings("EqualsAndHashcode")
+    public static class Entry<E> {
+        private final String key;
+        private final E value;
+
+        Entry() {
+            this("", null);
+        }
+
+        Entry(String key, E value) {
+            this.key = key;
+            this.value = value;
+        }
+
+        String getKey() {
+            return key;
+        }
+
+        E getValue() {
+            return value;
+        }
+
+        int hashCode(int seed) {
+            return ImageStringsReader.hashCode(key, seed);
+        }
+
+        @Override
+        public int hashCode() {
+            return ImageStringsReader.hashCode(key);
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (other == this) {
+                return true;
+            }
+            if (!(other instanceof Entry)) {
+                return false;
+            }
+            Entry<?> entry = (Entry<?>) other;
+            return entry.key.equals(key);
+        }
+    }
+
+    static class Bucket<E> implements Comparable<Bucket<E>> {
+        final List<Entry<E>> list = new ArrayList<>();
+
+        void add(Entry<E> entry) {
+            list.add(entry);
+        }
+
+        int getSize() {
+            return list.size();
+        }
+
+        List<Entry<E>> getList() {
+            return list;
+        }
+
+        Entry<E> getFirst() {
+            assert !list.isEmpty() : "bucket should never be empty";
+            return list.get(0);
+        }
+
+        @Override
+        public int hashCode() {
+            return getFirst().hashCode();
+        }
+
+        @Override
+        @SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
+        public boolean equals(Object obj) {
+            return this == obj;
+        }
+
+        @Override
+        public int compareTo(Bucket<E> o) {
+            return o.getSize() - getSize();
+        }
+    }
+
+    public PerfectHashBuilder(Class<?> entryComponent, Class<?> bucketComponent) {
+        this.entryComponent = entryComponent;
+        this.bucketComponent = bucketComponent;
+    }
+
+    public int getCount() {
+        return map.size();
+    }
+
+    public int[] getRedirect() {
+        return redirect.clone();
+    }
+
+    public Entry<E>[] getOrder() {
+        return order.clone();
+    }
+
+    public Entry<E> put(String key, E value) {
+        return put(new Entry<>(key, value));
+    }
+
+    public Entry<E> put(Entry<E> entry) {
+        Entry<E> old = map.put(entry.key, entry);
+
+        if (old == null) {
+            count++;
+        }
+
+        return old;
+    }
+
+    @SuppressWarnings("unchecked")
+    public void generate() {
+        // If the table is empty then exit early.
+        boolean redo = count != 0;
+
+        // Repeat until a valid packing is achieved.
+        while (redo) {
+            redo = false;
+
+            // Allocate the resulting redirect and order tables.
+            redirect = new int[count];
+            order = (Entry<E>[])Array.newInstance(entryComponent, count);
+
+            // Place all the entries in bucket chains based on hash. Sort by
+            // length of chain.
+            Bucket<E>[] sorted = createBuckets();
+            int free = 0;
+
+            // Iterate through the chains, longest first.
+            for (Bucket<E> bucket : sorted) {
+                if (bucket.getSize() != 1) {
+                    // Attempt to pack entries until no collisions occur.
+                    if (!collidedEntries(bucket, count)) {
+                        // Failed to pack. Meed to grow table.
+                        redo = true;
+                        break;
+                    }
+                } else {
+                    // A no collision entry (bucket.getSize() == 1). Find a free
+                    // spot in the order table.
+                    for ( ; free < count && order[free] != null; free++) {}
+
+                    // If none found, then grow table.
+                    if (free >= count) {
+                        redo = true;
+                        break;
+                    }
+
+                    // Store entry in order table.
+                    order[free] = bucket.getFirst();
+                    // Twos complement of order index stired in the redirect table.
+                    redirect[(bucket.hashCode() & 0x7FFFFFFF) % count] = -1 - free;
+                    // Update free slot index.
+                    free++;
+                }
+            }
+
+            // If packing failed, then bump table size. Make odd to increase
+            // chances of being relatively prime.
+            if (redo) {
+                count = (count + 1) | 1;
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private Bucket<E>[] createBuckets() {
+        // Build bucket chains based on key hash.  Collisions end up in same chain.
+        Bucket<E>[] buckets = (Bucket<E>[])Array.newInstance(bucketComponent, count);
+
+        map.values().stream().forEach((entry) -> {
+            int index = (entry.hashCode() & 0x7FFFFFFF) % count;
+            Bucket<E> bucket = buckets[index];
+
+            if (bucket == null) {
+                buckets[index] = bucket = new Bucket<>();
+            }
+
+            bucket.add(entry);
+        });
+
+        // Sort chains, longest first.
+        Bucket<E>[] sorted = Arrays.asList(buckets).stream()
+                .filter((bucket) -> (bucket != null))
+                .sorted()
+                .toArray((length) -> {
+                    return (Bucket<E>[])Array.newInstance(bucketComponent, length);
+                });
+
+        return sorted;
+    }
+
+    private boolean collidedEntries(Bucket<E> bucket, int count) {
+        // Track packing attempts.
+        List<Integer> undo = new ArrayList<>();
+        // Start with a new hash seed.
+        int seed = ImageStringsReader.HASH_MULTIPLIER + 1;
+        int retry = 0;
+
+        // Attempt to pack all the entries in a single chain.
+        redo:
+        while (true) {
+            for (Entry<E> entry : bucket.getList()) {
+                // Compute new hash.
+                int index = entry.hashCode(seed) % count;
+
+                // If a collision is detected.
+                if (order[index] != null) {
+                    // Only retry so many times with current table size.
+                    if (++retry > RETRY_LIMIT) {
+                        return false;
+                    }
+
+                    // Undo the attempted packing.
+                    undo.stream().forEach((i) -> {
+                        order[i] = null;
+                    });
+
+                    // Reset the undo list and bump up the hash seed.
+                    undo.clear();
+                    seed++;
+
+                    // Zero seed is not valid.
+                    if (seed == 0) {
+                        seed = 1;
+                    }
+
+                    // Try again.
+                    continue redo;
+                }
+
+                // No collision.
+                order[index] = entry;
+                undo.add(index);
+            }
+
+            // Entire chain packed. Record hash seed used.
+            redirect[(bucket.hashCode() & 0x7FFFFFFF) % count] = seed;
+
+            break;
+        }
+
+        return true;
+    }
+ }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/PluginContextImpl.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal;
+
+import java.util.Properties;
+
+import jdk.tools.jlink.plugin.PluginContext;
+
+public final class PluginContextImpl implements PluginContext {
+    private final Properties releaseProps = new Properties();
+
+    public Properties getReleaseProperties() {
+        return releaseProps;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/PluginOrderingGraph.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import jdk.tools.jlink.plugin.Plugin;
+import jdk.tools.jlink.plugin.PluginException;
+
+/**
+ *
+ * @author jdenise
+ */
+public class PluginOrderingGraph {
+
+    static class Node {
+
+        Plugin plugin;
+        Set<Node> nexts = new HashSet<>();
+        Set<Node> previous = new HashSet<>();
+
+        @Override
+        public String toString() {
+            return plugin.getName();
+        }
+    }
+
+    public static List<Plugin> sort(List<Plugin> plugs) {
+        List<Plugin> plugins = new ArrayList<>();
+        plugins.addAll(plugs);
+
+        // for each plugin creates its graph.
+        Map<Plugin, Node> graphs = buildGraphs(plugins);
+
+        // At this points all individual graphs are connected
+        // Check for cycles.
+        for (Node n : graphs.values()) {
+            checkCycle(n);
+        }
+
+        List<Plugin> orderedPlugins = new ArrayList<>();
+        // Retrieve the current roots, add them to the result, remove them from
+        while (!plugins.isEmpty()) {
+            // Build the current set of graphs from the list of input plugins
+            Map<Plugin, Node> currentGraphs = buildGraphs(plugins);
+            // Retrieve the root nodes (no previous)
+            List<Node> roots = getRoots(currentGraphs);
+            for (Node n : roots) {
+                // add them to the ordered list.
+                orderedPlugins.add(n.plugin);
+                // remove them from the input list.
+                plugins.remove(n.plugin);
+            }
+        }
+        return orderedPlugins;
+    }
+
+    // Create a grapth according to list of plugins.
+    private static Map<Plugin, Node> buildGraphs(List<Plugin> plugins) {
+        Map<String, Node> nodeStore = new HashMap<>();
+        for (Plugin p : plugins) {
+            Node newNode = new Node();
+            newNode.plugin = p;
+            nodeStore.put(p.getName(), newNode);
+        }
+        // for each plugin creates its graph.
+        Map<Plugin, Node> graphs = new LinkedHashMap<>();
+        for (Plugin p : plugins) {
+            Node node = nodeStore.get(p.getName());
+            for (String after : p.isAfter()) {
+                Node previous = nodeStore.get(after);
+                if (previous == null) {
+                    continue;
+                }
+                node.previous.add(previous);
+                previous.nexts.add(node);
+            }
+            for (String before : p.isBefore()) {
+                Node next = nodeStore.get(before);
+                if (next == null) {
+                    continue;
+                }
+                node.nexts.add(next);
+                next.previous.add(node);
+            }
+            graphs.put(p, node);
+
+        }
+        return graphs;
+    }
+
+    private static List<Node> getRoots(Map<Plugin, Node> graphs) {
+        List<Node> ret = new ArrayList<>();
+        for (Node n : graphs.values()) {
+            if (n.previous.isEmpty()) {
+                ret.add(n);
+            }
+        }
+        return ret;
+    }
+
+    private static void checkCycle(Node root) {
+        for (Node next : root.nexts) {
+            Set<Node> path = new LinkedHashSet<>();
+            path.add(root);
+            checkCycle(next, root, path);
+        }
+    }
+
+    private static void checkCycle(Node current, Node root, Set<Node> path) {
+        path.add(current);
+        if (current == root) {
+            StringBuilder builder = new StringBuilder();
+            for (Node p : path) {
+                builder.append(p.plugin.getName()).append(">");
+            }
+            builder.append(root);
+            throw new PluginException("Cycle detected for " + builder.toString()
+                    + ". Please fix Plugin ordering (before, after constraints).");
+        }
+
+        for (Node n : current.nexts) {
+            checkCycle(n, root, path);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/PluginRepository.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal;
+
+import java.lang.reflect.Layer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.ServiceLoader;
+import jdk.tools.jlink.plugin.Plugin;
+import jdk.tools.jlink.plugin.PluginException;
+import jdk.tools.jlink.plugin.PostProcessorPlugin;
+import jdk.tools.jlink.plugin.TransformerPlugin;
+
+/**
+ *
+ * Plugin Providers repository. Plugin Providers are
+ * retrieved thanks to the ServiceLoader mechanism.
+ */
+public final class PluginRepository {
+
+    private PluginRepository() {
+    }
+
+    private static final Map<String, Plugin> registeredPlugins = new HashMap<>();
+
+    /**
+     * Retrieves the plugin associated to the passed name. If multiple providers
+     * exist for the same name,
+     * then an exception is thrown.
+     * @param name The plugin provider name.
+     * @param pluginsLayer
+     * @return A provider or null if not found.
+     */
+    public static Plugin getPlugin(String name,
+            Layer pluginsLayer) {
+        Plugin tp = getPlugin(TransformerPlugin.class, name, pluginsLayer);
+        Plugin ppp = getPlugin(PostProcessorPlugin.class, name, pluginsLayer);
+
+        // We should not have a transformer plugin and a post processor plugin
+        // of the same name. That kind of duplicate is detected here.
+        if (tp != null && ppp != null) {
+            throw new PluginException("Multiple plugin "
+                        + "for the name " + name);
+        }
+
+        return tp != null? tp : ppp;
+    }
+
+    /**
+     * Build plugin for the passed name.
+     *
+     * @param config Optional config.
+     * @param name Non null name.
+     * @param pluginsLayer
+     * @return A plugin or null if no plugin found.
+     */
+    public static Plugin newPlugin(Map<String, String> config, String name,
+            Layer pluginsLayer) {
+        Objects.requireNonNull(name);
+        Objects.requireNonNull(pluginsLayer);
+        Plugin plugin = getPlugin(name, pluginsLayer);
+        if (plugin != null) {
+            plugin.configure(config);
+        }
+        return plugin;
+    }
+
+    /**
+     * Explicit registration of a plugin in the repository. Used by unit tests
+     * @param plugin The plugin to register.
+     */
+    public synchronized static void registerPlugin(Plugin plugin) {
+        Objects.requireNonNull(plugin);
+        registeredPlugins.put(plugin.getName(), plugin);
+    }
+
+    /**
+     * Explicit unregistration of a plugin in the repository. Used by unit
+     * tests
+     *
+     * @param name Plugin name
+     */
+    public synchronized static void unregisterPlugin(String name) {
+        Objects.requireNonNull(name);
+        registeredPlugins.remove(name);
+    }
+
+    public static List<Plugin> getPlugins(Layer pluginsLayer) {
+        List<Plugin> plugins = new ArrayList<>();
+        plugins.addAll(getPlugins(TransformerPlugin.class, pluginsLayer));
+        plugins.addAll(getPlugins(PostProcessorPlugin.class, pluginsLayer));
+        return plugins;
+    }
+
+    private static <T extends Plugin> T getPlugin(Class<T> clazz, String name,
+            Layer pluginsLayer) {
+        Objects.requireNonNull(name);
+        Objects.requireNonNull(pluginsLayer);
+        @SuppressWarnings("unchecked")
+        T provider = null;
+        List<T> javaProviders = getPlugins(clazz, pluginsLayer);
+        for(T factory : javaProviders) {
+            if (factory.getName().equals(name)) {
+                if (provider != null) {
+                    throw new PluginException("Multiple plugin "
+                            + "for the name " + name);
+                }
+                provider = factory;
+            }
+        }
+        return provider;
+    }
+
+    /**
+     * The post processors accessible in the current context.
+     *
+     * @param pluginsLayer
+     * @return The list of post processors.
+     */
+    private static <T extends Plugin> List<T> getPlugins(Class<T> clazz, Layer pluginsLayer) {
+        Objects.requireNonNull(pluginsLayer);
+        List<T> factories = new ArrayList<>();
+        try {
+            Iterator<T> providers
+                    = ServiceLoader.load(pluginsLayer, clazz).iterator();
+            while (providers.hasNext()) {
+                factories.add(providers.next());
+            }
+            registeredPlugins.values().stream().forEach((fact) -> {
+                if (clazz.isInstance(fact)) {
+                    @SuppressWarnings("unchecked")
+                    T trans = (T) fact;
+                    factories.add(trans);
+                }
+            });
+            return factories;
+        } catch (Exception ex) {
+            throw new PluginException(ex);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/PoolImpl.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Objects;
+import jdk.internal.jimage.decompressor.CompressedResourceHeader;
+import jdk.tools.jlink.plugin.Pool;
+
+/**
+ * Pool of module data.
+ */
+public class PoolImpl extends Pool {
+
+    /**
+     * A resource that has been compressed.
+     */
+    public static final class CompressedModuleData extends ModuleData {
+
+        private final long uncompressed_size;
+
+        private CompressedModuleData(String module, String path,
+                InputStream stream, long size,
+                long uncompressed_size) {
+            super(module, path, ModuleDataType.CLASS_OR_RESOURCE, stream, size);
+            this.uncompressed_size = uncompressed_size;
+        }
+
+        public long getUncompressedSize() {
+            return uncompressed_size;
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (!(other instanceof CompressedModuleData)) {
+                return false;
+            }
+            CompressedModuleData f = (CompressedModuleData) other;
+            return f.getPath().equals(getPath());
+        }
+
+        @Override
+        public int hashCode() {
+            return super.hashCode();
+        }
+    }
+
+    private boolean isReadOnly;
+    private final StringTable table;
+
+    public PoolImpl() {
+        this(ByteOrder.nativeOrder(), new StringTable() {
+
+            @Override
+            public int addString(String str) {
+                return -1;
+            }
+            @Override
+            public String getString(int id) {
+                return null;
+            }
+        });
+    }
+
+    public PoolImpl(ByteOrder order) {
+        this(order, new StringTable() {
+
+            @Override
+            public int addString(String str) {
+                return -1;
+            }
+            @Override
+            public String getString(int id) {
+                return null;
+            }
+        });
+    }
+
+    public PoolImpl(ByteOrder order, StringTable table) {
+        super(order);
+        this.table = table;
+    }
+
+    public StringTable getStringTable() {
+        return table;
+    }
+
+    /**
+     * Make this Resources instance read-only. No resource can be added.
+     */
+    public void setReadOnly() {
+        isReadOnly = true;
+    }
+
+    /**
+     * Read only state.
+     *
+     * @return true if readonly false otherwise.
+     */
+    @Override
+    public boolean isReadOnly() {
+        return isReadOnly;
+    }
+
+    public static CompressedModuleData newCompressedResource(ModuleData original,
+            ByteBuffer compressed,
+            String plugin, String pluginConfig, StringTable strings,
+            ByteOrder order) {
+        Objects.requireNonNull(original);
+        Objects.requireNonNull(compressed);
+        Objects.requireNonNull(plugin);
+
+        boolean isTerminal = !(original instanceof CompressedModuleData);
+        long uncompressed_size = original.getLength();
+        if (original instanceof CompressedModuleData) {
+            CompressedModuleData comp = (CompressedModuleData) original;
+            uncompressed_size = comp.getUncompressedSize();
+        }
+        int nameOffset = strings.addString(plugin);
+        int configOffset = -1;
+        if (pluginConfig != null) {
+            configOffset = strings.addString(plugin);
+        }
+        CompressedResourceHeader rh
+                = new CompressedResourceHeader(compressed.limit(), original.getLength(),
+                        nameOffset, configOffset, isTerminal);
+        // Merge header with content;
+        byte[] h = rh.getBytes(order);
+        ByteBuffer bb = ByteBuffer.allocate(compressed.limit() + h.length);
+        bb.order(order);
+        bb.put(h);
+        bb.put(compressed);
+        byte[] contentWithHeader = bb.array();
+
+        CompressedModuleData compressedResource
+                = new CompressedModuleData(original.getModule(), original.getPath(),
+                        new ByteArrayInputStream(contentWithHeader),
+                        contentWithHeader.length, uncompressed_size);
+        return compressedResource;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePrevisitor.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal;
+
+import jdk.tools.jlink.plugin.Pool;
+
+/**
+ * Plugin wishing to pre-visit the resources must implement this interface.
+ * Pre-visit can be useful when some activities are required prior to the actual
+ * Resource visit.
+ * The StringTable plays a special role during previsit. The passed Strings are NOT
+ * added to the jimage file. The string usage is tracked in order to build an efficient
+ * string storage.
+ */
+public interface ResourcePrevisitor {
+
+    /**
+     * Previsit the collection of resources.
+     *
+     * @param resources Read only resources.
+     * @param strings StringTable instance. Add string to the StringTable to track string
+     * usage.
+     * @throws PluginException
+     */
+    public void previsit(Pool resources, StringTable strings);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/StringTable.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal;
+
+/**
+* Added strings are stored in the jimage strings table.
+*/
+public interface StringTable {
+    /**
+     * Add a string to the jimage strings table.
+     * @param str The string to add.
+     * @return a String identifier.
+     */
+    public int addString(String str);
+
+    /**
+     * Retrieve a string from the passed id.
+     * @param id The string id.
+     * @return The string referenced by the passed id.
+     */
+    public String getString(int id);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,730 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.lang.module.Configuration;
+import java.lang.module.ModuleFinder;
+import java.lang.reflect.Layer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.Set;
+
+import jdk.internal.module.ConfigurableModuleFinder;
+import jdk.internal.module.ConfigurableModuleFinder.Phase;
+import jdk.tools.jlink.Jlink;
+import jdk.tools.jlink.Jlink.PluginsConfiguration;
+import jdk.tools.jlink.plugin.Plugin;
+import jdk.tools.jlink.plugin.Plugin.CATEGORY;
+import jdk.tools.jlink.builder.DefaultImageBuilder;
+import jdk.tools.jlink.builder.ImageBuilder;
+import jdk.tools.jlink.plugin.PluginException;
+import jdk.tools.jlink.internal.plugins.PluginsResourceBundle;
+import jdk.tools.jlink.internal.plugins.DefaultCompressPlugin;
+import jdk.tools.jlink.internal.plugins.StripDebugPlugin;
+
+/**
+ *
+ * JLink and JImage tools shared helper.
+ */
+public final class TaskHelper {
+
+    public static final String JLINK_BUNDLE = "jdk.tools.jlink.resources.jlink";
+    public static final String JIMAGE_BUNDLE = "jdk.tools.jimage.resources.jimage";
+
+    private static final String DEFAULTS_PROPERTY = "jdk.jlink.defaults";
+
+    public final class BadArgs extends Exception {
+
+        static final long serialVersionUID = 8765093759964640721L;
+
+        private BadArgs(String key, Object... args) {
+            super(bundleHelper.getMessage(key, args));
+            this.key = key;
+            this.args = args;
+        }
+
+        public BadArgs showUsage(boolean b) {
+            showUsage = b;
+            return this;
+        }
+        public final String key;
+        public final Object[] args;
+        public boolean showUsage;
+    }
+
+    public static class Option<T> {
+
+        public interface Processing<T> {
+
+            void process(T task, String opt, String arg) throws BadArgs;
+        }
+
+        final boolean hasArg;
+        final Processing<T> processing;
+        final boolean hidden;
+        final String[] aliases;
+
+        public Option(boolean hasArg, Processing<T> processing, boolean hidden, String... aliases) {
+            this.hasArg = hasArg;
+            this.processing = processing;
+            this.aliases = aliases;
+            this.hidden = hidden;
+        }
+
+        public Option(boolean hasArg, Processing<T> processing, String... aliases) {
+            this(hasArg, processing, false, aliases);
+        }
+
+        public boolean isHidden() {
+            return hidden;
+        }
+
+        public boolean matches(String opt) {
+            for (String a : aliases) {
+                if (a.equals(opt)) {
+                    return true;
+                } else if (opt.startsWith("--")
+                        && (hasArg && opt.startsWith(a + "="))) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public boolean ignoreRest() {
+            return false;
+        }
+
+        void process(T task, String opt, String arg) throws BadArgs {
+            processing.process(task, opt, arg);
+        }
+    }
+
+    private static class PlugOption extends Option<PluginsOptions> {
+
+        public PlugOption(boolean hasArg,
+                Processing<PluginsOptions> processing, boolean hidden, String... aliases) {
+            super(hasArg, processing, hidden, aliases);
+        }
+
+        public PlugOption(boolean hasArg,
+                Processing<PluginsOptions> processing, String... aliases) {
+            super(hasArg, processing, aliases);
+        }
+    }
+
+    private final class PluginsOptions {
+
+        private static final String PLUGINS_PATH = "--plugin-module-path";
+        private static final String POST_PROCESS = "--post-process-path";
+
+        private Layer pluginsLayer = Layer.boot();
+        private String lastSorter;
+        private boolean listPlugins;
+        private Path existingImage;
+
+        // plugin to args maps. Each plugin may be used more than once in command line.
+        // Each such occurrence results in a Map of arguments. So, there could be multiple
+        // args maps per plugin instance.
+        private final Map<Plugin, List<Map<String, String>>> pluginToMaps = new HashMap<>();
+        private final List<PlugOption> pluginsOptions = new ArrayList<>();
+        private final List<PlugOption> mainOptions = new ArrayList<>();
+
+        private PluginsOptions(String pp) throws BadArgs {
+
+            if (pp != null) {
+                String[] dirs = pp.split(File.pathSeparator);
+                List<Path> paths = new ArrayList<>(dirs.length);
+                for (String dir : dirs) {
+                    paths.add(Paths.get(dir));
+                }
+
+                pluginsLayer = createPluginsLayer(paths);
+            }
+
+            Set<String> optionsSeen = new HashSet<>();
+            for (Plugin plugin : PluginRepository.
+                    getPlugins(pluginsLayer)) {
+                if (!Utils.isDisabled(plugin)) {
+                    addOrderedPluginOptions(plugin, optionsSeen);
+                }
+            }
+            mainOptions.add(new PlugOption(false,
+                    (task, opt, arg) -> {
+                        // This option is handled prior
+                        // to have the options parsed.
+                    },
+                    "--plugins-modulepath"));
+            mainOptions.add(new PlugOption(true, (task, opt, arg) -> {
+                Path path = Paths.get(arg);
+                if (!Files.exists(path) || !Files.isDirectory(path)) {
+                    throw newBadArgs("err.existing.image.must.exist");
+                }
+                existingImage = path.toAbsolutePath();
+            }, true, POST_PROCESS));
+            mainOptions.add(new PlugOption(true,
+                    (task, opt, arg) -> {
+                        lastSorter = arg;
+                    },
+                    true, "--resources-last-sorter"));
+            mainOptions.add(new PlugOption(false,
+                    (task, opt, arg) -> {
+                        listPlugins = true;
+                    },
+                    "--list-plugins"));
+        }
+
+        private List<Map<String, String>> argListFor(Plugin plugin) {
+            List<Map<String, String>> mapList = pluginToMaps.get(plugin);
+            if (mapList == null) {
+                mapList = new ArrayList<>();
+                pluginToMaps.put(plugin, mapList);
+            }
+            return mapList;
+        }
+
+        private void addEmptyArgumentMap(Plugin plugin) {
+            argListFor(plugin).add(Collections.emptyMap());
+        }
+
+        private Map<String, String> addArgumentMap(Plugin plugin) {
+            Map<String, String> map = new HashMap<>();
+            argListFor(plugin).add(map);
+            return map;
+        }
+
+        private void addOrderedPluginOptions(Plugin plugin,
+            Set<String> optionsSeen) throws BadArgs {
+            String option = plugin.getOption();
+            if (option == null) {
+                return;
+            }
+
+            // make sure that more than one plugin does not use the same option!
+            if (optionsSeen.contains(option)) {
+                throw new BadArgs("err.plugin.mutiple.options",
+                        option);
+            }
+            optionsSeen.add(option);
+
+            PlugOption plugOption
+                    = new PlugOption(plugin.hasArguments(),
+                            (task, opt, arg) -> {
+                                if (!Utils.isFunctional(plugin)) {
+                                    throw newBadArgs("err.provider.not.functional",
+                                            option);
+                                }
+
+                                if (! plugin.hasArguments()) {
+                                    addEmptyArgumentMap(plugin);
+                                    return;
+                                }
+
+                                Map<String, String> m = addArgumentMap(plugin);
+                                // handle one or more arguments
+                                if (arg.indexOf(':') == -1) {
+                                    // single argument case
+                                    m.put(option, arg);
+                                } else {
+                                    // This option can accept more than one arguments
+                                    // like --option_name=arg_value:arg2=value2:arg3=value3
+
+                                    // ":" followed by word char condition takes care of args that
+                                    // like Windows absolute paths "C:\foo", "C:/foo" [cygwin] etc.
+                                    // This enforces that key names start with a word character.
+                                    String[] args = arg.split(":(?=\\w)", -1);
+                                    String firstArg = args[0];
+                                    if (firstArg.isEmpty()) {
+                                        throw newBadArgs("err.provider.additional.arg.error",
+                                            option, arg);
+                                    }
+                                    m.put(option, firstArg);
+                                    // process the additional arguments
+                                    for (int i = 1; i < args.length; i++) {
+                                        String addArg = args[i];
+                                        int eqIdx = addArg.indexOf('=');
+                                        if (eqIdx == -1) {
+                                            throw newBadArgs("err.provider.additional.arg.error",
+                                                option, arg);
+                                        }
+
+                                        String addArgName = addArg.substring(0, eqIdx);
+                                        String addArgValue = addArg.substring(eqIdx+1);
+                                        if (addArgName.isEmpty() || addArgValue.isEmpty()) {
+                                            throw newBadArgs("err.provider.additional.arg.error",
+                                                option, arg);
+                                        }
+                                        m.put(addArgName, addArgValue);
+                                    }
+                                }
+                            },
+                            "--" + option);
+            pluginsOptions.add(plugOption);
+
+            if (Utils.isFunctional(plugin)) {
+                if (Utils.isAutoEnabled(plugin)) {
+                    addEmptyArgumentMap(plugin);
+                }
+
+                if (plugin instanceof DefaultCompressPlugin) {
+                    plugOption
+                        = new PlugOption(false,
+                            (task, opt, arg) -> {
+                                Map<String, String> m = addArgumentMap(plugin);
+                                m.put(DefaultCompressPlugin.NAME, DefaultCompressPlugin.LEVEL_2);
+                            }, "-c");
+                    mainOptions.add(plugOption);
+                } else if (plugin instanceof StripDebugPlugin) {
+                    plugOption
+                        = new PlugOption(false,
+                            (task, opt, arg) -> {
+                                addArgumentMap(plugin);
+                            }, "-G");
+                    mainOptions.add(plugOption);
+                }
+            }
+        }
+
+        private PlugOption getOption(String name) throws BadArgs {
+            for (PlugOption o : pluginsOptions) {
+                if (o.matches(name)) {
+                    return o;
+                }
+            }
+            for (PlugOption o : mainOptions) {
+                if (o.matches(name)) {
+                    return o;
+                }
+            }
+            return null;
+        }
+
+        private PluginsConfiguration getPluginsConfig(Path output,
+                boolean genbom) throws IOException, BadArgs {
+            if (output != null) {
+                if (Files.exists(output)) {
+                    throw new PluginException(PluginsResourceBundle.
+                            getMessage("err.dir.already.exits", output));
+                }
+            }
+
+            PluginContextImpl pluginContext = new PluginContextImpl();
+            List<Plugin> pluginsList = new ArrayList<>();
+            for (Entry<Plugin, List<Map<String, String>>> entry : pluginToMaps.entrySet()) {
+                Plugin plugin = entry.getKey();
+                List<Map<String, String>> argsMaps = entry.getValue();
+
+                // same plugin option may be used multiple times in command line.
+                // we call configure once for each occurrence. It is upto the plugin
+                // to 'merge' and/or 'override' arguments.
+                for (Map<String, String> map : argsMaps) {
+                    plugin.configure(Collections.unmodifiableMap(map), pluginContext);
+                }
+
+                if (!Utils.isDisabled(plugin)) {
+                    pluginsList.add(plugin);
+                }
+            }
+
+            // recreate or postprocessing don't require an output directory.
+            ImageBuilder builder = null;
+            if (output != null) {
+                builder = new DefaultImageBuilder(genbom, output);
+
+            }
+            return new Jlink.PluginsConfiguration(pluginsList,
+                    builder, lastSorter, pluginContext);
+        }
+    }
+
+    private static final class ResourceBundleHelper {
+
+        private final ResourceBundle bundle;
+        private final ResourceBundle pluginBundle;
+
+        ResourceBundleHelper(String path) {
+            Locale locale = Locale.getDefault();
+            try {
+                bundle = ResourceBundle.getBundle(path, locale);
+                pluginBundle = ResourceBundle.getBundle("jdk.tools.jlink.resources.plugins", locale);
+            } catch (MissingResourceException e) {
+                throw new InternalError("Cannot find jlink resource bundle for locale " + locale);
+            }
+        }
+
+        String getMessage(String key, Object... args) {
+            String val;
+            try {
+                val = bundle.getString(key);
+            } catch (MissingResourceException e) {
+                // XXX OK, check in plugin bundle
+                val = pluginBundle.getString(key);
+            }
+            return MessageFormat.format(val, args);
+        }
+
+    }
+
+    public final class OptionsHelper<T> {
+
+        private final List<Option<T>> options;
+        private String[] command;
+        private String defaults;
+
+        OptionsHelper(List<Option<T>> options) {
+            this.options = options;
+        }
+
+        private boolean hasArgument(String optionName) throws BadArgs {
+            Option<?> opt = getOption(optionName);
+            if (opt == null) {
+                opt = pluginOptions.getOption(optionName);
+                if (opt == null) {
+                    throw new BadArgs("err.unknown.option", optionName).
+                            showUsage(true);
+                }
+            }
+            return opt.hasArg;
+        }
+
+        public boolean listPlugins() {
+            return pluginOptions.listPlugins;
+        }
+
+        private String getPluginsPath(String[] args) throws BadArgs {
+            String pp = null;
+            for (int i = 0; i < args.length; i++) {
+                if (args[i].equals(PluginsOptions.PLUGINS_PATH)) {
+                    if (i == args.length - 1) {
+                        throw new BadArgs("err.no.plugins.path").showUsage(true);
+                    } else {
+                        i += 1;
+                        pp = args[i];
+                        if (!pp.isEmpty() && pp.charAt(0) == '-') {
+                            throw new BadArgs("err.no.plugins.path").showUsage(true);
+                        }
+                        break;
+                    }
+                }
+            }
+            return pp;
+        }
+
+        public List<String> handleOptions(T task, String[] args) throws BadArgs {
+            // findbugs warning, copy instead of keeping a reference.
+            command = Arrays.copyOf(args, args.length);
+
+            // Must extract it prior to do any option analysis.
+            // Required to interpret custom plugin options.
+            // Unit tests can call Task multiple time in same JVM.
+            pluginOptions = new PluginsOptions(getPluginsPath(args));
+
+            // First extract plugins path if any
+            String pp = null;
+            List<String> filteredArgs = new ArrayList<>();
+            for (int i = 0; i < args.length; i++) {
+                if (args[i].equals(PluginsOptions.PLUGINS_PATH)) {
+                    if (i == args.length - 1) {
+                        throw new BadArgs("err.no.plugins.path").showUsage(true);
+                    } else {
+                        warning("warn.thirdparty.plugins.enabled");
+                        log.println(bundleHelper.getMessage("warn.thirdparty.plugins"));
+                        i += 1;
+                        String arg = args[i];
+                        if (!arg.isEmpty() && arg.charAt(0) == '-') {
+                            throw new BadArgs("err.no.plugins.path").showUsage(true);
+                        }
+                        pp = args[i];
+                    }
+                } else {
+                    filteredArgs.add(args[i]);
+                }
+            }
+            String[] arr = new String[filteredArgs.size()];
+            args = filteredArgs.toArray(arr);
+
+            List<String> rest = new ArrayList<>();
+            // process options
+            for (int i = 0; i < args.length; i++) {
+                if (!args[i].isEmpty() && args[i].charAt(0) == '-') {
+                    String name = args[i];
+                    PlugOption pluginOption = null;
+                    Option<T> option = getOption(name);
+                    if (option == null) {
+                        pluginOption = pluginOptions.getOption(name);
+                        if (pluginOption == null) {
+
+                            throw new BadArgs("err.unknown.option", name).
+                                    showUsage(true);
+                        }
+                    }
+                    Option<?> opt = pluginOption == null ? option : pluginOption;
+                    String param = null;
+                    if (opt.hasArg) {
+                        if (name.startsWith("--") && name.indexOf('=') > 0) {
+                            param = name.substring(name.indexOf('=') + 1,
+                                    name.length());
+                        } else if (i + 1 < args.length) {
+                            param = args[++i];
+                        }
+                        if (param == null || param.isEmpty()
+                                || (param.length() >= 2 && param.charAt(0) == '-'
+                                && param.charAt(1) == '-')) {
+                            throw new BadArgs("err.missing.arg", name).
+                                    showUsage(true);
+                        }
+                    }
+                    if (pluginOption != null) {
+                        pluginOption.process(pluginOptions, name, param);
+                    } else {
+                        option.process(task, name, param);
+                    }
+                    if (opt.ignoreRest()) {
+                        i = args.length;
+                    }
+                } else {
+                    rest.add(args[i]);
+                }
+            }
+            return rest;
+        }
+
+        private Option<T> getOption(String name) {
+            for (Option<T> o : options) {
+                if (o.matches(name)) {
+                    return o;
+                }
+            }
+            return null;
+        }
+
+        public void showHelp(String progName) {
+            showHelp(progName, true);
+        }
+
+        private void showHelp(String progName, boolean showsImageBuilder) {
+            log.println(bundleHelper.getMessage("main.usage", progName));
+            for (Option<?> o : options) {
+                String name = o.aliases[0].substring(1); // there must always be at least one name
+                name = name.charAt(0) == '-' ? name.substring(1) : name;
+                if (o.isHidden() || name.equals("h")) {
+                    continue;
+                }
+                log.println(bundleHelper.getMessage("main.opt." + name));
+            }
+
+            for (Option<?> o : pluginOptions.mainOptions) {
+                if (o.aliases[0].equals(PluginsOptions.POST_PROCESS)
+                        && !showsImageBuilder) {
+                    continue;
+                }
+                String name = o.aliases[0].substring(1); // there must always be at least one name
+                name = name.charAt(0) == '-' ? name.substring(1) : name;
+                if (o.isHidden()) {
+                    continue;
+                }
+                log.println(bundleHelper.getMessage("plugin.opt." + name));
+            }
+
+            log.println(bundleHelper.getMessage("main.command.files"));
+        }
+
+        public void listPlugins(boolean showsImageBuilder) {
+            log.println("\n" + bundleHelper.getMessage("main.extended.help"));
+            List<Plugin> pluginList = PluginRepository.
+                    getPlugins(pluginOptions.pluginsLayer);
+            for (Plugin plugin : Utils.
+                    getSortedPreProcessors(pluginList)) {
+                showPlugin(plugin, log, showsImageBuilder);
+            }
+
+            if (showsImageBuilder) {
+                for (Plugin plugin : Utils.getSortedPostProcessors(pluginList)) {
+                    showPlugin(plugin, log, showsImageBuilder);
+                }
+            }
+        }
+
+        private void showPlugin(Plugin plugin, PrintWriter log, boolean showsImageBuilder) {
+            if (showsPlugin(plugin, showsImageBuilder)) {
+                log.println("\n" + bundleHelper.getMessage("main.plugin.name")
+                        + ": " + plugin.getName());
+
+                // print verbose details for non-builtin plugins
+                if (!Utils.isBuiltin(plugin)) {
+                    log.println(bundleHelper.getMessage("main.plugin.class")
+                         + ": " + plugin.getClass().getName());
+                    log.println(bundleHelper.getMessage("main.plugin.module")
+                         + ": " + plugin.getClass().getModule().getName());
+                    CATEGORY category = Utils.getCategory(plugin);
+                    log.println(bundleHelper.getMessage("main.plugin.category")
+                         + ": " + category.getName());
+                    log.println(bundleHelper.getMessage("main.plugin.state")
+                        + ": " + plugin.getStateDescription());
+                }
+
+                String option = plugin.getOption();
+                if (option != null) {
+                    log.println(bundleHelper.getMessage("main.plugin.option")
+                        + ": --" + plugin.getOption()
+                        + (plugin.hasArguments()? ("=" + plugin.getArgumentsDescription()) : ""));
+                }
+
+                // description can be long spanning more than one line and so
+                // print a newline after description label.
+                log.println(bundleHelper.getMessage("main.plugin.description")
+                        + ": " + plugin.getDescription());
+            }
+        }
+
+        String[] getInputCommand() {
+            return command;
+        }
+
+        String getDefaults() {
+            return defaults;
+        }
+
+        public Layer getPluginsLayer() {
+            return pluginOptions.pluginsLayer;
+        }
+    }
+
+    private PluginsOptions pluginOptions;
+    private PrintWriter log;
+    private final ResourceBundleHelper bundleHelper;
+
+    public TaskHelper(String path) {
+        if (!JLINK_BUNDLE.equals(path) && !JIMAGE_BUNDLE.equals(path)) {
+            throw new IllegalArgumentException("Invalid Bundle");
+        }
+        this.bundleHelper = new ResourceBundleHelper(path);
+    }
+
+    public <T> OptionsHelper<T> newOptionsHelper(Class<T> clazz,
+            Option<?>[] options) {
+        List<Option<T>> optionsList = new ArrayList<>();
+        for (Option<?> o : options) {
+            @SuppressWarnings("unchecked")
+            Option<T> opt = (Option<T>) o;
+            optionsList.add(opt);
+        }
+        return new OptionsHelper<>(optionsList);
+    }
+
+    public BadArgs newBadArgs(String key, Object... args) {
+        return new BadArgs(key, args);
+    }
+
+    public String getMessage(String key, Object... args) {
+        return bundleHelper.getMessage(key, args);
+    }
+
+    public void setLog(PrintWriter log) {
+        this.log = log;
+    }
+
+    public void reportError(String key, Object... args) {
+        log.println(bundleHelper.getMessage("error.prefix") + " "
+                + bundleHelper.getMessage(key, args));
+    }
+
+    public void reportUnknownError(String message) {
+        log.println(bundleHelper.getMessage("error.prefix") + " " + message);
+    }
+
+    public void warning(String key, Object... args) {
+        log.println(bundleHelper.getMessage("warn.prefix") + " "
+                + bundleHelper.getMessage(key, args));
+    }
+
+    public PluginsConfiguration getPluginsConfig(Path output, boolean genbom)
+            throws IOException, BadArgs {
+        return pluginOptions.getPluginsConfig(output, genbom);
+    }
+
+    public Path getExistingImage() {
+        return pluginOptions.existingImage;
+    }
+
+    public void showVersion(boolean full) {
+        log.println(version(full ? "full" : "release"));
+    }
+
+    public String version(String key) {
+        return System.getProperty("java.version");
+    }
+
+    static Layer createPluginsLayer(List<Path> paths) {
+        Path[] arr = new Path[paths.size()];
+        paths.toArray(arr);
+        ModuleFinder finder = ModuleFinder.of(arr);
+
+        // jmods are located at link-time
+        if (finder instanceof ConfigurableModuleFinder) {
+            ((ConfigurableModuleFinder) finder).configurePhase(Phase.LINK_TIME);
+        }
+
+        Configuration bootConfiguration = Layer.boot().configuration();
+        try {
+            Configuration cf = bootConfiguration
+                .resolveRequiresAndUses(ModuleFinder.empty(),
+                                        finder,
+                                        Collections.emptySet());
+            ClassLoader scl = ClassLoader.getSystemClassLoader();
+            return Layer.boot().defineModulesWithOneLoader(cf, scl);
+        } catch (Exception ex) {
+            // Malformed plugin modules (e.g.: same package in multiple modules).
+            throw new PluginException("Invalid modules in the plugins path: " + ex);
+        }
+    }
+
+    // Display all plugins or pre processors only.
+    private static boolean showsPlugin(Plugin plugin, boolean showsImageBuilder) {
+        if (!Utils.isDisabled(plugin) && plugin.getOption() != null) {
+            if (Utils.isPostProcessor(plugin) && !showsImageBuilder) {
+                return false;
+            }
+            return true;
+        }
+        return false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Utils.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal;
+
+import java.lang.reflect.Module;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.function.Function;
+import jdk.tools.jlink.plugin.Plugin;
+import jdk.tools.jlink.plugin.Plugin.PluginType;
+
+/**
+ *
+ * @author jdenise
+ */
+public class Utils {
+
+    private Utils() {}
+
+    // current module
+    private static final Module THIS_MODULE = Utils.class.getModule();
+
+    public static final Function<String, String[]> listParser = (argument) -> {
+        String[] arguments = null;
+        if (argument != null) {
+            arguments = argument.split(",");
+            for (int i = 0; i < arguments.length; i++) {
+                arguments[i] = arguments[i].trim();
+            }
+        }
+        return arguments;
+    };
+
+    public static boolean isPostProcessor(Plugin.CATEGORY category) {
+        return category.equals(Plugin.CATEGORY.VERIFIER)
+                || category.equals(Plugin.CATEGORY.PROCESSOR)
+                || category.equals(Plugin.CATEGORY.PACKAGER);
+    }
+
+    public static boolean isPreProcessor(Plugin.CATEGORY category) {
+        return category.equals(Plugin.CATEGORY.COMPRESSOR)
+                || category.equals(Plugin.CATEGORY.FILTER)
+                || category.equals(Plugin.CATEGORY.MODULEINFO_TRANSFORMER)
+                || category.equals(Plugin.CATEGORY.SORTER)
+                || category.equals(Plugin.CATEGORY.TRANSFORMER);
+    }
+
+    public static boolean isPostProcessor(Plugin prov) {
+        if (prov.getType() != null) {
+            for (PluginType pt : prov.getType()) {
+                if (pt instanceof Plugin.CATEGORY) {
+                    return isPostProcessor((Plugin.CATEGORY) pt);
+                }
+            }
+        }
+        return false;
+    }
+
+    public static boolean isPreProcessor(Plugin prov) {
+        if (prov.getType() != null) {
+            for (PluginType pt : prov.getType()) {
+                if (pt instanceof Plugin.CATEGORY) {
+                    return isPreProcessor((Plugin.CATEGORY) pt);
+                }
+            }
+        }
+        return false;
+    }
+
+    public static Plugin.CATEGORY getCategory(Plugin provider) {
+        if (provider.getType() != null) {
+            for (Plugin.PluginType t : provider.getType()) {
+                if (t instanceof Plugin.CATEGORY) {
+                    return (Plugin.CATEGORY) t;
+                }
+            }
+        }
+        return null;
+    }
+
+    public static List<Plugin> getPostProcessors(List<Plugin> plugins) {
+        List<Plugin> res = new ArrayList<>();
+        for (Plugin p : plugins) {
+            if (isPostProcessor(p)) {
+                res.add(p);
+            }
+        }
+        return res;
+    }
+
+    public static List<Plugin> getSortedPostProcessors(List<Plugin> plugins) {
+        List<Plugin> res = getPostProcessors(plugins);
+        res.sort(new Comparator<Plugin>() {
+            @Override
+            public int compare(Plugin o1, Plugin o2) {
+                return o1.getName().compareTo(o2.getName());
+            }
+        });
+        return res;
+    }
+
+    public static List<Plugin> getSortedPreProcessors(List<Plugin> plugins) {
+        List<Plugin> res = getPreProcessors(plugins);
+        res.sort(new Comparator<Plugin>() {
+            @Override
+            public int compare(Plugin o1, Plugin o2) {
+                return o1.getName().compareTo(o2.getName());
+            }
+        });
+        return res;
+    }
+
+    public static List<Plugin> getPreProcessors(List<Plugin> plugins) {
+        List<Plugin> res = new ArrayList<>();
+        for (Plugin p : plugins) {
+            if (isPreProcessor(p)) {
+                res.add(p);
+            }
+        }
+        return res;
+    }
+
+    public static boolean isFunctional(Plugin prov) {
+        return prov.getState().contains(Plugin.STATE.FUNCTIONAL);
+    }
+
+    public static boolean isAutoEnabled(Plugin prov) {
+        return prov.getState().contains(Plugin.STATE.AUTO_ENABLED);
+    }
+
+    public static boolean isDisabled(Plugin prov) {
+        return prov.getState().contains(Plugin.STATE.DISABLED);
+    }
+
+    // is this a builtin (jdk.jlink) plugin?
+    public static boolean isBuiltin(Plugin prov) {
+        return THIS_MODULE.equals(prov.getClass().getModule());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/DefaultCompressPlugin.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal.plugins;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import jdk.tools.jlink.plugin.PluginException;
+import jdk.tools.jlink.internal.PoolImpl;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.TransformerPlugin;
+import jdk.tools.jlink.internal.ImagePluginStack;
+import jdk.tools.jlink.internal.ResourcePrevisitor;
+import jdk.tools.jlink.internal.StringTable;
+import jdk.tools.jlink.internal.Utils;
+
+/**
+ *
+ * ZIP and String Sharing compression plugin
+ */
+public final class DefaultCompressPlugin implements TransformerPlugin, ResourcePrevisitor {
+    public static final String NAME = "compress";
+    public static final String FILTER = "filter";
+    public static final String LEVEL_0 = "0";
+    public static final String LEVEL_1 = "1";
+    public static final String LEVEL_2 = "2";
+
+    private StringSharingPlugin ss;
+    private ZipPlugin zip;
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    @Override
+    public void visit(Pool in, Pool out) {
+        if (ss != null && zip != null) {
+            Pool output = new ImagePluginStack.OrderedResourcePool(in.getByteOrder(),
+                    ((PoolImpl) in).getStringTable());
+            ss.visit(in, output);
+            zip.visit(output, out);
+        } else if (ss != null) {
+            ss.visit(in, out);
+        } else if (zip != null) {
+            zip.visit(in, out);
+        }
+    }
+
+    @Override
+    public void previsit(Pool resources, StringTable strings) {
+        if (ss != null) {
+            ss.previsit(resources, strings);
+        }
+    }
+
+    @Override
+    public Set<PluginType> getType() {
+        Set<PluginType> set = new HashSet<>();
+        set.add(CATEGORY.COMPRESSOR);
+        return Collections.unmodifiableSet(set);
+    }
+
+    @Override
+    public String getDescription() {
+        return PluginsResourceBundle.getDescription(NAME);
+    }
+
+    @Override
+    public boolean hasArguments() {
+        return true;
+    }
+
+    @Override
+    public String getArgumentsDescription() {
+       return PluginsResourceBundle.getArgument(NAME);
+    }
+
+    @Override
+    public void configure(Map<String, String> config) {
+        try {
+            String filter = config.get(FILTER);
+            String[] patterns = filter == null ? null
+                    : Utils.listParser.apply(filter);
+            ResourceFilter resFilter = new ResourceFilter(patterns);
+            String level = config.get(NAME);
+            if (level != null) {
+                switch (level) {
+                    case LEVEL_0:
+                        ss = new StringSharingPlugin(resFilter);
+                        break;
+                    case LEVEL_1:
+                        zip = new ZipPlugin(resFilter);
+                        break;
+                    case LEVEL_2:
+                        ss = new StringSharingPlugin(resFilter);
+                        zip = new ZipPlugin(resFilter);
+                        break;
+                    default:
+                        throw new PluginException("Invalid level " + level);
+                }
+            } else {
+                ss = new StringSharingPlugin(resFilter);
+                zip = new ZipPlugin(resFilter);
+            }
+        } catch (IOException ex) {
+            throw new UncheckedIOException(ex);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ExcludeFilesPlugin.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal.plugins;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Predicate;
+import jdk.tools.jlink.plugin.TransformerPlugin;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Pool.ModuleDataType;
+import jdk.tools.jlink.internal.Utils;
+
+/**
+ *
+ * Exclude files plugin
+ */
+public final class ExcludeFilesPlugin implements TransformerPlugin {
+
+    public static final String NAME = "exclude-files";
+    private Predicate<String> predicate;
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    @Override
+    public void visit(Pool in, Pool out) {
+        in.visit((file) -> {
+            if (!file.getType().equals(ModuleDataType.CLASS_OR_RESOURCE)) {
+                file = predicate.test(file.getPath()) ? file : null;
+            }
+            return file;
+        }, out);
+    }
+
+    @Override
+    public Set<PluginType> getType() {
+        Set<PluginType> set = new HashSet<>();
+        set.add(CATEGORY.FILTER);
+        return Collections.unmodifiableSet(set);
+    }
+
+    @Override
+    public String getDescription() {
+        return PluginsResourceBundle.getDescription(NAME);
+    }
+
+    @Override
+    public boolean hasArguments() {
+        return true;
+    }
+
+    @Override
+    public String getArgumentsDescription() {
+       return PluginsResourceBundle.getArgument(NAME);
+    }
+
+    @Override
+    public void configure(Map<String, String> config) {
+        try {
+            String value = config.get(NAME);
+            predicate = new ResourceFilter(Utils.listParser.apply(value), true);
+        } catch (IOException ex) {
+            throw new UncheckedIOException(ex);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ExcludePlugin.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal.plugins;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Predicate;
+import jdk.tools.jlink.plugin.PluginException;
+import jdk.tools.jlink.plugin.TransformerPlugin;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.internal.Utils;
+
+/**
+ *
+ * Exclude resources plugin
+ */
+public final class ExcludePlugin implements TransformerPlugin {
+
+    public static final String NAME = "exclude-resources";
+    private Predicate<String> predicate;
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    @Override
+    public void visit(Pool in, Pool out) {
+        in.visit((resource) -> {
+            if (resource.getType().equals(Pool.ModuleDataType.CLASS_OR_RESOURCE)) {
+                resource = predicate.test(resource.getPath()) ? resource : null;
+            }
+            return resource;
+        }, out);
+    }
+
+    @Override
+    public String getDescription() {
+        return PluginsResourceBundle.getDescription(NAME);
+    }
+
+    @Override
+    public boolean hasArguments() {
+        return true;
+    }
+
+    @Override
+    public String getArgumentsDescription() {
+       return PluginsResourceBundle.getArgument(NAME);
+    }
+
+    @Override
+    public Set<PluginType> getType() {
+        Set<PluginType> set = new HashSet<>();
+        set.add(CATEGORY.FILTER);
+        return Collections.unmodifiableSet(set);
+    }
+
+    @Override
+    public void configure(Map<String, String> config) {
+        try {
+            String val = config.get(NAME);
+            predicate = new ResourceFilter(Utils.listParser.apply(val), true);
+        } catch (IOException ex) {
+            throw new PluginException(ex);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ExcludeVMPlugin.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal.plugins;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.UncheckedIOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import jdk.tools.jlink.plugin.TransformerPlugin;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Pool.ModuleDataType;
+import jdk.tools.jlink.internal.Utils;
+import jdk.tools.jlink.plugin.PluginException;
+
+/**
+ *
+ * Exclude VM plugin
+ */
+public final class ExcludeVMPlugin implements TransformerPlugin {
+
+    private static final class JvmComparator implements Comparator<Jvm> {
+
+        @Override
+        public int compare(Jvm o1, Jvm o2) {
+            return o1.getEfficience() - o2.getEfficience();
+        }
+    }
+
+    private enum Jvm {
+        // The efficience order server - client - minimal.
+        SERVER("server", 3), CLIENT("client", 2), MINIMAL("minimal", 1);
+        private final String name;
+        private final int efficience;
+
+        Jvm(String name, int efficience) {
+            this.name = name;
+            this.efficience = efficience;
+        }
+
+        private String getName() {
+            return name;
+        }
+
+        private int getEfficience() {
+            return efficience;
+        }
+    }
+
+    private static final String JVM_CFG = "jvm.cfg";
+
+    public static final String NAME = "vm";
+    private static final String ALL = "all";
+    private static final String CLIENT = "client";
+    private static final String SERVER = "server";
+    private static final String MINIMAL = "minimal";
+
+    private Predicate<String> predicate;
+    private Jvm target;
+    private boolean keepAll;
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    /**
+     * VM paths:
+     * /java.base/native/{architecture}/{server|client|minimal}/{shared lib}
+     * e.g.: /java.base/native/amd64/server/libjvm.so
+     * /java.base/native/server/libjvm.dylib
+     */
+    private List<Pool.ModuleData> getVMs(Pool in) {
+        String jvmlib = jvmlib();
+        List<Pool.ModuleData> ret = in.getModule("java.base").getContent().stream().filter((t) -> {
+            return t.getPath().endsWith("/" + jvmlib);
+        }).collect(Collectors.toList());
+        return ret;
+    }
+
+    @Override
+    public void visit(Pool in, Pool out) {
+        String jvmlib = jvmlib();
+        TreeSet<Jvm> existing = new TreeSet<>(new JvmComparator());
+        TreeSet<Jvm> removed = new TreeSet<>(new JvmComparator());
+        if (!keepAll) {
+            // First retrieve all available VM names and removed VM
+            List<Pool.ModuleData> jvms = getVMs(in);
+            for (Jvm jvm : Jvm.values()) {
+                for (Pool.ModuleData md : jvms) {
+                    if (md.getPath().endsWith("/" + jvm.getName() + "/" + jvmlib)) {
+                        existing.add(jvm);
+                        if (isRemoved(md)) {
+                            removed.add(jvm);
+                        }
+                    }
+                }
+            }
+        }
+        // Check that target exists
+        if (!keepAll) {
+            if (!existing.contains(target)) {
+                throw new PluginException("Selected VM " + target.getName() + " doesn't exist.");
+            }
+        }
+
+        // Rewrite the jvm.cfg file.
+        in.visit((file) -> {
+            if (!keepAll) {
+                if (file.getType().equals(ModuleDataType.NATIVE_LIB)) {
+                    if (file.getPath().endsWith(JVM_CFG)) {
+                        try {
+                            file = handleJvmCfgFile(file, existing, removed);
+                        } catch (IOException ex) {
+                            throw new UncheckedIOException(ex);
+                        }
+                    }
+                }
+                file = isRemoved(file) ? null : file;
+            }
+            return file;
+        }, out);
+
+    }
+
+    private boolean isRemoved(Pool.ModuleData file) {
+        return !predicate.test(file.getPath());
+    }
+
+    @Override
+    public Set<PluginType> getType() {
+        Set<PluginType> set = new HashSet<>();
+        set.add(CATEGORY.FILTER);
+        return Collections.unmodifiableSet(set);
+    }
+
+    @Override
+    public String getDescription() {
+        return PluginsResourceBundle.getDescription(NAME);
+    }
+
+    @Override
+    public boolean hasArguments() {
+        return true;
+    }
+
+    @Override
+    public String getArgumentsDescription() {
+       return PluginsResourceBundle.getArgument(NAME);
+    }
+
+    @Override
+    public void configure(Map<String, String> config) {
+        try {
+            String value = config.get(NAME);
+            String exclude = "";
+            switch (value) {
+                case ALL: {
+                    // no filter.
+                    keepAll = true;
+                    break;
+                }
+                case CLIENT: {
+                    target = Jvm.CLIENT;
+                    exclude = "/java.base/native*server/*,/java.base/native*minimal/*";
+                    break;
+                }
+                case SERVER: {
+                    target = Jvm.SERVER;
+                    exclude = "/java.base/native*client/*,/java.base/native*minimal/*";
+                    break;
+                }
+                case MINIMAL: {
+                    target = Jvm.MINIMAL;
+                    exclude = "/java.base/native*server/*,/java.base/native*client/*";
+                    break;
+                }
+                default: {
+                    throw new PluginException("Unknown option " + value);
+                }
+            }
+            predicate = new ResourceFilter(Utils.listParser.apply(exclude), true);
+        } catch (IOException ex) {
+            throw new UncheckedIOException(ex);
+        }
+    }
+
+    private Pool.ModuleData handleJvmCfgFile(Pool.ModuleData orig,
+            TreeSet<Jvm> existing,
+            TreeSet<Jvm> removed) throws IOException {
+        if (keepAll) {
+            return orig;
+        }
+        StringBuilder builder = new StringBuilder();
+        // Keep comments
+        try (BufferedReader reader
+                = new BufferedReader(new InputStreamReader(orig.stream(),
+                        StandardCharsets.UTF_8))) {
+            reader.lines().forEach((s) -> {
+                if (s.startsWith("#")) {
+                    builder.append(s).append("\n");
+                }
+            });
+        }
+        TreeSet<Jvm> remaining = new TreeSet<>(new JvmComparator());
+        // Add entry in jvm.cfg file from the more efficient to less efficient.
+        for (Jvm platform : existing) {
+            if (!removed.contains(platform)) {
+                remaining.add(platform);
+                builder.append("-").append(platform.getName()).append(" KNOWN\n");
+            }
+        }
+
+        // removed JVM are aliased to the most efficient remaining JVM (last one).
+        // The order in the file is from most to less efficient platform
+        for (Jvm platform : removed.descendingSet()) {
+            builder.append("-").append(platform.getName()).
+                    append(" ALIASED_TO -").
+                    append(remaining.last().getName()).append("\n");
+        }
+
+        byte[] content = builder.toString().getBytes(StandardCharsets.UTF_8);
+
+        return Pool.newImageFile(orig.getModule(),
+                orig.getPath(),
+                orig.getType(),
+                new ByteArrayInputStream(content), content.length);
+    }
+
+    private static String jvmlib() {
+        String lib = "libjvm.so";
+        if (isWindows()) {
+            lib = "jvm.dll";
+        } else if (isMac()) {
+            lib = "libjvm.dylib";
+        }
+        return lib;
+    }
+
+    private static boolean isWindows() {
+        return System.getProperty("os.name").startsWith("Windows");
+    }
+
+    private static boolean isMac() {
+        return System.getProperty("os.name").startsWith("Mac OS");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/FileCopierPlugin.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal.plugins;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.FileVisitor;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import jdk.tools.jlink.plugin.PluginException;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.Pool.ModuleDataType;
+import jdk.tools.jlink.plugin.TransformerPlugin;
+import jdk.tools.jlink.internal.Utils;
+
+/**
+ *
+ * Copy files to image from various locations.
+ */
+public class FileCopierPlugin implements TransformerPlugin {
+
+    public static final String NAME = "copy-files";
+
+    private static final class CopiedFile {
+
+        Path source;
+        Path target;
+    }
+    public static final String FAKE_MODULE = "$jlink-file-copier";
+
+    private final List<CopiedFile> files = new ArrayList<>();
+
+    /**
+     * Symbolic link to another path.
+     */
+    public static abstract class SymImageFile extends Pool.ModuleData {
+
+        private final String targetPath;
+
+        public SymImageFile(String targetPath, String module, String path,
+                Pool.ModuleDataType type, InputStream stream, long size) {
+            super(module, path, type, stream, size);
+            this.targetPath = targetPath;
+        }
+
+        public String getTargetPath() {
+            return targetPath;
+        }
+    }
+
+    private static final class SymImageFileImpl extends SymImageFile {
+
+        public SymImageFileImpl(String targetPath, Path file, String module,
+                String path, ModuleDataType type) {
+            super(targetPath, module, path, type, newStream(file), length(file));
+        }
+    }
+
+    private static long length(Path file) {
+        try {
+            return Files.size(file);
+        } catch (IOException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    private static InputStream newStream(Path file) {
+        try {
+            return Files.newInputStream(file);
+        } catch (IOException ex) {
+            throw new UncheckedIOException(ex);
+        }
+    }
+
+    private static final class DirectoryCopy implements FileVisitor<Path> {
+
+        private final Path source;
+        private final Pool pool;
+        private final String targetDir;
+        private final List<SymImageFile> symlinks = new ArrayList<>();
+
+        DirectoryCopy(Path source, Pool pool, String targetDir) {
+            this.source = source;
+            this.pool = pool;
+            this.targetDir = targetDir;
+        }
+
+        @Override
+        public FileVisitResult preVisitDirectory(Path dir,
+                BasicFileAttributes attrs) throws IOException {
+            return FileVisitResult.CONTINUE;
+        }
+
+        @Override
+        public FileVisitResult visitFile(Path file,
+                BasicFileAttributes attrs) throws IOException {
+            Objects.requireNonNull(file);
+            Objects.requireNonNull(attrs);
+            String path = targetDir + "/" + source.relativize(file);
+            if (attrs.isSymbolicLink()) {
+                Path symTarget = Files.readSymbolicLink(file);
+                if (!Files.exists(symTarget)) {
+                    // relative to file parent?
+                    Path parent = file.getParent();
+                    if (parent != null) {
+                        symTarget = parent.resolve(symTarget);
+                    }
+                }
+                if (!Files.exists(symTarget)) {
+                    System.err.println("WARNING: Skipping sym link, target "
+                            + Files.readSymbolicLink(file) + "not found");
+                    return FileVisitResult.CONTINUE;
+                }
+                SymImageFileImpl impl = new SymImageFileImpl(symTarget.toString(),
+                        file, path, Objects.requireNonNull(file.getFileName()).toString(),
+                        Pool.ModuleDataType.OTHER);
+                symlinks.add(impl);
+            } else {
+                addFile(pool, file, path);
+            }
+            return FileVisitResult.CONTINUE;
+        }
+
+        @Override
+        public FileVisitResult postVisitDirectory(Path dir, IOException exc)
+                throws IOException {
+            if (exc != null) {
+                throw exc;
+            }
+            return FileVisitResult.CONTINUE;
+        }
+
+        @Override
+        public FileVisitResult visitFileFailed(Path file, IOException exc)
+                throws IOException {
+            throw exc;
+        }
+    }
+
+    private static void addFile(Pool pool, Path file, String path)
+            throws IOException {
+        Objects.requireNonNull(pool);
+        Objects.requireNonNull(file);
+        Objects.requireNonNull(path);
+        ModuleData impl = Pool.newImageFile(FAKE_MODULE,
+                "/" + FAKE_MODULE + "/other/" + path,
+                Pool.ModuleDataType.OTHER, newStream(file), length(file));
+        try {
+            pool.add(impl);
+        } catch (Exception ex) {
+            throw new IOException(ex);
+        }
+    }
+
+    @Override
+    public Set<PluginType> getType() {
+        Set<PluginType> set = new HashSet<>();
+        set.add(CATEGORY.TRANSFORMER);
+        return Collections.unmodifiableSet(set);
+    }
+
+    @Override
+    public void configure(Map<String, String> config) {
+        String val = config.get(NAME);
+        String[] argument = Utils.listParser.apply(val);
+        if (argument == null || argument.length == 0) {
+            throw new RuntimeException("Invalid argument for " + NAME);
+        }
+
+        String javahome = System.getProperty("java.home");
+        for (String a : argument) {
+            int i = a.indexOf("=");
+            CopiedFile cf = new CopiedFile();
+            if (i == -1) {
+                Path file = Paths.get(a);
+                if (file.isAbsolute()) {
+                    cf.source = file;
+                    // The target is the image root directory.
+                    cf.target = file.getFileName();
+                } else {
+                    file = new File(javahome, a).toPath();
+                    cf.source = file;
+                    cf.target = Paths.get(a);
+                }
+            } else {
+                String target = a.substring(i + 1);
+                String f = a.substring(0, i);
+                Path file = Paths.get(f);
+                if (file.isAbsolute()) {
+                    cf.source = file;
+                } else {
+                    cf.source = new File(javahome,
+                            file.toFile().getPath()).toPath();
+                }
+                cf.target = Paths.get(target);
+            }
+            if (!Files.exists(cf.source)) {
+                System.err.println("Skipping file " + cf.source
+                        + ", it doesn't exist");
+            } else {
+                files.add(cf);
+            }
+        }
+    }
+
+    @Override
+    public void visit(Pool in, Pool out) {
+        in.visit((file) -> {
+            return file;
+        }, out);
+
+        // Add new files.
+        try {
+            for (CopiedFile file : files) {
+                if (Files.isRegularFile(file.source)) {
+                    addFile(out, file.source, file.target.toString());
+                } else if (Files.isDirectory(file.source)) {
+                    DirectoryCopy dc = new DirectoryCopy(file.source,
+                            out, file.target.toString());
+                    Files.walkFileTree(file.source, dc);
+                    // Add symlinks after actual content
+                    for (SymImageFile imf : dc.symlinks) {
+                        try {
+                            out.add(imf);
+                        } catch (Exception ex) {
+                            throw new PluginException(ex);
+                        }
+                    }
+                }
+            }
+        } catch (IOException ex) {
+            throw new UncheckedIOException(ex);
+        }
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    @Override
+    public String getDescription() {
+        return PluginsResourceBundle.getDescription(NAME);
+    }
+
+    @Override
+    public boolean hasArguments() {
+        return true;
+    }
+
+    @Override
+    public String getArgumentsDescription() {
+       return PluginsResourceBundle.getArgument(NAME);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal.plugins;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.IllformedLocaleException;
+import java.util.Locale;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Predicate;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.tools.jlink.plugin.TransformerPlugin;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.PluginException;
+import jdk.tools.jlink.internal.ResourcePrevisitor;
+import jdk.tools.jlink.internal.StringTable;
+import jdk.tools.jlink.internal.Utils;
+
+/**
+ * Plugin to explicitly specify the locale data included in jdk.localedata
+ * module. This plugin provides a jlink command line option "--include-locales"
+ * with an argument. The argument is a list of BCP 47 language tags separated
+ * by a comma. E.g.,
+ *
+ *  "jlink --include-locales en,ja,*-IN"
+ *
+ * This option will include locale data for all available English and Japanese
+ * languages, and ones for the country of India. All other locale data are
+ * filtered out on the image creation.
+ *
+ * Here are a few assumptions:
+ *
+ *  0. All locale data in java.base are unconditionally included.
+ *  1. All the selective locale data are in jdk.localedata module
+ *  2. Their package names are constructed by appending ".ext" to
+ *     the corresponding ones in java.base module.
+ *  3. Available locales string in LocaleDataMetaInfo class should
+ *     start with at least one white space character, e.g., " ar ar-EG ..."
+ *                                                           ^
+ */
+public final class IncludeLocalesPlugin implements TransformerPlugin, ResourcePrevisitor {
+
+    public static final String NAME = "include-locales";
+    private static final String MODULENAME = "jdk.localedata";
+    private static final Set<String> LOCALEDATA_PACKAGES = Set.of(
+        "sun.text.resources.cldr.ext",
+        "sun.text.resources.ext",
+        "sun.util.resources.cldr.ext",
+        "sun.util.resources.cldr.provider",
+        "sun.util.resources.ext",
+        "sun.util.resources.provider");
+    private static final String METAINFONAME = "LocaleDataMetaInfo";
+    private static final String META_FILES =
+        "*module-info.class," +
+        "*LocaleDataProvider*," +
+        "*" + METAINFONAME + "*,";
+    private static final String INCLUDE_LOCALE_FILES =
+        "*sun/text/resources/ext/[^\\/]+_%%.class," +
+        "*sun/util/resources/ext/[^\\/]+_%%.class," +
+        "*sun/text/resources/cldr/ext/[^\\/]+_%%.class," +
+        "*sun/util/resources/cldr/ext/[^\\/]+_%%.class,";
+    private Predicate<String> predicate;
+    private List<Locale.LanguageRange> priorityList;
+    private List<Locale> available;
+    private List<String> filtered;
+
+    // Special COMPAT provider locales
+    private static final String jaJPJPTag = "ja-JP-JP";
+    private static final String noNONYTag = "no-NO-NY";
+    private static final String thTHTHTag = "th-TH-TH";
+    private static final Locale jaJPJP = new Locale("ja", "JP", "JP");
+    private static final Locale noNONY = new Locale("no", "NO", "NY");
+    private static final Locale thTHTH = new Locale("th", "TH", "TH");
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    @Override
+    public void visit(Pool in, Pool out) {
+        in.visit((resource) -> {
+            if (resource.getModule().equals(MODULENAME)) {
+                String path = resource.getPath();
+                resource = predicate.test(path) ? resource: null;
+                if (resource != null) {
+                    byte[] bytes = resource.getBytes();
+                    ClassReader cr = new ClassReader(bytes);
+                    if (Arrays.stream(cr.getInterfaces())
+                        .anyMatch(i -> i.contains(METAINFONAME)) &&
+                        stripUnsupportedLocales(bytes, cr)) {
+                        resource = new Pool.ModuleData(MODULENAME, path,
+                            resource.getType(),
+                            new ByteArrayInputStream(bytes), bytes.length);
+                    }
+                }
+            }
+            return resource;
+        }, out);
+    }
+
+    @Override
+    public Set<PluginType> getType() {
+        Set<PluginType> set = new HashSet<>();
+        set.add(CATEGORY.FILTER);
+        return Collections.unmodifiableSet(set);
+    }
+
+    @Override
+    public String getDescription() {
+        return PluginsResourceBundle.getDescription(NAME);
+    }
+
+    @Override
+    public boolean hasArguments() {
+        return true;
+    }
+
+    @Override
+    public String getArgumentsDescription() {
+       return PluginsResourceBundle.getArgument(NAME);
+    }
+
+    @Override
+    public void configure(Map<String, String> config) {
+        priorityList = Arrays.stream(config.get(NAME).split(","))
+            .map(Locale.LanguageRange::new)
+            .collect(Collectors.toList());
+    }
+
+    @Override
+    public void previsit(Pool resources, StringTable strings) {
+        final Pattern p = Pattern.compile(".*((Data_)|(Names_))(?<tag>.*)\\.class");
+        Pool.Module module = resources.getModule(MODULENAME);
+
+        // jdk.localedata module validation
+        Set<String> packages = module.getAllPackages();
+        if (!packages.containsAll(LOCALEDATA_PACKAGES)) {
+            throw new PluginException("Missing locale data packages in jdk.localedata:\n\t" +
+                LOCALEDATA_PACKAGES.stream()
+                    .filter(pn -> !packages.contains(pn))
+                    .collect(Collectors.joining(",\n\t")));
+        }
+
+        available = Stream.concat(module.getContent().stream()
+                                    .map(md -> p.matcher(md.getPath()))
+                                    .filter(m -> m.matches())
+                                    .map(m -> m.group("tag").replaceAll("_", "-")),
+                                Stream.concat(Stream.of(jaJPJPTag), Stream.of(thTHTHTag)))
+            .distinct()
+            .sorted()
+            .map(IncludeLocalesPlugin::tagToLocale)
+            .collect(Collectors.toList());
+
+        filtered = filterLocales(available);
+
+        try {
+            String value = META_FILES + filtered.stream()
+                .map(s -> includeLocaleFilePatterns(s))
+                .collect(Collectors.joining(","));
+            predicate = new ResourceFilter(Utils.listParser.apply(value), false);
+        } catch (IOException ex) {
+            throw new UncheckedIOException(ex);
+        }
+    }
+
+    private String includeLocaleFilePatterns(String tag) {
+        String pTag = tag.replaceAll("-", "_");
+        String files = "";
+        int lastDelimiter = tag.length();
+        String isoSpecial = pTag.matches("^(he|yi|id).*") ?
+                            pTag.replaceFirst("he", "iw")
+                                .replaceFirst("yi", "ji")
+                                .replaceFirst("id", "in") : "";
+
+        // Add tag patterns including parents
+        while (true) {
+            pTag = pTag.substring(0, lastDelimiter);
+            files += INCLUDE_LOCALE_FILES.replaceAll("%%", pTag);
+
+            if (!isoSpecial.isEmpty()) {
+                isoSpecial = isoSpecial.substring(0, lastDelimiter);
+                files += INCLUDE_LOCALE_FILES.replaceAll("%%", isoSpecial);
+            }
+
+            lastDelimiter = pTag.lastIndexOf('_');
+            if (lastDelimiter == -1) {
+                break;
+            }
+        }
+
+        final String lang = pTag;
+
+        // Add possible special locales of the COMPAT provider
+        files += Set.of(jaJPJPTag, noNONYTag, thTHTHTag).stream()
+            .filter(stag -> lang.equals(stag.substring(0,2)))
+            .map(t -> INCLUDE_LOCALE_FILES.replaceAll("%%", t.replaceAll("-", "_")))
+            .collect(Collectors.joining(","));
+
+        // Add possible UN.M49 files (unconditional for now) for each language
+        files += INCLUDE_LOCALE_FILES.replaceAll("%%", lang + "_[0-9]{3}");
+        if (!isoSpecial.isEmpty()) {
+            files += INCLUDE_LOCALE_FILES.replaceAll("%%", isoSpecial + "_[0-9]{3}");
+        }
+
+        // Add Thai BreakIterator related files
+        if (lang.equals("th")) {
+            files += "*sun/text/resources/thai_dict," +
+                     "*sun/text/resources/[^\\/]+_th,";
+        }
+
+        // Add Taiwan resource bundles for Hong Kong
+        if (tag.startsWith("zh-HK")) {
+            files += INCLUDE_LOCALE_FILES.replaceAll("%%", "zh_TW");
+        }
+
+        return files;
+    }
+
+    private boolean stripUnsupportedLocales(byte[] bytes, ClassReader cr) {
+        char[] buf = new char[cr.getMaxStringLength()];
+        boolean[] modified = new boolean[1];
+
+        IntStream.range(1, cr.getItemCount())
+            .map(item -> cr.getItem(item))
+            .forEach(itemIndex -> {
+                if (bytes[itemIndex - 1] == 1 &&         // UTF-8
+                    bytes[itemIndex + 2] == (byte)' ') { // fast check for leading space
+                    int length = cr.readUnsignedShort(itemIndex);
+                    byte[] b = new byte[length];
+                    System.arraycopy(bytes, itemIndex + 2, b, 0, length);
+                    if (filterOutUnsupportedTags(b)) {
+                        // copy back
+                        System.arraycopy(b, 0, bytes, itemIndex + 2, length);
+                        modified[0] = true;
+                    }
+                }
+            });
+
+        return modified[0];
+    }
+
+    private boolean filterOutUnsupportedTags(byte[] b) {
+        List<Locale> locales;
+
+        try {
+            locales = Arrays.asList(new String(b).split(" ")).stream()
+                .filter(tag -> !tag.isEmpty())
+                .map(IncludeLocalesPlugin::tagToLocale)
+                .collect(Collectors.toList());
+        } catch (IllformedLocaleException ile) {
+            // Seems not an available locales string literal.
+            return false;
+        }
+
+        byte[] filteredBytes = filterLocales(locales).stream()
+            .collect(Collectors.joining(" "))
+            .getBytes();
+        System.arraycopy(filteredBytes, 0, b, 0, filteredBytes.length);
+        Arrays.fill(b, filteredBytes.length, b.length, (byte)' ');
+        return true;
+    }
+
+    private List<String> filterLocales(List<Locale> locales) {
+        List<String> ret =
+            Locale.filter(priorityList, locales, Locale.FilteringMode.EXTENDED_FILTERING).stream()
+                .map(loc ->
+                    // Locale.filter() does not preserve the case, which is
+                    // significant for "variant" equality. Retrieve the original
+                    // locales from the pre-filtered list.
+                    locales.stream()
+                        .filter(l -> l.toString().equalsIgnoreCase(loc.toString()))
+                        .findAny()
+                        .orElse(Locale.ROOT)
+                        .toLanguageTag())
+                .collect(Collectors.toList());
+
+        // no-NO-NY.toLanguageTag() returns "nn-NO", so specially handle it here
+        if (ret.contains("no-NO")) {
+            ret.add(noNONYTag);
+        }
+
+        return ret;
+    }
+
+    private static final Locale.Builder LOCALE_BUILDER = new Locale.Builder();
+    private static Locale tagToLocale(String tag) {
+        // ISO3166 compatibility
+        tag = tag.replaceFirst("^iw", "he").replaceFirst("^ji", "yi").replaceFirst("^in", "id");
+
+        switch (tag) {
+            case jaJPJPTag:
+                return jaJPJP;
+            case noNONYTag:
+                return noNONY;
+            case thTHTHTag:
+                return thTHTH;
+            default:
+                LOCALE_BUILDER.clear();
+                LOCALE_BUILDER.setLanguageTag(tag);
+                return LOCALE_BUILDER.build();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/OptimizationPlugin.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal.plugins;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.UncheckedIOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Consumer;
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.tools.jlink.internal.plugins.asm.AsmPools;
+import jdk.tools.jlink.internal.plugins.asm.AsmPlugin;
+import jdk.internal.org.objectweb.asm.tree.ClassNode;
+import jdk.internal.org.objectweb.asm.tree.MethodNode;
+import jdk.internal.org.objectweb.asm.util.CheckClassAdapter;
+import jdk.tools.jlink.internal.plugins.asm.AsmModulePool;
+import jdk.tools.jlink.internal.plugins.optim.ForNameFolding;
+import jdk.tools.jlink.internal.plugins.optim.ReflectionOptimizer.TypeResolver;
+import jdk.tools.jlink.plugin.PluginException;
+
+/**
+ *
+ * Optimize Classes following various strategies. Strategies are implementation
+ * of <code>ClassOptimizer</code> and <code>MethodOptimizer</code>.
+ */
+public final class OptimizationPlugin extends AsmPlugin {
+
+    public static final String NAME = "class-optim";
+    public static final String LOG  = "log";
+    public static final String ALL = "all";
+    public static final String FORNAME_REMOVAL = "forName-folding";
+
+    /**
+     * Default resolver. A resolver that retrieve types that are in an
+     * accessible package, are public or are located in the same package as the
+     * caller.
+     */
+    private static final class DefaultTypeResolver implements TypeResolver {
+
+        private final Set<String> packages;
+        private final AsmPools pools;
+
+        DefaultTypeResolver(AsmPools pools, AsmModulePool modulePool) {
+            Objects.requireNonNull(pools);
+            Objects.requireNonNull(modulePool);
+            this.pools = pools;
+            packages = pools.getGlobalPool().getAccessiblePackages(modulePool.getModuleName());
+        }
+
+        @Override
+        public ClassReader resolve(ClassNode cn, MethodNode mn, String type) {
+            int classIndex = cn.name.lastIndexOf("/");
+            String callerPkg = classIndex == -1 ? ""
+                    : cn.name.substring(0, classIndex);
+            int typeClassIndex = type.lastIndexOf("/");
+            String pkg = typeClassIndex == - 1 ? ""
+                    : type.substring(0, typeClassIndex);
+            ClassReader reader = null;
+            if (packages.contains(pkg) || pkg.equals(callerPkg)) {
+                ClassReader r = pools.getGlobalPool().getClassReader(type);
+                if (r != null) {
+                    // if not private
+                    if ((r.getAccess() & Opcodes.ACC_PRIVATE)
+                            != Opcodes.ACC_PRIVATE) {
+                        // public
+                        if (((r.getAccess() & Opcodes.ACC_PUBLIC)
+                                == Opcodes.ACC_PUBLIC)) {
+                            reader = r;
+                        } else if (pkg.equals(callerPkg)) {
+                            reader = r;
+                        }
+                    }
+                }
+            }
+            return reader;
+        }
+    }
+
+    public interface Optimizer {
+
+        void close() throws IOException;
+    }
+
+    public interface ClassOptimizer extends Optimizer {
+
+        boolean optimize(Consumer<String> logger, AsmPools pools,
+                AsmModulePool modulePool,
+                ClassNode cn) throws Exception;
+    }
+
+    public interface MethodOptimizer extends Optimizer {
+
+        boolean optimize(Consumer<String> logger, AsmPools pools,
+                AsmModulePool modulePool,
+                ClassNode cn, MethodNode m, TypeResolver resolver) throws Exception;
+    }
+
+    private List<Optimizer> optimizers = new ArrayList<>();
+
+    private OutputStream stream;
+    private int numMethods;
+
+    private void log(String content) {
+        if (stream != null) {
+            try {
+                content = content + "\n";
+                stream.write(content.getBytes(StandardCharsets.UTF_8));
+            } catch (IOException ex) {
+                System.err.println(ex);
+            }
+        }
+    }
+
+    private void close() throws IOException {
+        log("Num analyzed methods " + numMethods);
+
+        for (Optimizer optimizer : optimizers) {
+            try {
+                optimizer.close();
+            } catch (IOException ex) {
+                System.err.println("Error closing optimizer " + ex);
+            }
+        }
+        if (stream != null) {
+            stream.close();
+        }
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    @Override
+    public void visit(AsmPools pools) {
+        try {
+            for (AsmModulePool p : pools.getModulePools()) {
+                DefaultTypeResolver resolver = new DefaultTypeResolver(pools, p);
+                p.visitClassReaders((reader) -> {
+                    ClassWriter w = null;
+                    try {
+                        w = optimize(pools, p, reader, resolver);
+                    } catch (IOException ex) {
+                        throw new PluginException("Problem optimizing "
+                                + reader.getClassName(), ex);
+                    }
+                    return w;
+                });
+            }
+        } finally {
+            try {
+                close();
+            } catch (IOException ex) {
+                throw new UncheckedIOException(ex);
+            }
+        }
+    }
+
+    private ClassWriter optimize(AsmPools pools, AsmModulePool modulePool,
+            ClassReader reader, TypeResolver resolver)
+            throws IOException {
+        ClassNode cn = new ClassNode();
+        ClassWriter writer = null;
+        if ((reader.getAccess() & Opcodes.ACC_INTERFACE) == 0) {
+            reader.accept(cn, ClassReader.EXPAND_FRAMES);
+            boolean optimized = false;
+            for (Optimizer optimizer : optimizers) {
+                if (optimizer instanceof ClassOptimizer) {
+                    try {
+                        boolean optim = ((ClassOptimizer) optimizer).
+                                optimize(this::log, pools, modulePool, cn);
+                        if (optim) {
+                            optimized = true;
+                        }
+                    } catch (Throwable ex) {
+                        throw new PluginException("Exception optimizing "
+                                + reader.getClassName(), ex);
+                    }
+                } else {
+                    MethodOptimizer moptimizer = (MethodOptimizer) optimizer;
+                    for (MethodNode m : cn.methods) {
+                        if ((m.access & Opcodes.ACC_ABSTRACT) == 0
+                                && (m.access & Opcodes.ACC_NATIVE) == 0) {
+                            numMethods += 1;
+                            try {
+                                boolean optim = moptimizer.
+                                        optimize(this::log, pools, modulePool, cn,
+                                                m, resolver);
+                                if (optim) {
+                                    optimized = true;
+                                }
+                            } catch (Throwable ex) {
+                                throw new PluginException("Exception optimizing "
+                                        + reader.getClassName() + "." + m.name, ex);
+                            }
+
+                        }
+                    }
+                }
+            }
+
+            if (optimized) {
+                writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
+                try {
+                    // add a validation layer in between to check for class vallidity
+                    CheckClassAdapter ca = new CheckClassAdapter(writer);
+                    cn.accept(ca);
+                } catch (Exception ex) {
+                    throw new PluginException("Exception optimizing class " + cn.name, ex);
+                }
+            }
+        }
+        return writer;
+    }
+
+    @Override
+    public String getDescription() {
+        return PluginsResourceBundle.getDescription(NAME);
+    }
+
+    @Override
+    public boolean hasArguments() {
+        return true;
+    }
+
+    @Override
+    public String getArgumentsDescription() {
+       return PluginsResourceBundle.getArgument(NAME);
+    }
+
+    @Override
+    public void configure(Map<String, String> config) {
+        String strategies = config.get(NAME);
+        String[] arr = strategies.split(",");
+        for (String s : arr) {
+            if (s.equals(ALL)) {
+                optimizers.clear();
+                optimizers.add(new ForNameFolding());
+                break;
+            } else if (s.equals(FORNAME_REMOVAL)) {
+                optimizers.add(new ForNameFolding());
+            } else {
+                throw new PluginException("Unknown optimization");
+            }
+        }
+        String f = config.get(LOG);
+        if (f != null) {
+            try {
+                stream = new FileOutputStream(f);
+            } catch (IOException ex) {
+                throw new UncheckedIOException(ex);
+            }
+        }
+    }
+
+    @Override
+    public Set<PluginType> getType() {
+        Set<PluginType> set = new HashSet<>();
+        set.add(CATEGORY.TRANSFORMER);
+        return Collections.unmodifiableSet(set);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/PluginsResourceBundle.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal.plugins;
+
+import java.text.MessageFormat;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public final class PluginsResourceBundle {
+
+    static final String DESCRIPTION = "description";
+    static final String ARGUMENT = "argument";
+    private static final ResourceBundle pluginsBundle;
+
+    static {
+        Locale locale = Locale.getDefault();
+        try {
+            pluginsBundle = ResourceBundle.getBundle("jdk.tools.jlink."
+                    + "resources.plugins", locale);
+        } catch (MissingResourceException e) {
+            throw new InternalError("Cannot find jlink resource bundle for "
+                    + "locale " + locale);
+        }
+    }
+
+    private PluginsResourceBundle() {
+    }
+
+    public static String getArgument(String name, Object... args) {
+        return getMessage(name + "." + ARGUMENT, args);
+    }
+
+    public static String getDescription(String name) {
+        return getMessage(name + "." + DESCRIPTION, name);
+    }
+
+    public static String getOption(String name, String option) {
+        return getMessage(name + "." + option);
+    }
+
+    public static String getMessage(String key, Object... args) throws MissingResourceException {
+        String val = pluginsBundle.getString(key);
+        return MessageFormat.format(val, args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ReleaseInfoPlugin.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal.plugins;
+
+import java.lang.module.ModuleDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Properties;
+
+import jdk.tools.jlink.internal.Utils;
+import jdk.tools.jlink.plugin.ExecutableImage;
+import jdk.tools.jlink.plugin.PluginContext;
+import jdk.tools.jlink.plugin.PluginException;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.PostProcessorPlugin;
+
+/**
+ * This plugin adds/deletes information for 'release' file.
+ */
+public final class ReleaseInfoPlugin implements PostProcessorPlugin {
+    // option name
+    public static final String NAME = "release-info";
+    public static final String KEYS = "keys";
+
+    @Override
+    public Set<PluginType> getType() {
+        return Collections.singleton(CATEGORY.PROCESSOR);
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    @Override
+    public String getDescription() {
+        return PluginsResourceBundle.getDescription(NAME);
+    }
+
+    @Override
+    public Set<STATE> getState() {
+        return EnumSet.of(STATE.FUNCTIONAL);
+    }
+
+    @Override
+    public boolean hasArguments() {
+        return true;
+    }
+
+    @Override
+    public String getArgumentsDescription() {
+        return PluginsResourceBundle.getArgument(NAME);
+    }
+
+    @Override
+    public void configure(Map<String, String> config, PluginContext ctx) {
+        Properties release = ctx != null? ctx.getReleaseProperties() : null;
+        if (release != null) {
+            String operation = config.get(NAME);
+            switch (operation) {
+                case "add": {
+                    // leave it to open-ended! source, java_version, java_full_version
+                    // can be passed via this option like:
+                    //
+                    //     --release-info add:build_type=fastdebug,source=openjdk,java_version=9
+                    // and put whatever value that was passed in command line.
+
+                    config.keySet().stream().
+                        filter(s -> !NAME.equals(s)).
+                        forEach(s -> release.put(s, config.get(s)));
+                }
+                break;
+
+                case "del": {
+                    // --release-info del:keys=openjdk,java_version
+                    String[] keys = Utils.listParser.apply(config.get(KEYS));
+                    for (String k : keys) {
+                        release.remove(k);
+                    }
+                }
+                break;
+
+                default: {
+                    // --release-info <file>
+                    try (FileInputStream fis = new FileInputStream(operation)) {
+                        release.load(fis);
+                    } catch (IOException exp) {
+                        throw new RuntimeException(exp);
+                    }
+                }
+                break;
+            }
+        }
+    }
+
+    @Override
+    public List<String> process(ExecutableImage image) {
+        // Nothing to do! Release info copied already during configure!
+        return Collections.emptyList();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ResourceFilter.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal.plugins;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.function.Predicate;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+/**
+ *
+ * Filter in or out a resource
+ */
+public class ResourceFilter implements Predicate<String> {
+
+    private final Pattern inPatterns;
+    private final Pattern outPatterns;
+
+    static final String NEG = "^";
+
+    public ResourceFilter(String[] patterns) throws IOException {
+        this(patterns, false);
+    }
+
+    public ResourceFilter(String[] patterns, boolean negateAll) throws IOException {
+
+        // Get the patterns from a file
+        if (patterns != null && patterns.length == 1) {
+            String filePath = patterns[0];
+            File f = new File(filePath);
+            if (f.exists()) {
+                List<String> pats;
+                try (FileInputStream fis = new FileInputStream(f);
+                        InputStreamReader ins = new InputStreamReader(fis,
+                                StandardCharsets.UTF_8);
+                        BufferedReader reader = new BufferedReader(ins)) {
+                    pats = reader.lines().collect(Collectors.toList());
+                }
+                patterns = new String[pats.size()];
+                pats.toArray(patterns);
+            }
+        }
+
+        if (patterns != null && negateAll) {
+            String[] excluded = new String[patterns.length];
+            for (int i = 0; i < patterns.length; i++) {
+                excluded[i] = ResourceFilter.NEG + patterns[i];
+            }
+            patterns = excluded;
+        }
+
+        StringBuilder inPatternsBuilder = new StringBuilder();
+        StringBuilder outPatternsBuilder = new StringBuilder();
+        if (patterns != null) {
+            for (int i = 0; i < patterns.length; i++) {
+                String p = patterns[i];
+                p = p.replaceAll(" ", "");
+                StringBuilder builder = p.startsWith(NEG)
+                        ? outPatternsBuilder : inPatternsBuilder;
+                String pat = p.startsWith(NEG) ? p.substring(NEG.length()) : p;
+                builder.append(escape(pat));
+                if (i < patterns.length - 1) {
+                    builder.append("|");
+                }
+            }
+        }
+        this.inPatterns = inPatternsBuilder.length() == 0 ? null
+                : Pattern.compile(inPatternsBuilder.toString());
+        this.outPatterns = outPatternsBuilder.length() == 0 ? null
+                : Pattern.compile(outPatternsBuilder.toString());
+    }
+
+    public static String escape(String s) {
+        s = s.replaceAll(" ", "");
+        s = s.replaceAll("\\$", Matcher.quoteReplacement("\\$"));
+        s = s.replaceAll("\\.", Matcher.quoteReplacement("\\."));
+        s = s.replaceAll("\\*", ".+");
+        return s;
+    }
+
+    private boolean accept(String path) {
+        if (outPatterns != null) {
+            Matcher mout = outPatterns.matcher(path);
+            if (mout.matches()) {
+                //System.out.println("Excluding file " + resource.getPath());
+                return false;
+            }
+        }
+        boolean accepted = false;
+        // If the inPatterns is null, means that all resources are accepted.
+        if (inPatterns == null) {
+            accepted = true;
+        } else {
+            Matcher m = inPatterns.matcher(path);
+            if (m.matches()) {
+                //System.out.println("Including file " + resource.getPath());
+                accepted = true;
+            }
+        }
+        return accepted;
+    }
+
+    @Override
+    public boolean test(String path) {
+        return accept(path);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SortResourcesPlugin.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal.plugins;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import jdk.tools.jlink.plugin.PluginException;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.Pool.ModuleDataType;
+import jdk.tools.jlink.plugin.TransformerPlugin;
+import jdk.tools.jlink.internal.Utils;
+
+/**
+ *
+ * Sort Resources plugin
+ */
+public final class SortResourcesPlugin implements TransformerPlugin {
+
+    public static final String NAME = "sort-resources";
+    private final List<Pattern> filters = new ArrayList<>();
+    private List<String> orderedPaths;
+    private boolean isFile;
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    static class SortWrapper {
+
+        private final ModuleData resource;
+        private final int ordinal;
+
+        SortWrapper(ModuleData resource, int ordinal) {
+            this.resource = resource;
+            this.ordinal = ordinal;
+        }
+
+        ModuleData getResource() {
+            return resource;
+        }
+
+        String getPath() {
+            return resource.getPath();
+        }
+
+        int getOrdinal() {
+            return ordinal;
+        }
+    }
+
+    private int getPatternOrdinal(String path) {
+        int ordinal = -1;
+        for (int i = 0; i < filters.size(); i++) {
+            Matcher m = filters.get(i).matcher(path);
+            if (m.matches()) {
+                ordinal = i;
+                break;
+            }
+        }
+        return ordinal;
+    }
+
+    private int getFileOrdinal(String path) {
+        return orderedPaths.indexOf(path);
+    }
+
+    @Override
+    public void visit(Pool in, Pool out) {
+        in.getContent().stream()
+                .filter(w -> w.getType().equals(ModuleDataType.CLASS_OR_RESOURCE))
+                .map((r) -> new SortWrapper(r, isFile
+                        ? getFileOrdinal(r.getPath())
+                        : getPatternOrdinal(r.getPath())))
+                .sorted((sw1, sw2) -> {
+                    int ordinal1 = sw1.getOrdinal();
+                    int ordinal2 = sw2.getOrdinal();
+
+                    if (ordinal1 >= 0) {
+                        if (ordinal2 >= 0) {
+                            return ordinal1 - ordinal2;
+                        } else {
+                            return -1;
+                        }
+                    } else if (ordinal2 >= 0) {
+                        return 1;
+                    }
+
+                    return sw1.getPath().compareTo(sw2.getPath());
+                }).forEach((sw) -> {
+            try {
+                out.add(sw.getResource());
+            } catch (Exception ex) {
+                throw new RuntimeException(ex);
+            }
+        });
+        in.getContent().stream()
+                .filter(m -> !m.getType().equals(ModuleDataType.CLASS_OR_RESOURCE))
+                .forEach((m) -> {
+                    try {
+                        out.add(m);
+                    } catch (Exception ex) {
+                        throw new RuntimeException(ex);
+                    }
+                });
+    }
+
+    @Override
+    public Set<PluginType> getType() {
+        Set<PluginType> set = new HashSet<>();
+        set.add(CATEGORY.SORTER);
+        return Collections.unmodifiableSet(set);
+    }
+
+    @Override
+    public String getDescription() {
+        return PluginsResourceBundle.getDescription(NAME);
+    }
+
+    @Override
+    public boolean hasArguments() {
+        return true;
+    }
+
+    @Override
+    public String getArgumentsDescription() {
+       return PluginsResourceBundle.getArgument(NAME);
+    }
+
+    @Override
+    public void configure(Map<String, String> config) {
+        String val = config.get(NAME);
+        try {
+            String[] patterns = Utils.listParser.apply(val);
+            boolean isf = false;
+            List<String> paths = null;
+            if (patterns != null) {
+                if (patterns.length == 1) {
+                    String filePath = patterns[0];
+                    File f = new File(filePath);
+                    if (f.exists()) {
+                        isf = true;
+                        try (FileInputStream fis = new FileInputStream(f);
+                                InputStreamReader ins
+                                = new InputStreamReader(fis, StandardCharsets.UTF_8);
+                                BufferedReader reader = new BufferedReader(ins)) {
+                            paths = reader.lines().collect(Collectors.toList());
+                        }
+                    }
+                }
+                if (!isf) {
+                    for (String p : patterns) {
+                        p = p.replaceAll(" ", "");
+                        Pattern pattern = Pattern.compile(ResourceFilter.escape(p));
+                        filters.add(pattern);
+                    }
+                }
+            }
+            orderedPaths = paths;
+            isFile = isf;
+        } catch (IOException ex) {
+            throw new PluginException(ex);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StringSharingPlugin.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,421 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal.plugins;
+
+import com.sun.tools.classfile.Annotation;
+import com.sun.tools.classfile.Attribute;
+import com.sun.tools.classfile.Attributes;
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.ConstantPool;
+import com.sun.tools.classfile.ConstantPoolException;
+import com.sun.tools.classfile.Field;
+import com.sun.tools.classfile.LocalVariableTable_attribute;
+import com.sun.tools.classfile.LocalVariableTypeTable_attribute;
+import com.sun.tools.classfile.Method;
+import com.sun.tools.classfile.RuntimeInvisibleAnnotations_attribute;
+import com.sun.tools.classfile.RuntimeParameterAnnotations_attribute;
+import com.sun.tools.classfile.RuntimeVisibleAnnotations_attribute;
+import com.sun.tools.classfile.Signature_attribute;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import jdk.internal.jimage.decompressor.CompressIndexes;
+import jdk.internal.jimage.decompressor.SignatureParser;
+import jdk.internal.jimage.decompressor.StringSharingDecompressor;
+import jdk.tools.jlink.internal.PoolImpl;
+import jdk.tools.jlink.plugin.TransformerPlugin;
+import jdk.tools.jlink.plugin.PluginException;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.internal.ResourcePrevisitor;
+import jdk.tools.jlink.internal.StringTable;
+import jdk.tools.jlink.internal.Utils;
+
+/**
+ *
+ * A Plugin that stores the image classes constant pool UTF_8 entries into the
+ * Image StringsTable.
+ */
+public class StringSharingPlugin implements TransformerPlugin, ResourcePrevisitor {
+
+    public static final String NAME = "compact-cp";
+
+    private static final int[] SIZES;
+
+    static {
+        SIZES = StringSharingDecompressor.getSizes();
+    }
+
+    private static final class CompactCPHelper {
+
+        private static final class DescriptorsScanner {
+
+            private final ClassFile cf;
+
+            private DescriptorsScanner(ClassFile cf) {
+                this.cf = cf;
+            }
+
+            private Set<Integer> scan() throws Exception {
+                Set<Integer> utf8Descriptors = new HashSet<>();
+                scanConstantPool(utf8Descriptors);
+
+                scanFields(utf8Descriptors);
+
+                scanMethods(utf8Descriptors);
+
+                scanAttributes(cf.attributes, utf8Descriptors);
+
+                return utf8Descriptors;
+            }
+
+            private void scanAttributes(Attributes attributes,
+                    Set<Integer> utf8Descriptors) throws Exception {
+                for (Attribute a : attributes) {
+                    if (a instanceof Signature_attribute) {
+                        Signature_attribute sig = (Signature_attribute) a;
+                        utf8Descriptors.add(sig.signature_index);
+                    } else if (a instanceof RuntimeVisibleAnnotations_attribute) {
+                        RuntimeVisibleAnnotations_attribute an
+                                = (RuntimeVisibleAnnotations_attribute) a;
+                        for (Annotation annotation : an.annotations) {
+                            scanAnnotation(annotation, utf8Descriptors);
+                        }
+                    } else if (a instanceof RuntimeInvisibleAnnotations_attribute) {
+                        RuntimeInvisibleAnnotations_attribute an
+                                = (RuntimeInvisibleAnnotations_attribute) a;
+                        for (Annotation annotation : an.annotations) {
+                            scanAnnotation(annotation, utf8Descriptors);
+                        }
+                    } else if (a instanceof RuntimeParameterAnnotations_attribute) {
+                        RuntimeParameterAnnotations_attribute rap
+                                = (RuntimeParameterAnnotations_attribute) a;
+                        for (Annotation[] arr : rap.parameter_annotations) {
+                            for (Annotation an : arr) {
+                                scanAnnotation(an, utf8Descriptors);
+                            }
+                        }
+                    } else if (a instanceof LocalVariableTable_attribute) {
+                        LocalVariableTable_attribute lvt
+                                = (LocalVariableTable_attribute) a;
+                        for (LocalVariableTable_attribute.Entry entry
+                                : lvt.local_variable_table) {
+                            utf8Descriptors.add(entry.descriptor_index);
+                        }
+                    } else if (a instanceof LocalVariableTypeTable_attribute) {
+                        LocalVariableTypeTable_attribute lvt
+                                = (LocalVariableTypeTable_attribute) a;
+                        for (LocalVariableTypeTable_attribute.Entry entry
+                                : lvt.local_variable_table) {
+                            utf8Descriptors.add(entry.signature_index);
+                        }
+                    }
+                }
+            }
+
+            private void scanAnnotation(Annotation annotation,
+                    Set<Integer> utf8Descriptors) throws Exception {
+                utf8Descriptors.add(annotation.type_index);
+                for (Annotation.element_value_pair evp : annotation.element_value_pairs) {
+                    utf8Descriptors.add(evp.element_name_index);
+                    scanElementValue(evp.value, utf8Descriptors);
+                }
+            }
+
+            private void scanElementValue(Annotation.element_value value,
+                    Set<Integer> utf8Descriptors) throws Exception {
+                if (value instanceof Annotation.Enum_element_value) {
+                    Annotation.Enum_element_value eev
+                            = (Annotation.Enum_element_value) value;
+                    utf8Descriptors.add(eev.type_name_index);
+                }
+                if (value instanceof Annotation.Class_element_value) {
+                    Annotation.Class_element_value eev
+                            = (Annotation.Class_element_value) value;
+                    utf8Descriptors.add(eev.class_info_index);
+                }
+                if (value instanceof Annotation.Annotation_element_value) {
+                    Annotation.Annotation_element_value aev
+                            = (Annotation.Annotation_element_value) value;
+                    scanAnnotation(aev.annotation_value, utf8Descriptors);
+                }
+                if (value instanceof Annotation.Array_element_value) {
+                    Annotation.Array_element_value aev
+                            = (Annotation.Array_element_value) value;
+                    for (Annotation.element_value v : aev.values) {
+                        scanElementValue(v, utf8Descriptors);
+                    }
+                }
+            }
+
+            private void scanFields(Set<Integer> utf8Descriptors)
+                    throws Exception {
+                for (Field field : cf.fields) {
+                    int descriptorIndex = field.descriptor.index;
+                    utf8Descriptors.add(descriptorIndex);
+                    scanAttributes(field.attributes, utf8Descriptors);
+                }
+
+            }
+
+            private void scanMethods(Set<Integer> utf8Descriptors)
+                    throws Exception {
+                for (Method m : cf.methods) {
+                    int descriptorIndex = m.descriptor.index;
+                    utf8Descriptors.add(descriptorIndex);
+                    scanAttributes(m.attributes, utf8Descriptors);
+                }
+            }
+
+            private void scanConstantPool(Set<Integer> utf8Descriptors)
+                    throws Exception {
+                for (int i = 1; i < cf.constant_pool.size(); i++) {
+                    try {
+                        ConstantPool.CPInfo info = cf.constant_pool.get(i);
+                        if (info instanceof ConstantPool.CONSTANT_NameAndType_info) {
+                            ConstantPool.CONSTANT_NameAndType_info nameAndType
+                                    = (ConstantPool.CONSTANT_NameAndType_info) info;
+                            utf8Descriptors.add(nameAndType.type_index);
+                        }
+                        if (info instanceof ConstantPool.CONSTANT_MethodType_info) {
+                            ConstantPool.CONSTANT_MethodType_info mt
+                                    = (ConstantPool.CONSTANT_MethodType_info) info;
+                            utf8Descriptors.add(mt.descriptor_index);
+                        }
+
+                        if (info instanceof ConstantPool.CONSTANT_Double_info
+                                || info instanceof ConstantPool.CONSTANT_Long_info) {
+                            i++;
+                        }
+                    } catch (ConstantPool.InvalidIndex ex) {
+                        throw new IOException(ex);
+                    }
+                }
+            }
+        }
+
+        public byte[] transform(ModuleData resource, Pool out,
+                StringTable strings) throws IOException, Exception {
+            byte[] content = resource.getBytes();
+            ClassFile cf;
+            try (InputStream stream = new ByteArrayInputStream(content)) {
+                cf = ClassFile.read(stream);
+            } catch (ConstantPoolException ex) {
+                throw new IOException("Compressor EX " + ex + " for "
+                        + resource.getPath() + " content.length " + content.length, ex);
+            }
+            DescriptorsScanner scanner = new DescriptorsScanner(cf);
+            return optimize(resource, out, strings, scanner.scan(), content);
+        }
+
+        @SuppressWarnings("fallthrough")
+        private byte[] optimize(ModuleData resource, Pool resources,
+                StringTable strings,
+                Set<Integer> descriptorIndexes, byte[] content) throws Exception {
+            DataInputStream stream = new DataInputStream(new ByteArrayInputStream(content));
+            ByteArrayOutputStream outStream = new ByteArrayOutputStream(content.length);
+            DataOutputStream out = new DataOutputStream(outStream);
+            byte[] header = new byte[8]; //magic/4, minor/2, major/2
+            stream.readFully(header);
+            out.write(header);
+            int count = stream.readUnsignedShort();
+            out.writeShort(count);
+            for (int i = 1; i < count; i++) {
+                int tag = stream.readUnsignedByte();
+                byte[] arr;
+                switch (tag) {
+                    case ConstantPool.CONSTANT_Utf8: {
+                        String original = stream.readUTF();
+                        // 2 cases, a Descriptor or a simple String
+                        if (descriptorIndexes.contains(i)) {
+                            SignatureParser.ParseResult parseResult
+                                    = SignatureParser.parseSignatureDescriptor(original);
+                            List<Integer> indexes
+                                    = parseResult.types.stream().map((type) -> {
+                                        return strings.addString(type);
+                                    }).collect(Collectors.toList());
+                            if (!indexes.isEmpty()) {
+                                out.write(StringSharingDecompressor.EXTERNALIZED_STRING_DESCRIPTOR);
+                                int sigIndex = strings.addString(parseResult.formatted);
+                                byte[] compressed
+                                        = CompressIndexes.compress(sigIndex);
+                                out.write(compressed, 0, compressed.length);
+
+                                writeDescriptorReference(out, indexes);
+                                continue;
+                            }
+                        }
+                        // Put all strings in strings table.
+                        writeUTF8Reference(out, strings.addString(original));
+
+                        break;
+                    }
+
+                    case ConstantPool.CONSTANT_Long:
+                    case ConstantPool.CONSTANT_Double: {
+                        i++;
+                    }
+                    default: {
+                        out.write(tag);
+                        int size = SIZES[tag];
+                        arr = new byte[size];
+                        stream.readFully(arr);
+                        out.write(arr);
+                    }
+                }
+            }
+            out.write(content, content.length - stream.available(),
+                    stream.available());
+            out.flush();
+
+            return outStream.toByteArray();
+        }
+
+        private void writeDescriptorReference(DataOutputStream out,
+                List<Integer> indexes) throws IOException {
+            List<byte[]> buffers = new ArrayList<>();
+            int l = 0;
+            for (Integer index : indexes) {
+                byte[] buffer = CompressIndexes.compress(index);
+                l += buffer.length;
+                buffers.add(buffer);
+            }
+            ByteBuffer bb = ByteBuffer.allocate(l);
+            buffers.stream().forEach((buf) -> {
+                bb.put(buf);
+            });
+            byte[] compressed_indices = bb.array();
+            byte[] compressed_size = CompressIndexes.
+                    compress(compressed_indices.length);
+            out.write(compressed_size, 0, compressed_size.length);
+            out.write(compressed_indices, 0, compressed_indices.length);
+        }
+
+        private void writeUTF8Reference(DataOutputStream out, int index)
+                throws IOException {
+            out.write(StringSharingDecompressor.EXTERNALIZED_STRING);
+            byte[] compressed = CompressIndexes.compress(index);
+            out.write(compressed, 0, compressed.length);
+        }
+    }
+
+    private Predicate<String> predicate;
+
+    public StringSharingPlugin() throws IOException {
+        this(new String[0]);
+    }
+
+    StringSharingPlugin(String[] patterns) throws IOException {
+        this(new ResourceFilter(patterns));
+    }
+
+    StringSharingPlugin(Predicate<String> predicate) {
+        this.predicate = predicate;
+    }
+
+    @Override
+    public Set<PluginType> getType() {
+        Set<PluginType> set = new HashSet<>();
+        set.add(CATEGORY.COMPRESSOR);
+        return Collections.unmodifiableSet(set);
+    }
+
+    @Override
+    public void visit(Pool in, Pool result) {
+        CompactCPHelper visit = new CompactCPHelper();
+        in.visit((resource) -> {
+            ModuleData res = resource;
+            if (predicate.test(resource.getPath()) && resource.getPath().endsWith(".class")) {
+                byte[] compressed = null;
+                try {
+                    compressed = visit.transform(resource, result, ((PoolImpl) in).getStringTable());
+                } catch (Exception ex) {
+                    throw new PluginException(ex);
+                }
+                res = PoolImpl.newCompressedResource(resource,
+                        ByteBuffer.wrap(compressed), getName(), null,
+                        ((PoolImpl) in).getStringTable(), in.getByteOrder());
+            }
+            return res;
+        }, result);
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    @Override
+    public String getDescription() {
+        return PluginsResourceBundle.getDescription(NAME);
+    }
+
+    @Override
+    public boolean hasArguments() {
+        return true;
+    }
+
+    @Override
+    public String getArgumentsDescription() {
+       return PluginsResourceBundle.getArgument(NAME);
+    }
+
+    @Override
+    public void configure(Map<String, String> config) {
+        try {
+            String val = config.get(NAME);
+            predicate = new ResourceFilter(Utils.listParser.apply(val));
+        } catch (IOException ex) {
+            throw new PluginException(ex);
+        }
+    }
+
+    @Override
+    public void previsit(Pool resources, StringTable strings) {
+        CompactCPHelper preVisit = new CompactCPHelper();
+        for (ModuleData resource : resources.getContent()) {
+            if (resource.getType().equals(Pool.ModuleDataType.CLASS_OR_RESOURCE)
+                    && resource.getPath().endsWith(".class") && predicate.test(resource.getPath())) {
+                try {
+                    preVisit.transform(resource, null, strings);
+                } catch (Exception ex) {
+                    throw new PluginException(ex);
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StripDebugPlugin.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal.plugins;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Predicate;
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.Pool.ModuleDataType;
+import jdk.tools.jlink.plugin.TransformerPlugin;
+
+/**
+ *
+ * Strip debug attributes plugin
+ */
+public final class StripDebugPlugin implements TransformerPlugin {
+    private static final String[] PATTERNS = {"*.diz"};
+    public static final String NAME = "strip-debug";
+    private final Predicate<String> predicate;
+    public StripDebugPlugin() {
+        try {
+            predicate = new ResourceFilter(PATTERNS);
+        } catch (IOException ex) {
+            throw new UncheckedIOException(ex);
+        }
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    @Override
+    public Set<PluginType> getType() {
+        Set<PluginType> set = new HashSet<>();
+        set.add(CATEGORY.TRANSFORMER);
+        return Collections.unmodifiableSet(set);
+    }
+
+    @Override
+    public String getDescription() {
+        return PluginsResourceBundle.getDescription(NAME);
+    }
+
+    @Override
+    public void visit(Pool in, Pool out) {
+        //remove *.diz files as well as debug attributes.
+        in.visit((resource) -> {
+            ModuleData res = resource;
+            if (resource.getType().equals(ModuleDataType.CLASS_OR_RESOURCE)) {
+                String path = resource.getPath();
+                if (path.endsWith(".class")) {
+                    if (path.endsWith("module-info.class")) {
+                        // XXX. Do we have debug info? Is Asm ready for module-info?
+                    } else {
+                        ClassReader reader = new ClassReader(resource.getBytes());
+                        ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
+                        reader.accept(writer, ClassReader.SKIP_DEBUG);
+                        byte[] content = writer.toByteArray();
+                        res = Pool.newResource(path, new ByteArrayInputStream(content), content.length);
+                    }
+                }
+            } else if (predicate.test(res.getPath())) {
+                res = null;
+            }
+            return res;
+        }, out);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StripNativeCommandsPlugin.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal.plugins;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.TransformerPlugin;
+
+/**
+ *
+ * Strip Native Commands plugin
+ */
+public final class StripNativeCommandsPlugin implements TransformerPlugin {
+
+    public static final String NAME = "strip-native-commands";
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    @Override
+    public Set<PluginType> getType() {
+        Set<PluginType> set = new HashSet<>();
+        set.add(CATEGORY.FILTER);
+        return Collections.unmodifiableSet(set);
+    }
+
+    @Override
+    public void visit(Pool in, Pool out) {
+        in.visit((file) -> {
+            return file.getType() == Pool.ModuleDataType.NATIVE_CMD ? null : file;
+        }, out);
+    }
+
+    @Override
+    public String getDescription() {
+        return PluginsResourceBundle.getDescription(NAME);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModuleDescriptorPlugin.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,727 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal.plugins;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.module.ModuleDescriptor.*;
+import java.lang.module.ModuleDescriptor;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import jdk.internal.module.Checks;
+import jdk.internal.module.ModuleInfoExtender;
+import jdk.internal.module.SystemModules;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import jdk.internal.org.objectweb.asm.Opcodes;
+
+import static jdk.internal.org.objectweb.asm.Opcodes.*;
+import jdk.tools.jlink.plugin.PluginException;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.TransformerPlugin;
+
+/**
+ * Jlink plugin to reconstitute module descriptors for installed modules.
+ * It will extend module-info.class with ConcealedPackages attribute,
+ * if not present. It also determines the number of packages of
+ * the boot layer at link time.
+ *
+ * This plugin will override jdk.internal.module.SystemModules class
+ *
+ * @see java.lang.module.SystemModuleFinder
+ * @see SystemModules
+ */
+public final class SystemModuleDescriptorPlugin implements TransformerPlugin {
+    // TODO: packager has the dependency on the plugin name
+    // Keep it as "--installed-modules" until packager removes such
+    // dependency (should not need to specify this plugin since it
+    // is enabled by default)
+    private static final String NAME = "installed-modules";
+    private static final String DESCRIPTION = PluginsResourceBundle.getDescription(NAME);
+    private boolean enabled;
+
+    public SystemModuleDescriptorPlugin() {
+        this.enabled = true;
+    }
+
+    @Override
+    public Set<PluginType> getType() {
+        return Collections.singleton(CATEGORY.TRANSFORMER);
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    @Override
+    public String getDescription() {
+        return DESCRIPTION;
+    }
+
+    @Override
+    public Set<STATE> getState() {
+        return enabled ? EnumSet.of(STATE.AUTO_ENABLED, STATE.FUNCTIONAL)
+                       : EnumSet.of(STATE.DISABLED);
+    }
+
+    @Override
+    public void configure(Map<String, String> config) {
+        if (config.containsKey(NAME)) {
+            enabled = false;
+        }
+    }
+
+
+    @Override
+    public void visit(Pool in, Pool out) {
+        if (!enabled) {
+            throw new PluginException(NAME + " was set");
+        }
+
+        Builder builder = new Builder();
+
+        // generate the byte code to create ModuleDescriptors
+        // skip parsing module-info.class and skip name check
+        for (Pool.Module module : in.getModules()) {
+            Pool.ModuleData data = module.get("module-info.class");
+            if (data == null) {
+                // automatic module not supported yet
+                throw new PluginException("module-info.class not found for " + module.getName() + " module");
+            }
+            assert module.getName().equals(data.getModule());
+            try {
+                ByteArrayInputStream bain = new ByteArrayInputStream(data.getBytes());
+                ModuleDescriptor md = ModuleDescriptor.read(bain);
+                validateNames(md);
+
+                Builder.ModuleDescriptorBuilder mbuilder = builder.module(md, module.getAllPackages());
+                if (md.conceals().isEmpty() &&
+                        (md.exports().size() + md.conceals().size()) != module.getAllPackages().size()) {
+                    // add ConcealedPackages attribute if not exist
+                    bain.reset();
+                    ModuleInfoRewriter minfoWriter = new ModuleInfoRewriter(bain, mbuilder.conceals());
+                    // replace with the overridden version
+                    data = new Pool.ModuleData(data.getModule(), data.getPath(), data.getType(),
+                                               minfoWriter.stream(), minfoWriter.size());
+                }
+                out.add(data);
+            } catch (IOException e) {
+                throw new PluginException(e);
+            }
+
+        }
+
+        // Generate the new class
+        ClassWriter cwriter = builder.build();
+        for (Pool.ModuleData data : in.getContent()) {
+            if (data.getPath().endsWith("module-info.class"))
+                continue;
+
+            if (builder.isOverriddenClass(data.getPath())) {
+                byte[] bytes = cwriter.toByteArray();
+                Pool.ModuleData ndata = new Pool.ModuleData(data.getModule(), data.getPath(), data.getType(),
+                                                            new ByteArrayInputStream(bytes), bytes.length);
+                out.add(ndata);
+            } else {
+                out.add(data);
+            }
+        }
+    }
+
+    /*
+     * Add ConcealedPackages attribute
+     */
+    class ModuleInfoRewriter extends ByteArrayOutputStream {
+        final ModuleInfoExtender extender;
+        ModuleInfoRewriter(InputStream in, Set<String> conceals) throws IOException {
+            this.extender = ModuleInfoExtender.newExtender(in);
+            // Add ConcealedPackages attribute
+            this.extender.conceals(conceals);
+            this.extender.write(this);
+        }
+
+        InputStream stream() {
+            return new ByteArrayInputStream(buf);
+        }
+    }
+
+    void validateNames(ModuleDescriptor md) {
+        Checks.requireModuleName(md.name());
+        for (Requires req : md.requires()) {
+            Checks.requireModuleName(req.name());
+        }
+        for (Exports e : md.exports()) {
+            Checks.requirePackageName(e.source());
+            if (e.isQualified())
+               e.targets().forEach(Checks::requireModuleName);
+        }
+        for (Map.Entry<String, Provides> e : md.provides().entrySet()) {
+            String service = e.getKey();
+            Provides provides = e.getValue();
+            Checks.requireServiceTypeName(service);
+            Checks.requireServiceTypeName(provides.service());
+            provides.providers().forEach(Checks::requireServiceProviderName);
+        }
+        for (String service : md.uses()) {
+            Checks.requireServiceTypeName(service);
+        }
+        for (String pn : md.conceals()) {
+            Checks.requirePackageName(pn);
+        }
+    }
+
+    /*
+     * Returns the initial capacity for a new Set or Map of the given size
+     * to avoid resizing.
+     */
+    static final int initialCapacity(int size) {
+        if (size == 0) {
+            return 0;
+        } else {
+            // Adjust to try and get size/capacity as close to the
+            // HashSet/HashMap default load factor without going over.
+            return (int)(Math.ceil((double)size / 0.75));
+        }
+    }
+
+    /**
+     * Builder of a new jdk.internal.module.SystemModules class
+     * to reconstitute ModuleDescriptor of the installed modules.
+     */
+    static class Builder {
+        private static final String CLASSNAME =
+            "jdk/internal/module/SystemModules";
+        private static final String MODULE_DESCRIPTOR_BUILDER =
+            "jdk/internal/module/Builder";
+        private static final String MODULE_DESCRIPTOR_ARRAY_SIGNATURE =
+            "[Ljava/lang/module/ModuleDescriptor;";
+
+        // static variables in SystemModules class
+        private static final String MODULE_NAMES = "MODULE_NAMES";
+        private static final String PACKAGE_COUNT = "PACKAGES_IN_BOOT_LAYER";
+
+        private static final int BUILDER_VAR    = 0;
+        private static final int MD_VAR         = 1;   // variable for ModuleDescriptor
+        private static final int MODS_VAR       = 2;   // variable for Set<Modifier>
+        private static final int STRING_SET_VAR = 3;   // variable for Set<String>
+        private static final int MAX_LOCAL_VARS = 256;
+
+        private final ClassWriter cw;
+        private MethodVisitor mv;
+        private int nextLocalVar = 4;
+        private int nextModulesIndex = 0;
+
+        // list of all ModuleDescriptorBuilders, invoked in turn when building.
+        private final List<ModuleDescriptorBuilder> builders = new ArrayList<>();
+
+        // map Set<String> to a specialized builder to allow them to be
+        // deduplicated as they are requested
+        private final Map<Set<String>, StringSetBuilder> stringSets = new HashMap<>();
+
+        public Builder() {
+            this.cw = new ClassWriter(ClassWriter.COMPUTE_MAXS+ClassWriter.COMPUTE_FRAMES);
+        }
+
+        /*
+         * static initializer initializing the static fields
+         *
+         * static Map<String, ModuleDescriptor> map = new HashMap<>();
+         */
+        private void clinit(int numModules, int numPackages) {
+            cw.visit(Opcodes.V1_8, ACC_PUBLIC+ACC_FINAL+ACC_SUPER, CLASSNAME,
+                    null, "java/lang/Object", null);
+
+            // public static String[] MODULE_NAMES = new String[] {....};
+            cw.visitField(ACC_PUBLIC+ACC_FINAL+ACC_STATIC, MODULE_NAMES,
+                    "[Ljava/lang/String;", null, null)
+                    .visitEnd();
+
+            // public static int PACKAGES_IN_BOOT_LAYER;
+            cw.visitField(ACC_PUBLIC+ACC_FINAL+ACC_STATIC, PACKAGE_COUNT,
+                    "I", null, numPackages)
+                    .visitEnd();
+
+            this.mv = cw.visitMethod(ACC_STATIC, "<clinit>", "()V",
+                    null, null);
+            mv.visitCode();
+
+            // create the MODULE_NAMES array
+            pushInt(numModules);
+            mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
+
+            int index = 0;
+            for (ModuleDescriptorBuilder builder : builders) {
+                mv.visitInsn(DUP);       // arrayref
+                pushInt(index++);
+                mv.visitLdcInsn(builder.md.name());      // value
+                mv.visitInsn(AASTORE);
+            }
+
+            mv.visitFieldInsn(PUTSTATIC, CLASSNAME, MODULE_NAMES,
+                    "[Ljava/lang/String;");
+
+            mv.visitInsn(RETURN);
+            mv.visitMaxs(0, 0);
+            mv.visitEnd();
+
+        }
+
+        /*
+         * Adds the given ModuleDescriptor to the installed module list, and
+         * prepares mapping from Set<String> to StringSetBuilders to emit an
+         * optimized number of string sets during build.
+         */
+        public ModuleDescriptorBuilder module(ModuleDescriptor md, Set<String> packages) {
+            ModuleDescriptorBuilder builder = new ModuleDescriptorBuilder(md, packages);
+            builders.add(builder);
+
+            // exports
+            for (ModuleDescriptor.Exports e : md.exports()) {
+                if (e.isQualified()) {
+                    stringSets.computeIfAbsent(e.targets(), s -> new StringSetBuilder(s))
+                              .increment();
+                }
+            }
+
+            // provides
+            for (ModuleDescriptor.Provides p : md.provides().values()) {
+                stringSets.computeIfAbsent(p.providers(), s -> new StringSetBuilder(s))
+                          .increment();
+            }
+
+            // uses
+            stringSets.computeIfAbsent(md.uses(), s -> new StringSetBuilder(s))
+                      .increment();
+            return builder;
+        }
+
+        /*
+         * Generate bytecode for SystemModules
+         */
+        public ClassWriter build() {
+            int numModules = builders.size();
+            int numPackages = 0;
+            for (ModuleDescriptorBuilder builder : builders) {
+                numPackages += builder.md.packages().size();
+            }
+
+            this.clinit(numModules, numPackages);
+            this.mv = cw.visitMethod(ACC_PUBLIC+ACC_STATIC,
+                                     "modules", "()" + MODULE_DESCRIPTOR_ARRAY_SIGNATURE,
+                                     "()" + MODULE_DESCRIPTOR_ARRAY_SIGNATURE, null);
+            mv.visitCode();
+            pushInt(numModules);
+            mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor");
+            mv.visitVarInsn(ASTORE, MD_VAR);
+
+            for (ModuleDescriptorBuilder builder : builders) {
+                builder.build();
+            }
+            mv.visitVarInsn(ALOAD, MD_VAR);
+            mv.visitInsn(ARETURN);
+            mv.visitMaxs(0, 0);
+            mv.visitEnd();
+            return cw;
+        }
+
+        public boolean isOverriddenClass(String path) {
+            return path.equals("/java.base/" + CLASSNAME + ".class");
+        }
+
+        void pushInt(int num) {
+            if (num <= 5) {
+                mv.visitInsn(ICONST_0 + num);
+            } else if (num < Byte.MAX_VALUE) {
+                mv.visitIntInsn(BIPUSH, num);
+            } else if (num < Short.MAX_VALUE) {
+                mv.visitIntInsn(SIPUSH, num);
+            } else {
+                throw new IllegalArgumentException("exceed limit: " + num);
+            }
+        }
+
+        class ModuleDescriptorBuilder {
+            static final String REQUIRES_MODIFIER_CLASSNAME =
+                    "java/lang/module/ModuleDescriptor$Requires$Modifier";
+            static final String REQUIRES_MODIFIER_TYPE =
+                "Ljava/lang/module/ModuleDescriptor$Requires$Modifier;";
+            static final String BUILDER_TYPE = "Ljdk/internal/module/Builder;";
+            static final String REQUIRES_MODIFIER_STRING_SIG =
+                "(" + REQUIRES_MODIFIER_TYPE + "Ljava/lang/String;)" + BUILDER_TYPE;
+            static final String STRING_SET_SIG =
+                "(Ljava/lang/String;Ljava/util/Set;)" + BUILDER_TYPE;
+            static final String SET_STRING_SIG =
+                "(Ljava/util/Set;Ljava/lang/String;)" + BUILDER_TYPE;
+            static final String SET_SIG =
+                "(Ljava/util/Set;)" + BUILDER_TYPE;
+            static final String STRING_SIG = "(Ljava/lang/String;)" + BUILDER_TYPE;
+            static final String STRING_STRING_SIG =
+                "(Ljava/lang/String;Ljava/lang/String;)" + BUILDER_TYPE;
+
+            final ModuleDescriptor md;
+            final Set<String> packages;
+
+            ModuleDescriptorBuilder(ModuleDescriptor md, Set<String> packages) {
+                this.md = md;
+                this.packages = packages;
+            }
+
+            void newBuilder(String name, int reqs, int exports, int provides,
+                            int conceals, int packages) {
+                mv.visitTypeInsn(NEW, MODULE_DESCRIPTOR_BUILDER);
+                mv.visitInsn(DUP);
+                mv.visitLdcInsn(name);
+                pushInt(initialCapacity(reqs));
+                pushInt(initialCapacity(exports));
+                pushInt(initialCapacity(provides));
+                pushInt(initialCapacity(conceals));
+                pushInt(initialCapacity(packages));
+                mv.visitMethodInsn(INVOKESPECIAL, MODULE_DESCRIPTOR_BUILDER,
+                                   "<init>", "(Ljava/lang/String;IIIII)V", false);
+                mv.visitVarInsn(ASTORE, BUILDER_VAR);
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+            }
+
+            /*
+             * Returns the set of concealed packages from ModuleDescriptor, if present
+             * or compute it if the module oes not have ConcealedPackages attribute
+             */
+            Set<String> conceals() {
+                Set<String> conceals = md.conceals();
+                if (md.conceals().isEmpty() &&
+                        (md.exports().size() + md.conceals().size()) != packages.size()) {
+                    Set<String> exports = md.exports().stream()
+                                            .map(Exports::source)
+                                            .collect(Collectors.toSet());
+                    conceals = packages.stream()
+                                       .filter(pn -> !exports.contains(pn))
+                                       .collect(Collectors.toSet());
+                }
+
+                if (conceals.size() + md.exports().size() != packages.size() &&
+                    // jdk.localedata may have concealed packages that don't exist
+                    !md.name().equals("jdk.localedata")) {
+                    throw new AssertionError(md.name() + ": conceals=" + conceals.size() +
+                            ", exports=" + md.exports().size() + ", packages=" + packages.size());
+                }
+                return conceals;
+            }
+
+            void build() {
+                newBuilder(md.name(), md.requires().size(),
+                           md.exports().size(),
+                           md.provides().size(),
+                           conceals().size(),
+                           conceals().size() + md.exports().size());
+
+                // requires
+                for (ModuleDescriptor.Requires req : md.requires()) {
+                    switch (req.modifiers().size()) {
+                        case 0:
+                            requires(req.name());
+                            break;
+                        case 1:
+                            ModuleDescriptor.Requires.Modifier mod =
+                                req.modifiers().iterator().next();
+                            requires(mod, req.name());
+                            break;
+                        default:
+                            requires(req.modifiers(), req.name());
+                    }
+                }
+
+                // exports
+                for (ModuleDescriptor.Exports e : md.exports()) {
+                    if (e.isQualified()) {
+                        exports(e.source(), e.targets());
+                    } else {
+                        exports(e.source());
+                    }
+                }
+
+                // uses
+                uses(md.uses());
+
+                // provides
+                for (ModuleDescriptor.Provides p : md.provides().values()) {
+                    provides(p.service(), p.providers());
+                }
+
+                // concealed packages
+                for (String pn : conceals()) {
+                    conceals(pn);
+                }
+
+                if (md.version().isPresent()) {
+                    version(md.version().get());
+                }
+
+                if (md.mainClass().isPresent()) {
+                    mainClass(md.mainClass().get());
+                }
+
+                putModuleDescriptor();
+            }
+
+            /*
+             * Put ModuleDescriptor into the modules array
+             */
+            void putModuleDescriptor() {
+                mv.visitVarInsn(ALOAD, MD_VAR);
+                pushInt(nextModulesIndex++);
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+                    "build", "()Ljava/lang/module/ModuleDescriptor;", false);
+                mv.visitInsn(AASTORE);
+            }
+
+            /*
+             * Invoke Builder.requires(String mn)
+             */
+            void requires(String name) {
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                mv.visitLdcInsn(name);
+                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+                                   "requires", STRING_SIG, false);
+                mv.visitInsn(POP);
+            }
+
+            /*
+             * Invoke Builder.requires(Modifier mod, String mn)
+             */
+            void requires(ModuleDescriptor.Requires.Modifier mod, String name) {
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                mv.visitFieldInsn(GETSTATIC, REQUIRES_MODIFIER_CLASSNAME, mod.name(),
+                                  REQUIRES_MODIFIER_TYPE);
+                mv.visitLdcInsn(name);
+                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+                                   "requires", REQUIRES_MODIFIER_STRING_SIG, false);
+                mv.visitInsn(POP);
+            }
+
+            /*
+             * Invoke Builder.requires(Set<Modifier> mods, String mn)
+             *
+             * EnumSet<Modifier> mods = EnumSet.of(mod,....);
+             * Buidler.requires(mods, mn);
+             */
+            void requires(Set<ModuleDescriptor.Requires.Modifier> mods, String name) {
+                mv.visitVarInsn(ALOAD, MODS_VAR);
+                String signature = "(";
+                for (ModuleDescriptor.Requires.Modifier m : mods) {
+                    mv.visitFieldInsn(GETSTATIC, REQUIRES_MODIFIER_CLASSNAME, m.name(),
+                                      REQUIRES_MODIFIER_TYPE);
+                    signature += "Ljava/util/Enum;";
+                }
+                signature += ")Ljava/util/EnumSet;";
+                mv.visitMethodInsn(INVOKESTATIC, "java/util/EnumSet", "of",
+                                   signature, false);
+                mv.visitVarInsn(ASTORE, MODS_VAR);
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                mv.visitVarInsn(ALOAD, MODS_VAR);
+                mv.visitLdcInsn(name);
+                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+                                   "requires", SET_STRING_SIG, false);
+                mv.visitInsn(POP);
+            }
+
+            /*
+             * Invoke Builder.exports(String pn)
+             */
+            void exports(String pn) {
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+
+                mv.visitLdcInsn(pn);
+                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+                        "exports", STRING_SIG, false);
+                mv.visitInsn(POP);
+            }
+
+            /*
+             * Invoke Builder.exports(String pn, Set<String> targets)
+             *
+             * Set<String> targets = new HashSet<>();
+             * targets.add(t);
+             * :
+             * :
+             * Builder.exports(pn, targets);
+             */
+            void exports(String pn, Set<String> targets) {
+                int varIndex = stringSets.get(targets).build();
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                mv.visitLdcInsn(pn);
+                mv.visitVarInsn(ALOAD, varIndex);
+                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+                                   "exports", STRING_SET_SIG, false);
+                mv.visitInsn(POP);
+            }
+
+            /*
+             * Invokes Builder.uses(Set<String> uses)
+             */
+            void uses(Set<String> uses) {
+                int varIndex = stringSets.get(uses).build();
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                mv.visitVarInsn(ALOAD, varIndex);
+                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+                        "uses", SET_SIG, false);
+                mv.visitInsn(POP);
+            }
+
+            /*
+             * Invoke Builder.provides(String service, Set<String> providers)
+             *
+             * Set<String> providers = new HashSet<>();
+             * providers.add(impl);
+             * :
+             * :
+             * Builder.exports(service, providers);
+             */
+            void provides(String service, Set<String> providers) {
+                int varIndex = stringSets.get(providers).build();
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                mv.visitLdcInsn(service);
+                mv.visitVarInsn(ALOAD, varIndex);
+                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+                                   "provides", STRING_SET_SIG, false);
+                mv.visitInsn(POP);
+            }
+
+            /*
+             * Invoke Builder.conceals(String pn)
+             */
+            void conceals(String pn) {
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                mv.visitLdcInsn(pn);
+                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+                                   "conceals", STRING_SIG, false);
+                mv.visitInsn(POP);
+            }
+
+            /*
+             * Invoke Builder.mainClass(String cn)
+             */
+            void mainClass(String cn) {
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                mv.visitLdcInsn(cn);
+                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+                                   "mainClass", STRING_SIG, false);
+                mv.visitInsn(POP);
+            }
+
+            /*
+             * Invoke Builder.version(Version v);
+             */
+            void version(ModuleDescriptor.Version v) {
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                mv.visitLdcInsn(v.toString());
+                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+                                   "version", STRING_SIG, false);
+                mv.visitInsn(POP);
+            }
+
+        }
+
+        /*
+         * StringSetBuilder generates bytecode to create one single instance
+         * of HashSet for a given set of names and assign to a local variable
+         * slot.  When there is only one single reference to a Set<String>,
+         * it will reuse STRING_SET_VAR for reference.  For Set<String> with
+         * multiple references, it will use a new local variable.
+         */
+        class StringSetBuilder {
+            final Set<String> names;
+            int refCount;
+            int localVarIndex;
+            StringSetBuilder(Set<String> names) {
+                this.names = names;
+            }
+
+            void increment() {
+                refCount++;
+            }
+
+            /*
+             * Build bytecode for the Set<String> represented by this builder,
+             * or get the local variable index of a previously generated set
+             * (in the local scope).
+             *
+             * @return local variable index of the generated set.
+             */
+            int build() {
+                int index = localVarIndex;
+                if (localVarIndex == 0) {
+                    // if non-empty and more than one set reference this builder,
+                    // emit to a unique local
+                    index = refCount == 1 ? STRING_SET_VAR
+                                          : nextLocalVar++;
+                    if (index < MAX_LOCAL_VARS) {
+                        localVarIndex = index;
+                    } else {
+                        // overflow: disable optimization and keep localVarIndex = 0
+                        index = STRING_SET_VAR;
+                    }
+
+                    if (names.isEmpty()) {
+                        mv.visitMethodInsn(INVOKESTATIC, "java/util/Collections",
+                                "emptySet", "()Ljava/util/Set;", false);
+                        mv.visitVarInsn(ASTORE, index);
+                    } else if (names.size() == 1) {
+                        mv.visitLdcInsn(names.iterator().next());
+                        mv.visitMethodInsn(INVOKESTATIC, "java/util/Collections",
+                                "singleton", "(Ljava/lang/Object;)Ljava/util/Set;", false);
+                        mv.visitVarInsn(ASTORE, index);
+                    } else {
+                        mv.visitTypeInsn(NEW, "java/util/HashSet");
+                        mv.visitInsn(DUP);
+                        pushInt(initialCapacity(names.size()));
+                        mv.visitMethodInsn(INVOKESPECIAL, "java/util/HashSet",
+                                "<init>", "(I)V", false);
+
+                        mv.visitVarInsn(ASTORE, index);
+                        for (String t : names) {
+                            mv.visitVarInsn(ALOAD, index);
+                            mv.visitLdcInsn(t);
+                            mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Set",
+                                    "add", "(Ljava/lang/Object;)Z", true);
+                            mv.visitInsn(POP);
+                        }
+                    }
+                }
+                return index;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ZipPlugin.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal.plugins;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Predicate;
+import java.util.zip.Deflater;
+import jdk.tools.jlink.plugin.PluginException;
+import jdk.tools.jlink.internal.PoolImpl;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.Pool.ModuleDataType;
+import jdk.tools.jlink.plugin.TransformerPlugin;
+import jdk.tools.jlink.internal.Utils;
+
+/**
+ *
+ * ZIP Compression plugin
+ */
+public final class ZipPlugin implements TransformerPlugin {
+
+    public static final String NAME = "zip";
+    private Predicate<String> predicate;
+
+    public ZipPlugin() {
+
+    }
+
+    ZipPlugin(String[] patterns) throws IOException {
+        this(new ResourceFilter(patterns));
+    }
+
+    ZipPlugin(Predicate<String> predicate) {
+        this.predicate = predicate;
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    @Override
+    public Set<PluginType> getType() {
+        Set<PluginType> set = new HashSet<>();
+        set.add(CATEGORY.COMPRESSOR);
+        return Collections.unmodifiableSet(set);
+    }
+
+    @Override
+    public String getDescription() {
+        return PluginsResourceBundle.getDescription(NAME);
+    }
+
+    @Override
+    public boolean hasArguments() {
+        return false;
+    }
+
+    @Override
+    public String getArgumentsDescription() {
+        return PluginsResourceBundle.getArgument(NAME);
+    }
+
+    @Override
+    public void configure(Map<String, String> config) {
+        try {
+            String val = config.get(NAME);
+            predicate = new ResourceFilter(Utils.listParser.apply(val));
+        } catch (IOException ex) {
+            throw new PluginException(ex);
+        }
+    }
+
+    static byte[] compress(byte[] bytesIn) {
+        Deflater deflater = new Deflater();
+        deflater.setInput(bytesIn);
+        ByteArrayOutputStream stream = new ByteArrayOutputStream(bytesIn.length);
+        byte[] buffer = new byte[1024];
+
+        deflater.finish();
+        while (!deflater.finished()) {
+            int count = deflater.deflate(buffer);
+            stream.write(buffer, 0, count);
+        }
+
+        try {
+            stream.close();
+        } catch (IOException ex) {
+            return bytesIn;
+        }
+
+        byte[] bytesOut = stream.toByteArray();
+        deflater.end();
+
+        return bytesOut;
+    }
+
+    @Override
+    public void visit(Pool in, Pool out) {
+        in.visit((resource) -> {
+            ModuleData res = resource;
+            if (resource.getType().equals(ModuleDataType.CLASS_OR_RESOURCE)
+                    && predicate.test(resource.getPath())) {
+                byte[] compressed;
+                compressed = compress(resource.getBytes());
+                res = PoolImpl.newCompressedResource(resource,
+                        ByteBuffer.wrap(compressed), getName(), null,
+                        ((PoolImpl) in).getStringTable(), in.getByteOrder());
+            }
+            return res;
+        }, out);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/asm/AsmGlobalPool.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal.plugins.asm;
+
+import java.util.Set;
+
+/**
+ * A pool containing all class and resource files.
+ */
+public interface AsmGlobalPool extends AsmPool {
+
+    /**
+     * Associate a package to a module, useful when adding new classes in new
+     * packages. WARNING: In order to properly handle new package and/or new
+     * module, module-info class must be added and/or updated.
+     *
+     * @param pkg The new package, following java binary syntax (/-separated
+     * path name).
+     * @param module An existing or new module.
+     * @throws jdk.tools.jlink.plugins.PluginException If a mapping already
+     * exist for this package.
+     */
+    public void addPackageModuleMapping(String pkg, String module);
+
+    /**
+     * Return the set of accessible packages for a given module.
+     *
+     * @param module The module from which packages are accessible.
+     * @return Set of packages or null if the module is not found.
+     */
+    public Set<String> getAccessiblePackages(String module);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/asm/AsmModulePool.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal.plugins.asm;
+
+import java.lang.module.ModuleDescriptor;
+import java.util.Set;
+import jdk.internal.org.objectweb.asm.ClassReader;
+
+/**
+ * A pool for a given module
+ */
+public interface AsmModulePool extends AsmPool {
+
+    /**
+     * Associate a package to this module, useful when adding new classes in new
+     * packages. WARNING: In order to properly handle new package and/or new
+     * module, module-info class must be added and/or updated.
+     *
+     * @param pkg The new package, following java binary syntax (/-separated
+     * path name).
+     * @throws jdk.tools.jlink.plugins.PluginException If a mapping already
+     * exist for this package.
+     */
+    public void addPackage(String pkg);
+
+    /**
+     * The module name of this pool.
+     * @return The module name;
+     */
+    public String getModuleName();
+
+    /**
+     * Lookup the class in this pool and the required pools. NB: static module
+     * readability can be different at execution time.
+     *
+     * @param binaryName The class to lookup.
+     * @return The reader or null if not found
+     * @throws jdk.tools.jlink.plugins.PluginException
+     */
+    public ClassReader getClassReaderInDependencies(String binaryName);
+
+    /**
+     * Lookup the class in the exported packages of this module. "public
+     * requires" modules are looked up. NB: static module readability can be
+     * different at execution time.
+     *
+     * @param callerModule Name of calling module.
+     * @param binaryName The class to lookup.
+     * @return The reader or null if not found
+     * @throws jdk.tools.jlink.plugins.PluginException
+     */
+    public ClassReader getExportedClassReader(String callerModule,
+            String binaryName);
+
+    /**
+     * The module descriptor.
+     *
+     * @return The module descriptor;
+     */
+    public ModuleDescriptor getDescriptor();
+
+    /**
+     * Retrieve the internal and exported packages.
+     *
+     * @return
+     */
+    public Set<String> getAllPackages();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/asm/AsmPlugin.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal.plugins.asm;
+
+import java.util.Objects;
+import jdk.tools.jlink.plugin.TransformerPlugin;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.internal.PoolImpl;
+
+/**
+ * Extend this class to develop your own plugin in order to transform jimage
+ * resources.
+ *
+ */
+public abstract class AsmPlugin implements TransformerPlugin {
+
+    public AsmPlugin() {
+    }
+
+    @Override
+    public void visit(Pool allContent, Pool outResources) {
+        Objects.requireNonNull(allContent);
+        Objects.requireNonNull(outResources);
+        PoolImpl resources = new PoolImpl(allContent.getByteOrder());
+        for(ModuleData md : allContent.getContent()) {
+            if(md.getType().equals(Pool.ModuleDataType.CLASS_OR_RESOURCE)) {
+                resources.add(md);
+            } else {
+                outResources.add(md);
+            }
+        }
+        AsmPools pools = new AsmPools(resources);
+        visit(pools);
+        pools.fillOutputResources(outResources);
+    }
+
+    /**
+     * This is the method to implement in order to
+     * apply Asm transformation to jimage contained classes.
+     * @param pools The pool of Asm classes and other resource files.
+     * @param strings To add a string to the jimage strings table.
+     * @throws jdk.tools.jlink.plugin.PluginException
+     */
+    public abstract void visit(AsmPools pools);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/asm/AsmPool.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal.plugins.asm;
+
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.Collection;
+import java.util.List;
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.tools.jlink.plugin.Pool;
+
+/**
+ * A pool of ClassReader and other resource files.
+ * This class allows to transform and sort classes and resource files.
+ * <p>
+ * Classes in the class pool are named following java binary name specification.
+ * For example, java.lang.Object class is named java/lang/Object
+ * <p>
+ * Module information has been stripped out from class and other resource files
+ * (.properties, binary files, ...).</p>
+ */
+public interface AsmPool {
+
+    /**
+     * A resource that is not a class file.
+     * <p>
+     * The path of a resource is a /-separated path name that identifies the
+     * resource. For example com.foo.bar.Bundle.properties resource name is
+     * com/foo/bar/Bundle.properties </p>
+     * <p>
+     */
+    public class ResourceFile {
+
+        private final String path;
+        private final byte[] content;
+
+        public ResourceFile(String path, byte[] content) {
+            this.path = path;
+            this.content = content;
+        }
+
+        public String getPath() {
+            return path;
+        }
+
+        public byte[] getContent() {
+            return content;
+        }
+    }
+
+    /**
+     * To visit each Class contained in the pool
+     */
+    public interface ClassReaderVisitor {
+
+        /**
+         * Called for each ClassReader located in the pool.
+         *
+         * @param reader A class reader.
+         * @return A writer or null if the class has not been transformed.
+         */
+        public ClassWriter visit(ClassReader reader);
+    }
+
+    /**
+     * To visit each Resource contained in the pool
+     */
+    public interface ResourceFileVisitor {
+
+        /**
+         * Called for each Resource file located in the pool.
+         *
+         * @param reader A resource file.
+         * @return A resource file or null if the resource has not been
+         * transformed.
+         */
+        public ResourceFile visit(ResourceFile reader);
+    }
+
+    /**
+     * Contains the transformed classes. When the jimage file is generated,
+     * transformed classes take precedence on unmodified ones.
+     */
+    public interface WritableClassPool {
+
+        /**
+         * Add a class to the pool, if a class already exists, it is replaced.
+         *
+         * @param writer The class writer.
+         * @throws jdk.tools.jlink.plugin.PluginException
+         */
+        public void addClass(ClassWriter writer);
+
+        /**
+         * The class will be not added to the jimage file.
+         *
+         * @param className The class name to forget.
+         * @throws jdk.tools.jlink.plugin.PluginException
+         */
+        public void forgetClass(String className);
+
+        /**
+         * Get a transformed class.
+         *
+         * @param binaryName The java class binary name
+         * @return The ClassReader or null if the class is not found.
+         * @throws jdk.tools.jlink.plugin.PluginException
+         */
+        public ClassReader getClassReader(String binaryName);
+
+        /**
+         * Get a transformed class.
+         *
+         * @param res A class resource.
+         * @return The ClassReader or null if the class is not found.
+         * @throws jdk.tools.jlink.plugin.PluginException
+         */
+        public ClassReader getClassReader(Pool.ModuleData res);
+
+        /**
+         * Returns all the classes contained in the writable pool.
+         *
+         * @return The collection of classes.
+         */
+        public Collection<Pool.ModuleData> getClasses();
+    }
+
+    /**
+     * Contains the transformed resources. When the jimage file is generated,
+     * transformed resources take precedence on unmodified ones.
+     */
+    public interface WritableResourcePool {
+
+        /**
+         * Add a resource, if the resource exists, it is replaced.
+         *
+         * @param resFile The resource file to add.
+         * @throws jdk.tools.jlink.plugin.PluginException
+         */
+        public void addResourceFile(ResourceFile resFile);
+
+        /**
+         * The resource will be not added to the jimage file.
+         *
+         * @param resourceName
+         * @throws jdk.tools.jlink.plugin.PluginException If the resource to
+         * forget doesn't exist or is null.
+         */
+        public void forgetResourceFile(String resourceName);
+
+        /**
+         * Get a transformed resource.
+         *
+         * @param name The java resource name
+         * @return The Resource or null if the resource is not found.
+         */
+        public ResourceFile getResourceFile(String name);
+
+        /**
+         * Get a transformed resource.
+         *
+         * @param res The java resource
+         * @return The Resource or null if the resource is not found.
+         */
+        public ResourceFile getResourceFile(Pool.ModuleData res);
+
+        /**
+         * Returns all the resources contained in the writable pool.
+         *
+         * @return The array of resources.
+         */
+        public Collection<Pool.ModuleData> getResourceFiles();
+    }
+
+    /**
+     * To order the classes and resources within a jimage file.
+     */
+    public interface Sorter {
+
+        /**
+         * @param resources The resources will be added to the jimage following
+         * the order of this ResourcePool.
+         * @return The resource paths ordered in the way to use for storage in the jimage.
+         * @throws jdk.tools.jlink.plugin.PluginException
+         */
+        public List<String> sort(Pool resources);
+    }
+
+    /**
+     * The writable pool used to store transformed resources.
+     *
+     * @return The writable pool.
+     */
+    public WritableClassPool getTransformedClasses();
+
+    /**
+     * The writable pool used to store transformed resource files.
+     *
+     * @return The writable pool.
+     */
+    public WritableResourcePool getTransformedResourceFiles();
+
+    /**
+     * Set a sorter instance to sort all files. If no sorter is set, then input
+     * Resources will be added in the order they have been received followed by
+     * newly added resources.
+     *
+     * @param sorter
+     */
+    public void setSorter(Sorter sorter);
+
+    /**
+     * Returns the classes contained in the pool.
+     *
+     * @return The classes.
+     */
+    public Collection<Pool.ModuleData> getClasses();
+
+    /**
+     * Returns the resources contained in the pool. Resources are all the file
+     * that are not classes (eg: properties file, binary files, ...)
+     *
+     * @return The array of resource files.
+     */
+    public Collection<Pool.ModuleData> getResourceFiles();
+
+    /**
+     * Retrieves a resource based on the binary name. This name doesn't contain
+     * the module name.
+     * <b>NB:</b> When dealing with resources that have the same name in various
+     * modules (eg: META-INFO/*), you should use the <code>ResourcePool</code>
+     * referenced from this <code>AsmClassPool</code>.
+     *
+     * @param binaryName Name of a Java resource or null if the resource doesn't
+     * exist.
+     * @return
+     */
+    public ResourceFile getResourceFile(String binaryName);
+
+    /**
+     * Retrieves a resource for the passed resource.
+     *
+     * @param res The resource
+     * @return The resource file or null if it doesn't exist.
+     */
+    public ResourceFile getResourceFile(Pool.ModuleData res);
+
+    /**
+     * Retrieve a ClassReader from the pool.
+     *
+     * @param binaryName Class binary name
+     * @return A reader or null if the class is unknown
+     * @throws jdk.tools.jlink.plugin.PluginException
+     */
+    public ClassReader getClassReader(String binaryName);
+
+    /**
+     * Retrieve a ClassReader from the pool.
+     *
+     * @param res A resource.
+     * @return A reader or null if the class is unknown
+     * @throws jdk.tools.jlink.plugin.PluginException
+     */
+    public ClassReader getClassReader(Pool.ModuleData res);
+
+    /**
+     * To visit the set of ClassReaders.
+     *
+     * @param visitor The visitor.
+     * @throws jdk.tools.jlink.plugin.PluginException
+     */
+    public void visitClassReaders(ClassReaderVisitor visitor);
+
+    /**
+     * To visit the set of ClassReaders.
+     *
+     * @param visitor The visitor.
+     * @throws jdk.tools.jlink.plugin.PluginException
+     */
+    public void visitResourceFiles(ResourceFileVisitor visitor);
+
+    /**
+     * Returns the pool of all the resources (transformed and unmodified).
+     * The input resources are replaced by the transformed ones.
+     * If a sorter has been set, it is used to sort the returned resources.
+     *
+     * @param output The pool used to fill the jimage.
+     * @throws jdk.tools.jlink.plugin.PluginException
+     */
+    public void fillOutputResources(Pool output);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/asm/AsmPoolImpl.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,700 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal.plugins.asm;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Requires;
+import java.lang.module.ModuleDescriptor.Requires.Modifier;
+import java.lang.module.ModuleDescriptor.Exports;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.tools.jlink.internal.ImageFileCreator;
+import jdk.tools.jlink.internal.PoolImpl;
+import jdk.tools.jlink.plugin.PluginException;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Pool.ModuleData;
+
+/**
+ * A pool of ClassReader and other resource files. This class allows to
+ * transform and sort classes and resource files.
+ * <p>
+ * Classes in the class pool are named following java binary name specification.
+ * For example, java.lang.Object class is named java/lang/Object
+ * <p>
+ * Module information has been stripped out from class and other resource files
+ * (.properties, binary files, ...).</p>
+ */
+final class AsmPoolImpl implements AsmModulePool {
+
+    /**
+     * Contains the transformed classes. When the jimage file is generated,
+     * transformed classes take precedence on unmodified ones.
+     */
+    public final class WritableClassPoolImpl implements WritableClassPool {
+
+        private WritableClassPoolImpl() {
+        }
+
+        /**
+         * Add a class to the pool, if a class already exists, it is replaced.
+         *
+         * @param writer The class writer.
+         * @throws java.io.IOException
+         */
+        @Override
+        public void addClass(ClassWriter writer) {
+            Objects.requireNonNull(writer);
+            // Retrieve the className
+            ClassReader reader = newClassReader(writer.toByteArray());
+            String className = reader.getClassName();
+            String path;
+            if (className.endsWith("module-info")) {
+                // remove the module name contained in the class name
+                className = className.substring(className.indexOf("/") + 1);
+                path = "/" + moduleName + "/" + className;
+            } else {
+                path = toClassNamePath(className);
+            }
+
+            byte[] content = writer.toByteArray();
+            ModuleData res = Pool.newResource(path,
+                    new ByteArrayInputStream(content), content.length);
+            transformedClasses.put(className, res);
+        }
+
+        /**
+         * The class will be not added to the jimage file.
+         *
+         * @param className The class name to forget.
+         */
+        @Override
+        public void forgetClass(String className) {
+            Objects.requireNonNull(className);
+            // do we have a resource?
+            ModuleData res = transformedClasses.get(className);
+            if (res == null) {
+                res = inputClasses.get(className);
+                if (res == null) {
+                    throw new PluginException("Unknown class " + className);
+                }
+            }
+            String path = toClassNamePath(className);
+            forgetResources.add(path);
+            // Just in case it has been added.
+            transformedClasses.remove(className);
+        }
+
+        /**
+         * Get a transformed class.
+         *
+         * @param binaryName The java class binary name
+         * @return The ClassReader or null if the class is not found.
+         */
+        @Override
+        public ClassReader getClassReader(String binaryName) {
+            Objects.requireNonNull(binaryName);
+            ModuleData res = transformedClasses.get(binaryName);
+            ClassReader reader = null;
+            if (res != null) {
+                reader = getClassReader(res);
+            }
+            return reader;
+        }
+
+        /**
+         * Returns all the classes contained in the writable pool.
+         *
+         * @return The array of transformed classes.
+         */
+        @Override
+        public Collection<ModuleData> getClasses() {
+            List<ModuleData> classes = new ArrayList<>();
+            for (Entry<String, ModuleData> entry : transformedClasses.entrySet()) {
+                classes.add(entry.getValue());
+            }
+            return classes;
+        }
+
+        @Override
+        public ClassReader getClassReader(ModuleData res) {
+            return newClassReader(res.getBytes());
+        }
+    }
+
+    /**
+     * Contains the transformed resources. When the jimage file is generated,
+     * transformed resources take precedence on unmodified ones.
+     */
+    public final class WritableResourcePoolImpl implements WritableResourcePool {
+
+        private WritableResourcePoolImpl() {
+        }
+
+        /**
+         * Add a resource, if the resource exists, it is replaced.
+         *
+         * @param resFile The resource file to add.
+         */
+        @Override
+        public void addResourceFile(ResourceFile resFile) {
+            Objects.requireNonNull(resFile);
+            String path = toResourceNamePath(resFile.getPath());
+            ModuleData res = Pool.newResource(path, resFile.getContent());
+            transformedResources.put(resFile.getPath(), res);
+        }
+
+        /**
+         * The resource will be not added to the jimage file.
+         *
+         * @param resourceName
+         * @throws java.io.IOException
+         */
+        @Override
+        public void forgetResourceFile(String resourceName) {
+            Objects.requireNonNull(resourceName);
+            String path = toResourceNamePath(resourceName);
+            // do we have a resource?
+            ModuleData res = transformedResources.get(resourceName);
+            if (res == null) {
+                res = inputResources.get(resourceName);
+                if (res == null) {
+                    throw new PluginException("Unknown resource " + resourceName);
+                }
+            }
+            forgetResources.add(path);
+            // Just in case it has been added.
+            transformedResources.remove(resourceName);
+        }
+
+        /**
+         * Get a transformed resource.
+         *
+         * @param name The java resource name
+         * @return The Resource or null if the resource is not found.
+         */
+        @Override
+        public ResourceFile getResourceFile(String name) {
+            Objects.requireNonNull(name);
+            ModuleData res = transformedResources.get(name);
+            ResourceFile resFile = null;
+            if (res != null) {
+                resFile = getResourceFile(res);
+            }
+            return resFile;
+        }
+
+        /**
+         * Returns all the resources contained in the writable pool.
+         *
+         * @return The array of transformed classes.
+         */
+        @Override
+        public Collection<ModuleData> getResourceFiles() {
+            List<ModuleData> resources = new ArrayList<>();
+            for (Entry<String, ModuleData> entry : transformedResources.entrySet()) {
+                resources.add(entry.getValue());
+            }
+            return resources;
+        }
+
+        @Override
+        public ResourceFile getResourceFile(ModuleData res) {
+            return new ResourceFile(toJavaBinaryResourceName(res.getPath()),
+                    res.getBytes());
+        }
+    }
+
+    private final Pool jimageResources;
+    private final Map<String, ModuleData> inputClasses;
+    private final Map<String, ModuleData> inputResources;
+    private final Map<String, String> inputClassPackageMapping;
+    private final Map<String, String> inputOtherPackageMapping;
+
+    private final WritableClassPool transClassesPool
+            = new WritableClassPoolImpl();
+    private final WritableResourcePool transResourcesPool
+            = new WritableResourcePoolImpl();
+
+    private Sorter sorter;
+
+    private final Map<String, ModuleData> transformedClasses
+            =            new LinkedHashMap<>();
+    private final Map<String, ModuleData> transformedResources
+            =            new LinkedHashMap<>();
+    private final List<String> forgetResources = new ArrayList<>();
+    private final Map<String, String> newPackageMapping = new HashMap<>();
+
+    private final String moduleName;
+
+    private final ModuleDescriptor descriptor;
+    private final AsmPools pools;
+
+    /**
+     * A new Asm pool.
+     *
+     * @param inputResources The raw resources to build the pool from.
+     * @param moduleName The name of a module.
+     * @param pools The resource pools.
+     * @param descriptor The module descriptor.
+     */
+    AsmPoolImpl(Pool inputResources, String moduleName,
+            AsmPools pools,
+            ModuleDescriptor descriptor) {
+        Objects.requireNonNull(inputResources);
+        Objects.requireNonNull(moduleName);
+        Objects.requireNonNull(pools);
+        Objects.requireNonNull(descriptor);
+        this.jimageResources = inputResources;
+        this.moduleName = moduleName;
+        this.pools = pools;
+        this.descriptor = descriptor;
+        Map<String, ModuleData> classes = new LinkedHashMap<>();
+        Map<String, ModuleData> resources = new LinkedHashMap<>();
+        Map<String, String> packageClassToModule = new HashMap<>();
+        Map<String, String> packageOtherToModule = new HashMap<>();
+        for (ModuleData res : inputResources.getContent()) {
+            if (res.getPath().endsWith(".class")) {
+                classes.put(toJavaBinaryClassName(res.getPath()), res);
+            } else {
+                resources.put(toJavaBinaryResourceName(res.getPath()), res);
+            }
+            String[] split = ImageFileCreator.splitPath(res.getPath());
+            if (ImageFileCreator.isClassPackage(res.getPath())) {
+                packageClassToModule.put(split[1], res.getModule());
+            } else {
+                // Keep a map of other resources
+                // Same resource names such as META-INF/* should be handled with full path name.
+                if (!split[1].isEmpty()) {
+                    packageOtherToModule.put(split[1], res.getModule());
+                }
+            }
+        }
+        this.inputClasses = Collections.unmodifiableMap(classes);
+        this.inputResources = Collections.unmodifiableMap(resources);
+
+        this.inputClassPackageMapping = Collections.unmodifiableMap(packageClassToModule);
+        this.inputOtherPackageMapping = Collections.unmodifiableMap(packageOtherToModule);
+    }
+
+    @Override
+    public String getModuleName() {
+        return moduleName;
+    }
+
+    /**
+     * The writable pool used to store transformed resources.
+     *
+     * @return The writable pool.
+     */
+    @Override
+    public WritableClassPool getTransformedClasses() {
+        return transClassesPool;
+    }
+
+    /**
+     * The writable pool used to store transformed resource files.
+     *
+     * @return The writable pool.
+     */
+    @Override
+    public WritableResourcePool getTransformedResourceFiles() {
+        return transResourcesPool;
+    }
+
+    /**
+     * Set a sorter instance to sort all files. If no sorter is set, then input
+     * Resources will be added in the order they have been received followed by
+     * newly added resources.
+     *
+     * @param sorter
+     */
+    @Override
+    public void setSorter(Sorter sorter) {
+        this.sorter = sorter;
+    }
+
+    /**
+     * Returns the classes contained in the pool.
+     *
+     * @return The array of classes.
+     */
+    @Override
+    public Collection<ModuleData> getClasses() {
+        return inputClasses.values();
+    }
+
+    /**
+     * Returns the resources contained in the pool. Resources are all the file
+     * that are not classes (eg: properties file, binary files, ...)
+     *
+     * @return The array of classes.
+     */
+    @Override
+    public Collection<ModuleData> getResourceFiles() {
+        return inputResources.values();
+    }
+
+    /**
+     * Retrieves a resource based on the binary name. This name doesn't contain
+     * the module name.
+     * <b>NB:</b> When dealing with resources that have the same name in various
+     * modules (eg: META-INFO/*), you should use the <code>ResourcePool</code>
+     * referenced from this <code>AsmClassPool</code>.
+     *
+     * @param binaryName Name of a Java resource or null if the resource doesn't
+     * exist.
+     * @return
+     */
+    @Override
+    public ResourceFile getResourceFile(String binaryName) {
+        Objects.requireNonNull(binaryName);
+        ModuleData res = inputResources.get(binaryName);
+        ResourceFile resFile = null;
+        if (res != null) {
+            resFile = getResourceFile(res);
+        }
+        return resFile;
+    }
+
+    /**
+     * Retrieve a ClassReader from the pool.
+     *
+     * @param binaryName Class binary name
+     * @return A reader or null if the class is unknown
+     */
+    @Override
+    public ClassReader getClassReader(String binaryName) {
+        Objects.requireNonNull(binaryName);
+        ModuleData res = inputClasses.get(binaryName);
+        ClassReader reader = null;
+        if (res != null) {
+            reader = getClassReader(res);
+        }
+        return reader;
+    }
+
+    @Override
+    public ResourceFile getResourceFile(ModuleData res) {
+        return new ResourceFile(toJavaBinaryResourceName(res.getPath()),
+                res.getBytes());
+    }
+
+    @Override
+    public ClassReader getClassReader(ModuleData res) {
+        return newClassReader(res.getBytes());
+    }
+
+    /**
+     * Lookup the class in this pool and the required pools. NB: static module
+     * readability can be different at execution time.
+     *
+     * @param binaryName The class to lookup.
+     * @return The reader or null if not found
+     */
+    @Override
+    public ClassReader getClassReaderInDependencies(String binaryName) {
+        Objects.requireNonNull(binaryName);
+        ClassReader reader = getClassReader(binaryName);
+        if (reader == null) {
+            for (Requires requires : descriptor.requires()) {
+                AsmModulePool pool = pools.getModulePool(requires.name());
+                reader = pool.getExportedClassReader(moduleName, binaryName);
+                if (reader != null) {
+                    break;
+                }
+            }
+        }
+        return reader;
+    }
+
+    /**
+     * Lookup the class in the exported packages of this module. "public
+     * requires" modules are looked up. NB: static module readability can be
+     * different at execution time.
+     *
+     * @param callerModule Name of calling module.
+     * @param binaryName The class to lookup.
+     * @return The reader or null if not found
+     */
+    @Override
+    public ClassReader getExportedClassReader(String callerModule, String binaryName) {
+        Objects.requireNonNull(callerModule);
+        Objects.requireNonNull(binaryName);
+        boolean exported = false;
+        ClassReader clazz = null;
+        for (Exports e : descriptor.exports()) {
+            String pkg = e.source();
+            Set<String> targets = e.targets();
+            System.out.println("PKG " + pkg);
+            if (targets.isEmpty() || targets.contains(callerModule)) {
+                if (binaryName.startsWith(pkg)) {
+                    String className = binaryName.substring(pkg.length());
+                    System.out.println("CLASS " + className);
+                    exported = !className.contains(".");
+                }
+                if (exported) {
+                    break;
+                }
+            }
+        }
+        // public requires (re-export)
+        if (!exported) {
+            for (Requires requires : descriptor.requires()) {
+                if (requires.modifiers().contains(Modifier.PUBLIC)) {
+                    AsmModulePool pool = pools.getModulePool(requires.name());
+                    clazz = pool.getExportedClassReader(moduleName, binaryName);
+                    if (clazz != null) {
+                        break;
+                    }
+                }
+            }
+        } else {
+            clazz = getClassReader(binaryName);
+        }
+        return clazz;
+
+    }
+
+    @Override
+    public ModuleDescriptor getDescriptor() {
+        return descriptor;
+    }
+
+    /**
+     * To visit the set of ClassReaders.
+     *
+     * @param visitor The visitor.
+     */
+    @Override
+    public void visitClassReaders(ClassReaderVisitor visitor) {
+        Objects.requireNonNull(visitor);
+        for (ModuleData res : getClasses()) {
+            ClassReader reader = newClassReader(res.getBytes());
+            ClassWriter writer = visitor.visit(reader);
+            if (writer != null) {
+
+                getTransformedClasses().addClass(writer);
+            }
+        }
+    }
+
+    /**
+     * To visit the set of ClassReaders.
+     *
+     * @param visitor The visitor.
+     */
+    @Override
+    public void visitResourceFiles(ResourceFileVisitor visitor) {
+        Objects.requireNonNull(visitor);
+        for (ModuleData resource : getResourceFiles()) {
+            ResourceFile resFile
+                    = new ResourceFile(toJavaBinaryResourceName(resource.getPath()),
+                            resource.getBytes());
+            ResourceFile res = visitor.visit(resFile);
+            if (res != null) {
+                getTransformedResourceFiles().addResourceFile(res);
+            }
+        }
+    }
+
+    /**
+     * Returns the pool of all the resources (transformed and unmodified). The
+     * input resources are replaced by the transformed ones. If a sorter has
+     * been set, it is used to sort the returned resources.     *
+     */
+    @Override
+    public void fillOutputResources(Pool outputResources) {
+        List<String> added = new ArrayList<>();
+        // If the sorter is null, use the input order.
+        // New resources are added at the end
+        // First input classes that have not been removed
+        Pool output = new PoolImpl(outputResources.getByteOrder(),
+                ((PoolImpl)outputResources).getStringTable());
+        for (ModuleData inResource : jimageResources.getContent()) {
+            if (!forgetResources.contains(inResource.getPath())) {
+                ModuleData resource = inResource;
+                // Do we have a transformed class with the same name?
+                ModuleData res = transformedResources.
+                        get(toJavaBinaryResourceName(inResource.getPath()));
+                if (res != null) {
+                    resource = res;
+                } else {
+                    res = transformedClasses.
+                            get(toJavaBinaryClassName(inResource.getPath()));
+                    if (res != null) {
+                        resource = res;
+                    }
+                }
+                output.add(resource);
+                added.add(resource.getPath());
+            }
+        }
+        // Then new resources
+        for (Map.Entry<String, ModuleData> entry : transformedResources.entrySet()) {
+            ModuleData resource = entry.getValue();
+            if (!forgetResources.contains(resource.getPath())) {
+                if (!added.contains(resource.getPath())) {
+                    output.add(resource);
+                }
+            }
+        }
+        // And new classes
+        for (Map.Entry<String, ModuleData> entry : transformedClasses.entrySet()) {
+            ModuleData resource = entry.getValue();
+            if (!forgetResources.contains(resource.getPath())) {
+                if (!added.contains(resource.getPath())) {
+                    output.add(resource);
+                }
+            }
+        }
+
+        AsmPools.sort(outputResources, output, sorter);
+    }
+
+    /**
+     * Associate a package to this module, useful when adding new classes in new
+     * packages. WARNING: In order to properly handle new package and/or new
+     * module, module-info class must be added and/or updated.
+     *
+     * @param pkg The new package, following java binary syntax (/-separated
+     * path name).
+     * @throws PluginException If a mapping already exist for this package.
+     */
+    @Override
+    public void addPackage(String pkg) {
+        Objects.requireNonNull(pkg);
+        Objects.requireNonNull(moduleName);
+        pkg = pkg.replaceAll("/", ".");
+        String mod = newPackageMapping.get(pkg);
+        if (mod != null) {
+            throw new PluginException(mod + " module already contains package " + pkg);
+        }
+        newPackageMapping.put(pkg, moduleName);
+    }
+
+    @Override
+    public Set<String> getAllPackages() {
+        ModuleDescriptor desc = getDescriptor();
+        Set<String> packages = new HashSet<>();
+        for (String p : desc.conceals()) {
+            packages.add(p.replaceAll("\\.", "/"));
+        }
+        for (String p : newPackageMapping.keySet()) {
+            packages.add(p.replaceAll("\\.", "/"));
+        }
+        for (Exports ex : desc.exports()) {
+            packages.add(ex.source().replaceAll("\\.", "/"));
+        }
+        return packages;
+    }
+
+    private static ClassReader newClassReader(byte[] bytes) {
+        try {
+            ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
+            ClassReader reader = new ClassReader(stream);
+            return reader;
+        } catch (IOException ex) {
+            throw new UncheckedIOException(ex);
+        }
+    }
+
+    private static String toJavaBinaryClassName(String path) {
+        if (path.endsWith("module-info.class")) {
+            path = removeClassExtension(path);
+        } else {
+            path = removeModuleName(path);
+            path = removeClassExtension(path);
+        }
+        return path;
+    }
+
+    private static String toJavaBinaryResourceName(String path) {
+        if (!path.endsWith("module-info.class")) {
+            path = removeModuleName(path);
+        }
+        return path;
+    }
+
+    private static String removeClassExtension(String path) {
+        return path.substring(0, path.length() - ".class".length());
+    }
+
+    private static String removeModuleName(String path) {
+        path = path.substring(1);
+        return path.substring(path.indexOf("/") + 1, path.length());
+    }
+
+    private String toClassNamePath(String className) {
+        return toResourceNamePath(className) + ".class";
+    }
+
+    /**
+     * Entry point to manage resource<->module association.
+     */
+    private String toResourceNamePath(String resourceName) {
+        if (!resourceName.startsWith("/")) {
+            resourceName = "/" + resourceName;
+        }
+        String pkg = toPackage(resourceName);
+        String module = inputClassPackageMapping.get(pkg);
+        if (module == null) {
+            module = newPackageMapping.get(pkg);
+            if (module == null) {
+                module = inputOtherPackageMapping.get(pkg);
+                if (module == null) {
+                    throw new PluginException("No module for package" + pkg);
+                }
+            }
+        }
+        return "/" + module + resourceName;
+    }
+
+    private static String toPackage(String path) {
+        if (path.startsWith("/")) {
+            path = path.substring(1);
+        }
+        int i = path.lastIndexOf("/");
+        if (i == -1) {
+            // Default package...
+            return "";
+        }
+        return path.substring(0, i).replaceAll("/", ".");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/asm/AsmPools.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,497 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal.plugins.asm;
+
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Exports;
+import java.lang.module.ModuleDescriptor.Requires;
+import static java.lang.module.ModuleDescriptor.Requires.Modifier.PUBLIC;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Set;
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.tools.jlink.internal.PoolImpl;
+import jdk.tools.jlink.internal.plugins.asm.AsmPool.Sorter;
+import jdk.tools.jlink.plugin.PluginException;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Pool.ModuleData;
+
+/**
+ * A container for pools of ClassReader and other resource files. A pool of all
+ * the resources or a pool for a given module can be retrieved
+ */
+public final class AsmPools {
+
+    /**
+     * Sort the order in which the modules will be stored in the jimage file.
+     */
+    public interface ModuleSorter {
+
+        /**
+         * Sort the list of modules.
+         *
+         * @param modules The list of module names. The module will be stored in
+         * the jimage following this order.
+         * @return A list of module names that expresses the order in which the
+         * modules are stored in the jimage.
+         */
+        public List<String> sort(List<String> modules);
+    }
+
+    private class AsmGlobalPoolImpl implements AsmGlobalPool {
+
+        private Sorter sorter = null;
+
+        private class GlobalWritableClassPool implements WritableClassPool {
+
+            @Override
+            public void addClass(ClassWriter writer) {
+                visitFirstNonFailingPool((AsmModulePool pool) -> {
+                    pool.getTransformedClasses().addClass(writer);
+                });
+            }
+
+            @Override
+            public void forgetClass(String className) {
+                visitFirstNonFailingPool((AsmModulePool pool) -> {
+                    pool.getTransformedClasses().forgetClass(className);
+                });
+            }
+
+            @Override
+            public ClassReader getClassReader(String binaryName) {
+                return visitPools((AsmModulePool pool) -> {
+                    return pool.getTransformedClasses().getClassReader(binaryName);
+                });
+            }
+
+            @Override
+            public Collection<Pool.ModuleData> getClasses() {
+                List<Pool.ModuleData> all = new ArrayList<>();
+                visitAllPools((AsmModulePool pool) -> {
+                    for (Pool.ModuleData rf : pool.getTransformedClasses().getClasses()) {
+                        all.add(rf);
+                    }
+                });
+                return all;
+            }
+
+            @Override
+            public ClassReader getClassReader(Pool.ModuleData res) {
+                return visitPools((AsmModulePool pool) -> {
+                    return pool.getTransformedClasses().getClassReader(res);
+                });
+            }
+
+        }
+
+        private class GlobalWritableResourcePool implements WritableResourcePool {
+
+            @Override
+            public void addResourceFile(ResourceFile resFile) {
+                visitFirstNonFailingPool((AsmModulePool pool) -> {
+                    pool.getTransformedResourceFiles().addResourceFile(resFile);
+                });
+            }
+
+            @Override
+            public void forgetResourceFile(String resourceName) {
+                visitFirstNonFailingPool((AsmModulePool pool) -> {
+                    pool.getTransformedResourceFiles().forgetResourceFile(resourceName);
+                });
+            }
+
+            @Override
+            public ResourceFile getResourceFile(String name) {
+                return visitPools((AsmModulePool pool) -> {
+                    return pool.getTransformedResourceFiles().getResourceFile(name);
+                });
+            }
+
+            @Override
+            public Collection<Pool.ModuleData> getResourceFiles() {
+                List<Pool.ModuleData> all = new ArrayList<>();
+                visitAllPools((AsmModulePool pool) -> {
+                    for (Pool.ModuleData rf : pool.getTransformedResourceFiles().getResourceFiles()) {
+                        all.add(rf);
+                    }
+                });
+                return all;
+            }
+
+            @Override
+            public ResourceFile getResourceFile(Pool.ModuleData res) {
+                return visitPools((AsmModulePool pool) -> {
+                    return pool.getTransformedResourceFiles().getResourceFile(res);
+                });
+            }
+
+        }
+
+        @Override
+        public AsmPool.WritableClassPool getTransformedClasses() {
+            return new GlobalWritableClassPool();
+        }
+
+        @Override
+        public AsmPool.WritableResourcePool getTransformedResourceFiles() {
+            return new GlobalWritableResourcePool();
+        }
+
+        @Override
+        public void setSorter(AsmPool.Sorter sorter) {
+            this.sorter = sorter;
+        }
+
+        @Override
+        public Collection<Pool.ModuleData> getClasses() {
+            List<Pool.ModuleData> all = new ArrayList<>();
+            visitAllPools((AsmModulePool pool) -> {
+                for (Pool.ModuleData rf : pool.getClasses()) {
+                    all.add(rf);
+                }
+            });
+            return all;
+        }
+
+        @Override
+        public Collection<Pool.ModuleData> getResourceFiles() {
+            List<Pool.ModuleData> all = new ArrayList<>();
+            visitAllPools((AsmModulePool pool) -> {
+                for (Pool.ModuleData rf : pool.getResourceFiles()) {
+                    all.add(rf);
+                }
+            });
+            return all;
+        }
+
+        @Override
+        public AsmPool.ResourceFile getResourceFile(String binaryName) {
+            return visitPools((AsmModulePool pool) -> {
+                return pool.getResourceFile(binaryName);
+            });
+        }
+
+        @Override
+        public ClassReader getClassReader(String binaryName) {
+            return visitPoolsEx((AsmModulePool pool) -> {
+                return pool.getClassReader(binaryName);
+            });
+        }
+
+        @Override
+        public ResourceFile getResourceFile(Pool.ModuleData res) {
+            return visitPools((AsmModulePool pool) -> {
+                return pool.getResourceFile(res);
+            });
+        }
+
+        @Override
+        public ClassReader getClassReader(Pool.ModuleData res) {
+            return visitPoolsEx((AsmModulePool pool) -> {
+                return pool.getClassReader(res);
+            });
+        }
+
+        @Override
+        public void visitClassReaders(AsmPool.ClassReaderVisitor visitor) {
+            visitAllPoolsEx((AsmModulePool pool) -> {
+                pool.visitClassReaders(visitor);
+            });
+        }
+
+        @Override
+        public void visitResourceFiles(AsmPool.ResourceFileVisitor visitor) {
+            visitAllPoolsEx((AsmModulePool pool) -> {
+                pool.visitResourceFiles(visitor);
+            });
+        }
+
+        @Override
+        public void fillOutputResources(Pool outputResources) {
+            AsmPools.this.fillOutputResources(outputResources);
+        }
+
+        @Override
+        public void addPackageModuleMapping(String pkg, String module) {
+            AsmModulePool p = pools.get(module);
+            if (p == null) {
+                throw new PluginException("Unknown module " + module);
+            }
+            p.addPackage(pkg);
+        }
+
+        @Override
+        public Set<String> getAccessiblePackages(String module) {
+            AsmModulePool p = pools.get(module);
+            if (p == null) {
+                return null;
+            }
+            ModuleDescriptor desc = p.getDescriptor();
+            Set<String> packages = new HashSet<>();
+            packages.addAll(p.getAllPackages());
+
+            // Retrieve direct dependencies and indirect ones (public)
+            Set<String> modules = new HashSet<>();
+            for (Requires req : desc.requires()) {
+                modules.add(req.name());
+                addAllRequirePublicModules(req.name(), modules);
+            }
+            // Add exported packages of readable modules
+            for (String readable : modules) {
+                AsmModulePool mp = pools.get(readable);
+                if (mp != null) {
+                    for (Exports e : mp.getDescriptor().exports()) {
+                        // exported to all or to the targeted module
+                        if (e.targets().isEmpty() || e.targets().contains(module)) {
+                            packages.add(e.source().replaceAll("\\.", "/"));
+                        }
+                    }
+
+                }
+            }
+            return packages;
+        }
+
+        private void addAllRequirePublicModules(String module, Set<String> modules) {
+            AsmModulePool p = pools.get(module);
+            if (p != null) {
+                for (Requires req : p.getDescriptor().requires()) {
+                    if (req.modifiers().contains(PUBLIC)) {
+                        modules.add(req.name());
+                        addAllRequirePublicModules(req.name(), modules);
+                    }
+                }
+            }
+        }
+
+    }
+
+    private interface VoidPoolVisitor {
+
+        void visit(AsmModulePool pool);
+    }
+
+    private interface VoidPoolVisitorEx {
+
+        void visit(AsmModulePool pool);
+    }
+
+    private interface RetPoolVisitor<P> {
+
+        P visit(AsmModulePool pool);
+    }
+
+    private final Map<String, AsmModulePool> pools = new LinkedHashMap<>();
+    private final AsmModulePool[] poolsArray;
+    private final AsmGlobalPoolImpl global;
+
+    private ModuleSorter moduleSorter;
+
+    /**
+     * A new Asm pools.
+     *
+     * @param inputResources The raw resources to build the pool from.
+     */
+    public AsmPools(Pool inputResources) {
+        Objects.requireNonNull(inputResources);
+        Map<String, Pool> resPools = new LinkedHashMap<>();
+        Map<String, ModuleDescriptor> descriptors = new HashMap<>();
+        for (Pool.ModuleData res : inputResources.getContent()) {
+            Pool p = resPools.get(res.getModule());
+            if (p == null) {
+                p = new PoolImpl(inputResources.getByteOrder(),
+                        ((PoolImpl)inputResources).getStringTable());
+                resPools.put(res.getModule(), p);
+            }
+            if (res.getPath().endsWith("module-info.class")) {
+                ByteBuffer bb = ByteBuffer.wrap(res.getBytes());
+                ModuleDescriptor descriptor = ModuleDescriptor.read(bb);
+                descriptors.put(res.getModule(), descriptor);
+            }
+            p.add(res);
+        }
+        poolsArray = new AsmModulePool[resPools.size()];
+        int i = 0;
+
+        for (Entry<String, Pool> entry : resPools.entrySet()) {
+            ModuleDescriptor descriptor = descriptors.get(entry.getKey());
+            if (descriptor == null) {
+                throw new PluginException("module-info.class not found for " + entry.getKey() + " module");
+            }
+            AsmModulePool p = new AsmPoolImpl(entry.getValue(),
+                    entry.getKey(), this, descriptor);
+            pools.put(entry.getKey(), p);
+            poolsArray[i] = p;
+            i += 1;
+        }
+        global = new AsmGlobalPoolImpl();
+    }
+
+    /**
+     * The pool containing all classes and other resources.
+     *
+     * @return The global pool
+     */
+    public AsmGlobalPool getGlobalPool() {
+        return global;
+    }
+
+    /**
+     * A pool for a given module
+     *
+     * @param name The module name
+     * @return The pool that contains content of the passed module or null if
+     * the module doesn't exist.
+     */
+    public AsmModulePool getModulePool(String name) {
+        Objects.requireNonNull(name);
+        return pools.get(name);
+    }
+
+    /**
+     * The array of module pools.
+     * @return The module pool array.
+     */
+    public AsmModulePool[] getModulePools() {
+        return poolsArray.clone();
+    }
+
+    /**
+     * Set a module sorter. Sorter is used when computing the output resources.
+     *
+     * @param moduleSorter The module sorter
+     */
+    public void setModuleSorter(ModuleSorter moduleSorter) {
+        Objects.requireNonNull(moduleSorter);
+        this.moduleSorter = moduleSorter;
+    }
+
+    /**
+     * Returns the pool of all the resources (transformed and unmodified). The
+     * input resources are replaced by the transformed ones. If a sorter has
+     * been set, it is used to sort in modules.
+     *
+     * @param outputResources The pool used to fill the jimage.
+     */
+    public void fillOutputResources(Pool outputResources) {
+        // First sort modules
+        List<String> modules = new ArrayList<>();
+        for (String k : pools.keySet()) {
+            modules.add(k);
+        }
+        if (moduleSorter != null) {
+            modules = moduleSorter.sort(modules);
+        }
+        Pool output = new PoolImpl(outputResources.getByteOrder(),
+                ((PoolImpl)outputResources).getStringTable());
+        for (String mn : modules) {
+            AsmPool pool = pools.get(mn);
+            pool.fillOutputResources(output);
+        }
+        sort(outputResources, output, global.sorter);
+    }
+
+    static void sort(Pool outputResources,
+            Pool transientOutput, Sorter sorter) {
+        if (sorter != null) {
+            List<String> order = sorter.sort(transientOutput);
+            for (String s : order) {
+                outputResources.add(transientOutput.get(s));
+            }
+        } else {
+            for (ModuleData res : transientOutput.getContent()) {
+                outputResources.add(res);
+            }
+        }
+    }
+
+    private void visitFirstNonFailingPool(VoidPoolVisitorEx pv) {
+        boolean found = false;
+        for (Entry<String, AsmModulePool> entry : pools.entrySet()) {
+            try {
+                pv.visit(entry.getValue());
+                found = true;
+                break;
+            } catch (Exception ex) {
+                // XXX OK, try  another one.
+            }
+        }
+        if (!found) {
+            throw new PluginException("No module found");
+        }
+    }
+
+    private void visitAllPools(VoidPoolVisitor pv) {
+        for (Entry<String, AsmModulePool> entry : pools.entrySet()) {
+            pv.visit(entry.getValue());
+        }
+    }
+
+    private void visitAllPoolsEx(VoidPoolVisitorEx pv) {
+        for (Entry<String, AsmModulePool> entry : pools.entrySet()) {
+            pv.visit(entry.getValue());
+        }
+    }
+
+    private <P> P visitPoolsEx(RetPoolVisitor<P> pv) {
+        P p = null;
+        for (Entry<String, AsmModulePool> entry : pools.entrySet()) {
+            try {
+                p = pv.visit(entry.getValue());
+                if (p != null) {
+                    break;
+                }
+            } catch (Exception ex) {
+                // XXX OK, try  another one.
+            }
+        }
+        return p;
+    }
+
+    private <P> P visitPools(RetPoolVisitor<P> pv) {
+        P p = null;
+        for (Entry<String, AsmModulePool> entry : pools.entrySet()) {
+            try {
+                p = pv.visit(entry.getValue());
+                if (p != null) {
+                    break;
+                }
+            } catch (Exception ex) {
+                // XXX OK, try  another one.
+            }
+        }
+        return p;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/optim/ControlFlow.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,520 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal.plugins.optim;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Set;
+import java.util.Stack;
+import java.util.TreeSet;
+import jdk.internal.org.objectweb.asm.tree.AbstractInsnNode;
+import jdk.internal.org.objectweb.asm.tree.MethodNode;
+import jdk.internal.org.objectweb.asm.tree.analysis.Analyzer;
+import jdk.internal.org.objectweb.asm.tree.analysis.AnalyzerException;
+import jdk.internal.org.objectweb.asm.tree.analysis.BasicInterpreter;
+import jdk.internal.org.objectweb.asm.tree.analysis.BasicValue;
+
+/**
+ * Split Java method onto a control flow.
+ *
+ */
+public final class ControlFlow {
+
+    /**
+     * A block of control
+     */
+    public static final class Block implements Comparable<Block> {
+
+        private final InstructionNode firstInstruction;
+        private final List<InstructionNode> instr = new ArrayList<>();
+        private final List<Block> reachable = new ArrayList<>();
+        private final List<Block> exceptionHandlers = new ArrayList<>();
+        private boolean isExceptionHandler;
+
+        private Block(InstructionNode firstInstruction) {
+            this.firstInstruction = firstInstruction;
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (!(other instanceof Block)) {
+                return false;
+            }
+            Block b = (Block) other;
+            return firstInstruction.equals(b.firstInstruction);
+        }
+
+        @Override
+        public int hashCode() {
+            int hash = 3;
+            hash = 79 * hash + Objects.hashCode(this.firstInstruction);
+            return hash;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder builder = new StringBuilder();
+            for (InstructionNode in : instr) {
+                builder.append(in).append(" ");
+            }
+            builder.append(" reachables: ");
+            for (Block r : reachable) {
+                builder.append(r.getFirstInstruction()).append(" ");
+            }
+            builder.append(" exception handlers: ");
+            for (Block r : exceptionHandlers) {
+                builder.append(r.getFirstInstruction()).append(" ");
+            }
+
+            return "block[" + getFirstInstruction() + "],ex:"
+                    + isExceptionHandler + ",  " + builder.toString();
+        }
+
+        /**
+         * @return the firstInstruction
+         */
+        public InstructionNode getFirstInstruction() {
+            return firstInstruction;
+        }
+
+        /**
+         * @return the instr
+         */
+        public List<InstructionNode> getInstructions() {
+            return Collections.unmodifiableList(instr);
+        }
+
+        /**
+         * @return the reachable
+         */
+        public List<Block> getReachableBlocks() {
+            return Collections.unmodifiableList(reachable);
+        }
+
+        /**
+         * @return the exceptionHandlers
+         */
+        public List<Block> getExceptionHandlerBlocks() {
+            return Collections.unmodifiableList(exceptionHandlers);
+        }
+
+        @Override
+        public int compareTo(Block t) {
+            return this.firstInstruction.index - t.firstInstruction.index;
+        }
+
+        public boolean isExceptionHandler() {
+            return isExceptionHandler;
+        }
+
+    }
+
+    private class ClosureBuilder {
+
+        private final Block root;
+
+        private ClosureBuilder(Block root) {
+            Objects.requireNonNull(root);
+            this.root = root;
+        }
+
+        private Set<Block> build() {
+            Set<Block> allReachable = new TreeSet<>();
+            addAll(root, allReachable);
+            // filter out the reachable from outside this graph
+            Iterator<Block> it = allReachable.iterator();
+            Set<Block> toExclude = new HashSet<>();
+            while (it.hasNext()) {
+                Block b = it.next();
+                for (Block ref : blocks) {
+                    if (!allReachable.contains(ref) && ref.reachable.contains(b)) {
+                        addAll(b, toExclude);
+                        break;
+                    }
+                }
+            }
+            //System.err.println("TO EXCLUDE:\n " + toExclude);
+            allReachable.removeAll(toExclude);
+            //System.err.println("CLOSURE:\n " + allReachable);
+            return Collections.unmodifiableSet(allReachable);
+        }
+
+        // Compute the set of blocks reachable from the current block
+        private void addAll(Block current, Set<Block> closure) {
+            Objects.requireNonNull(current);
+            closure.add(current);
+            for (Block ex : current.exceptionHandlers) {
+                Objects.requireNonNull(ex);
+                if (!closure.contains(ex)) {
+                    addAll(ex, closure);
+                }
+            }
+            for (Block r : current.reachable) {
+                Objects.requireNonNull(r);
+                if (!closure.contains(r)) {
+                    addAll(r, closure);
+                }
+            }
+
+        }
+    }
+
+    /**
+     * An instruction
+     */
+    public static final class InstructionNode {
+
+        private final int index;
+        private final List<InstructionNode> next = new ArrayList<>();
+        private final AbstractInsnNode instr;
+
+        private InstructionNode(int index, AbstractInsnNode instr) {
+            this.index = index;
+            this.instr = instr;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof InstructionNode)) {
+                return false;
+            }
+            final InstructionNode other = (InstructionNode) obj;
+            return this.getIndex() == other.getIndex();
+        }
+
+        @Override
+        public int hashCode() {
+            int hash = 3;
+            hash = 89 * hash + this.getIndex();
+            return hash;
+        }
+
+        @Override
+        public String toString() {
+            return getIndex() + "(" + (getInstr().getOpcode() == - 1 ? -1
+                    : Integer.toHexString(getInstr().getOpcode())) + ")";
+        }
+
+        /**
+         * @return the index
+         */
+        public int getIndex() {
+            return index;
+        }
+
+        /**
+         * @return the instr
+         */
+        public AbstractInsnNode getInstr() {
+            return instr;
+        }
+
+    }
+
+    private final Map<Integer, Block> allBlocks;
+    private final List<Block> blocks = new ArrayList<>();
+
+    private ControlFlow(Map<Integer, Block> allBlocks) {
+        this.allBlocks = allBlocks;
+        for (Block b : allBlocks.values()) {
+            blocks.add(b);
+        }
+        Collections.sort(blocks);
+    }
+
+    public List<Block> getBlocks() {
+
+        return Collections.unmodifiableList(blocks);
+    }
+
+    public Block getBlock(int firstInstr) {
+        return allBlocks.get(firstInstr);
+    }
+
+    public static ControlFlow createControlFlow(String owner,
+            MethodNode method) throws Exception {
+
+        BlockBuilder bb = new BlockBuilder(owner, method);
+        return bb.build();
+    }
+
+    /**
+     * Return the set of blocks that are only reachable from this block For
+     * example, if b is an Exception handler, returns all the blocks reachable
+     * only from this handler
+     *
+     * @param b
+     * @return
+     */
+    public Set<Block> getClosure(Block b) {
+        return new ClosureBuilder(b).build();
+    }
+
+    private static final class BlockBuilder {
+
+        private InstructionNode root;
+        private final Map<Integer, InstructionNode> instructions = new HashMap<>();
+        private final Map<Integer, List<Integer>> handlers = new HashMap<>();
+        private final Map<Integer, Block> allBlocks = new HashMap<>();
+
+        private final String owner;
+        private final MethodNode method;
+
+        private BlockBuilder(String owner, MethodNode method) {
+            this.owner = owner;
+            this.method = method;
+        }
+
+        private void analyze() throws AnalyzerException {
+            Analyzer<BasicValue> analyzer = new Analyzer<BasicValue>(new BasicInterpreter()) {
+
+                @Override
+                protected boolean newControlFlowExceptionEdge(int insn,
+                        int successor) {
+                    List<Integer> lst = handlers.get(successor);
+                    if (lst == null) {
+                        lst = new ArrayList<>();
+                        handlers.put(successor, lst);
+                    }
+                    lst.add(insn);
+                    return true;
+                }
+
+                @Override
+                protected void newControlFlowEdge(int from,
+                        int to) {
+                    if (root == null) {
+                        root = new InstructionNode(from, method.instructions.get(from));
+                        instructions.put(from, root);
+                    }
+                    InstructionNode fromNode = instructions.get(from);
+                    if (fromNode == null) {
+                        fromNode = new InstructionNode(from, method.instructions.get(from));
+                        instructions.put(from, fromNode);
+                    }
+                    InstructionNode toNode = instructions.get(to);
+                    if (toNode == null) {
+                        toNode = new InstructionNode(to, method.instructions.get(to));
+                        instructions.put(to, toNode);
+                    }
+                    if (!fromNode.next.contains(toNode)) {
+                        fromNode.next.add(toNode);
+                    }
+
+                }
+            };
+            analyzer.analyze(owner, method);
+        }
+
+        private Block newBlock(InstructionNode firstInstruction) {
+            Objects.requireNonNull(firstInstruction);
+            Block b = new Block(firstInstruction);
+            allBlocks.put(firstInstruction.getIndex(), b);
+            return b;
+        }
+
+        private ControlFlow build() throws AnalyzerException {
+            analyze();
+            buildBlocks();
+            return new ControlFlow(allBlocks);
+        }
+
+        private void buildBlocks() {
+            List<Block> reachableBlocks = new ArrayList<>();
+            createBlocks(root, reachableBlocks);
+            List<Block> handlersBlocks = new ArrayList<>();
+            for (Entry<Integer, List<Integer>> entry : handlers.entrySet()) {
+                InstructionNode node = instructions.get(entry.getKey());
+                createBlocks(node, handlersBlocks);
+            }
+
+            // attach handler to try blocks
+            for (Entry<Integer, List<Integer>> entry : handlers.entrySet()) {
+                Block handlerBlock = allBlocks.get(entry.getKey());
+                handlerBlock.isExceptionHandler = true;
+                int startTry = entry.getValue().get(0);
+                Block tryBlock = allBlocks.get(startTry);
+                if (tryBlock == null) {
+                    // Need to find the block that contains the instruction and
+                    // make a new block
+                    Block split = null;
+                    for (Block b : allBlocks.values()) {
+                        Iterator<InstructionNode> it = b.instr.iterator();
+                        while (it.hasNext()) {
+                            InstructionNode in = it.next();
+                            if (split == null) {
+                                if (in.index == startTry) {
+                                    split = newBlock(in);
+                                    split.instr.add(in);
+                                    it.remove();
+                                }
+                            } else {
+                                split.instr.add(in);
+                                it.remove();
+                            }
+                        }
+                        if (split != null) {
+                            Iterator<Block> reachables = b.reachable.iterator();
+                            while (reachables.hasNext()) {
+                                Block r = reachables.next();
+                                split.reachable.add(r);
+                                reachables.remove();
+                            }
+                            b.reachable.add(split);
+                            break;
+                        }
+                    }
+                    if (split == null) {
+                        throw new RuntimeException("No try block for handler " + handlerBlock);
+                    }
+                    split.exceptionHandlers.add(handlerBlock);
+                } else {
+                    tryBlock.exceptionHandlers.add(handlerBlock);
+                }
+            }
+
+//            System.err.println("ALL BLOCKS FOUND");
+//            Iterator<Entry<Integer, Block>> blockIt0 = allBlocks.entrySet().iterator();
+//            while (blockIt0.hasNext()) {
+//                Block b = blockIt0.next().getValue();
+//                System.err.println(b);
+//            }
+            //compute real exception blocks, if an instruction is in another block, stop.
+            Iterator<Entry<Integer, Block>> blockIt = allBlocks.entrySet().iterator();
+            while (blockIt.hasNext()) {
+                Block b = blockIt.next().getValue();
+                Iterator<InstructionNode> in = b.instr.iterator();
+                boolean found = false;
+                while (in.hasNext()) {
+                    int i = in.next().getIndex();
+                    if (found) {
+                        in.remove();
+                    } else {
+                        if (startsWith(b, i, allBlocks.values())) {
+                            // Move it to reachable
+                            Block r = allBlocks.get(i);
+                            b.reachable.add(r);
+                            found = true;
+                            in.remove();
+                        } else {
+                        }
+                    }
+                }
+            }
+
+//            System.err.println("Reduced blocks");
+//            Iterator<Entry<Integer, Block>> blockIt1 = allBlocks.entrySet().iterator();
+//            while (blockIt1.hasNext()) {
+//                Block b = blockIt1.next().getValue();
+//                System.err.println(b);
+//            }
+        }
+
+        private boolean startsWith(Block block, int index, Collection<Block> reachableBlocks) {
+            for (Block b : reachableBlocks) {
+                if (b != block && !b.instr.isEmpty() && b.instr.get(0).getIndex() == index) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        private static final class StackItem {
+
+            private final InstructionNode instr;
+            private final Block currentBlock;
+
+            private StackItem(InstructionNode instr, Block currentBlock) {
+                Objects.requireNonNull(instr);
+                Objects.requireNonNull(currentBlock);
+                this.instr = instr;
+                this.currentBlock = currentBlock;
+            }
+        }
+
+        /**
+         * This algorithm can't be recursive, possibly too much instructions in
+         * methods.
+         */
+        private void createBlocks(InstructionNode root, List<Block> blocks) {
+            final Stack<StackItem> stack = new Stack<>();
+            stack.push(new StackItem(root, newBlock(root)));
+            while (!stack.isEmpty()) {
+                final StackItem item = stack.pop();
+                final Block currentBlock = item.currentBlock;
+                final InstructionNode current = item.instr;
+                // loop
+                if (currentBlock.instr.contains(current)) {
+                    currentBlock.reachable.add(currentBlock);
+                    continue;
+                }
+                Block existing = allBlocks.get(current.index);
+                if (existing != null && existing != currentBlock) {
+                    currentBlock.reachable.add(existing);
+                    continue;
+                }
+                int previous = currentBlock.instr.size() > 0
+                        ? currentBlock.instr.get(currentBlock.instr.size() - 1).getIndex() : -1;
+                if (previous == -1 || current.getIndex() == previous + 1) {
+                    currentBlock.instr.add(current);
+                    if (current.next.isEmpty()) {
+                        blocks.add(currentBlock);
+                    } else {
+                        if (current.next.size() > 1) {
+                            blocks.add(currentBlock);
+                            for (InstructionNode n : current.next) {
+                                Block loop = allBlocks.get(n.index);
+                                if (loop == null) {
+                                    Block newBlock = newBlock(n);
+                                    currentBlock.reachable.add(newBlock);
+                                    stack.push(new StackItem(n, newBlock));
+                                } else { // loop
+                                    currentBlock.reachable.add(loop);
+                                }
+                            }
+                        } else {
+                            stack.push(new StackItem(current.next.get(0),
+                                    currentBlock));
+                        }
+                    }
+                } else { // to a new block...
+                    // Do nothing...
+                    blocks.add(currentBlock);
+                    Block newBlock = newBlock(current);
+                    currentBlock.reachable.add(newBlock);
+                    stack.push(new StackItem(current, newBlock));
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/optim/ForNameFolding.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal.plugins.optim;
+
+import java.io.IOException;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.function.Consumer;
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.tools.jlink.internal.plugins.asm.AsmPools;
+import jdk.internal.org.objectweb.asm.tree.ClassNode;
+import jdk.internal.org.objectweb.asm.tree.MethodNode;
+import jdk.tools.jlink.internal.plugins.OptimizationPlugin.MethodOptimizer;
+import jdk.tools.jlink.internal.plugins.asm.AsmModulePool;
+import jdk.tools.jlink.internal.plugins.optim.ControlFlow.Block;
+import jdk.tools.jlink.internal.plugins.optim.ReflectionOptimizer.Data;
+import jdk.tools.jlink.internal.plugins.optim.ReflectionOptimizer.TypeResolver;
+
+
+/**
+ * MethodOptimizer that removes Class.forName when possible.
+ * WARNING: This code is experimental.
+ * TODO: Need to check that the type is accessible prior to replace with a constant.
+ */
+public class ForNameFolding implements MethodOptimizer {
+
+    private int numNotReplaced;
+    private int numReplacement;
+    private int numRemovedHandlers;
+    private int instructionsRemoved;
+
+    private Consumer<String> logger;
+
+    @Override
+    public boolean optimize(Consumer<String> logger, AsmPools pools,
+            AsmModulePool modulePool,
+            ClassNode cn, MethodNode m, TypeResolver resolver) throws Exception {
+        this.logger = logger;
+        Data data = ReflectionOptimizer.replaceWithClassConstant(cn, m, createResolver(resolver));
+        instructionsRemoved += data.removedInstructions();
+        numRemovedHandlers += data.removedHandlers().size();
+        for (Entry<String, Set<Block>> entry : data.removedHandlers().entrySet()) {
+            logRemoval(cn.name + "." + m.name + "removed block for " + entry.getKey()
+                    + " : " + entry.getValue());
+        }
+        return data.removedInstructions() > 0;
+    }
+
+    public TypeResolver createResolver(TypeResolver resolver) {
+        return (ClassNode cn, MethodNode mn, String type) -> {
+            ClassReader reader = resolver.resolve(cn, mn, type);
+            if (reader == null) {
+                logNotReplaced(type);
+            } else {
+                logReplaced(type);
+            }
+            return reader;
+        };
+    }
+
+    private void logReplaced(String type) {
+        numReplacement += 1;
+    }
+
+    private void logNotReplaced(String type) {
+        numNotReplaced += 1;
+        if (logger != null) {
+            logger.accept(type + " not resolved");
+        }
+    }
+
+    private void logRemoval(String content) {
+        numRemovedHandlers += 1;
+        if (logger != null) {
+            logger.accept(content);
+        }
+    }
+
+    @Override
+    public void close() throws IOException {
+        if (logger != null) {
+            logger.accept("Class.forName Folding results:\n " + numReplacement
+                    + " removed reflection. " + numRemovedHandlers
+                    + " removed exception handlers."
+                    + numNotReplaced + " types unknown. "
+                    + instructionsRemoved + " instructions removed\n");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/optim/ReflectionOptimizer.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal.plugins.optim;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.IdentityHashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.Type;
+import jdk.internal.org.objectweb.asm.tree.AbstractInsnNode;
+import jdk.internal.org.objectweb.asm.tree.ClassNode;
+import jdk.internal.org.objectweb.asm.tree.LabelNode;
+import jdk.internal.org.objectweb.asm.tree.LdcInsnNode;
+import jdk.internal.org.objectweb.asm.tree.LineNumberNode;
+import jdk.internal.org.objectweb.asm.tree.MethodInsnNode;
+import jdk.internal.org.objectweb.asm.tree.MethodNode;
+import jdk.internal.org.objectweb.asm.tree.TryCatchBlockNode;
+import jdk.tools.jlink.internal.plugins.optim.ControlFlow.Block;
+
+/**
+ * Implement the reflection optimization.
+ */
+public class ReflectionOptimizer {
+
+    public static class Data {
+
+        private int removedInstructions;
+        private final Map<String, Set<Block>> removedHandlers = new HashMap<>();
+
+        private Data() {
+        }
+
+        public int removedInstructions() {
+            return removedInstructions;
+        }
+
+        public Map<String, Set<Block>> removedHandlers() {
+            return Collections.unmodifiableMap(removedHandlers);
+        }
+    }
+
+    public interface TypeResolver {
+
+        public ClassReader resolve(ClassNode cn, MethodNode m, String type);
+    }
+
+    public static Data replaceWithClassConstant(ClassNode cn, MethodNode m,
+            TypeResolver cch)
+            throws Exception {
+        Iterator<AbstractInsnNode> it = m.instructions.iterator();
+        LdcInsnNode insNode = null;
+        Map<LdcInsnNode, LdcInsnNode> replacement = new IdentityHashMap<>();
+        Data data = new Data();
+        while (it.hasNext()) {
+            AbstractInsnNode n = it.next();
+            if (n instanceof LdcInsnNode) {
+                LdcInsnNode ldc = (LdcInsnNode) n;
+                if (ldc.cst instanceof String) {
+                    insNode = ldc;
+                }
+            } else {
+                if (n instanceof MethodInsnNode && insNode != null) {
+                    MethodInsnNode met = (MethodInsnNode) n;
+                    if (met.name.equals("forName")
+                            && met.owner.equals("java/lang/Class")
+                            && met.desc.equals("(Ljava/lang/String;)Ljava/lang/Class;")) {
+                        // Can we load the type?
+                        Type type = null;
+                        String binaryName = insNode.cst.toString().replaceAll("\\.", "/");
+                        String unaryClassName = binaryName;
+                        int arrayIndex = binaryName.lastIndexOf("[");
+                        if (arrayIndex >= 0) {
+                            int objIndex = unaryClassName.indexOf("L");
+                            if (objIndex >= 0) {
+                                unaryClassName = unaryClassName.substring(objIndex + 1);
+                                unaryClassName = unaryClassName.substring(0,
+                                        unaryClassName.length() - 1);
+                            } else {
+                                //primitive, this is just fine.
+                                type = Type.getObjectType(binaryName);
+                            }
+                        }
+                        if (type == null) {
+                            if (cch.resolve(cn, m, unaryClassName) != null) {
+                                type = Type.getObjectType(binaryName);
+                            }
+                        }
+                        if (type != null) {
+                            replacement.put(insNode, new LdcInsnNode(type));
+                            it.remove();
+                            data.removedInstructions += 1;
+                        }
+                    } else {
+                        insNode = null;
+                    }
+                    // Virtual node, not taken into account
+                } else if (!(n instanceof LabelNode) && !(n instanceof LineNumberNode)) {
+                    insNode = null;
+                }
+            }
+        }
+        for (Map.Entry<LdcInsnNode, LdcInsnNode> entry : replacement.entrySet()) {
+            m.instructions.set(entry.getKey(), entry.getValue());
+        }
+        if (!replacement.isEmpty()) {
+            String[] types = {"java/lang/ClassNotFoundException"};
+            data.removedInstructions += deleteExceptionHandlers(cch, data, cn, m, types);
+
+        }
+        return data;
+    }
+
+    private static int deleteExceptionHandlers(TypeResolver cch, Data data,
+            ClassNode cn, MethodNode m, String[] exTypes)
+            throws Exception {
+        int instructionsRemoved = 0;
+        for (String ex : exTypes) {
+            ControlFlow f = ControlFlow.createControlFlow(cn.name, m);
+            List<Integer> removed = new ArrayList<>();
+            Set<ControlFlow.Block> blocksToRemove = new TreeSet<>();
+            Iterator<TryCatchBlockNode> it = m.tryCatchBlocks.iterator();
+            List<TryCatchBlockNode> tcbToRemove = new ArrayList<>();
+            while (it.hasNext()) {
+                TryCatchBlockNode bn = it.next();
+                if (bn.type == null
+                        || !bn.type.equals(ex) // An empty block
+                        || tcbToRemove.contains(bn)) {
+                    continue;
+                }
+                // Check that the handler is still required
+                if (!Utils.canThrowCheckedException(cch, cn, m, bn)) {
+                    // try to suppress it.
+                    int block = m.instructions.indexOf(bn.handler);
+                    ControlFlow.Block blockHandler = f.getBlock(block);
+                    if (blockHandler == null) {
+                        if (removed.contains(block)) {
+                            continue;
+                        } else {
+                            throw new Exception(cn.name
+                                    + ", no block for handler " + block);
+                        }
+                    }
+                    tcbToRemove.add(bn);
+                    // Don't delete block if shared (eg: ClassNotFoundException | NoSuchMethodException |
+                    Iterator<TryCatchBlockNode> it2 = m.tryCatchBlocks.iterator();
+                    boolean cont = false;
+                    while (it2.hasNext()) {
+                        TryCatchBlockNode bn2 = it2.next();
+                        if (bn2 != bn) {
+                            if (bn2.start.equals(bn.start)) {
+                                cont = true;
+                            }
+                        }
+                    }
+                    if (cont) {
+                        continue;
+                    }
+                    // An handler is a root, blocks that are only reachable by it
+                    // can be removed.
+                    Set<ControlFlow.Block> blocks = f.getClosure(blockHandler);
+                    StringBuilder sb = new StringBuilder();
+                    for (ControlFlow.Block b : blocks) {
+                        sb.append(b).append("\n");
+                        removed.add(b.getFirstInstruction().getIndex());
+                        // Remove Exception handler if the associated block has been removed
+                        for (TryCatchBlockNode tcb : m.tryCatchBlocks) {
+                            if (tcb != bn) {
+                                // An exception handler removed as a side effect.
+                                if (b.isExceptionHandler()
+                                        && b.getFirstInstruction().getInstr() == tcb.handler) {
+                                    tcbToRemove.add(tcb);
+                                }
+                            }
+                        }
+                    }
+                    blocksToRemove.addAll(blocks);
+
+                    data.removedHandlers.put(ex, blocks);
+
+                }
+            }
+
+            m.tryCatchBlocks.removeAll(tcbToRemove);
+
+            if (!blocksToRemove.isEmpty()) {
+                for (ControlFlow.Block b : blocksToRemove) {
+                    for (ControlFlow.InstructionNode ins : b.getInstructions()) {
+                        if (ins.getInstr().getOpcode() > 0) {
+                            instructionsRemoved += 1;
+                        }
+                    }
+                }
+                Utils.suppressBlocks(m, blocksToRemove);
+            }
+        }
+        return instructionsRemoved;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/optim/Utils.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal.plugins.optim;
+
+import java.util.Iterator;
+import java.util.Set;
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.tree.AbstractInsnNode;
+import jdk.internal.org.objectweb.asm.tree.ClassNode;
+import jdk.internal.org.objectweb.asm.tree.MethodInsnNode;
+import jdk.internal.org.objectweb.asm.tree.MethodNode;
+import jdk.internal.org.objectweb.asm.tree.TryCatchBlockNode;
+
+/**
+ * Optimization utility methods
+ */
+public class Utils {
+
+    public static boolean canThrowCheckedException(ReflectionOptimizer.TypeResolver cch,
+            ClassNode classNode, MethodNode m, TryCatchBlockNode bn) throws Exception {
+        int istart = m.instructions.indexOf(bn.start);
+        int iend = m.instructions.indexOf(bn.end);
+        for (int i = istart; i < iend - 1; i++) {
+            AbstractInsnNode instr = m.instructions.get(i);
+            if (instr instanceof MethodInsnNode) {
+                MethodInsnNode meth = (MethodInsnNode) instr;
+                ClassReader reader = cch.resolve(classNode, m, meth.owner);
+                if (reader != null) {
+                    ClassNode cn = new ClassNode();
+                    reader.accept(cn, ClassReader.EXPAND_FRAMES);
+                    for (MethodNode method : cn.methods) {
+                        if (method.name.equals(meth.name)) {
+                            for (String e : method.exceptions) {
+                                if (e.equals(bn.type)) {
+                                    return true;
+                                }
+                            }
+                        }
+                    }
+                } else {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public static void suppressBlocks(MethodNode m, Set<ControlFlow.Block> toRemove) throws Exception {
+        m.instructions.resetLabels();
+        Iterator<AbstractInsnNode> it = m.instructions.iterator();
+        while (it.hasNext()) {
+            AbstractInsnNode n = it.next();
+            Iterator<TryCatchBlockNode> handlers = m.tryCatchBlocks.iterator();
+            boolean cont = false;
+            // Do not delete instructions that are end of other try block.
+            while (handlers.hasNext()) {
+                TryCatchBlockNode handler = handlers.next();
+                if (handler.end == n) {
+                    cont = true;
+                }
+            }
+            if (cont) {
+                continue;
+            }
+
+            for (ControlFlow.Block b : toRemove) {
+                for (ControlFlow.InstructionNode ins : b.getInstructions()) {
+                    if (ins.getInstr() == n) {
+                        it.remove();
+                    }
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/ExecutableImage.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.plugin;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * An executable runtime image. Instance of this class contains the information
+ * needed to create image processes.
+ */
+public abstract class ExecutableImage {
+
+    private final Path home;
+    private final List<String> args;
+    private final Set<String> modules;
+
+    protected ExecutableImage(Path home, Set<String> modules,
+            List<String> args) {
+        Objects.requireNonNull(home);
+        Objects.requireNonNull(args);
+        if (!Files.exists(home)) {
+            throw new IllegalArgumentException("Invalid image home");
+        }
+        this.home = home;
+        this.modules = Collections.unmodifiableSet(modules);
+        this.args = Collections.unmodifiableList(args);
+    }
+
+    /**
+     * Image home directory,
+     *
+     * @return The home directory.
+     */
+    public Path getHome() {
+        return home;
+    }
+
+    /**
+     * The names of the modules located in the image.
+     *
+     * @return The set of modules.
+     */
+    public Set<String> getModules() {
+        return modules;
+    }
+
+    /**
+     * The list of arguments required to execute the image.
+     *
+     * @return The list of arguments.
+     */
+    public List<String> getExecutionArgs() {
+        return args;
+    }
+
+    /**
+     * Store new arguments required to execute the image.
+     *
+     * @param args Additional arguments
+     */
+    public abstract void storeLaunchArgs(List<String> args);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/Plugin.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.plugin;
+
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import jdk.tools.jlink.internal.plugins.PluginsResourceBundle;
+
+/**
+ * Base interface that jlink plugins should implement.
+ */
+public interface Plugin {
+
+    /**
+     * Type of plugin.
+     */
+    public interface PluginType {
+
+        public String getName();
+    }
+
+    /**
+     * Order of categories:
+     * <ol>
+     * <li>FILTER: Filter in/out resources or files.</li>
+     * <li>TRANSFORMER: Transform resources or files(eg: refactoring, bytecode
+     * manipulation).</li>
+     * <li>MODULEINFO_TRANSFORMER: Transform only module-info.class</li>
+     * <li>SORTER: Sort resources within the resource container.</li>
+     * <li>COMPRESSOR: Compress resource within the resouce containers.</li>
+     * <li>VERIFIER: Does some image verification.</li>
+     * <li>PROCESSOR: Does some post processing on image.</li>
+     * <li>PACKAGER: Final processing</li>
+     * </ol>
+     */
+    public enum CATEGORY implements PluginType {
+        FILTER("FILTER"),
+        TRANSFORMER("TRANSFORMER"),
+        MODULEINFO_TRANSFORMER("MODULEINFO_TRANSFORMER"),
+        SORTER("SORTER"),
+        COMPRESSOR("COMPRESSOR"),
+        VERIFIER("VERIFIER"),
+        PROCESSOR("PROCESSOR"),
+        PACKAGER("PACKAGER");
+
+        private final String name;
+
+        CATEGORY(String name) {
+            this.name = name;
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
+    }
+
+    /**
+     * Plugin state:
+     * <ul>
+     * <li>DISABLED: The plugin is not exposed in help and will be not called.</li>
+     * <li>AUTO_ENABLED: The plugin is enabled by default. It doesn't require its
+     * option to be present to be called.<li>
+     * <li>FUNCTIONAL: The plugin is properly configured and can operate.
+     * Non functional plugin must advertise their status in the
+     * {@link #getStateDescription() getStateDescription} method</li>
+     * </ul>
+     */
+    public enum STATE {
+        DISABLED,
+        AUTO_ENABLED,
+        FUNCTIONAL
+    }
+
+    /**
+     * The Plugin set of types.
+     * @return The set of types.
+     */
+    public default Set<PluginType> getType() {
+        return Collections.emptySet();
+    }
+
+    /**
+     * The Plugin set of states.
+     * @return The set of states.
+     */
+    public default Set<STATE> getState() {
+        return EnumSet.of(STATE.FUNCTIONAL);
+    }
+
+    /**
+     * The set of plugin names that must be located, within the stack of plugins,
+     * before this plugin.
+     * @return The set of names. By default this set is empty.
+     */
+    public default Set<String> isBefore() {
+        return Collections.emptySet();
+    }
+
+    /**
+     * The set of plugin names that must be located, within the stack of plugins,
+     * after this plugin.
+     * @return The set of names. By default this set is empty.
+     */
+    public default Set<String> isAfter() {
+        return Collections.emptySet();
+    }
+
+    /**
+     * The plugin name.
+     * @return The name.
+     */
+    public default String getName() {
+        return getClass().getName().replace('.', '-');
+    }
+
+    /**
+     * The plugin description.
+     * @return  The description.
+     */
+    public default String getDescription() {
+        return "";
+    }
+
+    /**
+     * The option that identifies this plugin. This may be null.
+     * "--" is prefixed to the String (when non-null) when invoking
+     * this plugin from jlink command line.
+     *
+     * @return The plugin option.
+     */
+    public default String getOption() {
+        return getName();
+    }
+
+    /**
+     * Has this plugin require one or more arguments?
+     * A plugin can have one or more optional arguments.
+     * <br>
+     * A plugin option with a single argument is specified as follows:
+     * <pre>
+     *     --plugin-option=arg_value
+     * </pre>
+     * If there are more than arguments, command line option looks like:
+     * <pre>
+     *     --plugin-option=arg_value:arg2=value2:arg3=value3...
+     *</pre>
+     *
+     * @return true if arguments are needed.
+     */
+    public default boolean hasArguments() {
+        return false;
+    }
+
+    /**
+     * The plugin argument(s) description.
+     * @return  The argument(s) description.
+     */
+    public default String getArgumentsDescription() {
+        return "";
+    }
+
+    /**
+     * Return a message indicating the status of the provider.
+     *
+     * @return A status description.
+     */
+    public default String getStateDescription() {
+        return getState().contains(STATE.FUNCTIONAL)
+                ? PluginsResourceBundle.getMessage("main.status.ok")
+                : PluginsResourceBundle.getMessage("main.status.not.ok");
+    }
+
+    /**
+     * Configure the plugin based on the passed configuration.
+     * This method is called prior to invoke the plugin.
+     *
+     * @param config The plugin configuration.
+     */
+    public default void configure(Map<String, String> config) {
+    }
+
+    /**
+     * Configure the plugin based on the passed configuration.
+     * This method is called prior to invoke the plugin.
+     *
+     * @param config The plugin configuration.
+     * @param ctx The plugin context
+     */
+    public default void configure(Map<String, String> config, PluginContext ctx) {
+        configure(config);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/PluginContext.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.plugin;
+
+import java.util.Properties;
+
+/**
+ * Interface to plugin (container) context.
+ */
+public interface PluginContext {
+    /**
+     * Returns 'release' properties
+     */
+    public Properties getReleaseProperties();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/PluginException.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.plugin;
+
+/**
+ * An unchecked exception thrown by jlink plugin API for unrecoverable
+ * conditions.
+ */
+public final class PluginException extends RuntimeException {
+
+    private static final long serialVersionUID = 7117982019443100395L;
+
+    public PluginException() {
+
+    }
+
+    public PluginException(Throwable ex) {
+        super(ex);
+    }
+
+    public PluginException(String msg) {
+        super(msg);
+    }
+
+    public PluginException(String msg, Throwable thr) {
+        super(msg, thr);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/Pool.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,528 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.plugin;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
+import java.lang.module.ModuleDescriptor;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import jdk.tools.jlink.internal.ImageFileCreator;
+import jdk.tools.jlink.internal.plugins.FileCopierPlugin;
+
+/**
+ * Pool of module data.
+ *
+ */
+public abstract class Pool {
+
+    /**
+     * Interface to visit the content of a Pool.
+     */
+    public interface Visitor {
+
+        /**
+         * Called for each visited ModuleData.
+         *
+         * @param content A ModuleData
+         * @return A ModuleData instance or null if the passed ModuleData is to
+         * be removed from the image.
+         * @throws PluginException
+         */
+        public ModuleData visit(ModuleData content);
+    }
+
+    /**
+     * Type of module data.
+     * <li>
+     * <ul>CLASS_OR_RESOURCE: A java class or resource file.</ul>
+     * <ul>CONFIG: A configuration file.</ul>
+     * <ul>NATIVE_CMD: A native process launcher.</ul>
+     * <ul>NATIVE_LIB: A native library.</ul>
+     * <ul>OTHER: Other kind of file.</ul>
+     * </li>
+     */
+    public static enum ModuleDataType {
+
+        CLASS_OR_RESOURCE,
+        CONFIG,
+        NATIVE_CMD,
+        NATIVE_LIB,
+        OTHER;
+    }
+
+    /**
+     * A module in the pool.
+     */
+    public interface Module {
+
+        /**
+         * The module name.
+         *
+         * @return The name.
+         */
+        public String getName();
+
+        /**
+         * Retrieves a ModuleData from a path (e.g:
+         * /mymodule/com.foo.bar/MyClass.class)
+         *
+         * @param path The piece of data path.
+         * @return A ModuleData or null if the path doesn't identify a
+         * ModuleData.
+         */
+        public ModuleData get(String path);
+
+        /**
+         * The module descriptor of this module.
+         *
+         * @return The module descriptor.
+         */
+        public ModuleDescriptor getDescriptor();
+
+        /**
+         * Add a ModuleData to this module.
+         *
+         * @param data The ModuleData to add.
+         */
+        public void add(ModuleData data);
+
+        /**
+         * Retrieves all the packages located in this module.
+         *
+         * @return The set of packages.
+         */
+        public Set<String> getAllPackages();
+
+        /**
+         * Retrieves the collection of ModuleData.
+         *
+         * @return The ModuleData collection.
+         */
+        public Collection<ModuleData> getContent();
+
+    }
+
+    private class ModuleImpl implements Module {
+
+        private final Map<String, ModuleData> moduleContent = new LinkedHashMap<>();
+        private ModuleDescriptor descriptor;
+        private final String name;
+
+        private ModuleImpl(String name) {
+            this.name = name;
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
+
+        @Override
+        public ModuleData get(String path) {
+            if (!path.startsWith("/")) {
+                path = "/" + path;
+            }
+            if (!path.startsWith("/" + name)) {
+                path = "/" + name + path;
+            }
+            return moduleContent.get(path);
+        }
+
+        @Override
+        public ModuleDescriptor getDescriptor() {
+            if (descriptor == null) {
+                String p = "/" + name + "/module-info.class";
+                ModuleData content = moduleContent.get(p);
+                if (content == null) {
+                    throw new PluginException("No module-info for " + name
+                            + " module");
+                }
+                ByteBuffer bb = ByteBuffer.wrap(content.getBytes());
+                descriptor = ModuleDescriptor.read(bb);
+            }
+            return descriptor;
+        }
+
+        @Override
+        public void add(ModuleData data) {
+            if (isReadOnly()) {
+                throw new PluginException("pool is readonly");
+            }
+            Objects.requireNonNull(data);
+            if (!data.getModule().equals(name)) {
+                throw new PluginException("Can't add resource " + data.getPath()
+                        + " to module " + name);
+            }
+            Pool.this.add(data);
+        }
+
+        @Override
+        public Set<String> getAllPackages() {
+            Set<String> pkgs = new HashSet<>();
+            moduleContent.values().stream().filter(m -> m.getType().
+                    equals(ModuleDataType.CLASS_OR_RESOURCE)).forEach((res) -> {
+                // Module metadata only contains packages with .class files
+                if (ImageFileCreator.isClassPackage(res.getPath())) {
+                    String[] split = ImageFileCreator.splitPath(res.getPath());
+                    String pkg = split[1];
+                    if (pkg != null && !pkg.isEmpty()) {
+                        pkgs.add(pkg);
+                    }
+                }
+            });
+            return pkgs;
+        }
+
+        @Override
+        public String toString() {
+            return getName();
+        }
+
+        @Override
+        public Collection<ModuleData> getContent() {
+            return Collections.unmodifiableCollection(moduleContent.values());
+        }
+    }
+
+    /**
+     * A ModuleData is the elementary unit of data inside an image. It is
+     * generally a file. e.g.: a java class file, a resource file, a shared
+     * library, ...
+     * <br>
+     * A ModuleData is identified by a path of the form:
+     * <ul>
+     * <li>For jimage content: /{module name}/{package1}/.../{packageN}/{file
+     * name}</li>
+     * <li>For other files (shared lib, launchers, config, ...):/{module name}/
+     * {@literal bin|conf|native}/{dir1}>/.../{dirN}/{file name}</li>
+     * </ul>
+     */
+    public static class ModuleData {
+
+        private final ModuleDataType type;
+        private final String path;
+        private final String module;
+        private final long length;
+        private final InputStream stream;
+        private byte[] buffer;
+
+        /**
+         * Create a new ModuleData.
+         *
+         * @param module The module name.
+         * @param path The data path identifier.
+         * @param type The data type.
+         * @param stream The data content stream.
+         * @param length The stream length.
+         */
+        public ModuleData(String module, String path, ModuleDataType type,
+                InputStream stream, long length) {
+            Objects.requireNonNull(module);
+            Objects.requireNonNull(path);
+            Objects.requireNonNull(type);
+            Objects.requireNonNull(stream);
+            this.path = path;
+            this.type = type;
+            this.module = module;
+            this.stream = stream;
+            this.length = length;
+        }
+
+        /**
+         * The ModuleData module name.
+         *
+         * @return The module name.
+         */
+        public final String getModule() {
+            return module;
+        }
+
+        /**
+         * The ModuleData path.
+         *
+         * @return The module path.
+         */
+        public final String getPath() {
+            return path;
+        }
+
+        /**
+         * The ModuleData type.
+         *
+         * @return The data type.
+         */
+        public final ModuleDataType getType() {
+            return type;
+        }
+
+        /**
+         * The ModuleData content as an array of byte.
+         *
+         * @return An Array of bytes.
+         */
+        public byte[] getBytes() {
+            if (buffer == null) {
+                try {
+                    buffer = stream.readAllBytes();
+                } catch (IOException ex) {
+                    throw new UncheckedIOException(ex);
+                }
+            }
+            return buffer;
+        }
+
+        /**
+         * The ModuleData content length.
+         *
+         * @return The length.
+         */
+        public long getLength() {
+            return length;
+        }
+
+        /**
+         * The ModuleData stream.
+         *
+         * @return The module data stream.
+         */
+        public InputStream stream() {
+            return stream;
+        }
+
+        @Override
+        public int hashCode() {
+            int hash = 7;
+            hash = 89 * hash + Objects.hashCode(this.path);
+            return hash;
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (!(other instanceof ModuleData)) {
+                return false;
+            }
+            ModuleData f = (ModuleData) other;
+            return f.path.equals(path);
+        }
+
+        @Override
+        public String toString() {
+            return getPath();
+        }
+    }
+
+    private final Map<String, ModuleData> resources = new LinkedHashMap<>();
+    private final Map<String, ModuleImpl> modules = new LinkedHashMap<>();
+    private final ModuleImpl fileCopierModule = new ModuleImpl(FileCopierPlugin.FAKE_MODULE);
+
+    private final ByteOrder order;
+
+    protected Pool() {
+        this(ByteOrder.nativeOrder());
+    }
+
+    protected Pool(ByteOrder order) {
+        Objects.requireNonNull(order);
+        this.order = order;
+    }
+
+    /**
+     * Read only state. No data can be added to a ReadOnly Pool.
+     *
+     * @return true if readonly false otherwise.
+     */
+    public abstract boolean isReadOnly();
+
+    /**
+     * Add a ModuleData.
+     *
+     * @param data The ModuleData to add.
+     */
+    public void add(ModuleData data) {
+        if (isReadOnly()) {
+            throw new PluginException("pool is readonly");
+        }
+        Objects.requireNonNull(data);
+        if (resources.get(data.getPath()) != null) {
+            throw new PluginException("Resource " + data.getPath()
+                    + " already present");
+        }
+        String modulename = data.getModule();
+        ModuleImpl m = modules.get(modulename);
+        // ## TODO: FileCopierPlugin should not add content to a module
+        // FAKE_MODULE is not really a module to be added in the image
+        if (FileCopierPlugin.FAKE_MODULE.equals(modulename)) {
+            m = fileCopierModule;
+        }
+        if (m == null) {
+            m = new ModuleImpl(modulename);
+            modules.put(modulename, m);
+        }
+        resources.put(data.getPath(), data);
+        m.moduleContent.put(data.getPath(), data);
+    }
+
+    /**
+     * Retrieves the module for the provided name.
+     *
+     * @param name The module name
+     * @return the module or null if the module doesn't exist.
+     */
+    public Module getModule(String name) {
+        Objects.requireNonNull(name);
+        return modules.get(name);
+    }
+
+    /**
+     * The collection of modules contained in this pool.
+     *
+     * @return The collection of modules.
+     */
+    public Collection<Module> getModules() {
+        return Collections.unmodifiableCollection(modules.values());
+    }
+
+    /**
+     * Get all ModuleData contained in this pool instance.
+     *
+     * @return The collection of resources;
+     */
+    public Collection<ModuleData> getContent() {
+        return Collections.unmodifiableCollection(resources.values());
+    }
+
+    /**
+     * Get the ModuleData for the passed path.
+     *
+     * @param path A data path
+     * @return A ModuleData instance or null if the data is not found
+     */
+    public ModuleData get(String path) {
+        Objects.requireNonNull(path);
+        return resources.get(path);
+    }
+
+    /**
+     * Check if the pool contains this data.
+     *
+     * @param data The module data to check existence for.
+     * @return The module data or null if not found.
+     */
+    public boolean contains(ModuleData data) {
+        Objects.requireNonNull(data);
+        return get(data.getPath()) != null;
+    }
+
+    /**
+     * Check if the Pool contains some content.
+     *
+     * @return True, no content, false otherwise.
+     */
+    public boolean isEmpty() {
+        return resources.isEmpty();
+    }
+
+    /**
+     * Visit the pool.
+     *
+     * @param visitor The Visitor called for each ModuleData found in the pool.
+     * @param output The pool to be filled with Visitor returned ModuleData.
+     */
+    public void visit(Visitor visitor, Pool output) {
+        for (ModuleData resource : getContent()) {
+            ModuleData res = visitor.visit(resource);
+            if (res != null) {
+                output.add(res);
+            }
+        }
+    }
+
+    /**
+     * The ByteOrder currently in use when generating the jimage file.
+     *
+     * @return The ByteOrder.
+     */
+    public ByteOrder getByteOrder() {
+        return order;
+    }
+
+    /**
+     * Create a ModuleData located inside a jimage file. Such ModuleData has a
+     * ModuleDataType being equals to CLASS_OR_RESOURCE.
+     *
+     * @param path The complete resource path (contains the module radical).
+     * @param content The resource content.
+     * @param size The content size.
+     * @return A new ModuleData.
+     */
+    public static ModuleData newResource(String path, InputStream content, long size) {
+        Objects.requireNonNull(path);
+        Objects.requireNonNull(content);
+        String[] split = ImageFileCreator.splitPath(path);
+        String module = split[0];
+        return new ModuleData(module, path, ModuleDataType.CLASS_OR_RESOURCE, content, size);
+    }
+
+    /**
+     * Create a ModuleData for a file that will be located inside a jimage file.
+     *
+     * @param path The resource path.
+     * @param content The resource content.
+     * @return A new ModuleData.
+     */
+    public static ModuleData newResource(String path, byte[] content) {
+        return newResource(path, new ByteArrayInputStream(content),
+                content.length);
+    }
+
+    /**
+     * Create a ModuleData for a file that will be located outside a jimage
+     * file.
+     *
+     * @param module The module in which this files is located.
+     * @param path The file path locator (doesn't contain the module name).
+     * @param type The ModuleData type.
+     * @param content The file content.
+     * @param size The content size.
+     * @return A new ModuleData.
+     */
+    public static ModuleData newImageFile(String module, String path, ModuleDataType type,
+            InputStream content, long size) {
+        Objects.requireNonNull(path);
+        Objects.requireNonNull(content);
+        return new ModuleData(module, path, type, content, size);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/PostProcessorPlugin.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.plugin;
+
+import java.util.List;
+
+/**
+ * Implement this interface to develop a PostProcessor plugin.
+ * PostProcessor plugins are called once the image has been generated and is executable.
+ **/
+public interface PostProcessorPlugin extends Plugin {
+
+    /**
+     * Post process an image.
+     *
+     * @param image The executable image.
+     * @return The list of arguments to add to launchers (if any).
+     */
+    public List<String> process(ExecutableImage image);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/TransformerPlugin.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.plugin;
+
+
+/**
+ * Implement this interface to develop a Transformer plugin.
+ * TransformerPlugin are called during image creation. This kind of plugin aims to
+ * modify the content of the runtime image.
+ */
+public interface TransformerPlugin extends Plugin {
+    /**
+     * Visit the content of the modules that are composing the image.
+     *
+     * @param in Read only content.
+     * @param out The pool to fill with content. This pool must contain
+     * the result of the visit.
+     *
+     * @throws PluginException
+     */
+    public void visit(Pool in, Pool out);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,73 @@
+main.usage.summary=\
+Usage: {0} <options> --modulepath <modulepath> --addmods <mods> --output <path>\n\
+use --help for a list of possible options
+
+main.usage=\
+Usage: {0} <options> --modulepath <modulepath> --addmods <mods> --output <path>\n\
+Possible options include:
+
+error.prefix=Error:
+warn.prefix=Warning:
+
+main.opt.help=\
+\  --help                            Print this help message
+
+main.opt.version=\
+\  --version                         Version information
+
+main.opt.modulepath=\
+\  --modulepath <modulepath>         Module path
+
+main.opt.addmods=\
+\  --addmods <mod>[,<mod>...]        Root modules to resolve
+
+main.opt.limitmods=\
+\  --limitmods <mod>[,<mod>...]      Limit the universe of observable modules
+
+main.opt.output=\
+\  --output <path>                   Location of output path
+
+main.command.files=\
+\  @<filename>                       Read options from file
+
+main.opt.endian=\
+\  --endian <little|big>             Byte order of generated jimage (default:native)
+
+main.opt.genbom=\
+\  --genbom                          Generate a bom file containing jlink info
+
+main.opt.saveopts=\
+\  --saveopts <filename>             Save jlink options in the given file
+
+main.msg.bug=\
+An exception has occurred in jlink. \
+Please file a bug at the Java Bug Database (http://bugreport.java.com/bugreport/) \
+after checking the database for duplicates. \
+Include your program and the following diagnostic in your report.  Thank you.
+
+main.extended.help=\
+List of available plugins:
+
+err.unknown.byte.order:unknown byte order {0}
+err.output.must.be.specified:--output must be specified
+err.modulepath.must.be.specified:--modulepath must be specified
+err.mods.must.be.specified:no modules specified to {0}
+err.path.not.found=path not found: {0}
+err.path.not.valid=invalid path: {0}
+err.existing.image.must.exist=existing image doesn't exists or is not a directory
+err.existing.image.invalid=existing image is not valid
+err.file.not.found=cannot find file: {0}
+err.file.error=cannot access file: {0}
+err.dir.exists={0} already exists
+err.badpattern=bad pattern {0}
+err.unknown.option=unknown option: {0}
+err.missing.arg=no value given for {0}
+err.internal.error=internal error: {0} {1} {2}
+err.invalid.arg.for.option=invalid argument for option: {0}
+err.option.after.class=option must be specified before classes: {0}
+err.option.unsupported={0} not supported: {1}
+err.config.defaults=property {0} is missing from configuration
+err.config.defaults.value=wrong value in defaults property: {0}
+err.bom.generation=bom file generation failed: {0}
+warn.invalid.arg=Invalid classname or pathname not exist: {0}
+warn.split.package=package {0} defined in {1} {2}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,153 @@
+release-info.argument=<file>|add:<key1>=<value1>:<key2>=<value2>:...|del:<key list>
+
+release-info.description=\
+<file> option is to load release properties from the supplied file.\n\
+add: is to add properties to the 'release' file.\n\
+Any number of <key>=<value> pairs can be passed.\n\
+del: is to delete the list of keys in release file.
+
+class-optim.argument=<all|forName-folding>[:log=<log file>]
+
+class-optim.description=\
+Class optimization. Warning: This plugin is experimental.\n\
+An optional <log file> can be specified to log applied optimizations.
+
+compress.argument=<0|1|2>[:filter=<pattern>]
+
+compress.description=\
+Compress all resources in the output image.\n\
+Level 0: constant string sharing\n\
+Level 1: ZIP\n\
+Level 2: both.\n\
+An optional filter can be specified to list the pattern of files to be filtered.\n\
+Use ^ for negation. eg: *Exception.class,*Error.class,^/java.base/java/lang/*
+
+compact-cp.argument=<resource paths>
+
+compact-cp.description=Constant Pool strings sharing.\n\
+By default, all resources are compressed. You can express the set \n\
+of resources to compress or not compress (use ^ for negation).
+
+copy-files.argument=<List of <file path>=<image target> to copy to the image>.
+
+copy-files.description=\
+If files to copy are not absolute path, JDK home dir is used.\n\
+eg: jrt-fs.jar,LICENSE,/home/me/myfile.txt=somewehere/conf.txt
+
+exclude-files.argument=<files to exclude | files of excluded files>
+
+exclude-files.description=\
+Specify files to exclude. eg: *.diz, /java.base/native/client/*
+
+exclude-resources.argument=<resources to exclude | file of excluded resources>
+
+exclude-resources.description=\
+Specify resources to exclude. eg: *.jcov, */META-INF/*
+
+installed-modules.description=Fast loading of module descriptors (always enabled)
+
+onoff.argument=<on|off>
+
+sort-resources.argument=<paths in priority order | file with resource paths>
+
+sort-resources.description=\
+Sort resources. eg: */modules-info.class,/java-base/java/lang/*
+
+strip-debug.description=\
+Strip debug information from the output image
+
+strip-native-commands.description=\
+Exclude native commands (such as java/java.exe) from the image
+
+vm.argument=<client|server|minimal|all>
+
+vm.description=\
+Select the HotSpot VM in the output image.  Default is all
+ 
+zip.argument=[comma separated list of resource paths]
+
+zip.description=ZIP Compression
+
+include-locales.argument=<langtag>[,<langtag>]*
+
+include-locales.description=BCP 47 language tags separated by a comma, allowing locale matching\ndefined in RFC 4647. eg: en,ja,*-IN
+
+main.status.ok=Functional.
+
+main.status.not.ok= Not functional.
+
+plugin.plugins.header=\
+List of available plugin options:
+
+plugin.opt.list-plugins=\
+\  --list-plugins                    List available plugins
+
+plugin.opt.post-process-path=\
+\  --post-process-path <imagefile>   Post process an existing image
+
+plugin.opt.resources-last-sorter=\
+\  --resources-last-sorter <name>    The last plugin allowed to sort resources
+
+plugin.opt.plugins-modulepath=\
+\  --plugin-module-path <modulepath> Custom plugins module path
+
+plugin.opt.c=\
+\  -c, --compress=2                  Enable compression of resources (level 2)
+
+plugin.opt.G=\
+\  -G, --strip-debug                 Strip debug information
+
+main.plugin.name=\
+\Plugin Name
+
+main.plugin.class=\
+\Plugin Class
+
+main.plugin.module=\
+\Plugin Module
+
+main.plugin.category=\
+\Category
+
+main.plugin.description=\
+\Description
+
+main.plugin.post.processors=\
+Image Post Processors:
+
+main.plugin.argument=\
+\Argument
+
+main.plugin.range.from=\
+Range from
+
+main.plugin.range.to=\
+to
+
+main.plugin.option=\
+\Option
+
+main.plugin.no.value=\
+\<empty>
+
+main.plugin.state=\
+Functional state
+
+err.provider.not.functional=The provider {0} is not functional.
+
+err.plugin.mutiple.options=More than one plugin enabled by {0} option
+err.provider.additional.arg.error=Error in additional argument specification in {0} option: {1}
+
+err.no.plugins.path=No plugins path argument.
+
+err.dir.already.exits=directory already exists: {0} 
+
+err.invalid.index=invalid index for option {0}
+
+err.plugin.option.not.set=Option {0} must be set.
+
+warn.thirdparty.plugins=\
+Enabling third party plugins can lead to unusable generated image.
+
+warn.thirdparty.plugins.enabled=\
+You have enabled third party plugins.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,1174 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jmod;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.UncheckedIOException;
+import java.lang.module.FindException;
+import java.lang.module.ModuleReference;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleDescriptor.Requires;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Version;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.nio.file.FileSystems;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.InvalidPathException;
+import java.nio.file.Path;
+import java.nio.file.PathMatcher;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Formatter;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.Optional;
+import java.util.ResourceBundle;
+import java.util.Set;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.stream.Collectors;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+
+import jdk.internal.joptsimple.BuiltinHelpFormatter;
+import jdk.internal.joptsimple.NonOptionArgumentSpec;
+import jdk.internal.joptsimple.OptionDescriptor;
+import jdk.internal.joptsimple.OptionException;
+import jdk.internal.joptsimple.OptionParser;
+import jdk.internal.joptsimple.OptionSet;
+import jdk.internal.joptsimple.OptionSpec;
+import jdk.internal.joptsimple.ValueConverter;
+import jdk.internal.module.ConfigurableModuleFinder;
+import jdk.internal.module.ConfigurableModuleFinder.Phase;
+import jdk.internal.module.Hasher;
+import jdk.internal.module.Hasher.DependencyHashes;
+import jdk.internal.module.ModuleInfoExtender;
+
+import static java.util.function.Function.identity;
+import static java.util.stream.Collectors.joining;
+import static java.util.stream.Collectors.toList;
+import static java.util.stream.Collectors.toMap;
+
+/**
+ * Implementation for the jmod tool.
+ */
+public class JmodTask {
+
+    static class CommandException extends RuntimeException {
+        private static final long serialVersionUID = 0L;
+        boolean showUsage;
+
+        CommandException(String key, Object... args) {
+            super(getMessageOrKey(key, args));
+        }
+
+        CommandException showUsage(boolean b) {
+            showUsage = b;
+            return this;
+        }
+
+        private static String getMessageOrKey(String key, Object... args) {
+            try {
+                return MessageFormat.format(ResourceBundleHelper.bundle.getString(key), args);
+            } catch (MissingResourceException e) {
+                return key;
+            }
+        }
+    }
+
+    static <T extends Throwable> void fail(Class<T> type,
+                                           String format,
+                                           Object... args) throws T {
+        String msg = new Formatter().format(format, args).toString();
+        try {
+            T t = type.getConstructor(String.class).newInstance(msg);
+            throw t;
+        } catch (InstantiationException |
+                 InvocationTargetException |
+                 NoSuchMethodException |
+                 IllegalAccessException e) {
+            throw new InternalError("Unable to create an instance of " + type, e);
+        }
+    }
+
+    private static final String PROGNAME = "jmod";
+    private static final String MODULE_INFO = "module-info.class";
+
+    private Options options;
+    private PrintStream out = System.out;
+    void setLog(PrintStream out) {
+        this.out = out;
+    }
+
+    /* Result codes. */
+    static final int EXIT_OK = 0, // Completed with no errors.
+                     EXIT_ERROR = 1, // Completed but reported errors.
+                     EXIT_CMDERR = 2, // Bad command-line arguments
+                     EXIT_SYSERR = 3, // System error or resource exhaustion.
+                     EXIT_ABNORMAL = 4;// terminated abnormally
+
+    enum Mode {
+        CREATE,
+        LIST,
+        DESCRIBE
+    };
+
+    static class Options {
+        Mode mode;
+        Path jmodFile;
+        boolean help;
+        boolean version;
+        List<Path> classpath;
+        List<Path> cmds;
+        List<Path> configs;
+        List<Path> libs;
+        ModuleFinder moduleFinder;
+        Version moduleVersion;
+        String mainClass;
+        String osName;
+        String osArch;
+        String osVersion;
+        Pattern dependenciesToHash;
+        List<PathMatcher> excludes;
+    }
+
+    public int run(String[] args) {
+
+        try {
+            handleOptions(args);
+            if (options == null) {
+                showUsageSummary();
+                return EXIT_CMDERR;
+            }
+            if (options.help) {
+                showHelp();
+                return EXIT_OK;
+            }
+            if (options.version) {
+                showVersion();
+                return EXIT_OK;
+            }
+
+            boolean ok;
+            switch (options.mode) {
+                case CREATE:
+                    ok = create();
+                    break;
+                case LIST:
+                    ok = list();
+                    break;
+                case DESCRIBE:
+                    ok = describe();
+                    break;
+                default:
+                    throw new AssertionError("Unknown mode: " + options.mode.name());
+            }
+
+            return ok ? EXIT_OK : EXIT_ERROR;
+        } catch (CommandException e) {
+            reportError(e.getMessage());
+            if (e.showUsage)
+                showUsageSummary();
+            return EXIT_CMDERR;
+        } catch (Exception x) {
+            reportError(x.getMessage());
+            x.printStackTrace();
+            return EXIT_ABNORMAL;
+        } finally {
+            out.flush();
+        }
+    }
+
+    private boolean list() throws IOException {
+        ZipFile zip = null;
+        try {
+            try {
+                zip = new ZipFile(options.jmodFile.toFile());
+            } catch (IOException x) {
+                throw new IOException("error opening jmod file", x);
+            }
+
+            // Trivially print the archive entries for now, pending a more complete implementation
+            zip.stream().forEach(e -> out.println(e.getName()));
+            return true;
+        } finally {
+            if (zip != null)
+                zip.close();
+        }
+    }
+
+    private Map<String, Path> modulesToPath(Set<ModuleDescriptor> modules) {
+        ModuleFinder finder = options.moduleFinder;
+
+        Map<String,Path> modPaths = new HashMap<>();
+        for (ModuleDescriptor m : modules) {
+            String name = m.name();
+
+            Optional<ModuleReference> omref = finder.find(name);
+            if (!omref.isPresent()) {
+                // this should not happen, module path bug?
+                fail(InternalError.class,
+                     "Selected module %s not on module path",
+                     name);
+            }
+
+            URI uri = omref.get().location().get();
+            modPaths.put(name, Paths.get(uri));
+
+        }
+        return modPaths;
+    }
+
+    private boolean describe() throws IOException {
+        ZipFile zip = null;
+        try {
+            try {
+                zip = new ZipFile(options.jmodFile.toFile());
+            } catch (IOException x) {
+                throw new IOException("error opening jmod file", x);
+            }
+
+            try (InputStream in = Files.newInputStream(options.jmodFile)) {
+                boolean found = printModuleDescriptor(in);
+                if (!found)
+                    throw new CommandException("err.module.descriptor.not.found");
+                return found;
+            }
+        } finally {
+            if (zip != null)
+                zip.close();
+        }
+    }
+
+    static <T> String toString(Set<T> set) {
+        if (set.isEmpty()) { return ""; }
+        return set.stream().map(e -> e.toString().toLowerCase(Locale.ROOT))
+                  .collect(joining(" "));
+    }
+
+    private boolean printModuleDescriptor(InputStream in)
+        throws IOException
+    {
+        final String mi = Section.CLASSES.jmodDir() + "/" + MODULE_INFO;
+        try (BufferedInputStream bis = new BufferedInputStream(in);
+             ZipInputStream zis = new ZipInputStream(bis)) {
+
+            ZipEntry e;
+            while ((e = zis.getNextEntry()) != null) {
+                if (e.getName().equals(mi)) {
+                    ModuleDescriptor md = ModuleDescriptor.read(zis);
+                    StringBuilder sb = new StringBuilder();
+                    sb.append("\n").append(md.toNameAndVersion());
+
+                    List<Requires> requires = md.requires().stream().sorted().collect(toList());
+                    if (!requires.isEmpty()) {
+                        requires.forEach(r -> {
+                                sb.append("\n  requires ");
+                                if (!r.modifiers().isEmpty())
+                                  sb.append(toString(r.modifiers())).append(" ");
+                                sb.append(r.name());
+                            });
+                    }
+
+                    List<String> l = md.uses().stream().sorted().collect(toList());
+                    if (!l.isEmpty()) {
+                        l.forEach(sv -> sb.append("\n  uses ").append(sv));
+                    }
+
+                    List<ModuleDescriptor.Exports> exports = sortExports(md.exports());
+                    if (!exports.isEmpty()) {
+                        exports.forEach(ex -> sb.append("\n  exports ").append(ex));
+                    }
+
+                    l = md.conceals().stream().sorted().collect(toList());
+                    if (!l.isEmpty()) {
+                        l.forEach(p -> sb.append("\n  conceals ").append(p));
+                    }
+
+                    Map<String, ModuleDescriptor.Provides> provides = md.provides();
+                    if (!provides.isEmpty()) {
+                        provides.values().forEach(p ->
+                                sb.append("\n  provides ").append(p.service())
+                                  .append(" with ")
+                                  .append(toString(p.providers())));
+                    }
+
+                    Optional<String> mc = md.mainClass();
+                    if (mc.isPresent())
+                        sb.append("\n  main-class " + mc.get());
+
+
+
+                    Optional<String> osname = md.osName();
+                    if (osname.isPresent())
+                        sb.append("\n  operating-system-name " + osname.get());
+
+                    Optional<String> osarch = md.osArch();
+                    if (osarch.isPresent())
+                        sb.append("\n  operating-system-architecture " + osarch.get());
+
+                    Optional<String> osversion = md.osVersion();
+                    if (osversion.isPresent())
+                        sb.append("\n  operating-system-version " + osversion.get());
+
+                    try {
+                        Method m = ModuleDescriptor.class.getDeclaredMethod("hashes");
+                        m.setAccessible(true);
+                        @SuppressWarnings("unchecked")
+                        Optional<Hasher.DependencyHashes> optHashes =
+                                (Optional<Hasher.DependencyHashes>) m.invoke(md);
+
+                        if (optHashes.isPresent()) {
+                            Hasher.DependencyHashes hashes = optHashes.get();
+                            hashes.names().stream().forEach(mod ->
+                                    sb.append("\n  hashes ").append(mod).append(" ")
+                                      .append(hashes.algorithm()).append(" ")
+                                      .append(hashes.hashFor(mod)));
+                        }
+                    } catch (ReflectiveOperationException x) {
+                        throw new InternalError(x);
+                    }
+                    out.println(sb.toString());
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    static List<ModuleDescriptor.Exports> sortExports(Set<ModuleDescriptor.Exports> exports) {
+        Map<String,ModuleDescriptor.Exports> map =
+                exports.stream()
+                       .collect(toMap(ModuleDescriptor.Exports::source,
+                                      identity()));
+        List<String> sources = exports.stream()
+                                      .map(ModuleDescriptor.Exports::source)
+                                      .sorted()
+                                      .collect(toList());
+
+        List<ModuleDescriptor.Exports> l = new ArrayList<>();
+        sources.forEach(e -> l.add(map.get(e)));
+        return l;
+    }
+
+    private boolean create() throws IOException {
+        JmodFileWriter jmod = new JmodFileWriter();
+
+        // create jmod with temporary name to avoid it being examined
+        // when scanning the module path
+        Path target = options.jmodFile;
+        Path tempTarget = target.resolveSibling(target.getFileName() + ".tmp");
+        try {
+            try (OutputStream out = Files.newOutputStream(tempTarget)) {
+                jmod.write(out);
+            }
+            Files.move(tempTarget, target);
+        } catch (Exception e) {
+            if (Files.exists(tempTarget)) {
+                try {
+                    Files.delete(tempTarget);
+                } catch (IOException ioe) {
+                    e.addSuppressed(ioe);
+                }
+            }
+            throw e;
+        }
+        return true;
+    }
+
+    private class JmodFileWriter {
+        final ModuleFinder moduleFinder = options.moduleFinder;
+        final List<Path> cmds = options.cmds;
+        final List<Path> libs = options.libs;
+        final List<Path> configs = options.configs;
+        final List<Path> classpath = options.classpath;
+        final Version moduleVersion = options.moduleVersion;
+        final String mainClass = options.mainClass;
+        final String osName = options.osName;
+        final String osArch = options.osArch;
+        final String osVersion = options.osVersion;
+        final Pattern dependenciesToHash = options.dependenciesToHash;
+        final List<PathMatcher> excludes = options.excludes;
+
+        JmodFileWriter() { }
+
+        /**
+         * Writes the jmod to the given output stream.
+         */
+        void write(OutputStream out) throws IOException {
+            try (ZipOutputStream zos = new ZipOutputStream(out)) {
+
+                // module-info.class
+                writeModuleInfo(zos, findPackages(classpath));
+
+                // classes
+                processClasses(zos, classpath);
+
+                processSection(zos, Section.NATIVE_CMDS, cmds);
+                processSection(zos, Section.NATIVE_LIBS, libs);
+                processSection(zos, Section.CONFIG, configs);
+            }
+        }
+
+        /**
+         * Returns a supplier of an input stream to the module-info.class
+         * on the class path of directories and JAR files.
+         */
+        Supplier<InputStream> newModuleInfoSupplier() throws IOException {
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            for (Path e: classpath) {
+                if (Files.isDirectory(e)) {
+                    Path mi = e.resolve(MODULE_INFO);
+                    if (Files.isRegularFile(mi)) {
+                        Files.copy(mi, baos);
+                        break;
+                    }
+                } else if (Files.isRegularFile(e) && e.toString().endsWith(".jar")) {
+                    try (JarFile jf = new JarFile(e.toFile())) {
+                        ZipEntry entry = jf.getEntry(MODULE_INFO);
+                        if (entry != null) {
+                            jf.getInputStream(entry).transferTo(baos);
+                            break;
+                        }
+                    } catch (ZipException x) {
+                        // Skip. Do nothing. No packages will be added.
+                    }
+                }
+            }
+            if (baos.size() == 0) {
+                return null;
+            } else {
+                byte[] bytes = baos.toByteArray();
+                return () -> new ByteArrayInputStream(bytes);
+            }
+        }
+
+        /**
+         * Writes the updated module-info.class to the ZIP output stream.
+         *
+         * The updated module-info.class will have a ConcealedPackages attribute
+         * with the set of module-private/non-exported packages.
+         *
+         * If --module-version, --main-class, or other options were provided
+         * then the corresponding class file attributes are added to the
+         * module-info here.
+         */
+        void writeModuleInfo(ZipOutputStream zos, Set<String> packages)
+            throws IOException
+        {
+            Supplier<InputStream> miSupplier = newModuleInfoSupplier();
+            if (miSupplier == null) {
+                throw new IOException(MODULE_INFO + " not found");
+            }
+
+            ModuleDescriptor descriptor;
+            try (InputStream in = miSupplier.get()) {
+                descriptor = ModuleDescriptor.read(in);
+            }
+
+            // copy the module-info.class into the jmod with the additional
+            // attributes for the version, main class and other meta data
+            try (InputStream in = miSupplier.get()) {
+                ModuleInfoExtender extender = ModuleInfoExtender.newExtender(in);
+
+                // Add (or replace) the ConcealedPackages attribute
+                if (packages != null) {
+                    Set<String> exported = descriptor.exports().stream()
+                        .map(ModuleDescriptor.Exports::source)
+                        .collect(Collectors.toSet());
+                    Set<String> concealed = packages.stream()
+                        .filter(p -> !exported.contains(p))
+                        .collect(Collectors.toSet());
+                    extender.conceals(concealed);
+                }
+
+                // --main-class
+                if (mainClass != null)
+                    extender.mainClass(mainClass);
+
+                // --os-name, --os-arch, --os-version
+                if (osName != null || osArch != null || osVersion != null)
+                    extender.targetPlatform(osName, osArch, osVersion);
+
+                // --module-version
+                if (moduleVersion != null)
+                    extender.version(moduleVersion);
+
+                // --hash-dependencies
+                if (dependenciesToHash != null) {
+                    String name = descriptor.name();
+                    Set<Requires> dependences = descriptor.requires();
+                    extender.hashes(hashDependences(name, dependences));
+                }
+
+                // write the (possibly extended or modified) module-info.class
+                String e = Section.CLASSES.jmodDir() + "/" + MODULE_INFO;
+                ZipEntry ze = new ZipEntry(e);
+                zos.putNextEntry(ze);
+                extender.write(zos);
+                zos.closeEntry();
+            }
+        }
+
+        /**
+         * Examines the module dependences of the given module
+         * and computes the hash of any module that matches the
+         * pattern {@code dependenciesToHash}.
+         */
+        DependencyHashes hashDependences(String name, Set<Requires> moduleDependences)
+            throws IOException
+        {
+            Set<ModuleDescriptor> descriptors = new HashSet<>();
+            for (Requires md: moduleDependences) {
+                String dn = md.name();
+                if (dependenciesToHash.matcher(dn).find()) {
+                    try {
+                        Optional<ModuleReference> omref = moduleFinder.find(dn);
+                        if (!omref.isPresent()) {
+                            throw new RuntimeException("Hashing module " + name
+                                + " dependencies, unable to find module " + dn
+                                + " on module path");
+                        }
+                        descriptors.add(omref.get().descriptor());
+                    } catch (FindException x) {
+                        throw new IOException("error reading module path", x);
+                    }
+                }
+            }
+
+            Map<String, Path> map = modulesToPath(descriptors);
+            if (map.size() == 0) {
+                return null;
+            } else {
+                // use SHA-256 for now, easy to make this configurable if needed
+                return Hasher.generate(map, "SHA-256");
+            }
+        }
+
+        /**
+         * Returns the set of all packages on the given class path.
+         */
+        Set<String> findPackages(List<Path> classpath) {
+            Set<String> packages = new HashSet<>();
+            for (Path path : classpath) {
+                if (Files.isDirectory(path)) {
+                    packages.addAll(findPackages(path));
+                } else if (Files.isRegularFile(path) && path.toString().endsWith(".jar")) {
+                    try (JarFile jf = new JarFile(path.toString())) {
+                        packages.addAll(findPackages(jf));
+                    } catch (ZipException x) {
+                        // Skip. Do nothing. No packages will be added.
+                    } catch (IOException ioe) {
+                        throw new UncheckedIOException(ioe);
+                    }
+                }
+            }
+            return packages;
+        }
+
+        /**
+         * Returns the set of packages in the given directory tree.
+         */
+        Set<String> findPackages(Path dir) {
+            try {
+                return Files.find(dir, Integer.MAX_VALUE,
+                        ((path, attrs) -> attrs.isRegularFile() &&
+                                path.toString().endsWith(".class")))
+                        .map(path -> toPackageName(dir.relativize(path)))
+                        .filter(pkg -> pkg.length() > 0)   // module-info
+                        .distinct()
+                        .collect(Collectors.toSet());
+            } catch (IOException ioe) {
+                throw new UncheckedIOException(ioe);
+            }
+        }
+
+        /**
+         * Returns the set of packages in the given JAR file.
+         */
+        Set<String> findPackages(JarFile jf) {
+            return jf.stream()
+                     .filter(e -> e.getName().endsWith(".class"))
+                     .map(e -> toPackageName(e))
+                     .filter(pkg -> pkg.length() > 0)   // module-info
+                     .distinct()
+                     .collect(Collectors.toSet());
+        }
+
+        String toPackageName(Path path) {
+            String name = path.toString();
+            assert name.endsWith(".class");
+            int index = name.lastIndexOf(File.separatorChar);
+            if (index != -1)
+                return name.substring(0, index).replace(File.separatorChar, '.');
+
+            if (!name.equals(MODULE_INFO)) {
+                IOException e = new IOException(name  + " in the unnamed package");
+                throw new UncheckedIOException(e);
+            }
+            return "";
+        }
+
+        String toPackageName(ZipEntry entry) {
+            String name = entry.getName();
+            assert name.endsWith(".class");
+            int index = name.lastIndexOf("/");
+            if (index != -1)
+                return name.substring(0, index).replace('/', '.');
+            else
+                return "";
+        }
+
+        void processClasses(ZipOutputStream zos, List<Path> classpaths)
+            throws IOException
+        {
+            if (classpaths == null)
+                return;
+
+            for (Path p : classpaths) {
+                if (Files.isDirectory(p)) {
+                    processSection(zos, Section.CLASSES, p);
+                } else if (Files.isRegularFile(p) && p.toString().endsWith(".jar")) {
+                    try (JarFile jf = new JarFile(p.toFile())) {
+                        JarEntryConsumer jec = new JarEntryConsumer(zos, jf);
+                        jf.stream().filter(jec).forEach(jec);
+                    }
+                }
+            }
+        }
+
+        void processSection(ZipOutputStream zos, Section section, List<Path> paths)
+            throws IOException
+        {
+            if (paths == null)
+                return;
+
+            for (Path p : paths)
+                processSection(zos, section, p);
+        }
+
+        void processSection(ZipOutputStream zos, Section section, Path top)
+            throws IOException
+        {
+            final String prefix = section.jmodDir();
+
+            Files.walkFileTree(top, new SimpleFileVisitor<Path>() {
+                @Override
+                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
+                    throws IOException
+                {
+                    Path relPath = top.relativize(file);
+                    if (!relPath.toString().equals(MODULE_INFO)
+                            && !matches(relPath, excludes)) {
+                        try (InputStream in = Files.newInputStream(file)) {
+                            writeZipEntry(zos, in, prefix, relPath.toString());
+                        }
+                    }
+                    return FileVisitResult.CONTINUE;
+                }
+            });
+        }
+
+        boolean matches(Path path, List<PathMatcher> matchers) {
+            if (matchers != null) {
+                for (PathMatcher pm : matchers) {
+                    if (pm.matches(path))
+                        return true;
+                }
+            }
+            return false;
+        }
+
+        void writeZipEntry(ZipOutputStream zos, InputStream in, String prefix, String other)
+            throws IOException
+        {
+            String name = Paths.get(prefix, other).toString()
+                               .replace(File.separatorChar, '/');
+            ZipEntry ze = new ZipEntry(name);
+            zos.putNextEntry(ze);
+            in.transferTo(zos);
+            zos.closeEntry();
+        }
+
+        class JarEntryConsumer implements Consumer<JarEntry>, Predicate<JarEntry> {
+            final ZipOutputStream zos;
+            final JarFile jarfile;
+            JarEntryConsumer(ZipOutputStream zos, JarFile jarfile) {
+                this.zos = zos;
+                this.jarfile = jarfile;
+            }
+            @Override
+            public void accept(JarEntry je) {
+                try (InputStream in = jarfile.getInputStream(je)) {
+                    writeZipEntry(zos, in, Section.CLASSES.jmodDir(), je.getName());
+                } catch (IOException e) {
+                    throw new UncheckedIOException(e);
+                }
+            }
+            @Override
+            public boolean test(JarEntry je) {
+                String name = je.getName();
+                // ## no support for excludes. Is it really needed?
+                return !name.endsWith(MODULE_INFO) && !je.isDirectory();
+            }
+        }
+    }
+
+    enum Section {
+        NATIVE_LIBS("native"),
+        NATIVE_CMDS("bin"),
+        CLASSES("classes"),
+        CONFIG("conf"),
+        UNKNOWN("unknown");
+
+        private final String jmodDir;
+
+        Section(String jmodDir) {
+            this.jmodDir = jmodDir;
+        }
+
+        String jmodDir() { return jmodDir; }
+    }
+
+    static class ClassPathConverter implements ValueConverter<Path> {
+        static final ValueConverter<Path> INSTANCE = new ClassPathConverter();
+
+        private static final Path CWD = Paths.get("");
+
+        @Override
+        public Path convert(String value) {
+            try {
+                Path path = CWD.resolve(value);
+                if (Files.notExists(path))
+                    throw new CommandException("err.path.not.found", path);
+                if (! (Files.isDirectory(path) ||
+                       (Files.isRegularFile(path) && path.toString().endsWith(".jar"))))
+                    throw new CommandException("err.invalid.class.path.entry", path);
+                return path;
+            } catch (InvalidPathException x) {
+                throw new CommandException("err.path.not.valid", value);
+            }
+        }
+
+        @Override  public Class<Path> valueType() { return Path.class; }
+
+        @Override  public String valuePattern() { return "path"; }
+    }
+
+    static class DirPathConverter implements ValueConverter<Path> {
+        static final ValueConverter<Path> INSTANCE = new DirPathConverter();
+
+        private static final Path CWD = Paths.get("");
+
+        @Override
+        public Path convert(String value) {
+            try {
+                Path path = CWD.resolve(value);
+                if (Files.notExists(path))
+                    throw new CommandException("err.path.not.found", path);
+                if (!Files.isDirectory(path))
+                    throw new CommandException("err.path.not.a.dir", path);
+                return path;
+            } catch (InvalidPathException x) {
+                throw new CommandException("err.path.not.valid", value);
+            }
+        }
+
+        @Override  public Class<Path> valueType() { return Path.class; }
+
+        @Override  public String valuePattern() { return "path"; }
+    }
+
+    static class ModuleVersionConverter implements ValueConverter<Version> {
+        @Override
+        public Version convert(String value) {
+            try {
+                return Version.parse(value);
+            } catch (IllegalArgumentException x) {
+                throw new CommandException("err.invalid.version", x.getMessage());
+            }
+        }
+
+        @Override public Class<Version> valueType() { return Version.class; }
+
+        @Override public String valuePattern() { return "module-version"; }
+    }
+
+    static class PatternConverter implements ValueConverter<Pattern> {
+        @Override
+        public Pattern convert(String value) {
+            try {
+                return Pattern.compile(value);
+            } catch (PatternSyntaxException e) {
+                throw new CommandException("err.bad.pattern", value);
+            }
+        }
+
+        @Override public Class<Pattern> valueType() { return Pattern.class; }
+
+        @Override public String valuePattern() { return "pattern"; }
+    }
+
+    static class GlobConverter implements ValueConverter<PathMatcher> {
+        @Override
+        public PathMatcher convert(String pattern) {
+            try {
+                return FileSystems.getDefault()
+                                  .getPathMatcher("glob:" + pattern);
+            } catch (PatternSyntaxException e) {
+                throw new CommandException("err.bad.pattern", pattern);
+            }
+        }
+
+        @Override public Class<PathMatcher> valueType() { return PathMatcher.class; }
+
+        @Override public String valuePattern() { return "pattern"; }
+    }
+
+    /* Support for @<file> in jmod help */
+    private static final String CMD_FILENAME = "@<filename>";
+
+    /**
+     * This formatter is adding the @filename option and does the required
+     * formatting.
+     */
+    private static final class JmodHelpFormatter extends BuiltinHelpFormatter {
+
+        private JmodHelpFormatter() { super(80, 2); }
+
+        @Override
+        public String format(Map<String, ? extends OptionDescriptor> options) {
+            Map<String, OptionDescriptor> all = new HashMap<>();
+            all.putAll(options);
+            all.put(CMD_FILENAME, new OptionDescriptor() {
+                @Override
+                public Collection<String> options() {
+                    List<String> ret = new ArrayList<>();
+                    ret.add(CMD_FILENAME);
+                    return ret;
+                }
+                @Override
+                public String description() { return getMessage("main.opt.cmdfile"); }
+                @Override
+                public List<?> defaultValues() { return Collections.emptyList(); }
+                @Override
+                public boolean isRequired() { return false; }
+                @Override
+                public boolean acceptsArguments() { return false; }
+                @Override
+                public boolean requiresArgument() { return false; }
+                @Override
+                public String argumentDescription() { return null; }
+                @Override
+                public String argumentTypeIndicator() { return null; }
+                @Override
+                public boolean representsNonOptions() { return false; }
+            });
+            String content = super.format(all);
+            StringBuilder builder = new StringBuilder();
+
+            builder.append("\n").append(" Main operation modes:\n  ");
+            builder.append(getMessage("main.opt.mode.create")).append("\n  ");
+            builder.append(getMessage("main.opt.mode.list")).append("\n  ");
+            builder.append(getMessage("main.opt.mode.describe")).append("\n\n");
+
+            String cmdfile = null;
+            String[] lines = content.split("\n");
+            for (String line : lines) {
+                if (line.startsWith("--@")) {
+                    cmdfile = line.replace("--" + CMD_FILENAME, CMD_FILENAME + "  ");
+                } else if (line.startsWith("Option") || line.startsWith("------")) {
+                    builder.append(" ").append(line).append("\n");
+                } else if (!line.matches("Non-option arguments")){
+                    builder.append("  ").append(line).append("\n");
+                }
+            }
+            if (cmdfile != null) {
+                builder.append("  ").append(cmdfile).append("\n");
+            }
+            return builder.toString();
+        }
+    }
+
+    private final OptionParser parser = new OptionParser();
+
+    private void handleOptions(String[] args) {
+        parser.formatHelpWith(new JmodHelpFormatter());
+
+        OptionSpec<Path> classPath
+                = parser.accepts("class-path", getMessage("main.opt.class-path"))
+                        .withRequiredArg()
+                        .withValuesSeparatedBy(File.pathSeparatorChar)
+                        .withValuesConvertedBy(ClassPathConverter.INSTANCE);
+
+        OptionSpec<Path> cmds
+                = parser.accepts("cmds", getMessage("main.opt.cmds"))
+                        .withRequiredArg()
+                        .withValuesSeparatedBy(File.pathSeparatorChar)
+                        .withValuesConvertedBy(DirPathConverter.INSTANCE);
+
+        OptionSpec<Path> config
+                = parser.accepts("config", getMessage("main.opt.config"))
+                        .withRequiredArg()
+                        .withValuesSeparatedBy(File.pathSeparatorChar)
+                        .withValuesConvertedBy(DirPathConverter.INSTANCE);
+
+        OptionSpec<PathMatcher> excludes
+                = parser.accepts("exclude", getMessage("main.opt.exclude"))
+                        .withRequiredArg()
+                        .withValuesConvertedBy(new GlobConverter());
+
+        OptionSpec<Pattern> hashDependencies
+                = parser.accepts("hash-dependencies", getMessage("main.opt.hash-dependencies"))
+                        .withRequiredArg()
+                        .withValuesConvertedBy(new PatternConverter());
+
+        OptionSpec<Void> help
+                = parser.accepts("help", getMessage("main.opt.help"))
+                        .forHelp();
+
+        OptionSpec<Path> libs
+                = parser.accepts("libs", getMessage("main.opt.libs"))
+                        .withRequiredArg()
+                        .withValuesSeparatedBy(File.pathSeparatorChar)
+                        .withValuesConvertedBy(DirPathConverter.INSTANCE);
+
+        OptionSpec<String> mainClass
+                = parser.accepts("main-class", getMessage("main.opt.main-class"))
+                        .withRequiredArg()
+                        .describedAs(getMessage("main.opt.main-class.arg"));
+
+        OptionSpec<Path> modulePath  // TODO: short version of --mp ??
+                = parser.acceptsAll(Arrays.asList("mp", "modulepath"),
+                                    getMessage("main.opt.modulepath"))
+                        .withRequiredArg()
+                        .withValuesSeparatedBy(File.pathSeparatorChar)
+                        .withValuesConvertedBy(DirPathConverter.INSTANCE);
+
+        OptionSpec<Version> moduleVersion
+                = parser.accepts("module-version", getMessage("main.opt.module-version"))
+                        .withRequiredArg()
+                        .withValuesConvertedBy(new ModuleVersionConverter());
+
+        OptionSpec<String> osName
+                = parser.accepts("os-name", getMessage("main.opt.os-name"))
+                        .withRequiredArg()
+                        .describedAs(getMessage("main.opt.os-name.arg"));
+
+        OptionSpec<String> osArch
+                = parser.accepts("os-arch", getMessage("main.opt.os-arch"))
+                        .withRequiredArg()
+                        .describedAs(getMessage("main.opt.os-arch.arg"));
+
+        OptionSpec<String> osVersion
+                = parser.accepts("os-version", getMessage("main.opt.os-version"))
+                        .withRequiredArg()
+                        .describedAs(getMessage("main.opt.os-version.arg"));
+
+        OptionSpec<Void> version
+                = parser.accepts("version", getMessage("main.opt.version"));
+
+        NonOptionArgumentSpec<String> nonOptions
+                = parser.nonOptions();
+
+        try {
+            OptionSet opts = parser.parse(args);
+
+            if (opts.has(help) || opts.has(version)) {
+                options = new Options();
+                options.help = opts.has(help);
+                options.version = opts.has(version);
+                return;  // informational message will be shown
+            }
+
+            List<String> words = opts.valuesOf(nonOptions);
+            if (words.isEmpty())
+                throw new CommandException("err.missing.mode").showUsage(true);
+            String verb = words.get(0);
+            options = new Options();
+            try {
+                options.mode = Enum.valueOf(Mode.class, verb.toUpperCase());
+            } catch (IllegalArgumentException e) {
+                throw new CommandException("err.invalid.mode", verb).showUsage(true);
+            }
+
+            if (opts.has(classPath))
+                options.classpath = opts.valuesOf(classPath);
+            if (opts.has(cmds))
+                options.cmds = opts.valuesOf(cmds);
+            if (opts.has(config))
+                options.configs = opts.valuesOf(config);
+            if (opts.has(excludes))
+                options.excludes = opts.valuesOf(excludes);
+            if (opts.has(libs))
+                options.libs = opts.valuesOf(libs);
+            if (opts.has(modulePath)) {
+                Path[] dirs = opts.valuesOf(modulePath).toArray(new Path[0]);
+                options.moduleFinder = ModuleFinder.of(dirs);
+                if (options.moduleFinder instanceof ConfigurableModuleFinder)
+                    ((ConfigurableModuleFinder)options.moduleFinder).configurePhase(Phase.LINK_TIME);
+            }
+            if (opts.has(moduleVersion))
+                options.moduleVersion = opts.valueOf(moduleVersion);
+            if (opts.has(mainClass))
+                options.mainClass = opts.valueOf(mainClass);
+            if (opts.has(osName))
+                options.osName = opts.valueOf(osName);
+            if (opts.has(osArch))
+                options.osArch = opts.valueOf(osArch);
+            if (opts.has(osVersion))
+                options.osVersion = opts.valueOf(osVersion);
+            if (opts.has(hashDependencies)) {
+                options.dependenciesToHash = opts.valueOf(hashDependencies);
+                // if storing hashes of dependencies then the module path is required
+                if (options.moduleFinder == null)
+                    throw new CommandException("err.modulepath.must.be.specified").showUsage(true);
+            }
+
+            if (words.size() <= 1)
+                throw new CommandException("err.jmod.must.be.specified").showUsage(true);
+            Path path = Paths.get(words.get(1));
+            if (options.mode.equals(Mode.CREATE) && Files.exists(path))
+                throw new CommandException("err.file.already.exists", path);
+            else if ((options.mode.equals(Mode.LIST) ||
+                          options.mode.equals(Mode.DESCRIBE))
+                      && Files.notExists(path))
+                throw new CommandException("err.jmod.not.found", path);
+            options.jmodFile = path;
+
+            if (words.size() > 2)
+                throw new CommandException("err.unknown.option",
+                        words.subList(2, words.size())).showUsage(true);
+
+            if (options.mode.equals(Mode.CREATE) && options.classpath == null)
+                throw new CommandException("err.classpath.must.be.specified").showUsage(true);
+            if (options.mainClass != null && !isValidJavaIdentifier(options.mainClass))
+                throw new CommandException("err.invalid.main-class", options.mainClass);
+        } catch (OptionException e) {
+             throw new CommandException(e.getMessage());
+        }
+    }
+
+    /**
+     * Returns true if, and only if, the given main class is a legal.
+     */
+    static boolean isValidJavaIdentifier(String mainClass) {
+        if (mainClass.length() == 0)
+            return false;
+
+        if (!Character.isJavaIdentifierStart(mainClass.charAt(0)))
+            return false;
+
+        int n = mainClass.length();
+        for (int i=1; i < n; i++) {
+            char c = mainClass.charAt(i);
+            if (!Character.isJavaIdentifierPart(c) && c != '.')
+                return false;
+        }
+        if (mainClass.charAt(n-1) == '.')
+            return false;
+
+        return true;
+    }
+
+    private void reportError(String message) {
+        out.println(getMessage("error.prefix") + " " + message);
+    }
+
+    private void warning(String key, Object... args) {
+        out.println(getMessage("warn.prefix") + " " + getMessage(key, args));
+    }
+
+    private void showUsageSummary() {
+        out.println(getMessage("main.usage.summary", PROGNAME));
+    }
+
+    private void showHelp() {
+        out.println(getMessage("main.usage", PROGNAME));
+        try {
+            parser.printHelpOn(out);
+        } catch (IOException x) {
+            throw new AssertionError(x);
+        }
+    }
+
+    private void showVersion() {
+        out.println(version());
+    }
+
+    private String version() {
+        return System.getProperty("java.version");
+    }
+
+    private static String getMessage(String key, Object... args) {
+        try {
+            return MessageFormat.format(ResourceBundleHelper.bundle.getString(key), args);
+        } catch (MissingResourceException e) {
+            throw new InternalError("Missing message: " + key);
+        }
+    }
+
+    private static class ResourceBundleHelper {
+        static final ResourceBundle bundle;
+
+        static {
+            Locale locale = Locale.getDefault();
+            try {
+                bundle = ResourceBundle.getBundle("jdk.tools.jmod.resources.jmod", locale);
+            } catch (MissingResourceException e) {
+                throw new InternalError("Cannot find jmod resource bundle for locale " + locale);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jmod/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jmod;
+
+import java.io.*;
+
+public class Main {
+    public static void main(String... args) throws Exception {
+        JmodTask t = new JmodTask();
+        int rc = t.run(args);
+        System.exit(rc);
+    }
+
+    /**
+     * Entry point that does <i>not</i> call System.exit.
+     *
+     * @param args command line arguments
+     * @param out output stream
+     * @return an exit code. 0 means success, non-zero means an error occurred.
+     */
+    public static int run(String[] args, PrintStream out) {
+        JmodTask t = new JmodTask();
+        t.setLog(out);
+        return t.run(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jmod/resources/jmod.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,58 @@
+main.usage.summary=\
+Usage: {0} (create|list|describe) <OPTIONS> <jmod-file>\n\
+use --help for a list of possible options
+
+main.usage=\
+Usage: {0} (create|list|describe) <OPTIONS> <jmod-file>
+
+error.prefix=Error:
+warn.prefix=Warning:
+
+main.opt.mode.create=\
+\create    - Creates a new jmod archive
+main.opt.mode.list=\
+\list      - Prints the names of all the entries
+main.opt.mode.describe=\
+\describe  - Prints the module details
+
+main.opt.help=Print this usage message
+main.opt.version=Version information
+main.opt.class-path=Application jar files|dir containing classes
+main.opt.libs=Location of native libraries
+main.opt.cmds=Location of native commands
+main.opt.config=Location of user-editable config files
+main.opt.exclude=Exclude files, given as a PATTERN
+main.opt.module-version= Module version
+main.opt.modulepath=Module path
+main.opt.main-class=Main class
+main.opt.main-class.arg=class-name
+main.opt.os-name=Operating system name
+main.opt.os-name.arg=os-name
+main.opt.os-arch=Operating system architecture
+main.opt.os-arch.arg=os-arch
+main.opt.os-version=Operating system version
+main.opt.os-version.arg=os-version
+main.opt.hash-dependencies=Compute and record hashes of dependencies matched by the pattern
+main.opt.cmdfile=Read options from the specified file
+
+err.missing.mode=one of create, list, or describe must be specified
+err.invalid.mode=mode must be one of create, list, or describe: {0}
+err.classpath.must.be.specified=--class-path must be specified
+err.jmod.must.be.specified=jmod-file must be specified
+err.invalid.version=invalid module version {0}
+err.output.must.be.specified:--output must be specified
+err.mods.must.be.specified:--mods must be specified
+err.modulepath.must.be.specified:--module-path must be specified when hashing dependencies
+err.invalid.main-class:invalid main-class name: {0}
+err.path.not.found=path not found: {0}
+err.path.not.valid=invalid path: {0}
+err.path.not.a.dir=path must be a directory: {0}
+err.invalid.class.path.entry=invalid class path entry: {0}
+err.file.already.exists=file already exists: {0}
+err.jmod.not.found=no jmod file found: {0}
+err.bad.pattern=bad pattern {0}
+err.unknown.option=unknown option(s): {0}
+err.missing.arg=no value given for {0}
+err.internal.error=internal error: {0} {1} {2}
+err.module.descriptor.not.found=Module descriptor not found
+warn.invalid.arg=Invalid classname or pathname not exist: {0}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.jlink {
+    exports jdk.tools.jlink;
+    exports jdk.tools.jlink.plugin;
+    exports jdk.tools.jlink.builder;
+
+    requires jdk.internal.opt;
+    requires jdk.jdeps;
+
+    uses jdk.tools.jlink.plugin.TransformerPlugin;
+    uses jdk.tools.jlink.plugin.PostProcessorPlugin;
+
+    provides jdk.tools.jlink.plugin.TransformerPlugin with jdk.tools.jlink.internal.plugins.FileCopierPlugin;
+    provides jdk.tools.jlink.plugin.TransformerPlugin with jdk.tools.jlink.internal.plugins.StripDebugPlugin;
+    provides jdk.tools.jlink.plugin.TransformerPlugin with jdk.tools.jlink.internal.plugins.ExcludePlugin;
+    provides jdk.tools.jlink.plugin.TransformerPlugin with jdk.tools.jlink.internal.plugins.ExcludeFilesPlugin;
+    provides jdk.tools.jlink.plugin.TransformerPlugin with jdk.tools.jlink.internal.plugins.SystemModuleDescriptorPlugin;
+    provides jdk.tools.jlink.plugin.TransformerPlugin with jdk.tools.jlink.internal.plugins.StripNativeCommandsPlugin;
+    provides jdk.tools.jlink.plugin.TransformerPlugin with jdk.tools.jlink.internal.plugins.SortResourcesPlugin;
+    provides jdk.tools.jlink.plugin.TransformerPlugin with jdk.tools.jlink.internal.plugins.DefaultCompressPlugin;
+    provides jdk.tools.jlink.plugin.TransformerPlugin with jdk.tools.jlink.internal.plugins.OptimizationPlugin;
+    provides jdk.tools.jlink.plugin.TransformerPlugin with jdk.tools.jlink.internal.plugins.ExcludeVMPlugin;
+    provides jdk.tools.jlink.plugin.TransformerPlugin with jdk.tools.jlink.internal.plugins.IncludeLocalesPlugin;
+    provides jdk.tools.jlink.plugin.PostProcessorPlugin with jdk.tools.jlink.internal.plugins.ReleaseInfoPlugin;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jsobject/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.jsobject {
+    requires java.desktop;
+    exports netscape.javascript;
+
+    uses jdk.internal.netscape.javascript.spi.JSObjectProvider;
+}
--- a/src/jdk.jvmstat.rmi/share/classes/META-INF/services/sun.jvmstat.monitor.MonitoredHostService	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-sun.jvmstat.perfdata.monitor.protocol.rmi.MonitoredHostRmiService
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jvmstat.rmi/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.jvmstat.rmi {
+    requires java.rmi;
+    requires jdk.jvmstat;
+
+    // RMI needs to serialize types in this package
+    exports sun.jvmstat.monitor.remote to java.rmi;
+
+    provides sun.jvmstat.monitor.MonitoredHostService with sun.jvmstat.perfdata.monitor.protocol.rmi.MonitoredHostRmiService;
+}
+
--- a/src/jdk.jvmstat/share/classes/META-INF/services/sun.jvmstat.monitor.MonitoredHostService	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-sun.jvmstat.perfdata.monitor.protocol.file.MonitoredHostFileService
-sun.jvmstat.perfdata.monitor.protocol.local.MonitoredHostLocalService
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jvmstat/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.jvmstat {
+    exports sun.jvmstat.monitor to
+        jdk.attach,
+        jdk.jcmd,
+        jdk.jconsole,
+        jdk.jvmstat.rmi;
+    exports sun.jvmstat.monitor.event to
+        jdk.jcmd,
+        jdk.jvmstat.rmi;
+    exports sun.jvmstat.perfdata.monitor to
+        jdk.jvmstat.rmi;
+
+    uses sun.jvmstat.monitor.MonitoredHostService;
+    provides sun.jvmstat.monitor.MonitoredHostService with sun.jvmstat.perfdata.monitor.protocol.file.MonitoredHostFileService;
+    provides sun.jvmstat.monitor.MonitoredHostService with sun.jvmstat.perfdata.monitor.protocol.local.MonitoredHostLocalService;
+}
+
--- a/src/jdk.localedata/share/classes/META-INF/services/sun.util.locale.provider.LocaleDataMetaInfo	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-sun.util.resources.provider.NonBaseLocaleDataMetaInfo
-sun.util.resources.cldr.provider.CLDRLocaleDataMetaInfo
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.localedata/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.localedata {
+    provides sun.util.locale.provider.LocaleDataMetaInfo with
+        sun.util.resources.cldr.provider.CLDRLocaleDataMetaInfo;
+    provides sun.util.locale.provider.LocaleDataMetaInfo with
+        sun.util.resources.provider.NonBaseLocaleDataMetaInfo;
+    provides sun.util.resources.LocaleData.CommonResourceBundleProvider with
+        sun.util.resources.provider.LocaleDataProvider;
+    provides sun.util.resources.LocaleData.SupplementaryResourceBundleProvider with
+        sun.util.resources.provider.SupplementaryLocaleDataProvider;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.localedata/share/classes/sun/util/resources/provider/LocaleDataProvider.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.util.resources.provider;
+
+import java.lang.reflect.Module;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import sun.util.locale.provider.ResourceBundleProviderSupport;
+import sun.util.resources.LocaleData;
+
+/**
+ * {@code LocaleDataProvider} in module jdk.localedata implements
+ * {@code LocaleDataBundleProvider} in module java.base. This class works as a
+ * service agent between {@code ResourceBundle.getBundle} callers in java.base
+ * and resource bundles in jdk.localedata.
+ */
+public class LocaleDataProvider extends LocaleData.CommonResourceBundleProvider {
+    @Override
+    protected boolean isSupportedInModule(String baseName, Locale locale) {
+        // The assumption here is that there are two modules containing
+        // resource bundles for locale support. If resource bundles are split
+        // into more modules, this method will need to be changed to determine
+        // what locales are exactly supported.
+        return !super.isSupportedInModule(baseName, locale);
+    }
+
+    @Override
+    public ResourceBundle getBundle(String baseName, Locale locale) {
+        if (isSupportedInModule(baseName, locale)) {
+            Module module = LocaleDataProvider.class.getModule();
+            String bundleName = toBundleName(baseName, locale);
+            return ResourceBundleProviderSupport.loadResourceBundle(module, bundleName);
+        }
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.localedata/share/classes/sun/util/resources/provider/SupplementaryLocaleDataProvider.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.util.resources.provider;
+
+import java.lang.reflect.Module;
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+import sun.util.locale.provider.ResourceBundleProviderSupport;
+import sun.util.resources.LocaleData;
+
+/**
+ * {@code SupplementaryLocaleDataProvider} in module jdk.localedata implements
+ * {@code JavaTimeSupplementaryProvider} in module java.base. This class works as a
+ * service agent between {@code ResourceBundle.getBundle} callers in java.base
+ * and resource bundles in jdk.localedata.
+ */
+public class SupplementaryLocaleDataProvider extends LocaleData.SupplementaryResourceBundleProvider {
+    @Override
+    protected boolean isSupportedInModule(String baseName, Locale locale) {
+        // The assumption here is that there are two modules containing
+        // resource bundles for locale support. If resource bundles are split
+        // into more modules, this method will need to be changed to determine
+        // what locales are exactly supported.
+        return !super.isSupportedInModule(baseName, locale);
+    }
+
+    @Override
+    public ResourceBundle getBundle(String baseName, Locale locale) {
+        Module module = LocaleDataProvider.class.getModule();
+        String bundleName = toBundleName(baseName, locale);
+        return ResourceBundleProviderSupport.loadResourceBundle(module, bundleName);
+    }
+}
--- a/src/jdk.management/share/classes/META-INF/services/sun.management.spi.PlatformMBeanProvider	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-#
-# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.  Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-com.sun.management.internal.PlatformMBeanProviderImpl
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.management/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.management {
+    requires public java.management;
+
+    exports com.sun.management;
+
+    provides sun.management.spi.PlatformMBeanProvider with
+        com.sun.management.internal.PlatformMBeanProviderImpl;
+}
+
--- a/src/jdk.naming.dns/share/classes/META-INF/services/sun.net.spi.nameservice.NameServiceDescriptor	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-# dns service provider descriptor
-sun.net.spi.nameservice.dns.DNSNameServiceDescriptor
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.naming.dns/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.naming.dns {
+    requires java.naming;
+
+    exports com.sun.jndi.url.dns to
+        java.naming;
+
+    provides javax.naming.spi.InitialContextFactory
+        with com.sun.jndi.dns.DnsContextFactory;
+    provides sun.net.spi.nameservice.NameServiceDescriptor
+        with sun.net.spi.nameservice.dns.DNSNameServiceDescriptor;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.naming.rmi/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.naming.rmi {
+    requires java.naming;
+    requires java.rmi;
+    provides javax.naming.spi.InitialContextFactory
+        with com.sun.jndi.rmi.registry.RegistryContextFactory;
+
+    // temporary export until NamingManager.getURLContext uses services
+    exports com.sun.jndi.url.rmi to java.naming;
+    exports com.sun.jndi.rmi.registry to java.rmi;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.pack200/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.pack200 {
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.policytool/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.policytool {
+    requires java.desktop;
+    requires java.logging;
+    requires java.management;
+    requires java.sql;
+    requires java.security.jgss;
+    requires jdk.security.jgss;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.rmic/share/classes/jdk/rmi/rmic/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.rmi.rmic;
+
+/**
+ * The initial class for the rmic tool.
+ */
+
+public class Main {
+    public static void main(String[] args) {
+        sun.rmi.rmic.Main.main(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.rmic/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.rmic {
+    requires java.corba;
+    requires jdk.compiler;
+    requires jdk.javadoc;
+    exports jdk.rmi.rmic;
+}
+
--- a/src/jdk.rmic/share/classes/sun/rmi/rmic/BatchEnvironment.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/jdk.rmic/share/classes/sun/rmi/rmic/BatchEnvironment.java	Thu Mar 17 19:04:16 2016 +0000
@@ -382,8 +382,7 @@
                 /* File is an ordinay file  */
                 String arcname = file.toLowerCase();
                 if (! (arcname.endsWith(".zip") ||
-                       arcname.endsWith(".jar") ||
-                       arcname.endsWith(".jimage"))) {
+                       arcname.endsWith(".jar"))) {
                     /* File name don't have right extension */
 //                      if (warn)
 //                          log.warning(Position.NOPOS,
--- a/src/jdk.rmic/share/classes/sun/tools/java/ClassPath.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/jdk.rmic/share/classes/sun/tools/java/ClassPath.java	Thu Mar 17 19:04:16 2016 +0000
@@ -41,6 +41,7 @@
 import java.nio.file.FileSystem;
 import java.nio.file.FileSystems;
 import java.nio.file.Path;
+import java.nio.file.ProviderNotFoundException;
 import java.nio.file.spi.FileSystemProvider;
 
 /**
@@ -53,7 +54,6 @@
  */
 public
 class ClassPath {
-    private static final String JIMAGE_EXT = ".jimage";
     private FileSystem getJrtFileSystem() {
         return FileSystems.getFileSystem(URI.create("jrt:/"));
     }
@@ -98,10 +98,14 @@
      * order.
      */
     public ClassPath() {
+        // though this property is removed. Check for null and use only
+        // if it is not null (when bootstrap JDK is used).
         String syscp = System.getProperty("sun.boot.class.path");
         String envcp = System.getProperty("env.class.path");
         if (envcp == null) envcp = ".";
-        String cp = syscp + File.pathSeparator + envcp;
+
+        // add syscp only if not null!
+        String cp = syscp == null? envcp : (syscp + File.pathSeparator + envcp);
         init(cp);
     }
 
@@ -121,8 +125,8 @@
         }
         // Build the class path
         ClassPathEntry[] path = new ClassPathEntry[n+1];
+
         int len = pathstr.length();
-        boolean jrtAdded = false;
         for (i = n = 0; i < len; i = j + 1) {
             if ((j = pathstr.indexOf(dirSeparator, i)) == -1) {
                 j = len;
@@ -133,25 +137,27 @@
                 String filename = pathstr.substring(i, j);
                 File file = new File(filename);
                 if (file.isFile()) {
-                    if (filename.endsWith(JIMAGE_EXT)) {
-                        if (jrtAdded) continue;
-                        FileSystem fs = getJrtFileSystem();
-                        path[n++] = new JrtClassPathEntry(fs);
-                        jrtAdded = true;
-                    } else {
-                        try {
-                            ZipFile zip = new ZipFile(file);
-                            path[n++] = new ZipClassPathEntry(zip);
-                        } catch (ZipException e) {
-                        } catch (IOException e) {
-                            // Ignore exceptions, at least for now...
-                        }
+                    try {
+                        ZipFile zip = new ZipFile(file);
+                        path[n++] = new ZipClassPathEntry(zip);
+                    } catch (ZipException e) {
+                    } catch (IOException e) {
+                        // Ignore exceptions, at least for now...
                     }
                 } else {
                     path[n++] = new DirClassPathEntry(file);
                 }
             }
         }
+
+        // add jrt file system at the end
+        try {
+            FileSystem fs = getJrtFileSystem();
+            path[n++] = new JrtClassPathEntry(fs);
+        } catch (ProviderNotFoundException ignored) {
+            // this could happen during jdk build with earlier JDK as bootstrap
+        }
+
         // Trim class path to exact size
         this.path = new ClassPathEntry[n];
         System.arraycopy((Object)path, 0, (Object)this.path, 0, n);
@@ -171,30 +177,31 @@
         }
 
         // Build the class path
-        ClassPathEntry[] path = new ClassPathEntry[patharray.length];
+        ClassPathEntry[] path = new ClassPathEntry[patharray.length + 1];
         int n = 0;
-        boolean jrtAdded = false;
         for (String name : patharray) {
             File file = new File(name);
             if (file.isFile()) {
-                if (name.endsWith(JIMAGE_EXT)) {
-                    if (jrtAdded) continue;
-                    FileSystem fs = getJrtFileSystem();
-                    path[n++] = new JrtClassPathEntry(fs);
-                    jrtAdded = true;
-                } else {
-                    try {
-                        ZipFile zip = new ZipFile(file);
-                        path[n++] = new ZipClassPathEntry(zip);
-                    } catch (ZipException e) {
-                    } catch (IOException e) {
-                        // Ignore exceptions, at least for now...
-                    }
-               }
+                try {
+                    ZipFile zip = new ZipFile(file);
+                    path[n++] = new ZipClassPathEntry(zip);
+                } catch (ZipException e) {
+                } catch (IOException e) {
+                    // Ignore exceptions, at least for now...
+                }
             } else {
                 path[n++] = new DirClassPathEntry(file);
             }
         }
+
+        // add jrt file system at the end
+        try {
+            FileSystem fs = getJrtFileSystem();
+            path[n++] = new JrtClassPathEntry(fs);
+        } catch (ProviderNotFoundException ignored) {
+            // this could happen with earlier version of JDK used as bootstrap
+        }
+
         // Trim class path to exact size
         this.path = new ClassPathEntry[n];
         System.arraycopy((Object)path, 0, (Object)this.path, 0, n);
@@ -383,28 +390,12 @@
 // a ClassPathEntry that represents jrt file system
 final class JrtClassPathEntry extends ClassPathEntry {
     private final FileSystem fs;
-    // module directory paths in jrt fs
-    private final Set<Path> jrtModules;
     // package name to package directory path mapping (lazily filled)
     private final Map<String, Path> pkgDirs;
 
     JrtClassPathEntry(FileSystem fs) {
         this.fs = fs;
-        this.jrtModules = new LinkedHashSet<>();
         this.pkgDirs = new HashMap<>();
-
-        // fill in module directories at the root dir
-        Path root = fs.getPath("/modules");
-        try {
-            try (DirectoryStream<Path> stream = Files.newDirectoryStream(root)) {
-                for (Path entry: stream) {
-                    if (Files.isDirectory(entry))
-                        jrtModules.add(entry);
-                }
-            }
-        } catch (IOException ioExp) {
-            throw new UncheckedIOException(ioExp);
-        }
     }
 
     void close() throws IOException {
@@ -417,17 +408,31 @@
             return pkgDirs.get(pkgName);
         }
 
-        for (Path modPath : jrtModules) {
-            Path pkgDir = fs.getPath(modPath.toString(), pkgName);
-            // check if package directory is under any of the known modules
-            if (Files.exists(pkgDir)) {
-                // it is a package directory only if contains atleast one .class file
-                try (DirectoryStream<Path> stream = Files.newDirectoryStream(pkgDir)) {
-                    for (Path p : stream) {
-                        if (Files.isRegularFile(p) && p.toString().endsWith(".class")) {
-                            // cache package-to-package dir mapping for future
-                            pkgDirs.put(pkgName, pkgDir);
-                            return pkgDir;
+        Path pkgLink = fs.getPath("/packages/" + pkgName.replace('/', '.'));
+        // check if /packages/$PACKAGE directory exists
+        if (Files.isDirectory(pkgLink)) {
+           try (DirectoryStream<Path> stream = Files.newDirectoryStream(pkgLink)) {
+                for (Path p : stream) {
+                    // find first symbolic link to module directory
+                    if (Files.isSymbolicLink(p)) {
+                        Path modDir = Files.readSymbolicLink(p);
+                        if (Files.isDirectory(modDir)) {
+                            // get package subdirectory under /modules/$MODULE/
+                            Path pkgDir = fs.getPath(modDir.toString() + "/" + pkgName);
+                            if (Files.isDirectory(pkgDir)) {
+                                // it is a package directory only if contains
+                                // at least one .class file
+                                try (DirectoryStream<Path> pstream =
+                                        Files.newDirectoryStream(pkgDir)) {
+                                    for (Path f : pstream) {
+                                        if (Files.isRegularFile(f)
+                                                && f.toString().endsWith(".class")) {
+                                            pkgDirs.put(pkgName, pkgDir);
+                                            return pkgDir;
+                                        }
+                                    }
+                                }
+                            }
                         }
                     }
                 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.sctp/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.sctp {
+    exports com.sun.nio.sctp;
+}
+
--- a/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisNumericGroupPrincipal.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisNumericGroupPrincipal.java	Thu Mar 17 19:04:16 2016 +0000
@@ -57,7 +57,8 @@
           (new java.security.PrivilegedAction<java.util.ResourceBundle>() {
               public java.util.ResourceBundle run() {
                   return (java.util.ResourceBundle.getBundle
-                                ("sun.security.util.AuthResources"));
+                                ("sun.security.util.AuthResources",
+                                sun.security.util.ResourcesMgr.class.getModule()));
               }
           });
 
--- a/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisNumericUserPrincipal.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisNumericUserPrincipal.java	Thu Mar 17 19:04:16 2016 +0000
@@ -56,7 +56,8 @@
           (new java.security.PrivilegedAction<java.util.ResourceBundle>() {
               public java.util.ResourceBundle run() {
                   return (java.util.ResourceBundle.getBundle
-                                ("sun.security.util.AuthResources"));
+                                ("sun.security.util.AuthResources",
+                                 sun.security.util.ResourcesMgr.class.getModule()));
               }
            });
 
--- a/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisPrincipal.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisPrincipal.java	Thu Mar 17 19:04:16 2016 +0000
@@ -54,7 +54,8 @@
           (new java.security.PrivilegedAction<java.util.ResourceBundle>() {
               public java.util.ResourceBundle run() {
                   return (java.util.ResourceBundle.getBundle
-                                ("sun.security.util.AuthResources"));
+                                ("sun.security.util.AuthResources",
+                                 sun.security.util.ResourcesMgr.class.getModule()));
               }
           });
 
--- a/src/jdk.security.auth/share/classes/com/sun/security/auth/X500Principal.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/jdk.security.auth/share/classes/com/sun/security/auth/X500Principal.java	Thu Mar 17 19:04:16 2016 +0000
@@ -59,7 +59,8 @@
         (new java.security.PrivilegedAction<java.util.ResourceBundle>() {
               public java.util.ResourceBundle run() {
                   return (java.util.ResourceBundle.getBundle
-                                ("sun.security.util.AuthResources"));
+                                ("sun.security.util.AuthResources",
+                                 sun.security.util.ResourcesMgr.class.getModule()));
               }
         });
 
--- a/src/jdk.security.auth/share/classes/com/sun/security/auth/module/JndiLoginModule.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/jdk.security.auth/share/classes/com/sun/security/auth/module/JndiLoginModule.java	Thu Mar 17 19:04:16 2016 +0000
@@ -157,7 +157,8 @@
             new PrivilegedAction<ResourceBundle>() {
                 public ResourceBundle run() {
                     return ResourceBundle.getBundle(
-                            "sun.security.util.AuthResources");
+                            "sun.security.util.AuthResources",
+                            sun.security.util.ResourcesMgr.class.getModule());
                 }
             }
     );
--- a/src/jdk.security.auth/share/classes/com/sun/security/auth/module/KeyStoreLoginModule.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/jdk.security.auth/share/classes/com/sun/security/auth/module/KeyStoreLoginModule.java	Thu Mar 17 19:04:16 2016 +0000
@@ -116,7 +116,8 @@
             new PrivilegedAction<ResourceBundle>() {
                 public ResourceBundle run() {
                     return ResourceBundle.getBundle(
-                            "sun.security.util.AuthResources");
+                            "sun.security.util.AuthResources",
+                            sun.security.util.ResourcesMgr.class.getModule());
                 }
             }
     );
--- a/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java	Thu Mar 17 19:04:16 2016 +0000
@@ -423,7 +423,8 @@
             new PrivilegedAction<ResourceBundle>() {
                 public ResourceBundle run() {
                     return ResourceBundle.getBundle(
-                            "sun.security.util.AuthResources");
+                            "sun.security.util.AuthResources",
+                            sun.security.util.ResourcesMgr.class.getModule());
                 }
             }
     );
--- a/src/jdk.security.auth/share/classes/com/sun/security/auth/module/LdapLoginModule.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/src/jdk.security.auth/share/classes/com/sun/security/auth/module/LdapLoginModule.java	Thu Mar 17 19:04:16 2016 +0000
@@ -310,7 +310,8 @@
             new PrivilegedAction<ResourceBundle>() {
                 public ResourceBundle run() {
                     return ResourceBundle.getBundle(
-                        "sun.security.util.AuthResources");
+                        "sun.security.util.AuthResources",
+                        sun.security.util.ResourcesMgr.class.getModule());
                 }
             }
         );
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.security.auth/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.security.auth {
+    requires public java.naming;
+    requires java.security.jgss;
+
+    exports com.sun.security.auth;
+    exports com.sun.security.auth.callback;
+    exports com.sun.security.auth.login;
+    exports com.sun.security.auth.module;
+    provides javax.security.auth.spi.LoginModule with
+        com.sun.security.auth.module.Krb5LoginModule;
+    provides javax.security.auth.spi.LoginModule with
+        com.sun.security.auth.module.UnixLoginModule;
+    provides javax.security.auth.spi.LoginModule with
+        com.sun.security.auth.module.JndiLoginModule;
+    provides javax.security.auth.spi.LoginModule with
+        com.sun.security.auth.module.KeyStoreLoginModule;
+    provides javax.security.auth.spi.LoginModule with
+        com.sun.security.auth.module.LdapLoginModule;
+    provides javax.security.auth.spi.LoginModule with
+        com.sun.security.auth.module.NTLoginModule;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.security.jgss/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.security.jgss {
+    requires public java.security.jgss;
+    requires java.logging;
+    requires java.security.sasl;
+    exports com.sun.security.jgss;
+    provides java.security.Provider with com.sun.security.sasl.gsskerb.JdkSASL;
+}
+
--- a/src/jdk.zipfs/share/classes/META-INF/services/java.nio.file.spi.FileSystemProvider	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-jdk.nio.zipfs.ZipFileSystemProvider
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.zipfs/share/classes/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.zipfs {
+    provides java.nio.file.spi.FileSystemProvider with jdk.nio.zipfs.ZipFileSystemProvider;
+}
+
--- a/test/Makefile	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/Makefile	Thu Mar 17 19:04:16 2016 +0000
@@ -87,8 +87,8 @@
 
 # Expect JPRT to set PRODUCT_HOME (the product or jdk in this case to test)
 ifndef PRODUCT_HOME
-  # Try to use j2sdk-image if it exists
-  ABS_JDK_IMAGE = $(ABS_PLATFORM_BUILD_ROOT)/images/j2sdk-image
+  # Try to use images/jdk if it exists
+  ABS_JDK_IMAGE = $(ABS_PLATFORM_BUILD_ROOT)/images/jdk
   PRODUCT_HOME :=                       		\
     $(shell                             		\
       if [ -d $(ABS_JDK_IMAGE) ] ; then 		\
@@ -234,7 +234,7 @@
 
 # Expect JT_HOME to be set for jtreg tests. (home for jtreg)
 ifndef JT_HOME
-  JT_HOME = $(SLASH_JAVA)/re/jtreg/4.1/promoted/latest/binaries/jtreg
+  JT_HOME = $(SLASH_JAVA)/re/jtreg/4.2/promoted/latest/binaries/jtreg
   ifdef JPRT_JTREG_HOME
     JT_HOME = $(JPRT_JTREG_HOME)
   endif
--- a/test/ProblemList.txt	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/ProblemList.txt	Thu Mar 17 19:04:16 2016 +0000
@@ -222,6 +222,9 @@
 # 8062724
 java/rmi/activation/Activatable/extLoadedImpl/ext.sh            generic-all
 
+# 8145980
+sun/rmi/rmic/newrmic/equivalence/run.sh                         generic-all
+
 ############################################################################
 
 # jdk_security
@@ -308,6 +311,12 @@
 # 8074580
 sun/security/pkcs11/rsa/TestKeyPairGenerator.java               generic-all
 
+# 8038079
+sun/security/krb5/auto/HttpNegotiateServer.java                 generic-all
+
+# 8130302
+sun/security/tools/keytool/autotest.sh                          generic-all
+
 ############################################################################
 
 # jdk_sound
@@ -341,10 +350,12 @@
 # Tests take too long, on sparcs see 7143279
 # also see 8059906
 tools/pack200/CommandLineTests.java                             generic-all
-tools/pack200/Pack200Test.java                                  solaris-all,macosx-all
 
-# 8007410
-tools/launcher/FXLauncherTest.java                              linux-all
+# 8059906 fails on solaris and macosx, 8151901 
+tools/pack200/Pack200Test.java                                  generic-all
+
+# 8068049 
+tools/launcher/FXLauncherTest.java                              linux-all,macosx-all
 
 ############################################################################
 
@@ -395,8 +406,8 @@
 # 8031482
 sun/tools/jcmd/TestJcmdSanity.java				windows-all
 
-# 8072131
-sun/tools/jmap/heapconfig/JMapHeapConfigTest.java macosx-all
+# 8072131, 8132452
+sun/tools/jmap/heapconfig/JMapHeapConfigTest.java generic-all
 
 # 8046285
 sun/tools/jstatd/TestJstatdExternalRegistry.java                generic-all
@@ -410,11 +421,25 @@
 # 8057732
 sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java    generic-all
 
+# 8059035
+sun/tools/jinfo/JInfoSanityTest.java                           generic-all
+
+# 8151899
+demo/jvmti/compiledMethodLoad/CompiledMethodLoadTest.java       generic-all
+
 ############################################################################
 
 # jdk_other
 
+# 8141370
+com/sun/jndi/ldap/DeadSSLLdapTimeoutTest.java			linux-i586,macosx-all
+
 ############################################################################
 
-# 8141370
-com/sun/jndi/ldap/DeadSSLLdapTimeoutTest.java			linux-i586,macosx-all
+# core_tools
+
+# 8150975
+# tools/jimage/JImageTest.java                                    linux-i586,windows-i586
+
+############################################################################
+
--- a/test/TEST.ROOT	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/TEST.ROOT	Thu Mar 17 19:04:16 2016 +0000
@@ -26,8 +26,8 @@
 # Allow querying of sun.arch.data.model in @requires clauses
 requires.properties=sun.arch.data.model 
 
-# Tests using jtreg 4.1 b12 features
-requiredVersion=4.1 b12
+# Tests using jtreg 4.2 b01 features
+requiredVersion=4.2 b01
 
 # Path to libraries in the topmost test directory. This is needed so @library
 # does not need ../../ notation to reach them
--- a/test/TEST.groups	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/TEST.groups	Thu Mar 17 19:04:16 2016 +0000
@@ -76,6 +76,7 @@
     jdk/lambda \
     jdk/internal/misc \
     jdk/internal/ref \
+    jdk/modules \
     vm
 
 # All of the java.util package
@@ -239,7 +240,6 @@
 #
 core_tools = \
     tools \
-    jdk/internal/jimage \
     jdk/internal/jrtfs \
     sun/tools/java \
     sun/tools/jrunscript
@@ -522,7 +522,6 @@
   java/util/jar/Manifest/CreateManifest.java \
   java/util/logging/TestMainAppContext.java \
   java/util/logging/TestLoggingWithMainAppContext.java \
-  java/util/ResourceBundle/Control/Bug6530694.java \
   java/text/Bidi/BidiConformance.java \
   java/text/Bidi/BidiEmbeddingTest.java \
   java/text/Bidi/Bug7042148.java \
--- a/test/com/sun/jdi/EarlyReturnNegativeTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/com/sun/jdi/EarlyReturnNegativeTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -227,9 +227,7 @@
         String methodName = origMethodName.substring(2);
         ThreadReference tr = event.thread();
 
-        if (vmm.majorInterfaceVersion() >= 1 &&
-            vmm.minorInterfaceVersion() >= 6 &&
-            vm().canForceEarlyReturn()) {
+        if (vm().canForceEarlyReturn()) {
 
             /* There are some incompatible classes of values.  In the following,
              * we test each combination.
--- a/test/com/sun/jdi/EarlyReturnTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/com/sun/jdi/EarlyReturnTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -565,9 +565,7 @@
         String methodName = origMethodName.substring(2);
         ThreadReference tr = event.thread();
 
-        if (vmm.majorInterfaceVersion() >= 1 &&
-            vmm.minorInterfaceVersion() >= 6 &&
-            vm().canForceEarlyReturn()) {
+        if (vm().canForceEarlyReturn()) {
 
             try {
 
@@ -664,9 +662,7 @@
     // This is the MethodExitEvent handler.
     public void methodExited(MethodExitEvent event) {
         String origMethodName = event.method().name();
-        if (vmm.majorInterfaceVersion() >= 1 &&
-            vmm.minorInterfaceVersion() >= 6 &&
-            vm().canGetMethodReturnValues()) {
+        if (vm().canGetMethodReturnValues()) {
             Value retValue = event.returnValue();
 
             if (!origMethodName.startsWith("s_") &&
--- a/test/com/sun/jdi/ImmutableResourceTest.sh	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/com/sun/jdi/ImmutableResourceTest.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -93,18 +93,18 @@
 echo "JDK under test is: $TESTJAVA"
 #
 CP="-classpath ${TESTCLASSES}"
-# Compile the test class using the classpath we need:
 #
 env
 #
 set -vx
 #
-#Compile.  tools.jar is required on the classpath.
-${TESTJAVA}/bin/javac -d "${TESTCLASSES}" ${CP} -g \
-                         "${TESTSRC}"/"${TARGETCLASS}".java
+# Compile test class
+${TESTJAVA}/bin/javac -XaddExports:jdk.jdi/com.sun.tools.example.debug.tty=ALL-UNNAMED \
+   -d "${TESTCLASSES}" ${CP} -g "${TESTSRC}"/"${TARGETCLASS}".java
 #
-#Run the test class, again with the classpath we need:
-${TESTJAVA}/bin/java ${CP} ${TARGETCLASS}
+# Run the test class, again with the classpath we need:
+${TESTJAVA}/bin/java -XaddExports:jdk.jdi/com.sun.tools.example.debug.tty=ALL-UNNAMED \
+    ${CP} ${TARGETCLASS}
 status=$?
 echo "test status was: $status"
 if [ $status -eq "0" ];
--- a/test/com/sun/jdi/MethodExitReturnValuesTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/com/sun/jdi/MethodExitReturnValuesTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -488,9 +488,7 @@
             return;
         }
 
-        if (vmm.majorInterfaceVersion() >= 1 &&
-            vmm.minorInterfaceVersion() >= 6 &&
-            vm().canGetMethodReturnValues()) {
+        if (vm().canGetMethodReturnValues()) {
             Value retValue = event.returnValue();
 
             if ("sin".equals(origMethodName)) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/jdi/ModulesTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ *  @test
+ *  @bug 8049365
+ *  @summary Tests the JDI and JDWP update for modules
+ *
+ *  @modules jdk.jdi
+ *  @run build TestScaffold VMConnection TargetListener TargetAdapter
+ *  @run compile -g ModulesTest.java
+ *  @run driver ModulesTest
+ */
+import com.sun.jdi.*;
+import com.sun.jdi.event.*;
+import com.sun.jdi.request.*;
+
+import java.util.*;
+
+    /********** target program **********/
+
+class ModulesTarg {
+
+    public static void main(String[] args){
+        System.out.println("Goodbye from ModulesTarg!");
+    }
+}
+
+    /********** test program **********/
+
+public class ModulesTest extends TestScaffold {
+    static final String FailPrefix = "ModulesTest: failed: ";
+
+    private static ModuleReference bootUnnamedModule = null;
+    private static ModuleReference appUnnamedModule  = null;
+    private static ModuleReference extUnnamedModule  = null;
+
+    private ReferenceType targetClass;
+    private List<ModuleReference> modules;
+
+
+    ModulesTest (String args[]) {
+        super(args);
+    }
+
+    public static void main(String[] args) throws Exception {
+        new ModulesTest(args).startTests();
+    }
+
+    /********** test core **********/
+
+    private boolean reftypeSanityCheck(ModuleReference module, ReferenceType type) {
+        ModuleReference other = type.module();
+        if (other == null) {
+            testFailed = true;
+            println(FailPrefix + "a ModuleReference should never be null #1");
+            return false;
+        }
+        // Sanity checks: make sure there is no crash or exception
+        String otherName = other.name();
+        boolean cond = module.canRead(other);
+        return true;
+    }
+
+    private void checkLoaderDefinedClasses(ModuleReference module, ClassLoaderReference loader) {
+        String moduleName = module.name();
+        List<ReferenceType> definedClasses = loader.definedClasses();
+        boolean origModuleWasObserved = false;
+
+        for (ReferenceType type: definedClasses) {
+            ClassLoaderReference otherLoader = type.classLoader();
+            if (!loader.equals(otherLoader)) {
+                testFailed = true;
+                println(FailPrefix + "all classes defined by a ClassLoader" +
+                        " should refer to the defining ClassLoader");
+                return;
+            }
+            if (!reftypeSanityCheck(module, type)) {
+                return;
+            }
+        }
+    }
+
+    private void checkLoaderVisibleClasses(ModuleReference module, ClassLoaderReference loader) {
+        String moduleName = module.name();
+        List<ReferenceType> visibleClasses = loader.visibleClasses();
+
+        for (ReferenceType type: visibleClasses) {
+            if (!type.isPrepared()) {
+                continue; // Safety: skip unprepared classes
+            }
+            if (!reftypeSanityCheck(module, type)) {
+                return;
+            }
+        }
+    }
+
+    // Check any ClassLoader except the bootsrtap ClassLoader
+    private void checkClassLoader(ModuleReference module, ClassLoaderReference loader) {
+        checkLoaderDefinedClasses(module, loader);
+        checkLoaderVisibleClasses(module, loader);
+    }
+
+    // Sanity checks to make sure there are no crashes or exceptions.
+    private void checkModule(ModuleReference module, ModuleReference other, int checkIdx) {
+        if (module == null) {
+            testFailed = true;
+            println(FailPrefix + "a ModuleReference should never be null #2");
+            return;
+        }
+        String name = module.name();
+        println("\n--- Check #" + checkIdx);
+        println("    module name: " + name);
+
+        ClassLoaderReference loader = module.classLoader();
+        println("    loader: " + loader);
+
+        if (loader != null) {
+            checkClassLoader(module, loader);
+            String classloaderName = loader.toString();
+            if (classloaderName.contains("AppClassLoader") && name == null) {
+                if (appUnnamedModule != null) {
+                    testFailed = true;
+                    println(FailPrefix + "multiple unnamed modules in AppClassLoader");
+                }
+                appUnnamedModule = module;
+            }
+            if (classloaderName.contains("PlatformClassLoader") && name == null) {
+                if (extUnnamedModule != null) {
+                    testFailed = true;
+                    println(FailPrefix + "multiple unnamed modules in PlatformClassLoader");
+                }
+                extUnnamedModule = module;
+            }
+        } else if (name == null) {
+            if (bootUnnamedModule != null) {
+                testFailed = true;
+                println(FailPrefix + "multiple unnamed modules in BootClassLoader");
+            }
+            bootUnnamedModule = module;
+        }
+        boolean cond = module.canRead(other);
+        println("    can read: " + cond);
+    }
+
+    // Check that the java.lang.String class was loaded by the java.base module.
+    private void checkBaseModule() {
+        List<ReferenceType> clist = vm().classesByName("java.lang.String");
+        if (clist.size() != 1) {
+            testFailed = true;
+            println(FailPrefix + "just one java.lang.String class is expected" +
+                    "but found multiple class instances: " + clist.size());
+            return;
+        }
+        ModuleReference module = clist.get(0).module();
+        if (module == null) {
+            testFailed = true;
+            println(FailPrefix + "a ModuleReference should never be null #3");
+        }
+        if (module.name().compareTo("java.base") != 0) {
+            testFailed = true;
+            println(FailPrefix + "java.lang.String must belong to java.base module");
+        }
+    }
+
+    // Check that the unnamed modules of the bootsrtap, application
+    // and platform class loaders were observed.
+    private void checkUnnamedModules() {
+        if (bootUnnamedModule == null) {
+            testFailed = true;
+            println(FailPrefix + "unnamed module of BootClassLoader was not observed");
+        }
+        if (appUnnamedModule == null) {
+            testFailed = true;
+            println(FailPrefix + "unnamed module of AppClassLoader was not observed");
+        }
+        if (extUnnamedModule == null) {
+            testFailed = true;
+            println(FailPrefix + "unnamed module of PlatformClassLoader was not observed");
+        }
+
+        for (ModuleReference module : modules) {
+            if (!bootUnnamedModule.canRead(module)) {
+                testFailed = true;
+                println(FailPrefix + "boot unnamed module must read any module" +
+                        "but a non-readible module is found: " + module.name());
+            }
+            if (!appUnnamedModule.canRead(module)) {
+                testFailed = true;
+                println(FailPrefix + "app unnamed module must read any module" +
+                        "but a non-readible module is found: " + module.name());
+            }
+            if (!extUnnamedModule.canRead(module)) {
+                testFailed = true;
+                println(FailPrefix + "ext unnamed module must read any module" +
+                        "but a non-readible module is found: " + module.name());
+            }
+        }
+    }
+
+    protected void runTests() throws Exception {
+        /*
+         * Get to the top of main() to determine targetClass
+         */
+        BreakpointEvent bpe = startToMain("ModulesTarg");
+        targetClass = bpe.location().declaringType();
+
+        if (!vm().canGetModuleInfo()) {
+            testFailed = true;
+            println(FailPrefix + "vm().canGetModuleInfo() returned false");
+        }
+        ModuleReference other = targetClass.module();
+        modules = vm().allModules();
+
+        int checkIdx = 0;
+
+        for (ModuleReference module : modules) {
+            checkModule(module, other, checkIdx++);
+            other = module;
+        }
+
+        checkBaseModule();
+        checkUnnamedModules();
+
+        /*
+         * resume the target until end
+         */
+        listenUntilVMDisconnect();
+
+        /*
+         * deal with results of test
+         * if anything has called failure("foo") testFailed will be true
+         */
+        if (!testFailed) {
+            println("ModulesTest: passed");
+        } else {
+            throw new Exception("ModulesTest: some checks failed");
+        }
+    }
+}
--- a/test/com/sun/management/HotSpotDiagnosticMXBean/CheckOrigin.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/com/sun/management/HotSpotDiagnosticMXBean/CheckOrigin.java	Thu Mar 17 19:04:16 2016 +0000
@@ -61,6 +61,7 @@
 
             ProcessBuilder pb = ProcessTools.
                 createJavaProcessBuilder(
+                    "-XaddExports:jdk.attach/sun.tools.attach=ALL-UNNAMED",
                     "-XX:+UseConcMarkSweepGC",  // this will cause UseParNewGC to be FLAG_SET_ERGO
                     "-XX:+UseCodeAging",
                     "-XX:+UseCerealGC",         // Should be ignored.
--- a/test/java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusToFrontTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusToFrontTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -26,7 +26,8 @@
   @bug       6187066
   @summary   Tests the Window.autoRequestFocus property for the Window.toFront() method.
   @author    anton.tarasov: area=awt.focus
-  @library    ../../regtesthelpers
+  @library /java/awt/patchlib     ../../regtesthelpers
+  @build java.desktop/java.awt.Helper
   @build      Util
   @run       main AutoRequestFocusToFrontTest
 */
--- a/test/java/awt/Focus/FocusEmbeddedFrameTest/FocusEmbeddedFrameTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/Focus/FocusEmbeddedFrameTest/FocusEmbeddedFrameTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -26,9 +26,12 @@
   @bug       6516675
   @summary   Tests that EmbeddedFrame can be focused.
   @author    anton.tarasov: area=awt-focus
+  @requires (os.family == "windows")
   @modules   java.desktop/java.awt.peer
              java.desktop/sun.awt
-  @library   ../../regtesthelpers
+             java.desktop/sun.awt.windows
+  @library /java/awt/patchlib    ../../regtesthelpers
+  @build java.desktop/java.awt.Helper
   @build     Util UtilInternal
   @run       main FocusEmbeddedFrameTest
 */
--- a/test/java/awt/Mixing/AWT_Mixing/JButtonInGlassPaneOverlapping.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/Mixing/AWT_Mixing/JButtonInGlassPaneOverlapping.java	Thu Mar 17 19:04:16 2016 +0000
@@ -32,9 +32,10 @@
 @test
 @summary Simple Overlapping test for javax.swing.JButton
 @author sergey.grinev@oracle.com: area=awt.mixing
-@library ../../regtesthelpers
+@library /java/awt/patchlib  ../../regtesthelpers
 @modules java.desktop/sun.awt
          java.desktop/java.awt.peer
+@build java.desktop/java.awt.Helper
 @build Util
 @run main JButtonInGlassPaneOverlapping
  */
--- a/test/java/awt/Mixing/AWT_Mixing/JButtonOverlapping.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/Mixing/AWT_Mixing/JButtonOverlapping.java	Thu Mar 17 19:04:16 2016 +0000
@@ -32,9 +32,10 @@
 @test
 @summary Simple Overlapping test for javax.swing.JButton
 @author sergey.grinev@oracle.com: area=awt.mixing
-@library ../../regtesthelpers
+@library /java/awt/patchlib  ../../regtesthelpers
 @modules java.desktop/sun.awt
          java.desktop/java.awt.peer
+@build java.desktop/java.awt.Helper
 @build Util
 @run main JButtonOverlapping
  */
--- a/test/java/awt/Mixing/AWT_Mixing/JColorChooserOverlapping.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/Mixing/AWT_Mixing/JColorChooserOverlapping.java	Thu Mar 17 19:04:16 2016 +0000
@@ -31,9 +31,10 @@
 @test
 @summary Simple Overlapping test for javax.swing.JColorChooser
 @author sergey.grinev@oracle.com: area=awt.mixing
-@library ../../regtesthelpers
+@library /java/awt/patchlib  ../../regtesthelpers
 @modules java.desktop/sun.awt
          java.desktop/java.awt.peer
+@build java.desktop/java.awt.Helper
 @build Util
 @run main JColorChooserOverlapping
  */
--- a/test/java/awt/Mixing/AWT_Mixing/JComboBoxOverlapping.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/Mixing/AWT_Mixing/JComboBoxOverlapping.java	Thu Mar 17 19:04:16 2016 +0000
@@ -42,9 +42,10 @@
 @test
 @summary Overlapping test for javax.swing.JScrollPane
 @author sergey.grinev@oracle.com: area=awt.mixing
-@library ../../regtesthelpers
+@library /java/awt/patchlib  ../../regtesthelpers
 @modules java.desktop/sun.awt
          java.desktop/java.awt.peer
+@build java.desktop/java.awt.Helper
 @build Util
 @run main JComboBoxOverlapping
  */
--- a/test/java/awt/Mixing/AWT_Mixing/JEditorPaneInGlassPaneOverlapping.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/Mixing/AWT_Mixing/JEditorPaneInGlassPaneOverlapping.java	Thu Mar 17 19:04:16 2016 +0000
@@ -33,9 +33,10 @@
 @test
 @summary Simple Overlapping test for javax.swing.JLabel
 @author sergey.grinev@oracle.com: area=awt.mixing
-@library ../../regtesthelpers
+@library /java/awt/patchlib  ../../regtesthelpers
 @modules java.desktop/sun.awt
          java.desktop/java.awt.peer
+@build java.desktop/java.awt.Helper
 @build Util
 @run main JEditorPaneInGlassPaneOverlapping
  */
--- a/test/java/awt/Mixing/AWT_Mixing/JEditorPaneOverlapping.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/Mixing/AWT_Mixing/JEditorPaneOverlapping.java	Thu Mar 17 19:04:16 2016 +0000
@@ -31,9 +31,10 @@
 @test
 @summary Simple Overlapping test for javax.swing.JLabel
 @author sergey.grinev@oracle.com: area=awt.mixing
-@library ../../regtesthelpers
+@library /java/awt/patchlib  ../../regtesthelpers
 @modules java.desktop/sun.awt
          java.desktop/java.awt.peer
+@build java.desktop/java.awt.Helper
 @build Util
 @run main JEditorPaneOverlapping
  */
--- a/test/java/awt/Mixing/AWT_Mixing/JLabelInGlassPaneOverlapping.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/Mixing/AWT_Mixing/JLabelInGlassPaneOverlapping.java	Thu Mar 17 19:04:16 2016 +0000
@@ -33,9 +33,10 @@
 @test
 @summary Simple Overlapping test for javax.swing.JLabel
 @author sergey.grinev@oracle.com: area=awt.mixing
-@library ../../regtesthelpers
+@library /java/awt/patchlib  ../../regtesthelpers
 @modules java.desktop/sun.awt
          java.desktop/java.awt.peer
+@build java.desktop/java.awt.Helper
 @build Util
 @run main JLabelInGlassPaneOverlapping
  */
--- a/test/java/awt/Mixing/AWT_Mixing/JLabelOverlapping.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/Mixing/AWT_Mixing/JLabelOverlapping.java	Thu Mar 17 19:04:16 2016 +0000
@@ -32,9 +32,10 @@
 @test
 @summary Simple Overlapping test for javax.swing.JLabel
 @author sergey.grinev@oracle.com: area=awt.mixing
-@library ../../regtesthelpers
+@library /java/awt/patchlib  ../../regtesthelpers
 @modules java.desktop/sun.awt
          java.desktop/java.awt.peer
+@build java.desktop/java.awt.Helper
 @build Util
 @run main JLabelOverlapping
  */
--- a/test/java/awt/Mixing/AWT_Mixing/JListInGlassPaneOverlapping.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/Mixing/AWT_Mixing/JListInGlassPaneOverlapping.java	Thu Mar 17 19:04:16 2016 +0000
@@ -32,9 +32,10 @@
 @test
 @summary Simple Overlapping test for javax.swing.JList
 @author sergey.grinev@oracle.com: area=awt.mixing
-@library ../../regtesthelpers
+@library /java/awt/patchlib  ../../regtesthelpers
 @modules java.desktop/sun.awt
          java.desktop/java.awt.peer
+@build java.desktop/java.awt.Helper
 @build Util
 @run main JListInGlassPaneOverlapping
  */
--- a/test/java/awt/Mixing/AWT_Mixing/JListOverlapping.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/Mixing/AWT_Mixing/JListOverlapping.java	Thu Mar 17 19:04:16 2016 +0000
@@ -31,9 +31,10 @@
 @test
 @summary Simple Overlapping test for javax.swing.JList
 @author sergey.grinev@oracle.com: area=awt.mixing
-@library ../../regtesthelpers
+@library /java/awt/patchlib  ../../regtesthelpers
 @modules java.desktop/sun.awt
          java.desktop/java.awt.peer
+@build java.desktop/java.awt.Helper
 @build Util
 @run main JListOverlapping
  */
--- a/test/java/awt/Mixing/AWT_Mixing/JMenuBarOverlapping.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/Mixing/AWT_Mixing/JMenuBarOverlapping.java	Thu Mar 17 19:04:16 2016 +0000
@@ -47,9 +47,10 @@
 @test
 @summary Overlapping test for javax.swing.JScrollPane
 @author sergey.grinev@oracle.com: area=awt.mixing
-@library ../../regtesthelpers
+@library /java/awt/patchlib  ../../regtesthelpers
 @modules java.desktop/sun.awt
          java.desktop/java.awt.peer
+@build java.desktop/java.awt.Helper
 @build Util
 @run main JMenuBarOverlapping
  */
--- a/test/java/awt/Mixing/AWT_Mixing/JPanelInGlassPaneOverlapping.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/Mixing/AWT_Mixing/JPanelInGlassPaneOverlapping.java	Thu Mar 17 19:04:16 2016 +0000
@@ -33,9 +33,10 @@
 @test
 @summary Simple Overlapping test for javax.swing.JPanel
 @author sergey.grinev@oracle.com: area=awt.mixing
-@library ../../regtesthelpers
+@library /java/awt/patchlib ../../regtesthelpers
 @modules java.desktop/sun.awt
          java.desktop/java.awt.peer
+@build java.desktop/java.awt.Helper
 @build Util
 @run main JPanelInGlassPaneOverlapping
  */
--- a/test/java/awt/Mixing/AWT_Mixing/JPanelOverlapping.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/Mixing/AWT_Mixing/JPanelOverlapping.java	Thu Mar 17 19:04:16 2016 +0000
@@ -32,9 +32,10 @@
 @test
 @summary Simple Overlapping test for javax.swing.JPanel
 @author sergey.grinev@oracle.com: area=awt.mixing
-@library ../../regtesthelpers
+@library /java/awt/patchlib  ../../regtesthelpers
 @modules java.desktop/sun.awt
          java.desktop/java.awt.peer
+@build java.desktop/java.awt.Helper
 @build Util
 @run main JPanelOverlapping
  */
--- a/test/java/awt/Mixing/AWT_Mixing/JPopupMenuOverlapping.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/Mixing/AWT_Mixing/JPopupMenuOverlapping.java	Thu Mar 17 19:04:16 2016 +0000
@@ -44,9 +44,10 @@
 @test
 @summary Overlapping test for javax.swing.JScrollPane
 @author sergey.grinev@oracle.com: area=awt.mixing
-@library ../../regtesthelpers
+@library /java/awt/patchlib  ../../regtesthelpers
 @modules java.desktop/sun.awt
          java.desktop/java.awt.peer
+@build java.desktop/java.awt.Helper
 @build Util
 @run main JPopupMenuOverlapping
  */
--- a/test/java/awt/Mixing/AWT_Mixing/JProgressBarInGlassPaneOverlapping.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/Mixing/AWT_Mixing/JProgressBarInGlassPaneOverlapping.java	Thu Mar 17 19:04:16 2016 +0000
@@ -33,9 +33,10 @@
 @test
 @summary Simple Overlapping test for javax.swing.JProgressBar
 @author sergey.grinev@oracle.com: area=awt.mixing
-@library ../../regtesthelpers
+@library /java/awt/patchlib  ../../regtesthelpers
 @modules java.desktop/sun.awt
          java.desktop/java.awt.peer
+@build java.desktop/java.awt.Helper
 @build Util
 @run main JProgressBarInGlassPaneOverlapping
  */
--- a/test/java/awt/Mixing/AWT_Mixing/JProgressBarOverlapping.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/Mixing/AWT_Mixing/JProgressBarOverlapping.java	Thu Mar 17 19:04:16 2016 +0000
@@ -32,9 +32,10 @@
 @test
 @summary Simple Overlapping test for javax.swing.JProgressBar
 @author sergey.grinev@oracle.com: area=awt.mixing
-@library ../../regtesthelpers
+@library /java/awt/patchlib  ../../regtesthelpers
 @modules java.desktop/sun.awt
          java.desktop/java.awt.peer
+@build java.desktop/java.awt.Helper
 @build Util
 @run main JProgressBarOverlapping
  */
--- a/test/java/awt/Mixing/AWT_Mixing/JScrollBarInGlassPaneOverlapping.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/Mixing/AWT_Mixing/JScrollBarInGlassPaneOverlapping.java	Thu Mar 17 19:04:16 2016 +0000
@@ -36,9 +36,10 @@
 @test
 @summary Simple Overlapping test for javax.swing.JScrollBar
 @author sergey.grinev@oracle.com: area=awt.mixing
-@library ../../regtesthelpers
+@library /java/awt/patchlib  ../../regtesthelpers
 @modules java.desktop/sun.awt
          java.desktop/java.awt.peer
+@build java.desktop/java.awt.Helper
 @build Util
 @run main JScrollBarInGlassPaneOverlapping
  */
--- a/test/java/awt/Mixing/AWT_Mixing/JScrollBarOverlapping.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/Mixing/AWT_Mixing/JScrollBarOverlapping.java	Thu Mar 17 19:04:16 2016 +0000
@@ -35,9 +35,10 @@
 @test
 @summary Simple Overlapping test for javax.swing.JScrollBar
 @author sergey.grinev@oracle.com: area=awt.mixing
-@library ../../regtesthelpers
+@library /java/awt/patchlib  ../../regtesthelpers
 @modules java.desktop/sun.awt
          java.desktop/java.awt.peer
+@build java.desktop/java.awt.Helper
 @build Util
 @run main JScrollBarOverlapping
  */
--- a/test/java/awt/Mixing/AWT_Mixing/JSliderInGlassPaneOverlapping.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/Mixing/AWT_Mixing/JSliderInGlassPaneOverlapping.java	Thu Mar 17 19:04:16 2016 +0000
@@ -33,9 +33,10 @@
 @test
 @summary Simple Overlapping test for javax.swing.JSlider
 @author sergey.grinev@oracle.com: area=awt.mixing
-@library ../../regtesthelpers
+@library /java/awt/patchlib  ../../regtesthelpers
 @modules java.desktop/sun.awt
          java.desktop/java.awt.peer
+@build java.desktop/java.awt.Helper
 @build Util
 @run main JSliderInGlassPaneOverlapping
  */
--- a/test/java/awt/Mixing/AWT_Mixing/JSliderOverlapping.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/Mixing/AWT_Mixing/JSliderOverlapping.java	Thu Mar 17 19:04:16 2016 +0000
@@ -32,9 +32,10 @@
 @test
 @summary Simple Overlapping test for javax.swing.JSlider
 @author sergey.grinev@oracle.com: area=awt.mixing
-@library ../../regtesthelpers
+@library /java/awt/patchlib  ../../regtesthelpers
 @modules java.desktop/sun.awt
          java.desktop/java.awt.peer
+@build java.desktop/java.awt.Helper
 @build Util
 @run main JSliderOverlapping
  */
--- a/test/java/awt/Mixing/AWT_Mixing/JSpinnerInGlassPaneOverlapping.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/Mixing/AWT_Mixing/JSpinnerInGlassPaneOverlapping.java	Thu Mar 17 19:04:16 2016 +0000
@@ -35,9 +35,10 @@
 @test
 @summary Simple Overlapping test for javax.swing.JSpinner
 @author sergey.grinev@oracle.com: area=awt.mixing
-@library ../../regtesthelpers
+@library /java/awt/patchlib  ../../regtesthelpers
 @modules java.desktop/sun.awt
          java.desktop/java.awt.peer
+@build java.desktop/java.awt.Helper
 @build Util
 @run main JSpinnerInGlassPaneOverlapping
  */
--- a/test/java/awt/Mixing/AWT_Mixing/JSpinnerOverlapping.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/Mixing/AWT_Mixing/JSpinnerOverlapping.java	Thu Mar 17 19:04:16 2016 +0000
@@ -34,9 +34,10 @@
 @test
 @summary Simple Overlapping test for javax.swing.JSpinner
 @author sergey.grinev@oracle.com: area=awt.mixing
-@library ../../regtesthelpers
+@library /java/awt/patchlib  ../../regtesthelpers
 @modules java.desktop/sun.awt
          java.desktop/java.awt.peer
+@build java.desktop/java.awt.Helper
 @build Util
 @run main JSpinnerOverlapping
  */
--- a/test/java/awt/Mixing/AWT_Mixing/JTableInGlassPaneOverlapping.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/Mixing/AWT_Mixing/JTableInGlassPaneOverlapping.java	Thu Mar 17 19:04:16 2016 +0000
@@ -35,9 +35,10 @@
 @test
 @summary Simple Overlapping test for JTable
 @author sergey.grinev@oracle.com: area=awt.mixing
-@library ../../regtesthelpers
+@library /java/awt/patchlib  ../../regtesthelpers
 @modules java.desktop/sun.awt
          java.desktop/java.awt.peer
+@build java.desktop/java.awt.Helper
 @build Util
 @run main JTableInGlassPaneOverlapping
  */
--- a/test/java/awt/Mixing/AWT_Mixing/JTableOverlapping.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/Mixing/AWT_Mixing/JTableOverlapping.java	Thu Mar 17 19:04:16 2016 +0000
@@ -31,9 +31,10 @@
 @test
 @summary Simple Overlapping test for JTable
 @author sergey.grinev@oracle.com: area=awt.mixing
-@library ../../regtesthelpers
+@library /java/awt/patchlib  ../../regtesthelpers
 @modules java.desktop/sun.awt
          java.desktop/java.awt.peer
+@build java.desktop/java.awt.Helper
 @build Util
 @run main JTableOverlapping
  */
--- a/test/java/awt/Mixing/AWT_Mixing/JTextAreaInGlassPaneOverlapping.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/Mixing/AWT_Mixing/JTextAreaInGlassPaneOverlapping.java	Thu Mar 17 19:04:16 2016 +0000
@@ -33,9 +33,10 @@
 @test
 @summary Simple Overlapping test for javax.swing.JLabel
 @author sergey.grinev@oracle.com: area=awt.mixing
-@library ../../regtesthelpers
+@library /java/awt/patchlib  ../../regtesthelpers
 @modules java.desktop/sun.awt
          java.desktop/java.awt.peer
+@build java.desktop/java.awt.Helper
 @build Util
 @run main JTextAreaInGlassPaneOverlapping
  */
--- a/test/java/awt/Mixing/AWT_Mixing/JTextAreaOverlapping.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/Mixing/AWT_Mixing/JTextAreaOverlapping.java	Thu Mar 17 19:04:16 2016 +0000
@@ -32,9 +32,10 @@
 @test
 @summary Simple Overlapping test for javax.swing.JLabel
 @author sergey.grinev@oracle.com: area=awt.mixing
-@library ../../regtesthelpers
+@library /java/awt/patchlib  ../../regtesthelpers
 @modules java.desktop/sun.awt
          java.desktop/java.awt.peer
+@build java.desktop/java.awt.Helper
 @build Util
 @run main JTextAreaOverlapping
  */
--- a/test/java/awt/Mixing/AWT_Mixing/JTextFieldInGlassPaneOverlapping.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/Mixing/AWT_Mixing/JTextFieldInGlassPaneOverlapping.java	Thu Mar 17 19:04:16 2016 +0000
@@ -33,9 +33,10 @@
 @test
 @summary Simple Overlapping test for javax.swing.JLabel
 @author sergey.grinev@oracle.com: area=awt.mixing
-@library ../../regtesthelpers
+@library /java/awt/patchlib  ../../regtesthelpers
 @modules java.desktop/sun.awt
          java.desktop/java.awt.peer
+@build java.desktop/java.awt.Helper
 @build Util
 @run main JTextFieldInGlassPaneOverlapping
  */
--- a/test/java/awt/Mixing/AWT_Mixing/JTextFieldOverlapping.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/Mixing/AWT_Mixing/JTextFieldOverlapping.java	Thu Mar 17 19:04:16 2016 +0000
@@ -32,9 +32,10 @@
 @test
 @summary Simple Overlapping test for javax.swing.JLabel
 @author sergey.grinev@oracle.com: area=awt.mixing
-@library ../../regtesthelpers
+@library /java/awt/patchlib  ../../regtesthelpers
 @modules java.desktop/sun.awt
          java.desktop/java.awt.peer
+@build java.desktop/java.awt.Helper
 @build Util
 @run main JTextFieldOverlapping
  */
--- a/test/java/awt/Mixing/AWT_Mixing/JToggleButtonInGlassPaneOverlapping.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/Mixing/AWT_Mixing/JToggleButtonInGlassPaneOverlapping.java	Thu Mar 17 19:04:16 2016 +0000
@@ -32,9 +32,10 @@
 @test
 @summary Simple Overlapping test for javax.swing.JToggleButton
 @author sergey.grinev@oracle.com: area=awt.mixing
-@library ../../regtesthelpers
+@library /java/awt/patchlib  ../../regtesthelpers
 @modules java.desktop/sun.awt
          java.desktop/java.awt.peer
+@build java.desktop/java.awt.Helper
 @build Util
 @run main JToggleButtonInGlassPaneOverlapping
  */
--- a/test/java/awt/Mixing/AWT_Mixing/JToggleButtonOverlapping.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/Mixing/AWT_Mixing/JToggleButtonOverlapping.java	Thu Mar 17 19:04:16 2016 +0000
@@ -31,9 +31,10 @@
 @test
 @summary Simple Overlapping test for javax.swing.JToggleButton
 @author sergey.grinev@oracle.com: area=awt.mixing
-@library ../../regtesthelpers
+@library /java/awt/patchlib  ../../regtesthelpers
 @modules java.desktop/sun.awt
          java.desktop/java.awt.peer
+@build java.desktop/java.awt.Helper
 @build Util
 @run main JToggleButtonOverlapping
  */
--- a/test/java/awt/Mixing/AWT_Mixing/MixingFrameResizing.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/Mixing/AWT_Mixing/MixingFrameResizing.java	Thu Mar 17 19:04:16 2016 +0000
@@ -41,9 +41,10 @@
 @bug 6777370
 @summary Issues when resizing the JFrame with HW components
 @author sergey.grinev@oracle.com: area=awt.mixing
-@library ../../regtesthelpers
+@library /java/awt/patchlib  ../../regtesthelpers
 @modules java.desktop/sun.awt
          java.desktop/java.awt.peer
+@build java.desktop/java.awt.Helper
 @build Util
 @run main MixingFrameResizing
  */
--- a/test/java/awt/Mixing/AWT_Mixing/OverlappingTestBase.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/Mixing/AWT_Mixing/OverlappingTestBase.java	Thu Mar 17 19:04:16 2016 +0000
@@ -108,8 +108,8 @@
     {    if (Toolkit.getDefaultToolkit().getClass().getName().matches(".*L.*Toolkit")) {
              // No EmbeddedFrame in LWToolkit/LWCToolkit, yet
              // And it should be programmed some other way, too, in any case
-             System.err.println("skipTestingEmbeddedFrame");
-             skipTestingEmbeddedFrame = true;
+             //System.err.println("skipTestingEmbeddedFrame");
+             //skipTestingEmbeddedFrame = true;
          }else {
              System.err.println("do not skipTestingEmbeddedFrame");
          }
@@ -241,21 +241,40 @@
                 container.setVisible(true); // create peer
 
                 long frameWindow = 0;
-                String getWindowMethodName = "getHWnd";
+                String getWindowMethodName = null;
+                String eframeClassName = null;
                 if (Toolkit.getDefaultToolkit().getClass().getName().contains("XToolkit")) {
+                    java.awt.Helper.addExports("sun.awt.X11", OverlappingTestBase.class.getModule());
                     getWindowMethodName = "getWindow";
+                    eframeClassName = "sun.awt.X11.XEmbeddedFrame";
+                }else if (Toolkit.getDefaultToolkit().getClass().getName().contains(".WToolkit")) {
+                    java.awt.Helper.addExports("sun.awt.windows", OverlappingTestBase.class.getModule());
+                    getWindowMethodName = "getHWnd";
+                    eframeClassName = "sun.awt.windows.WEmbeddedFrame";
+                }else if (isMac) {
+                    java.awt.Helper.addExports("sun.lwawt", OverlappingTestBase.class.getModule());
+                    java.awt.Helper.addExports("sun.lwawt.macosx", OverlappingTestBase.class.getModule());
+                    eframeClassName = "sun.lwawt.macosx.CViewEmbeddedFrame";
                 }
+
                 ComponentPeer peer = AWTAccessor.getComponentAccessor()
                                                 .getPeer(embedder);
-                //  System.err.println("Peer: " + peer);
-                Method getWindowMethod = peer.getClass().getMethod(getWindowMethodName);
-                frameWindow = (Long) getWindowMethod.invoke(peer);
-//                System.err.println("frame peer ID: " + frameWindow);
+                if (!isMac) {
+                    Method getWindowMethod = peer.getClass().getMethod(getWindowMethodName);
+                    frameWindow = (Long) getWindowMethod.invoke(peer);
+                } else {
+                    Method m_getPlatformWindowMethod = peer.getClass().getMethod("getPlatformWindow");
+                    Object platformWindow = m_getPlatformWindowMethod.invoke(peer);
+                    Class classPlatformWindow = Class.forName("sun.lwawt.macosx.CPlatformWindow");
 
-                String eframeClassName = "sun.awt.windows.WEmbeddedFrame";
-                if (Toolkit.getDefaultToolkit().getClass().getName().contains("XToolkit")) {
-                    eframeClassName = "sun.awt.X11.XEmbeddedFrame";
+                    Method m_getContentView = classPlatformWindow.getMethod("getContentView");
+                    Object contentView = m_getContentView.invoke(platformWindow);
+                    Class classContentView = Class.forName("sun.lwawt.macosx.CPlatformView");
+
+                    Method m_getAWTView = classContentView.getMethod("getAWTView");
+                    frameWindow = (Long) m_getAWTView.invoke(contentView);
                 }
+
                 Class eframeClass = Class.forName(eframeClassName);
                 Constructor eframeCtor = eframeClass.getConstructor(long.class);
                 EmbeddedFrame eframe = (EmbeddedFrame) eframeCtor.newInstance(frameWindow);
--- a/test/java/awt/Toolkit/Headless/WrappedToolkitTest/WrappedToolkitTest.sh	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/Toolkit/Headless/WrappedToolkitTest/WrappedToolkitTest.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -28,7 +28,7 @@
 #   @bug 6282388 8030640
 #   @summary Tests that AWT use correct toolkit to be wrapped into HeadlessToolkit
 #   @author artem.ananiev@sun.com: area=awt.headless
-#   @compile TestWrapped.java
+#   compile TestWrapped.java
 #   @run shell WrappedToolkitTest.sh
 
 # Beginning of subroutines:
@@ -105,22 +105,54 @@
 fi
 echo "JDK under test is: $TESTJAVA"
 
-#Deal with .class files:
-if [ -n "${STANDALONE}" ] ; then
-   # then compile all .java files (if there are any) into .class files
-   if [ -a *.java ]; then
-      ${TESTJAVA}/bin/javac$ ./*.java ;
-   fi
-   # else in harness so copy all the class files from where jtreg put them
-   # over to the scratch directory this test is running in. 
-   else cp ${TESTCLASSES}/*.class . ;
-fi
-
+##Deal with .class files:
+#if [ -n "${STANDALONE}" ] ; then
+#   # then compile all .java files (if there are any) into .class files
+#   if [ -a *.java ]; then
+#      ${TESTJAVA}/bin/javac$ ./*.java ;
+#   fi
+#   # else in harness so copy all the class files from where jtreg put them
+#   # over to the scratch directory this test is running in. 
+#   else cp ${TESTCLASSES}/*.class . ;
+#fi
+#
 #if in test harness, then copy the entire directory that the test is in over 
 # to the scratch directory.  This catches any support files needed by the test.
 if [ -z "${STANDALONE}" ] ; 
    then cp ${TESTSRC}/* . 
 fi
+case "$OS" in
+  Windows* | CYGWIN* )
+    ${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} \
+                         -XaddExports:java.desktop/sun.awt=ALL-UNNAMED,java.desktop/sun.awt.windows=ALL-UNNAMED ${CP} \
+                         *.java
+    status=$?
+    if [ ! $status -eq "0" ]; then
+      fail "Compilation failed";
+    fi
+    ;;
+
+  SunOS | Linux )
+    ${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} \
+                         -XaddExports:java.desktop/sun.awt=ALL-UNNAMED,java.desktop/sun.awt.X11=ALL-UNNAMED ${CP} \
+                         *.java
+    status=$?
+    if [ ! $status -eq "0" ]; then
+      fail "Compilation failed";
+    fi
+    ;;
+
+  Darwin)
+    ${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} \
+                         -XaddExports:java.desktop/sun.awt=ALL-UNNAMED,java.desktop/sun.lwawt.macosx=ALL-UNNAMED ${CP} \
+                         *.java
+    status=$?
+    if [ ! $status -eq "0" ]; then
+      fail "Compilation failed";
+    fi
+    ;;
+
+esac
 
 #Just before executing anything, make sure it has executable permission!
 chmod 777 ./*
@@ -130,12 +162,14 @@
 case "$OS" in
   Windows* | CYGWIN* )
     ${TESTJAVA}/bin/java ${TESTVMOPTS} -Djava.awt.headless=true \
+                         -XaddExports:java.desktop/sun.awt=ALL-UNNAMED,java.desktop/sun.awt.windows=ALL-UNNAMED ${CP} \
                          TestWrapped sun.awt.windows.WToolkit
     status=$?
     if [ ! $status -eq "0" ]; then
       fail "Test FAILED: toolkit wrapped into HeadlessToolkit is not an instance of sun.awt.windows.WToolkit";
     fi
     ${TESTJAVA}/bin/java ${TESTVMOPTS} -Djava.awt.headless=true \
+                         -XaddExports:java.desktop/sun.awt=ALL-UNNAMED,java.desktop/sun.awt.windows=ALL-UNNAMED ${CP} \
                          -Dawt.toolkit=sun.awt.windows.WToolkit \
                          TestWrapped sun.awt.windows.WToolkit
     status=$?
@@ -146,6 +180,7 @@
 
   SunOS | Linux )
     ${TESTJAVA}/bin/java ${TESTVMOPTS} -Djava.awt.headless=true \
+                         -XaddExports:java.desktop/sun.awt=ALL-UNNAMED,java.desktop/sun.awt.X11=ALL-UNNAMED ${CP} \
                          -Dawt.toolkit=sun.awt.X11.XToolkit \
                          TestWrapped sun.awt.X11.XToolkit
     status=$?
@@ -153,6 +188,7 @@
       fail "Test FAILED: toolkit wrapped into HeadlessToolkit is not an instance of sun.awt.xawt.XToolkit";
     fi
     AWT_TOOLKIT=XToolkit ${TESTJAVA}/bin/java ${TESTVMOPTS} \
+                         -XaddExports:java.desktop/sun.awt=ALL-UNNAMED,java.desktop/sun.awt.X11=ALL-UNNAMED ${CP} \
                                               -Djava.awt.headless=true \
                                               TestWrapped sun.awt.X11.XToolkit
     status=$?
@@ -163,12 +199,14 @@
 
   Darwin)
     ${TESTJAVA}/bin/java ${TESTVMOPTS} -Djava.awt.headless=true \
+                         -XaddExports:java.desktop/sun.awt=ALL-UNNAMED,java.desktop/sun.lwawt.macosx=ALL-UNNAMED ${CP} \
                          TestWrapped sun.lwawt.macosx.LWCToolkit
     status=$?
     if [ ! $status -eq "0" ]; then
       fail "Test FAILED: toolkit wrapped into HeadlessToolkit is not an instance of sun.lwawt.macosx.LWCToolkit";
     fi
     ${TESTJAVA}/bin/java ${TESTVMOPTS} -Djava.awt.headless=true \
+                         -XaddExports:java.desktop/sun.awt=ALL-UNNAMED,java.desktop/sun.lwawt.macosx=ALL-UNNAMED ${CP} \
                          -Dawt.toolkit=sun.lwawt.macosx.LWCToolkit \
                          TestWrapped sun.lwawt.macosx.LWCToolkit
     status=$?
--- a/test/java/awt/TrayIcon/ActionCommand/ActionCommand.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/TrayIcon/ActionCommand/ActionCommand.java	Thu Mar 17 19:04:16 2016 +0000
@@ -31,6 +31,8 @@
  *          (single clicked, on Mac)
  * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com)
  * @library ../../../../lib/testlibrary ../
+ * @library /java/awt/patchlib
+ * @build java.desktop/java.awt.Helper
  * @build ExtendedRobot SystemTrayIconHelper
  * @run main ActionCommand
  */
--- a/test/java/awt/TrayIcon/ActionEventMask/ActionEventMask.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/TrayIcon/ActionEventMask/ActionEventMask.java	Thu Mar 17 19:04:16 2016 +0000
@@ -33,7 +33,9 @@
  *          triggered when multiple AWTEventListeners and ActionListeners
  *          are added.
  * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com)
+ * @library /java/awt/patchlib
  * @library ../../../../lib/testlibrary ../
+ * @build java.desktop/java.awt.Helper
  * @build ExtendedRobot SystemTrayIconHelper
  * @run main ActionEventMask
  */
--- a/test/java/awt/TrayIcon/ModalityTest/ModalityTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/TrayIcon/ModalityTest/ModalityTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -29,8 +29,10 @@
  * @test
  * @summary Check for MouseEvents with all mouse buttons
  * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com)
+ * @library /java/awt/patchlib
  * @library ../../../../lib/testlibrary ../
  * @build ExtendedRobot SystemTrayIconHelper
+ * @build java.desktop/java.awt.Helper
  * @run main ModalityTest
  */
 public class ModalityTest {
--- a/test/java/awt/TrayIcon/MouseEventMask/MouseEventMaskTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/TrayIcon/MouseEventMask/MouseEventMaskTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -32,7 +32,9 @@
  *          checks if all listeners are triggered when AWTEventListeners
  *          and MouseListeners are added.
  * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com)
+ * @library /java/awt/patchlib
  * @library ../../../../lib/testlibrary ../
+ * @build java.desktop/java.awt.Helper
  * @build ExtendedRobot SystemTrayIconHelper
  * @run main MouseEventMaskTest
  */
--- a/test/java/awt/TrayIcon/SecurityCheck/FunctionalityCheck/FunctionalityCheck.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/TrayIcon/SecurityCheck/FunctionalityCheck/FunctionalityCheck.java	Thu Mar 17 19:04:16 2016 +0000
@@ -29,7 +29,9 @@
  * @test
  * @summary Check for MouseEvents with all mouse buttons
  * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com)
+ * @library /java/awt/patchlib
  * @library ../../../../../lib/testlibrary ../../
+ * @build java.desktop/java.awt.Helper
  * @build ExtendedRobot SystemTrayIconHelper
  * @run main/othervm/policy=tray.policy -Djava.security.manager FunctionalityCheck
  */
--- a/test/java/awt/TrayIcon/SystemTrayIconHelper.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/TrayIcon/SystemTrayIconHelper.java	Thu Mar 17 19:04:16 2016 +0000
@@ -81,6 +81,9 @@
             try {
                 // sun.lwawt.macosx.CTrayIcon
                 Field f_peer = getField( java.awt.TrayIcon.class, "peer");
+                Method m_addExports = Class.forName("java.awt.Helper").getDeclaredMethod("addExports", String.class, java.lang.reflect.Module.class);
+                m_addExports.invoke(null, "sun.lwawt.macosx", robot.getClass().getModule());
+
 
                 Object peer = f_peer.get(icon);
                 Method m_getModel = peer.getClass().getDeclaredMethod(
@@ -102,6 +105,9 @@
         } else {
             try {
                 // sun.awt.X11.XTrayIconPeer
+                Method m_addExports = Class.forName("java.awt.Helper").getDeclaredMethod("addExports", String.class, java.lang.reflect.Module.class);
+                m_addExports.invoke(null, "sun.awt.X11", robot.getClass().getModule());
+
                 Field f_peer = getField(java.awt.TrayIcon.class, "peer");
 
                 SystemTrayIconHelper.openTrayIfNeeded(robot);
--- a/test/java/awt/TrayIcon/TrayIconEventModifiers/TrayIconEventModifiersTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/TrayIcon/TrayIconEventModifiers/TrayIconEventModifiersTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -34,7 +34,9 @@
  * @summary Check if MouseEvent has the proper modifiers when
  *          TrayIcon is clicked pressing the modifier keys
  * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com)
+ * @library /java/awt/patchlib
  * @library ../../../../lib/testlibrary ../
+ * @build java.desktop/java.awt.Helper
  * @build ExtendedRobot SystemTrayIconHelper
  * @run main TrayIconEventModifiersTest
  */
--- a/test/java/awt/TrayIcon/TrayIconEvents/TrayIconEventsTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/TrayIcon/TrayIconEvents/TrayIconEventsTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -30,7 +30,9 @@
  * @test
  * @summary Check for MouseEvents with all mouse buttons
  * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com)
+ * @library /java/awt/patchlib
  * @library ../../../../lib/testlibrary ../
+ * @build java.desktop/java.awt.Helper
  * @build ExtendedRobot SystemTrayIconHelper
  * @run main TrayIconEventsTest
  */
--- a/test/java/awt/TrayIcon/TrayIconMouseTest/TrayIconMouseTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/TrayIcon/TrayIconMouseTest/TrayIconMouseTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -31,7 +31,9 @@
  *          it is double clicked using mouse button 1 (or single clicked
  *          with button 3 (on Mac OS X))
  * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com)
+ * @library /java/awt/patchlib
  * @library ../../../../lib/testlibrary ../
+ * @build java.desktop/java.awt.Helper
  * @build ExtendedRobot SystemTrayIconHelper
  * @run main TrayIconMouseTest
  */
--- a/test/java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -29,7 +29,9 @@
  * @summary Check if a JPopupMenu can be displayed when TrayIcon is
  *          right clicked. It uses a JWindow as the parent of the JPopupMenu
  * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com)
+ * @library /java/awt/patchlib
  * @library ../../../../lib/testlibrary ../
+ * @build java.desktop/java.awt.Helper
  * @build ExtendedRobot SystemTrayIconHelper
  * @run main TrayIconPopupTest
  */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/awt/datatransfer/ConstructFlavoredObjectTest/ConstructFlavoredObjectTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.SystemFlavorMap;
+import java.io.IOException;
+import java.io.Reader;
+import javax.swing.JLabel;
+import javax.swing.TransferHandler;
+/*
+ * @test
+ * @bug 8130329
+ * @summary  Audit Core Reflection in module java.desktop AWT/Miscellaneous area
+ *           for places that will require changes to work with modules
+ * @author Alexander Scherbatiy
+ */
+public class ConstructFlavoredObjectTest {
+
+    private static final String TEST_MIME_TYPE = "text/plain;class="
+            + MyStringReader.class.getName();
+
+    public static void main(String[] args) throws Exception {
+
+        final DataFlavor dataFlavor = new DataFlavor(TEST_MIME_TYPE);
+        SystemFlavorMap systemFlavorMap = (SystemFlavorMap) SystemFlavorMap.
+                getDefaultFlavorMap();
+        systemFlavorMap.addUnencodedNativeForFlavor(dataFlavor, "TEXT");
+        systemFlavorMap.addFlavorForUnencodedNative("TEXT", dataFlavor);
+
+        TransferHandler transferHandler = new TransferHandler("Test Handler");
+
+        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+        transferHandler.exportToClipboard(new JLabel("Test"), clipboard,
+                TransferHandler.COPY);
+
+        Object clipboardData = clipboard.getData(dataFlavor);
+
+        if (!(clipboardData instanceof MyStringReader)) {
+            throw new RuntimeException("Wrong clipboard data!");
+        }
+    }
+
+    public static class MyStringReader extends Reader {
+
+        public MyStringReader(Reader reader) {
+        }
+
+        @Override
+        public int read(char[] cbuf, int off, int len) throws IOException {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public void close() throws IOException {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/awt/datatransfer/DataFlavor/DataFlavorRemoteTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+  @test
+  @bug 8051636
+  @summary DataTransferer optional dependency on RMI
+  @author Semyon Sadetsky
+  @library ../../regtesthelpers/process
+  @build ProcessResults ProcessCommunicator
+  @run main DataFlavorRemoteTest
+*/
+
+import test.java.awt.regtesthelpers.process.ProcessCommunicator;
+import test.java.awt.regtesthelpers.process.ProcessResults;
+
+import java.awt.*;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.Transferable;
+import java.awt.datatransfer.UnsupportedFlavorException;
+import java.io.IOException;
+import java.io.Serializable;
+
+interface Hello extends java.rmi.Remote {
+    String sayHello();
+}
+
+public class DataFlavorRemoteTest {
+
+    public static void main(String[] args) throws Exception {
+        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+        Producer contents = new Producer();
+        clipboard.setContents(contents, null);
+        ProcessResults processResults =
+                ProcessCommunicator
+                        .executeChildProcess(Consumer.class, new String[0]);
+        if (!"Hello".equals(processResults.getStdErr())) {
+            throw new RuntimeException("transfer of remote object failed");
+        }
+        System.out.println("ok");
+    }
+
+    static class Consumer {
+        public static void main(String[] args) throws Exception {
+            Clipboard clipboard =
+                    Toolkit.getDefaultToolkit().getSystemClipboard();
+            DataFlavor dataFlavor = new DataFlavor(DataFlavor.javaRemoteObjectMimeType +
+                    ";class=Hello" );
+            Object data = clipboard.getData(dataFlavor);
+            System.err.print(((Hello) data).sayHello());
+        }
+
+    }
+}
+
+class Producer implements Transferable {
+
+    private final DataFlavor dataFlavor;
+    private final HelloImpl impl;
+
+    private static class HelloImpl implements Hello, Serializable {
+        @Override
+        public String sayHello() {
+            return "Hello";
+        }
+    }
+
+    public Producer() throws Exception {
+        dataFlavor = new DataFlavor(DataFlavor.javaRemoteObjectMimeType +
+                ";class=Hello" );
+        impl = new HelloImpl();
+        System.out.println(impl.hashCode());
+    }
+
+    Hello getImpl() {
+        return impl;
+    }
+
+    @Override
+    public DataFlavor[] getTransferDataFlavors() {
+        return new DataFlavor[]{dataFlavor};
+    }
+
+    @Override
+    public boolean isDataFlavorSupported(DataFlavor flavor) {
+        return flavor.equals(dataFlavor);
+    }
+
+    @Override
+    public Object getTransferData(DataFlavor flavor)
+            throws UnsupportedFlavorException, IOException {
+        return impl;
+    }
+
+}
--- a/test/java/awt/grab/EmbeddedFrameTest1/EmbeddedFrameTest1.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/grab/EmbeddedFrameTest1/EmbeddedFrameTest1.java	Thu Mar 17 19:04:16 2016 +0000
@@ -28,7 +28,8 @@
   @author oleg.sukhodolsky area=awt.grab
   @modules java.desktop/java.awt.peer
            java.desktop/sun.awt
-  @library ../../regtesthelpers
+  @library /java/awt/patchlib  ../../regtesthelpers
+  @build java.desktop/java.awt.Helper
   @build Util UtilInternal
   @run main EmbeddedFrameTest1
 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/awt/patchlib/java.desktop/java/awt/Helper.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.awt;
+import java.lang.reflect.Module;
+public class Helper {
+    private Helper() { }
+    public static void addExports(String pn, Module target) {
+        java.awt.Component.class.getModule().addExports(pn, target);
+    }
+}
--- a/test/java/awt/regtesthelpers/Util.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/regtesthelpers/Util.java	Thu Mar 17 19:04:16 2016 +0000
@@ -212,22 +212,6 @@
         robot.waitForIdle();
     }
 
-    public static Field getField(final Class klass, final String fieldName) {
-        return AccessController.doPrivileged(new PrivilegedAction<Field>() {
-            public Field run() {
-                try {
-                    Field field = klass.getDeclaredField(fieldName);
-                    assert (field != null);
-                    field.setAccessible(true);
-                    return field;
-                } catch (SecurityException se) {
-                    throw new RuntimeException("Error: unexpected exception caught!", se);
-                } catch (NoSuchFieldException nsfe) {
-                    throw new RuntimeException("Error: unexpected exception caught!", nsfe);
-                }
-            }
-        });
-    }
 
     /*
      * Waits for a notification and for a boolean condition to become true.
@@ -461,6 +445,10 @@
 
         try {
             final Class _clazz = clazz;
+            Method m_addExports = Class.forName("java.awt.Helper").getDeclaredMethod("addExports", String.class, java.lang.reflect.Module.class);
+            // No MToolkit anymore: nothing to do about it.
+            // We may be called from non-X11 system, and this permission cannot be delegated to a test.
+            m_addExports.invoke(null, "sun.awt.X11", Util.class.getModule());
             Method m_getWMID = (Method)AccessController.doPrivileged(new PrivilegedAction() {
                     public Object run() {
                         try {
@@ -478,6 +466,10 @@
                     }
                 });
             return ((Integer)m_getWMID.invoke(null, new Object[] {})).intValue();
+        } catch (ClassNotFoundException cnfe) {
+            cnfe.printStackTrace();
+        } catch (NoSuchMethodException nsme) {
+            nsme.printStackTrace();
         } catch (IllegalAccessException iae) {
             iae.printStackTrace();
         } catch (InvocationTargetException ite) {
--- a/test/java/awt/regtesthelpers/UtilInternal.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/regtesthelpers/UtilInternal.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,7 +33,6 @@
 
 import sun.awt.AWTAccessor;
 
-
 /**
    Class with static methods using internal/proprietary API by necessity.
 */
@@ -50,6 +49,8 @@
                                           .getPeer(embedder);
         System.out.println("frame's peer = " + frame_peer);
         if ("sun.awt.windows.WToolkit".equals(tk.getClass().getName())) {
+            java.awt.Helper.addExports("sun.awt.windows", UtilInternal.class.getModule());
+
             Class comp_peer_class =
                 Class.forName("sun.awt.windows.WComponentPeer");
             System.out.println("comp peer class = " + comp_peer_class);
@@ -63,8 +64,8 @@
             Constructor constructor = clazz.getConstructor (new Class [] {Long.TYPE});
             return (Frame) constructor.newInstance (new Object[] {hwnd});
         } else if ("sun.awt.X11.XToolkit".equals(tk.getClass().getName())) {
+            java.awt.Helper.addExports("sun.awt.X11", UtilInternal.class.getModule());
             Class x_base_window_class = Class.forName("sun.awt.X11.XBaseWindow");
-            System.out.println("x_base_window_class = " + x_base_window_class);
             Method get_window = x_base_window_class.getMethod("getWindow", new Class[0]);
             System.out.println("get_window = " + get_window);
             long window = (Long) get_window.invoke(frame_peer, new Object[0]);
--- a/test/java/awt/xembed/server/TesterClient.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/awt/xembed/server/TesterClient.java	Thu Mar 17 19:04:16 2016 +0000
@@ -32,6 +32,8 @@
     public static void main(String[] args) throws Throwable {
         // First parameter is the name of the test, second is the window, the rest are rectangles
         Class cl = Class.forName("sun.awt.X11.XEmbedServerTester");
+        cl.getModule().addExports("sun.awt.X11",TesterClient.class.getModule());
+
         test = cl.getMethod(args[0], new Class[0]);
         long window = Long.parseLong(args[1]);
         Rectangle r[] = new Rectangle[(args.length-2)/4];
--- a/test/java/beans/XMLEncoder/sun_swing_PrintColorUIResource.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/beans/XMLEncoder/sun_swing_PrintColorUIResource.java	Thu Mar 17 19:04:16 2016 +0000
@@ -25,8 +25,8 @@
  * @test
  * @bug 6589532
  * @summary Tests PrintColorUIResource value encoding
+ * @modules java.desktop/sun.swing
  * @author Sergey Malenkov
- * @modules java.desktop/sun.swing
  */
 
 import java.awt.Color;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Class/Foo.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package foo;
+
+// Loaded by a custom class loader in GetPackageTest
+public class Foo {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Class/GetModuleTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,153 @@
+/**
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Exercise Class#getModule
+ * @modules java.base/jdk.internal.org.objectweb.asm
+ *          java.desktop
+ * @run testng GetModuleTest
+ */
+
+import java.awt.Component;
+import java.lang.reflect.Field;
+import java.lang.reflect.Module;
+
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import static jdk.internal.org.objectweb.asm.Opcodes.*;
+import sun.misc.Unsafe;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+public class GetModuleTest {
+
+    static final Unsafe U;
+    static {
+        try {
+            Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
+            theUnsafe.setAccessible(true);
+            U = (Unsafe) theUnsafe.get(null);
+        } catch (Exception e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    private static final Module TEST_MODULE = GetModuleTest.class.getModule();
+
+
+    @DataProvider(name = "testclasses")
+    public Object[][] testClasses() {
+        return new Object[][] {
+
+            // unnamed module
+
+            { GetModuleTest.class,      null },
+            { GetModuleTest[].class,    null },
+            { GetModuleTest[][].class,  null },
+
+            // should return named module
+
+            { int.class,            "java.base" },
+            { int[].class,          "java.base" },
+            { int[][].class,        "java.base" },
+            { void.class,           "java.base" },
+
+            { Object.class,         "java.base" },
+            { Object[].class,       "java.base" },
+            { Object[][].class,     "java.base" },
+            { Component.class,      "java.desktop" },
+            { Component[].class,    "java.desktop" },
+            { Component[][].class,  "java.desktop" },
+        };
+    }
+
+    @Test(dataProvider = "testclasses")
+    public void testGetModule(Class<?> type, String expected) {
+        Module m = type.getModule();
+        assertNotNull(m);
+        if (expected == null) {
+            assertTrue(m == TEST_MODULE);
+        } else {
+            assertEquals(m.getName(), expected);
+        }
+    }
+
+
+    @DataProvider(name = "hostclasses")
+    public Object[][] hostClasses() {
+        return new Object[][] {
+
+            { GetModuleTest.class,      null },
+            { GetModuleTest[].class,    null },
+            { Object.class,             null },
+            { Object[].class,           null },
+            { Component.class,          null },
+            { Component[].class,        null },
+
+        };
+    }
+
+    /**
+     * Exercise Class::getModule on VM anonymous classes
+     */
+    @Test(dataProvider = "hostclasses")
+    public void testGetModuleOnVMAnonymousClass(Class<?> hostClass, String ignore) {
+
+        // choose a class name in the same package as the host class
+        String prefix = packageName(hostClass);
+        if (prefix.length() > 0)
+            prefix = prefix.replace('.', '/') + "/";
+        String className = prefix + "Anon";
+
+        // create the class
+        String superName = "java/lang/Object";
+        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS
+                                         + ClassWriter.COMPUTE_FRAMES);
+        cw.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER,
+                 className, null, superName, null);
+        byte[] classBytes = cw.toByteArray();
+        int cpPoolSize = constantPoolSize(classBytes);
+        Class<?> anonClass
+            = U.defineAnonymousClass(hostClass, classBytes, new Object[cpPoolSize]);
+
+        assertTrue(anonClass.getModule() == hostClass.getModule());
+    }
+
+    private static String packageName(Class<?> c) {
+        if (c.isArray()) {
+            return packageName(c.getComponentType());
+        } else {
+            String name = c.getName();
+            int dot = name.lastIndexOf('.');
+            if (dot == -1) return "";
+            return name.substring(0, dot);
+        }
+    }
+
+    private static int constantPoolSize(byte[] classFile) {
+        return ((classFile[8] & 0xFF) << 8) | (classFile[9] & 0xFF);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Class/GetPackageTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,116 @@
+/**
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Basic test for Class.getPackage
+ * @compile Foo.java
+ * @run testng GetPackageTest
+ */
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.math.BigInteger;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Properties;
+
+import static org.testng.Assert.*;
+
+public class GetPackageTest {
+    private static Class<?> fooClass; // definePackage is not called for Foo class
+
+    @BeforeTest
+    public static void loadFooClass() throws ClassNotFoundException {
+        TestClassLoader loader = new TestClassLoader();
+        fooClass = loader.loadClass("foo.Foo");
+        assertEquals(fooClass.getClassLoader(), loader);
+    }
+
+    @DataProvider(name = "testclasses")
+    public Object[][] testClasses() {
+        return new Object[][] {
+                // primitive type, void, array types
+                { int.class,            null },
+                { long[].class,         null },
+                { Object[][].class,     null },
+                { void.class,           null },
+
+                // unnamed package
+                { GetPackageTest.class, "" },
+
+                // named package
+                { fooClass,             "foo" },
+                { Object.class,         "java.lang" },
+                { Properties.class,     "java.util" },
+                { BigInteger.class,     "java.math" },
+                { Test.class,           "org.testng.annotations" },
+        };
+    }
+
+    @Test(dataProvider = "testClasses")
+    public void testGetPackage(Class<?> type, String expected) {
+        Package p = type.getPackage();
+        if (expected == null) {
+            assertTrue(p == null);
+        } else {
+            assertEquals(p.getName(), expected);
+        }
+    }
+
+    static class TestClassLoader extends ClassLoader {
+        public TestClassLoader() {
+            super();
+        }
+
+        public TestClassLoader(ClassLoader parent) {
+            super(parent);
+        }
+
+        @Override
+        protected Class<?> findClass(String name) throws ClassNotFoundException {
+            Path p = Paths.get(System.getProperty("test.classes", "."));
+
+            try {
+                byte[] bb = Files.readAllBytes(p.resolve("foo/Foo.class"));
+                return defineClass(name, bb, 0, bb.length);
+            } catch (IOException e) {
+                throw new UncheckedIOException(e);
+            }
+        }
+        @Override
+        protected Class<?> loadClass(String cn, boolean resolve) throws ClassNotFoundException {
+            if (!cn.equals("foo.Foo"))
+                return super.loadClass(cn, resolve);
+            return findClass(cn);
+        }
+
+    }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Class/forName/modules/TestDriver.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.stream.Stream;
+
+import jdk.testlibrary.FileUtils;
+import static jdk.testlibrary.ProcessTools.*;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * @test
+ * @bug 8087335
+ * @summary Tests for Class.forName(Module,String)
+ * @library /lib/testlibrary
+ * @modules jdk.compiler
+ * @build TestDriver CompilerUtils jdk.testlibrary.ProcessTools jdk.testlibrary.FileUtils TestMain TestLayer
+ * @run testng TestDriver
+ */
+
+public class TestDriver {
+
+    private static final String TEST_SRC =
+            Paths.get(System.getProperty("test.src")).toString();
+    private static final String TEST_CLASSES =
+            Paths.get(System.getProperty("test.classes")).toString();
+
+    private static final Path MOD_SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path MOD_DEST_DIR = Paths.get("mods");
+
+    private static final String[] modules = new String[] {"m1", "m2", "m3"};
+
+    /**
+     * Compiles all modules used by the test.
+     */
+    @BeforeClass
+    public void setup() throws Exception {
+        assertTrue(CompilerUtils.compile(
+                        MOD_SRC_DIR, MOD_DEST_DIR,
+                        "-modulesourcepath",
+                        MOD_SRC_DIR.toString()));
+
+        copyDirectories(MOD_DEST_DIR.resolve("m1"), Paths.get("mods1"));
+        copyDirectories(MOD_DEST_DIR.resolve("m2"), Paths.get("mods2"));
+    }
+
+    @Test
+    public void test() throws Exception {
+        String[] options = new String[] {
+                "-cp", TEST_CLASSES,
+                "-mp", MOD_DEST_DIR.toString(),
+                "-addmods", String.join(",", modules),
+                "-m", "m2/p2.test.Main"
+        };
+        runTest(options);
+    }
+
+    @Test
+    public void testUnnamedModule() throws Exception {
+        String[] options = new String[] {
+                "-cp", TEST_CLASSES,
+                "-mp", MOD_DEST_DIR.toString(),
+                "-addmods", String.join(",", modules),
+                "TestMain"
+        };
+        runTest(options);
+    }
+
+    @Test
+    public void testLayer() throws Exception {
+        String[] options = new String[] {
+                "-cp", TEST_CLASSES,
+                "TestLayer"
+        };
+
+        runTest(options);
+    }
+
+    @Test
+    public void testDeniedClassLoaderAccess() throws Exception {
+        String[] options = new String[] {
+                "-mp", MOD_DEST_DIR.toString(),
+                "-addmods", String.join(",", modules),
+                "-m", "m3/p3.NoGetClassLoaderAccess"
+        };
+        assertTrue(executeTestJava(options)
+                        .outputTo(System.out)
+                        .errorTo(System.err)
+                        .getExitValue() == 0);
+    }
+
+    @Test
+    public void testDeniedAccess() throws Exception {
+        Path policyFile = Paths.get(TEST_SRC, "policy.denied");
+
+        String[] options = new String[] {
+                "-Djava.security.manager",
+                "-Djava.security.policy=" + policyFile.toString(),
+                "-mp", MOD_DEST_DIR.toString(),
+                "-addmods", String.join(",", modules),
+                "-m", "m3/p3.NoAccess"
+        };
+        assertTrue(executeTestJava(options)
+                        .outputTo(System.out)
+                        .errorTo(System.err)
+                        .getExitValue() == 0);
+    }
+
+    private String[] runWithSecurityManager(String[] options) {
+        Path policyFile = Paths.get(TEST_SRC, "policy");
+        Stream<String> opts = Stream.concat(Stream.of("-Djava.security.manager",
+                                                      "-Djava.security.policy=" + policyFile.toString()),
+                                            Arrays.stream(options));
+        return opts.toArray(String[]::new);
+    }
+
+    private void runTest(String[] options) throws Exception {
+        assertTrue(executeTestJava(options)
+                        .outputTo(System.out)
+                        .errorTo(System.err)
+                        .getExitValue() == 0);
+
+        assertTrue(executeTestJava(runWithSecurityManager(options))
+                        .outputTo(System.out)
+                        .errorTo(System.err)
+                        .getExitValue() == 0);
+    }
+
+    private void copyDirectories(Path source, Path dest) throws IOException {
+        if (Files.exists(dest))
+            FileUtils.deleteFileTreeWithRetry(dest);
+        Files.walk(source, Integer.MAX_VALUE)
+                .filter(Files::isRegularFile)
+                .forEach(p -> {
+                    try {
+                        Path to = dest.resolve(source.relativize(p));
+                        Files.createDirectories(to.getParent());
+                        Files.copy(p, to);
+                    } catch (IOException e) {
+                        throw new UncheckedIOException(e);
+                    }
+                });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Class/forName/modules/TestLayer.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.lang.module.Configuration;
+import java.lang.module.ModuleFinder;
+import java.lang.reflect.Layer;
+import java.lang.reflect.Method;
+import java.lang.reflect.Module;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Set;
+
+public class TestLayer {
+    private static final Path MODS_DIR = Paths.get("mods");
+    private static final Set<String> modules = Set.of("m1", "m2");
+
+    public static void main(String[] args) throws Exception {
+        // disable security manager until Class.forName is called.
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            System.setSecurityManager(null);
+        }
+
+        ModuleFinder finder = ModuleFinder.of(MODS_DIR);
+
+        Configuration parent = Layer.boot().configuration();
+        Configuration cf = parent.resolveRequiresAndUses(ModuleFinder.empty(),
+                                                         finder,
+                                                         modules);
+
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+        Layer layer = Layer.boot().defineModulesWithManyLoaders(cf, scl);
+
+        Module m1 = layer.findModule("m1").get();
+        Module m2 = layer.findModule("m2").get();
+
+        if (sm != null) {
+            System.setSecurityManager(sm);
+        }
+
+        // find exported and non-exported class from a named module
+        findClass(m1, "p1.A");
+        findClass(m1, "p1.internal.B");
+        findClass(m2, "p2.C");
+
+        // find class from unnamed module
+        ClassLoader ld = TestLayer.class.getClassLoader();
+        findClass(ld.getUnnamedModule(), "TestDriver");
+
+        // check if clinit should not be initialized
+        // compile without module-path; so use reflection
+        Class<?> c = Class.forName(m1, "p1.Initializer");
+        Method m = c.getMethod("isInited");
+        Boolean isClinited = (Boolean) m.invoke(null);
+        if (isClinited.booleanValue()) {
+           throw new RuntimeException("clinit should not be invoked");
+        }
+    }
+
+    static Class<?> findClass(Module module, String cn) {
+        Class<?> c = Class.forName(module, cn);
+        if (c == null) {
+            throw new RuntimeException(cn + " not found in " + module);
+        }
+        if (c.getModule() != module) {
+            throw new RuntimeException(c.getModule() + " != " + module);
+        }
+        return c;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Class/forName/modules/TestMain.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.lang.reflect.Layer;
+import java.lang.reflect.Method;
+import java.lang.reflect.Module;
+
+public class TestMain {
+    public static void main(String[] args) throws Exception {
+        Layer boot = Layer.boot();
+        Module m1 = boot.findModule("m1").get();
+        Module m2 = boot.findModule("m2").get();
+
+        // find exported and non-exported class from a named module
+        findClass(m1, "p1.A");
+        findClass(m1, "p1.internal.B");
+        findClass(m2, "p2.C");
+
+        // find class from unnamed module
+        ClassLoader loader = TestMain.class.getClassLoader();
+        findClass(loader.getUnnamedModule(), "TestDriver");
+
+        // check if clinit should not be initialized
+        // compile without module-path; so use reflection
+        Class<?> c = Class.forName(m1, "p1.Initializer");
+        Method m = c.getMethod("isInited");
+        Boolean isClinited = (Boolean) m.invoke(null);
+        if (isClinited.booleanValue()) {
+            throw new RuntimeException("clinit should not be invoked");
+        }
+    }
+
+    static Class<?> findClass(Module module, String cn) {
+        Class<?> c = Class.forName(module, cn);
+        if (c == null) {
+            throw new RuntimeException(cn + " not found in " + module);
+        }
+        if (c.getModule() != module) {
+            throw new RuntimeException(c.getModule() + " != " + module);
+        }
+        return c;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Class/forName/modules/policy	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,7 @@
+grant {
+    permission java.lang.RuntimePermission "setSecurityManager";
+    permission java.lang.RuntimePermission "getBootLayer";
+    permission java.lang.RuntimePermission "getClassLoader";
+    permission java.io.FilePermission "mods/-", "read";
+    permission java.util.PropertyPermission "user.dir", "read";
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Class/forName/modules/policy.denied	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,11 @@
+grant {
+    permission java.lang.RuntimePermission "setSecurityManager";
+    permission java.lang.RuntimePermission "getBootLayer";
+    permission java.lang.RuntimePermission "getClassLoader";
+    permission java.io.FilePermission "mods1", "read";
+    permission java.io.FilePermission "mods2", "read";
+    // only grant access to p1.* classes
+    // no access to p1.internal.* and p2.* classes
+    permission java.io.FilePermission "mods1/p1/*", "read";
+    permission java.util.PropertyPermission "user.dir", "read";
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Class/forName/modules/src/m1/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m1 {
+    exports p1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Class/forName/modules/src/m1/p1/A.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p1;
+
+public class A {
+    static {
+        Initializer.init();
+        System.out.println("p1.A is initialzed");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Class/forName/modules/src/m1/p1/Initializer.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p1;
+
+public class Initializer {
+    private static boolean inited = false;
+    static synchronized void init() {
+        inited = true;
+    }
+    public static synchronized boolean isInited() {
+        return inited;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Class/forName/modules/src/m1/p1/internal/B.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p1.internal;
+
+public class B {
+    public B() {}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Class/forName/modules/src/m2/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m2 {
+    exports p2;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Class/forName/modules/src/m2/p2/C.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p2;
+
+public class C {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Class/forName/modules/src/m2/p2/test/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p2.test;
+
+import java.lang.reflect.Layer;
+import java.lang.reflect.Module;
+
+public class Main {
+    public static void main(String... args) throws Exception {
+        Layer boot = Layer.boot();
+        Module m1 = boot.findModule("m1").get();
+        Module m2 = Main.class.getModule();
+
+        // find exported and non-exported class from a named module
+        findClass(m1, "p1.A");
+        findClass(m1, "p1.internal.B");
+        findClass(m2, "p2.C");
+
+        // find class from unnamed module
+        ClassLoader loader = m2.getClassLoader();
+        findClass(loader.getUnnamedModule(), "TestDriver");
+
+        try {
+            Class<?> c = findClass(m1, "p1.internal.B");
+            c.newInstance();
+            throw new RuntimeException(c.getName() + " is not exported to m2");
+        } catch (IllegalAccessException e) {}
+    }
+
+    static Class<?> findClass(Module module, String cn) {
+        Class<?> c = Class.forName(module, cn);
+        if (c == null) {
+            throw new RuntimeException(cn + " not found in " + module);
+        }
+        if (c.getModule() != module) {
+            throw new RuntimeException(c.getModule() + " != " + module);
+        }
+        return c;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Class/forName/modules/src/m3/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m3 {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Class/forName/modules/src/m3/p3/NoAccess.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p3;
+
+import java.io.FilePermission;
+import java.lang.module.Configuration;
+import java.lang.module.ModuleFinder;
+import java.lang.reflect.Layer;
+import java.lang.reflect.Module;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.AccessControlException;
+import java.security.Permission;
+import java.util.Set;
+
+public class NoAccess {
+    private static final Module M3 = NoAccess.class.getModule();
+    private static final Path MODS_DIR1 = Paths.get("mods1");
+    private static final Path MODS_DIR2 = Paths.get("mods2");
+    public static void main(String[] args) throws Exception {
+        // disable security manager until Class.forName is called.
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            System.setSecurityManager(null);
+        }
+
+        ModuleFinder finder = ModuleFinder.of(Paths.get("mods1"), Paths.get("mods2"));
+
+        Layer bootLayer = Layer.boot();
+        Configuration parent = bootLayer.configuration();
+
+        Configuration cf = parent.resolveRequiresAndUses(finder,
+                                                         ModuleFinder.empty(),
+                                                         Set.of("m1", "m2"));
+
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+        Layer layer = bootLayer.defineModulesWithManyLoaders(cf, scl);
+
+        if (sm != null) {
+            System.setSecurityManager(sm);
+        }
+
+        Module m1 = bootLayer.findModule("m1").get();
+        Module m2 = bootLayer.findModule("m2").get();
+        Module m3 = bootLayer.findModule("m3").get();
+
+        findClass(m1, "p1.internal.B");
+        findClass(m2, "p2.C");
+        findClass(m3, "p3.internal.Foo");
+
+        // permissions granted
+        findClass(m1, "p1.A");
+        findClass(m1, "p1.internal.B");
+        findClass(m2, "p2.C");
+        findClass(m3, "p3.internal.Foo");
+
+
+        // m1 and m2 from a different layer
+        m1 = layer.findModule("m1").get();
+        m2 = layer.findModule("m2").get();
+        m3 = layer.findModule("m3").get();
+
+        findClass(m1, "p1.A");
+        findClass(m3, "p3.internal.Foo");
+
+        // no permission
+        Path path = MODS_DIR1.resolve("p1").resolve("internal").resolve("B.class");
+        findClass(m1, "p1.internal.B", new FilePermission(path.toString(), "read"));
+        path = MODS_DIR2.resolve("p2").resolve("C.class");
+        findClass(m2, "p2.C", new FilePermission(path.toString(), "read"));
+    }
+
+    static Class<?> findClass(Module module, String cn) {
+        return findClass(module, cn, null);
+    }
+
+    static Class<?> findClass(Module module, String cn, Permission perm) {
+        try {
+            Class<?> c = Class.forName(module, cn);
+            if (c == null) {
+                throw new RuntimeException(cn + " not found in " + module);
+            }
+            if (c.getModule() != module) {
+                throw new RuntimeException(c.getModule() + " != " + module);
+            }
+            return c;
+        } catch (AccessControlException e) {
+            if (e.getPermission().equals(perm))
+                return null;
+            throw e;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Class/forName/modules/src/m3/p3/NoGetClassLoaderAccess.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p3;
+
+import java.lang.reflect.Layer;
+import java.lang.reflect.Module;
+import java.security.AccessControlException;
+import java.security.Permission;
+
+/**
+ * Verify RuntimePermission("getClassLoader") is needed to load
+ * a class in another module
+ */
+public class NoGetClassLoaderAccess {
+    private static final Module m3 = NoGetClassLoaderAccess.class.getModule();
+    private static final Permission GET_CLASSLOADER_PERMISSION = new RuntimePermission("getClassLoader");
+
+    public static void main(String[] args) throws Exception {
+        Layer boot = Layer.boot();
+
+        System.setSecurityManager(new SecurityManager());
+        Module m1 = boot.findModule("m1").get();
+        Module m2 = boot.findModule("m2").get();
+        findClass(m1, "p1.A");
+        findClass(m1, "p1.internal.B");
+        findClass(m2, "p2.C");
+        findClass(m3, "p3.internal.Foo");
+    }
+
+    static Class<?> findClass(Module module, String cn) {
+        try {
+            Class<?> c = Class.forName(module, cn);
+            if (c == null) {
+                throw new RuntimeException(cn + " not found in " + module);
+            }
+            if (c.getModule() != module) {
+                throw new RuntimeException(c.getModule() + " != " + module);
+            }
+            return c;
+        } catch (AccessControlException e) {
+            if (module != m3) {
+                if (e.getPermission().equals(GET_CLASSLOADER_PERMISSION))
+                    return null;
+            }
+            throw e;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Class/forName/modules/src/m3/p3/internal/Foo.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p3.internal;
+
+public class Foo {
+}
--- a/test/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -23,7 +23,11 @@
 
 import java.io.FilePermission;
 import java.io.IOException;
+import java.lang.reflect.AccessibleObject;
 import java.lang.reflect.Field;
+import java.lang.reflect.Module;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.InaccessibleObjectException;
 import java.lang.reflect.ReflectPermission;
 import java.net.URI;
 import java.nio.file.FileSystem;
@@ -47,6 +51,8 @@
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.stream.Stream;
 
+import jdk.internal.module.Modules;
+
 /**
  * @test
  * @bug 8065552
@@ -54,6 +60,7 @@
  *          set accessible if the right permission is granted; this test
  *          loads all the classes in the BCL, get their declared fields,
  *          and call setAccessible(false) followed by setAccessible(true);
+ * @modules java.base/jdk.internal.module
  * @run main/othervm FieldSetAccessibleTest UNSECURE
  * @run main/othervm FieldSetAccessibleTest SECURE
  *
@@ -73,22 +80,47 @@
 
 
     // Test that all fields for any given class can be made accessibles
-    static void testSetFieldsAccessible(Class<?> c) {
+    static void testSetFieldsAccessible(Class<?> c, boolean expectException) {
         for (Field f : c.getDeclaredFields()) {
             fieldCount.incrementAndGet();
-            f.setAccessible(false);
-            f.setAccessible(true);
+            boolean expect = expectException;
+            if ((c == Module.class || c == AccessibleObject.class) &&
+                !Modifier.isPublic(f.getModifiers())) {
+                expect = true;
+            }
+            try {
+                f.setAccessible(false);
+                f.setAccessible(true);
+                if (expect) {
+                    throw new RuntimeException(
+                        String.format("Expected InaccessibleObjectException is not thrown "
+                                      + "for field %s in class %s%n", f.getName(), c.getName()));
+                }
+            } catch (InaccessibleObjectException expected) {
+                if (!expect) {
+                    throw new RuntimeException(expected);
+                }
+            }
         }
     }
 
     // Performs a series of test on the given class.
     // At this time, we only call testSetFieldsAccessible(c)
-    public static boolean test(Class<?> c) {
-        //System.out.println(c.getName());
+    public static boolean test(Class<?> c, boolean addExports) {
+        Module self = FieldSetAccessibleTest.class.getModule();
+        Module target = c.getModule();
+        String pn = c.getPackage().getName();
+        boolean exported = self.canRead(target) && target.isExported(pn, self);
+        if (addExports && !exported) {
+            Modules.addExports(target, pn, self);
+            exported = true;
+        }
+        boolean expectException = !exported;
+
         classCount.incrementAndGet();
 
         // Call getDeclaredFields() and try to set their accessible flag.
-        testSetFieldsAccessible(c);
+        testSetFieldsAccessible(c, expectException);
 
         // add more tests here...
 
@@ -154,17 +186,25 @@
         final long start = System.nanoTime();
         boolean classFound = false;
         int index = 0;
-        for (String s: iterable) {
+        for (String s : iterable) {
             if (index == maxIndex) break;
             try {
                 if (index < startIndex) continue;
-                if (test(s)) {
+                if (test(s, false)) {
                     classFound = true;
                 }
             } finally {
                 index++;
             }
         }
+
+        // Re-test with all packages exported
+        for (String s : iterable) {
+            test(s, true);
+        }
+
+        classCount.set(classCount.get() / 2);
+        fieldCount.set(fieldCount.get() / 2);
         long elapsed = System.nanoTime() - start;
         long secs = elapsed / 1000_000_000;
         long millis = (elapsed % 1000_000_000) / 1000_000;
@@ -187,17 +227,13 @@
         }
     }
 
-    static boolean test(String s) {
+    static boolean test(String s, boolean addExports) {
         try {
-            if (s.startsWith("WrapperGenerator")) {
-                System.out.println("Skipping "+ s);
-                return false;
-            }
             final Class<?> c = Class.forName(
                     s.replace('/', '.').substring(0, s.length() - 6),
                     false,
                     systemClassLoader);
-            return test(c);
+            return test(c, addExports);
         } catch (Exception t) {
             t.printStackTrace(System.err);
             failed.add(s);
@@ -224,7 +260,7 @@
                     .filter(x -> x.getNameCount() > 2)
                     .map( x-> x.subpath(2, x.getNameCount()))
                     .map( x -> x.toString())
-                    .filter(s -> s.endsWith(".class"));
+                    .filter(s -> s.endsWith(".class") && !s.endsWith("module-info.class"));
         }
 
         @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Class/getPackageName/Basic.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @compile Basic.java
+ * @run testng p.Basic
+ * @summary Basic test for java.lang.Class::getPackageName
+ */
+
+package p;
+
+import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+import static org.testng.Assert.*;
+
+public class Basic {
+
+
+    // -- member classes --
+
+    static class Nested {
+        static class Foo { }
+    }
+
+    Class<?> getNestedClass1() {
+        return Nested.class;
+    }
+    Class<?> getNestedClass2() {
+        return Nested.Foo.class;
+    }
+
+    class Inner {
+        class Foo { }
+    }
+
+    Class<?> getInnerClass1() {
+        return Inner.class;
+    }
+    Class<?> getInnerClass2() {
+        return Inner.Foo.class;
+    }
+
+    // -- local and anonymous classes --
+
+    Class<?> getLocalClass1() {
+        class Local { }
+        return Local.class;
+    }
+
+    Class<?> getLocalClass2() {
+        class Local {
+            class Foo { }
+        }
+        return Local.Foo.class;
+    }
+
+    Class<?> getLocalClass3() {
+        class Local {
+            final Class<?> c;
+            Local() {
+                class Foo { }
+                this.c = Foo.class;
+            }
+            Class<?> get() {
+                return c;
+            }
+        }
+        return new Local().get();
+    }
+
+    Class<?> getAnonymousClass1() {
+        Runnable r = new Runnable() { public void run() { } };
+        return r.getClass();
+    }
+
+    Class<?> getAnonymousClass2() {
+        class Local {
+            Class<?> get() {
+                Runnable r = new Runnable() { public void run() { } };
+                return r.getClass();
+            }
+        }
+        return new Local().get();
+    }
+
+    Class<?> getAnonymousClass3() {
+        Runnable r = () -> { };
+        return r.getClass();
+    }
+
+    Class<?> getAnonymousClass4() {
+        class Local {
+            Class<?> get() {
+                Runnable r = () -> { };
+                return r.getClass();
+            }
+        }
+        return new Local().get();
+    }
+
+    Class<?> getAnonymousClass5() {
+        class Local {
+            final Class<?> c;
+            Local() {
+                Runnable r = new Runnable() { public void run() { } };
+                this.c = r.getClass();
+            }
+            Class<?> get() {
+                return c;
+            }
+        }
+        return new Local().get();
+    }
+
+    Class<?> getAnonymousClass6() {
+        class Local {
+            final Class<?> c;
+            Local() {
+                Runnable r = () -> { };
+                this.c = r.getClass();
+            }
+            Class<?> get() {
+                return c;
+            }
+        }
+        return new Local().get();
+    }
+
+    static final String TEST_PACKAGE = Basic.class.getPackage().getName();
+
+    @DataProvider(name = "classes")
+    public Object[][] classes() {
+        return new Object[][] {
+
+            { Basic.class,                  TEST_PACKAGE },
+            { Basic[].class,                null },
+            { Basic[][].class,              null },
+
+            { getNestedClass1(),            TEST_PACKAGE },
+            { getNestedClass2(),            TEST_PACKAGE },
+            { getInnerClass1(),             TEST_PACKAGE },
+            { getInnerClass2(),             TEST_PACKAGE },
+
+            { getLocalClass1(),             TEST_PACKAGE },
+            { getLocalClass2(),             TEST_PACKAGE },
+            { getLocalClass3(),             TEST_PACKAGE },
+
+            { getAnonymousClass1(),         TEST_PACKAGE },
+            { getAnonymousClass2(),         TEST_PACKAGE },
+            { getAnonymousClass3(),         TEST_PACKAGE },
+            { getAnonymousClass4(),         TEST_PACKAGE },
+            { getAnonymousClass5(),         TEST_PACKAGE },
+            { getAnonymousClass6(),         TEST_PACKAGE },
+
+            { Object.class,                 "java.lang" },
+            { Object[].class,               null },
+            { Object[][].class,             null },
+
+            { int.class,                    null },
+            { int[].class,                  null },
+            { int[][].class,                null },
+
+            { void.class,                   null },
+
+        };
+    }
+
+    @Test(dataProvider = "classes")
+    public void testPackageName(Class<?> type, String expected) {
+        assertEquals(type.getPackageName(), expected);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Class/getResource/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.lang.module.Configuration;
+import java.lang.module.ResolvedModule;
+import java.lang.reflect.Layer;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/**
+ * Basic test of Class getResource and getResourceAsStream when invoked from
+ * code in named modules.
+ */
+
+public class Main {
+
+    static final String NAME = "myresource";
+
+    public static void main(String[] args) throws IOException {
+
+        // create m1/myresource containing "m1"
+        Path file = directoryFor("m1").resolve(NAME);
+        Files.write(file, "m1".getBytes("UTF-8"));
+
+        // create m2/myresource containing "m2"
+        file = directoryFor("m2").resolve(NAME);
+        Files.write(file, "m2".getBytes("UTF-8"));
+
+        // check that m3/myresource does not exist
+        assertTrue(Files.notExists(directoryFor("m3").resolve(NAME)));
+
+        // invoke Class getResource from the unnamed module
+        URL url0 = Main.class.getResource("/" + NAME);
+        assertNull(url0);
+
+        // invoke Class getResource from modules m1-m3
+        URL url1 = p1.Main.getResource("/" + NAME);
+        URL url2 = p2.Main.getResource("/" + NAME);
+        URL url3 = p3.Main.getResource("/" + NAME);
+        assertNotNull(url1);
+        assertNotNull(url2);
+        assertNull(url3);
+
+        // check contents of resurces at url1 and url2
+        assertEquals(new String(readAll(url1), "UTF-8"), "m1");
+        assertEquals(new String(readAll(url2), "UTF-8"), "m2");
+
+        // invoke Class getResourceAsStream from the unnamed module
+        InputStream in0 = Main.class.getResourceAsStream("/" + NAME);
+        assertNull(in0);
+
+        // invoke Class getResourceAsStream from modules m1-m3
+        try (InputStream in = p1.Main.getResourceAsStream("/" + NAME)) {
+            String s = new String(in.readAllBytes(), "UTF-8");
+            assertEquals(s, "m1");
+        }
+        try (InputStream in = p2.Main.getResourceAsStream("/" + NAME)) {
+            String s = new String(in.readAllBytes(), "UTF-8");
+            assertEquals(s, "m2");
+        }
+        InputStream in3 = p3.Main.getResourceAsStream("/" + NAME);
+        assertNull(in3);
+
+        // invoke Module getResources on modules m1-m3
+        InputStream in1 = p1.Main.class.getModule().getResourceAsStream("/" + NAME);
+        InputStream in2 = p2.Main.class.getModule().getResourceAsStream("/" + NAME);
+        in3 = p3.Main.class.getModule().getResourceAsStream("/" + NAME);
+        assertNotNull(in1);
+        assertNotNull(in2);
+        assertNull(in3);
+
+        // check the content of in1 and in2
+        String s1 = new String(in1.readAllBytes(), "UTF-8");
+        String s2 = new String(in2.readAllBytes(), "UTF-8");
+        assertEquals(s1, "m1");
+        assertEquals(s2, "m2");
+
+        // SecurityManager case
+        System.setSecurityManager(new SecurityManager());
+
+        assertNull(Main.class.getResource("/" + NAME));
+        assertNull(p1.Main.getResource("/" + NAME));
+        assertNull(p2.Main.getResource("/" + NAME));
+        assertNull(p3.Main.getResource("/" + NAME));
+
+        assertNull(Main.class.getResourceAsStream("/" + NAME));
+        assertNull(p1.Main.getResourceAsStream("/" + NAME));
+        assertNull(p2.Main.getResourceAsStream("/" + NAME));
+        assertNull(p3.Main.getResourceAsStream("/" + NAME));
+
+        System.out.println("Success!");
+    }
+
+    /**
+     * Returns the directory for the given module (by name).
+     */
+    static Path directoryFor(String name) {
+        Configuration cf = Layer.boot().configuration();
+        ResolvedModule resolvedModule = cf.findModule(name).orElse(null);
+        if (resolvedModule == null)
+            throw new RuntimeException("not found: " + name);
+        Path dir = Paths.get(resolvedModule.reference().location().get());
+        if (!Files.isDirectory(dir))
+            throw new RuntimeException("not a directory: " + dir);
+        return dir;
+    }
+
+    static byte[] readAll(URL url) throws IOException {
+        try (InputStream in = url.openStream()) {
+            return in.readAllBytes();
+        }
+    }
+
+    static void assertTrue(boolean condition) {
+        if (!condition) throw new RuntimeException();
+    }
+
+    static void assertNull(Object o) {
+        assertTrue(o == null);
+    }
+
+    static void assertNotNull(Object o) {
+        assertTrue(o != null);
+    }
+
+    static void assertEquals(Object actual, Object expected) {
+        if (expected == null) {
+            assertNull(actual);
+        } else {
+            assertTrue(expected.equals(actual));
+        }
+    }
+
+    static void assertNotEquals(Object actual, Object expected) {
+        if (expected == null) {
+            assertNotNull(actual);
+        } else {
+            assertTrue(!expected.equals(actual));
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Class/getResource/ResourcesTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import static jdk.testlibrary.ProcessTools.executeTestJava;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/**
+ * @test
+ * @library /lib/testlibrary
+ * @modules jdk.compiler
+ * @build ResourcesTest CompilerUtils jdk.testlibrary.*
+ * @run testng ResourcesTest
+ * @summary Driver for basic test of Class getResource and getResourceAsStream
+ */
+
+@Test
+public class ResourcesTest {
+
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path CLASSES_DIR = Paths.get("classes");
+    private static final Path MODS_DIR = Paths.get("mods");
+
+
+    /**
+     * Compiles the modules used by the test and the test Main
+     */
+    @BeforeTest
+    public void compileAll() throws Exception {
+        boolean compiled;
+
+        // javac -modulesource mods -d mods src/**
+        compiled = CompilerUtils
+            .compile(SRC_DIR,
+                     MODS_DIR,
+                     "-modulesourcepath", SRC_DIR.toString());
+        assertTrue(compiled);
+
+        // javac -mp mods -d classes Main.java
+        compiled = CompilerUtils
+            .compile(Paths.get(TEST_SRC, "Main.java"),
+                     CLASSES_DIR,
+                     "-mp", MODS_DIR.toString(),
+                     "-addmods", "m1,m2,m3");
+        assertTrue(compiled);
+
+    }
+
+    /**
+     * Run the test
+     */
+    public void runTest() throws Exception {
+
+        int exitValue
+            = executeTestJava("-mp", MODS_DIR.toString(),
+                              "-addmods", "m1,m2,m3",
+                               "-cp", CLASSES_DIR.toString(),
+                              "Main")
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
+
+        assertTrue(exitValue == 0);
+
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Class/getResource/src/m1/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m1 {
+    exports p1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Class/getResource/src/m1/p1/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p1;
+
+import java.io.InputStream;
+import java.net.URL;
+
+public class Main {
+    private Main() { }
+
+    public static URL getResource(String name) {
+        return Main.class.getResource(name);
+    }
+
+    public static InputStream getResourceAsStream(String name) {
+        return Main.class.getResourceAsStream(name);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Class/getResource/src/m2/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m2 {
+    exports p2;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Class/getResource/src/m2/p2/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p2;
+
+import java.io.InputStream;
+import java.net.URL;
+
+public class Main {
+    private Main() { }
+
+    public static URL getResource(String name) {
+        return Main.class.getResource(name);
+    }
+
+    public static InputStream getResourceAsStream(String name) {
+        return Main.class.getResourceAsStream(name);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Class/getResource/src/m3/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m3 {
+    exports p3;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Class/getResource/src/m3/p3/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p3;
+
+import java.io.InputStream;
+import java.net.URL;
+
+public class Main {
+    private Main() { }
+
+    public static URL getResource(String name) {
+        return Main.class.getResource(name);
+    }
+
+    public static InputStream getResourceAsStream(String name) {
+        return Main.class.getResourceAsStream(name);
+    }
+}
--- a/test/java/lang/ClassLoader/GetSystemPackage.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/lang/ClassLoader/GetSystemPackage.java	Thu Mar 17 19:04:16 2016 +0000
@@ -85,15 +85,15 @@
         buildJar("no-manifest.jar", null);
 
         runSubProcess("System package with manifest improperly resolved.",
-                "-Xbootclasspath/p:" + testClassesDir + "/manifest.jar",
+                "-Xbootclasspath/a:" + testClassesDir + "/manifest.jar",
                 "GetSystemPackage", "system-manifest");
 
         runSubProcess("System package from directory improperly resolved.",
-                "-Xbootclasspath/p:" + testClassesDir, "GetSystemPackage",
+                "-Xbootclasspath/a:" + testClassesDir, "GetSystemPackage",
                 "system-no-manifest");
 
         runSubProcess("System package with no manifest improperly resolved",
-                "-Xbootclasspath/p:" + testClassesDir + "/no-manifest.jar",
+                "-Xbootclasspath/a:" + testClassesDir + "/no-manifest.jar",
                 "GetSystemPackage", "system-no-manifest");
 
         runSubProcess("Classpath package with manifest improperly resolved",
@@ -112,8 +112,6 @@
                 testClassesDir + "/package2/Class2.class");
         jar.addClassFile("GetSystemPackage.class",
                 testClassesDir + "/GetSystemPackage.class");
-        jar.addClassFile("GetSystemPackageClassLoader.class",
-                testClassesDir + "/GetSystemPackageClassLoader.class");
         jar.build();
     }
 
@@ -128,9 +126,10 @@
     }
 
     private static void verifyPackage(boolean hasManifest,
-            boolean isSystemPackage) throws Exception
+                                      boolean isSystemPackage)
+            throws Exception
     {
-        Class c = Class.forName("package2.Class2");
+        Class<?> c = Class.forName("package2.Class2");
         Package pkg = c.getPackage();
         if (pkg == null || pkg != Package.getPackage("package2") ||
                 !"package2".equals(pkg.getName())) {
@@ -148,14 +147,11 @@
         }
         if (!hasManifest && specificationTitle != null) {
             fail("Invalid manifest for package " + pkg.getName() + ": was " +
-                 specificationTitle + " expected: null");
+                    specificationTitle + " expected: null");
         }
 
-        // force the use of a classloader with no parent, then retrieve the
-        // package in a way that bypasses the classloader pkg maps
-        GetSystemPackageClassLoader classLoader =
-                new GetSystemPackageClassLoader();
-        Package systemPkg = classLoader.getSystemPackage("package2");
+        ClassLoader ld = c.getClassLoader();
+        Package systemPkg = ld != null ? null : Package.getPackage("package2");
 
         if (findPackage("java.lang") == null) {
             fail("java.lang not found via Package.getPackages()");
@@ -194,21 +190,6 @@
 }
 
 /*
- * This classloader bypasses the system classloader to give as direct access
- * to Package.getSystemPackage() as possible
- */
-class GetSystemPackageClassLoader extends ClassLoader {
-
-    public GetSystemPackageClassLoader() {
-        super(null);
-    }
-
-    public Package getSystemPackage(String name) {
-        return super.getPackage(name);
-    }
-}
-
-/*
  * Helper class for building jar files
  */
 class JarBuilder {
--- a/test/java/lang/ClassLoader/findSystemClass/Loader.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/lang/ClassLoader/findSystemClass/Loader.java	Thu Mar 17 19:04:16 2016 +0000
@@ -44,7 +44,6 @@
  *      - Loadee.java            (source for a class that refers to Loader)
  *      - Loadee.classfile       (to test findSystemClass)
  *      - Loadee.resource        (to test getSystemResource)
- *      - java/lang/Object.class (to test getSystemResources)
  *
  * The extension ".classfile" is so the class file is not seen by any loader
  * other than Loader.  If you need to make any changes you will have to
@@ -127,25 +126,6 @@
                 throw new Exception
                     ("java.lang.ClassLoader.getSystemResource() test failed!");
         }
-
-        if ((tests & RESOURCES) == RESOURCES) {
-            report("getSystemResources()");
-            java.util.Enumeration e =
-                getSystemResources("java/lang/Object.class");
-            HashSet hs = new HashSet();
-            while (e.hasMoreElements()) {
-                URL u = (URL)e.nextElement();
-                if (u == null)
-                    break;
-                System.out.println("url: " + u);
-                hs.add(u);
-            }
-            if (hs.size() != 2) {
-                throw
-                    new Exception("java.lang.ClassLoader.getSystemResources()"+
-                                  " did not find all resources");
-            }
-        }
     }
 
     private static void report(String s) {
--- a/test/java/lang/ClassLoader/getResource/GetResource.sh	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/lang/ClassLoader/getResource/GetResource.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -29,21 +29,12 @@
 #
 # @run shell GetResource.sh
 
-if [ "${TESTSRC}" = "" ] ; then
-    TESTSRC=`pwd`
-fi
-if [ "${TESTCLASSES}" = "" ] ; then
-    TESTCLASSES=`pwd`
-fi
-
-if [ "${TESTJAVA}" = "" ] ; then
-    echo "TESTJAVA not set.  Test cannot execute."
-    echo "FAILED!!!"
-    exit 1
-fi
-
-if [ "${COMPILEJAVA}" = "" ] ; then
-    COMPILEJAVA="${TESTJAVA}"
+if [ -z "$TESTJAVA" ]; then
+  if [ $# -lt 1 ]; then exit 1; fi
+  TESTJAVA="$1"; shift
+  COMPILEJAVA="${TESTJAVA}"
+  TESTSRC="`pwd`"
+  TESTCLASSES="`pwd`"
 fi
 
 # set platform-specific variables
@@ -96,12 +87,7 @@
 cd ${TESTCLASSES}
 DIR=`pwd`
 
-#    Expected    -Xbootclasspath
-#    Location    or -classpath
-runTest "a"      "-Xbootclasspath/p:a"
-runTest "a"      "-Xbootclasspath/p:a${PS}b"
-runTest "b"      "-Xbootclasspath/p:b" 
-runTest "b"      "-Xbootclasspath/p:b${PS}a"
+#    Expected    -classpath
 runTest "a"      -cp a
 runTest "a"      -cp "a${PS}b"
 runTest "b"      -cp b
@@ -109,16 +95,10 @@
 
 cd ${DIR}/a
 
-runTest "a"      "-Xbootclasspath/p:."
-runTest "b"      "-Xbootclasspath/p:../b" 
-
 # no -classpath
 runTest "a"      -cp "${PS}"                            
 runTest "b"      -cp "../b"                   
 
-# Test empty path in bootclasspath not default to current working directory
-runTest "b"      "-Xbootclasspath/p:${PS}../b" 
-
 # Test empty path in classpath default to current working directory
 runTest "a"      -cp "${PS}../b"
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/ClassLoader/getResource/modules/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.lang.module.Configuration;
+import java.lang.module.ResolvedModule;
+import java.lang.reflect.Layer;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/**
+ * Basic test of ClassLoader getResource and getResourceAsStream when
+ * invoked from code in named modules.
+ */
+
+public class Main {
+
+    static final String NAME = "myresource";
+
+    public static void main(String[] args) throws IOException {
+
+        // create m1/myresource containing "m1"
+        Path file = directoryFor("m1").resolve(NAME);
+        Files.write(file, "m1".getBytes("UTF-8"));
+
+        // create m2/myresource containing "m2"
+        file = directoryFor("m2").resolve(NAME);
+        Files.write(file, "m2".getBytes("UTF-8"));
+
+        // check that m3/myresource does not exist
+        assertTrue(Files.notExists(directoryFor("m3").resolve(NAME)));
+
+        // invoke ClassLoader getResource from the unnamed module
+        assertNull(Main.class.getClassLoader().getResource("/" + NAME));
+
+        // invoke ClassLoader getResource from modules m1-m3
+        // Resources in a named module are private to that module.
+        // ClassLoader.getResource should not find resource in named modules.
+        assertNull(p1.Main.getResourceInClassLoader("/" + NAME));
+        assertNull(p2.Main.getResourceInClassLoader("/" + NAME));
+        assertNull(p3.Main.getResourceInClassLoader("/" + NAME));
+
+        // invoke ClassLoader getResourceAsStream from the unnamed module
+        assertNull(Main.class.getClassLoader().getResourceAsStream("/" + NAME));
+
+        // invoke ClassLoader getResourceAsStream from modules m1-m3
+        // Resources in a named module are private to that module.
+        // ClassLoader.getResourceAsStream should not find resource in named modules.
+        assertNull(p1.Main.getResourceAsStreamInClassLoader("/" + NAME));
+        assertNull(p2.Main.getResourceAsStreamInClassLoader("/" + NAME));
+        assertNull(p3.Main.getResourceAsStreamInClassLoader("/" + NAME));
+
+        // SecurityManager case
+        System.setSecurityManager(new SecurityManager());
+
+        assertNull(Main.class.getClassLoader().getResource("/" + NAME));
+        assertNull(p1.Main.getResourceInClassLoader("/" + NAME));
+        assertNull(p2.Main.getResourceInClassLoader("/" + NAME));
+        assertNull(p3.Main.getResourceInClassLoader("/" + NAME));
+
+        assertNull(Main.class.getClassLoader().getResourceAsStream("/" + NAME));
+        assertNull(p1.Main.getResourceAsStreamInClassLoader("/" + NAME));
+        assertNull(p2.Main.getResourceAsStreamInClassLoader("/" + NAME));
+        assertNull(p3.Main.getResourceAsStreamInClassLoader("/" + NAME));
+
+        System.out.println("Success!");
+    }
+
+    /**
+     * Returns the directory for the given module (by name).
+     */
+    static Path directoryFor(String mn) {
+        Configuration cf = Layer.boot().configuration();
+        ResolvedModule resolvedModule = cf.findModule(mn).orElse(null);
+        if (resolvedModule == null)
+            throw new RuntimeException("not found: " + mn);
+        Path dir = Paths.get(resolvedModule.reference().location().get());
+        if (!Files.isDirectory(dir))
+            throw new RuntimeException("not a directory: " + dir);
+        return dir;
+    }
+
+    static void assertTrue(boolean condition) {
+        if (!condition) throw new RuntimeException();
+    }
+
+    static void assertNull(Object o) {
+        assertTrue(o == null);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/ClassLoader/getResource/modules/ResourcesTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import static jdk.testlibrary.ProcessTools.executeTestJava;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/**
+ * @test
+ * @bug 8087335
+ * @library /lib/testlibrary
+ * @modules jdk.compiler
+ * @build ResourcesTest CompilerUtils jdk.testlibrary.*
+ * @run testng ResourcesTest
+ * @summary Driver for basic test of ClassLoader getResource and getResourceAsStream
+ */
+
+@Test
+public class ResourcesTest {
+
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path CLASSES_DIR = Paths.get("classes");
+    private static final Path MODS_DIR = Paths.get("mods");
+
+    /**
+     * Compiles the modules used by the test and the test Main
+     */
+    @BeforeTest
+    public void compileAll() throws Exception {
+        boolean compiled;
+
+        // javac -modulesource mods -d mods src/**
+        compiled = CompilerUtils
+            .compile(SRC_DIR,
+                     MODS_DIR,
+                     "-modulesourcepath", SRC_DIR.toString());
+        assertTrue(compiled);
+
+        // javac -mp mods -d classes Main.java
+        compiled = CompilerUtils
+            .compile(Paths.get(TEST_SRC, "Main.java"),
+                     CLASSES_DIR,
+                     "-mp", MODS_DIR.toString(),
+                     "-addmods", "m1,m2,m3");
+        assertTrue(compiled);
+    }
+
+    /**
+     * Run the test
+     */
+    public void runTest() throws Exception {
+        int exitValue
+            = executeTestJava("-mp", MODS_DIR.toString(),
+                              "-addmods", "m1,m2,m3",
+                               "-cp", CLASSES_DIR.toString(),
+                              "Main")
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
+
+        assertTrue(exitValue == 0);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/ClassLoader/getResource/modules/src/m1/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m1 {
+    exports p1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/ClassLoader/getResource/modules/src/m1/p1/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p1;
+
+import java.io.InputStream;
+import java.net.URL;
+
+public class Main {
+    private Main() { }
+
+    public static URL getResourceInClassLoader(String name) {
+        return Main.class.getClassLoader().getResource(name);
+    }
+
+    public static InputStream getResourceAsStreamInClassLoader(String name) {
+        return Main.class.getClassLoader().getResourceAsStream(name);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/ClassLoader/getResource/modules/src/m2/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m2 {
+    exports p2;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/ClassLoader/getResource/modules/src/m2/p2/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p2;
+
+import java.io.InputStream;
+import java.net.URL;
+
+public class Main {
+    private Main() { }
+
+    public static URL getResourceInClassLoader(String name) {
+        return Main.class.getClassLoader().getResource(name);
+    }
+
+    public static InputStream getResourceAsStreamInClassLoader(String name) {
+        return Main.class.getClassLoader().getResourceAsStream(name);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/ClassLoader/getResource/modules/src/m3/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m3 {
+    exports p3;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/ClassLoader/getResource/modules/src/m3/p3/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p3;
+
+import java.io.InputStream;
+import java.net.URL;
+
+public class Main {
+    private Main() { }
+
+    public static URL getResourceInClassLoader(String name) {
+        return Main.class.getClassLoader().getResource(name);
+    }
+
+    public static InputStream getResourceAsStreamInClassLoader(String name) {
+        return Main.class.getClassLoader().getResourceAsStream(name);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/ClassLoader/platformClassLoader/DefinePlatformClass.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Test java.* class defined by the platform class loader
+ * @build jdk.zipfs/java.fake.Fake
+ * @modules jdk.zipfs/java.fake
+ * @run main DefinePlatformClass
+ */
+
+import java.fake.Fake;
+
+public class DefinePlatformClass {
+    public static void main(String... args) {
+        Fake fake = new Fake();
+        fake.run();
+        ClassLoader loader = fake.getClass().getClassLoader();
+        if (loader != ClassLoader.getPlatformClassLoader()) {
+            throw new RuntimeException("unexpected class loader: " + loader);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/ClassLoader/platformClassLoader/jdk.zipfs/java/fake/Fake.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.fake;
+
+public class Fake {
+    public void run() {}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Package/Foo.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package foo;
+
+public class Foo {
+    /**
+     * Returns all Packages visible to the class loader defining by
+     * this Foo class.  Package.getPackages() is caller-sensitive.
+     */
+    public static Package[] getPackages() {
+        return Package.getPackages();
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Package/GetPackages.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Test Package object is local to each ClassLoader.
+ *          There can be one Package object of "foo" name defined by
+ *          different class loader.
+ * @compile Foo.java
+ * @run testng GetPackages
+ */
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.lang.reflect.*;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+public class GetPackages {
+    final TestClassLoader loader;
+    final Class<?> fooClass;
+    /*
+     * Each TestClassLoader defines a "foo.Foo" class which has a unique
+     * Package object of "foo" regardless whether its ancestor class loader
+     * defines a package "foo" or not.
+     */
+    GetPackages(TestClassLoader loader) throws ClassNotFoundException {
+        this.loader = loader;
+        this.fooClass = loader.loadClass("foo.Foo");
+    }
+
+    /*
+     * Check package "foo" defined locally in the TestClassLoader
+     * as well as its ancestors.
+     */
+    void checkPackage() throws ClassNotFoundException {
+        // Name of an unnamed package is empty string
+        assertEquals(this.getClass().getPackage().getName(), "");
+
+        assertEquals(fooClass.getClassLoader(), loader);
+
+        Package p = loader.getDefinedPackage("foo");
+        assertEquals(p.getName(), "foo");
+        assertEquals(p, loader.getPackage("foo"));
+
+        if (loader.getParent() != null) {
+            Package p2 = ((TestClassLoader)loader.getParent()).getDefinedPackage("foo");
+            assertTrue(p != p2);
+        }
+
+        long count = Arrays.stream(loader.getDefinedPackages())
+                            .map(Package::getName)
+                            .filter(pn -> pn.equals("foo"))
+                            .count();
+        assertEquals(count, 1);
+    }
+
+    /*
+     * Check the number of package "foo" defined to this class loader and
+     * its ancestors
+     */
+    Package[] getPackagesFromLoader() {
+        return loader.packagesInClassLoaderChain();
+    }
+
+    /*
+     * Package.getPackages is caller-sensitve.  Call through Foo class
+     * to find all Packages visible to this TestClassLoader and its ancestors
+     */
+    Package[] getPackagesFromFoo() throws Exception {
+        Method m = fooClass.getMethod("getPackages");
+        return (Package[])m.invoke(null);
+    }
+
+    private static long numFooPackages(Package[] pkgs) throws Exception {
+        return Arrays.stream(pkgs)
+                     .filter(p -> p.getName().equals("foo"))
+                     .count();
+    }
+
+    @DataProvider(name = "loaders")
+    public static Object[][] testLoaders() {
+        TestClassLoader loader1 = new TestClassLoader(null);
+        TestClassLoader loader2 = new TestClassLoader(loader1);
+        TestClassLoader loader3 = new TestClassLoader(loader2);
+
+        // Verify the number of expected Package object of "foo" visible
+        // to the class loader
+        return new Object[][] {
+                { loader1, 1 },
+                { loader2, 2 },
+                { loader3, 3 }
+        };
+    }
+
+    @Test(dataProvider = "loaders")
+    public static void test(TestClassLoader loader, long expected) throws Exception {
+        GetPackages test = new GetPackages(loader);
+        // check package "foo" existence
+        test.checkPackage();
+
+        assertEquals(numFooPackages(test.getPackagesFromLoader()), expected);
+        assertEquals(numFooPackages(test.getPackagesFromFoo()), expected);
+    }
+}
+
+class TestClassLoader extends ClassLoader {
+    public TestClassLoader() {
+        super();
+    }
+
+    public TestClassLoader(ClassLoader parent) {
+        super(parent);
+    }
+
+    public Package getPackage(String pn) {
+        return super.getPackage(pn);
+    }
+
+    public Package[] packagesInClassLoaderChain() {
+        return super.getPackages();
+    }
+
+    @Override
+    protected Class<?> findClass(String name) throws ClassNotFoundException {
+        Path p = Paths.get(System.getProperty("test.classes", "."));
+
+        try {
+            byte[] bb = Files.readAllBytes(p.resolve("foo/Foo.class"));
+            return defineClass(name, bb, 0, bb.length);
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+    @Override
+    protected Class<?> loadClass(String cn, boolean resolve) throws ClassNotFoundException {
+        if (!cn.equals("foo.Foo"))
+            return super.loadClass(cn, resolve);
+        return findClass(cn);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Package/annotation/PackageInfoTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Basic test of package-info in named module and duplicate
+ *          package-info in unnamed module
+ * @modules java.compiler
+ *          java.desktop
+ *          jdk.compiler
+ *          jdk.xml.dom
+ * @build jdk.xml.dom/org.w3c.dom.css.Fake
+ *        jdk.xml.dom/org.w3c.dom.css.FakePackage
+ * @compile/module=jdk.xml.dom org/w3c/dom/css/package-info.java
+ * @compile package-info.java PackageInfoTest.java
+ * @run testng p.PackageInfoTest
+ */
+
+package p;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.lang.annotation.Annotation;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import org.w3c.dom.css.CSSRule;
+
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.ToolProvider;
+
+import static org.testng.Assert.*;
+
+public class PackageInfoTest {
+    @DataProvider(name = "jdkClasses")
+    public Object[][] jdkClasses() {
+        return new Object[][] {
+            { java.awt.Button.class,             null },
+            { java.lang.Object.class,            null },
+            { org.w3c.dom.css.CSSRule.class,     null },
+            { loadClass("org.w3c.dom.css.Fake"), loadClass("org.w3c.dom.css.FakePackage") },
+        };
+    }
+
+    @Test(dataProvider = "jdkClasses")
+    public void testPackageInfo(Class<?> type, Class<? extends Annotation> annType) {
+        Package pkg = type.getPackage();
+        assertTrue(pkg.isSealed());
+        assertTrue(annType == null || pkg.getDeclaredAnnotations().length != 0);
+        if (annType != null) {
+            assertTrue(pkg.isAnnotationPresent(annType));
+        }
+    }
+
+    private Class<?> loadClass(String name) {
+        return Class.forName(CSSRule.class.getModule(), name);
+    }
+
+    @DataProvider(name = "classpathClasses")
+    public Object[][] cpClasses() throws IOException, ClassNotFoundException {
+        // these classes will be loaded from classpath in unnamed module
+        return new Object[][]{
+                { p.PackageInfoTest.class, Deprecated.class }
+        };
+    }
+
+    @Test(dataProvider = "classpathClasses")
+    public void testClassPathPackage(Class<?> type, Class<? extends Annotation> annType) {
+        Package pkg = type.getPackage();
+        assertTrue(pkg.isSealed() == false);
+        assertTrue(pkg.isAnnotationPresent(annType));
+    }
+
+    static final String[] otherClasses = new String[] {
+            "p/package-info.class",
+            "p/Duplicate.class",
+            "p/Bar.class"
+    };
+
+    @Test
+    public void testDuplicatePackage() throws Exception {
+        // a custom class loader loading another package p annotated with @Duplicate
+        Path classes = Paths.get(System.getProperty("test.classes", "."), "tmp");
+        Files.createDirectories(classes);
+        URLClassLoader loader = new URLClassLoader(new URL[] { classes.toUri().toURL() });
+
+        // clean up before compiling classes
+        Arrays.stream(otherClasses)
+                .forEach(c -> {
+                    try {
+                        Files.deleteIfExists(classes.resolve(c));
+                    } catch (IOException e) {
+                        throw new UncheckedIOException(e);
+                    }
+                });
+
+        Path src = Paths.get(System.getProperty("test.src", "."), "src", "p");
+        compile(classes,
+                src.resolve("package-info.java"),
+                src.resolve("Duplicate.java"),
+                src.resolve("Bar.java"));
+
+        // verify if classes are present
+        Arrays.stream(otherClasses)
+              .forEach(c -> {
+                  if (Files.notExists(classes.resolve(c))) {
+                      throw new RuntimeException(c + " not exist");
+                  }
+        });
+
+        Class<?> c = Class.forName("p.Bar", true, loader);
+        assertTrue(c.getClassLoader() == loader);
+        assertTrue(this.getClass().getClassLoader() != loader);
+
+        // package p defined by the custom class loader
+        Package pkg = c.getPackage();
+        assertTrue(pkg.getName().equals("p"));
+        assertTrue(pkg.isSealed() == false);
+
+        // package p defined by the application class loader
+        Package p = this.getClass().getPackage();
+        assertTrue(p.getName().equals("p"));
+        assertTrue(p != pkg);
+
+        Arrays.stream(pkg.getDeclaredAnnotations())
+              .forEach(ann -> System.out.format("%s @%s%n", pkg.getName(), ann));
+
+        Arrays.stream(p.getDeclaredAnnotations())
+              .forEach(ann -> System.out.format("%s @%s%n", p.getName(), ann));
+
+        // local package p defined by loader
+        Class<? extends Annotation> ann =
+            (Class<? extends Annotation>)Class.forName("p.Duplicate", false, loader);
+        assertTrue(pkg.isAnnotationPresent(ann));
+    }
+
+    private void compile(Path destDir, Path... files) throws IOException {
+        compile(null, destDir, files);
+    }
+
+    private void compile(String option, Path destDir, Path... files)
+            throws IOException
+    {
+        System.err.println("compile...");
+        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+        try (StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null)) {
+            Iterable<? extends JavaFileObject> fileObjects =
+                fm.getJavaFileObjectsFromPaths(Arrays.asList(files));
+
+            List<String> options = new ArrayList<>();
+            if (option != null) {
+                options.add(option);
+            }
+            if (destDir != null) {
+                options.add("-d");
+                options.add(destDir.toString());
+            }
+            options.add("-cp");
+            options.add(System.getProperty("test.classes", "."));
+
+            JavaCompiler.CompilationTask task =
+                compiler.getTask(null, fm, null, options, null, fileObjects);
+            if (!task.call())
+                throw new AssertionError("compilation failed");
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Package/annotation/jdk.xml.dom/org/w3c/dom/css/Fake.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.w3c.dom.css;
+
+public class Fake {}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Package/annotation/jdk.xml.dom/org/w3c/dom/css/FakePackage.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.w3c.dom.css;
+
+import java.lang.annotation.*;
+import static java.lang.annotation.ElementType.*;
+
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(value={PACKAGE})
+public @interface FakePackage {
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Package/annotation/jdk.xml.dom/org/w3c/dom/css/package-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+@FakePackage
+package org.w3c.dom.css;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Package/annotation/package-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+@Deprecated
+package p;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Package/annotation/src/p/Bar.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p;
+
+public class Bar {}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Package/annotation/src/p/Duplicate.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p;
+
+import java.lang.annotation.*;
+import static java.lang.annotation.ElementType.*;
+
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(value={PACKAGE})
+public @interface Duplicate {
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Package/annotation/src/p/package-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+@Duplicate
+package p;
--- a/test/java/lang/SecurityManager/RestrictedPackages.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/lang/SecurityManager/RestrictedPackages.java	Thu Mar 17 19:04:16 2016 +0000
@@ -77,6 +77,7 @@
         "jdk.internal.",
         "jdk.nashorn.internal.",
         "jdk.nashorn.tools.",
+        "jdk.rmi.rmic.",
         "jdk.tools.jimage.",
         "com.sun.activation.registries.",
         "com.sun.java.accessibility.util.internal."
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/SecurityManager/modules/CustomSecurityManager.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,66 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+# @test
+# @summary Basic test of -Djava.security.manager to a class in named module.
+
+set -e
+
+if [ -z "$TESTJAVA" ]; then
+  if [ $# -lt 1 ]; then exit 1; fi
+  TESTJAVA="$1"; shift
+  COMPILEJAVA="${TESTJAVA}"
+  TESTSRC=`pwd`
+  TESTCLASSES=`pwd`
+fi
+
+OS=`uname -s`
+case "$OS" in
+  Windows*)
+    PS=";"
+    ;;
+  CYGWIN* )
+    PS=";"
+    ;;
+  * )
+    PS=":"
+    ;;
+esac
+
+JAVAC="$COMPILEJAVA/bin/javac"
+JAVA="$TESTJAVA/bin/java ${TESTVMOPTS}"
+
+mkdir -p mods
+$JAVAC -d mods -modulesourcepath ${TESTSRC} `find ${TESTSRC}/m -name "*.java"`
+
+mkdir -p classes
+$JAVAC -d classes ${TESTSRC}/Test.java
+
+$JAVA -cp classes -mp mods -addmods m \
+    -Djava.security.manager \
+    -Djava.security.policy=${TESTSRC}/test.policy Test
+$JAVA -cp classes -mp mods -addmods m \
+    -Djava.security.manager=p.CustomSecurityManager \
+    -Djava.security.policy=${TESTSRC}/test.policy Test
+
+exit 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/SecurityManager/modules/Test.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.lang.reflect.Module;
+
+public class Test {
+    public static void main(String... args) {
+        SecurityManager sm = System.getSecurityManager();
+        Module module = sm.getClass().getModule();
+        String s = System.getProperty("java.security.manager");
+        String expected = s.isEmpty() ? "java.base" : "m";
+        if (!module.isNamed() || !module.getName().equals(expected)) {
+            throw new RuntimeException(module + " expected module m instead");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/SecurityManager/modules/m/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/SecurityManager/modules/m/p/CustomSecurityManager.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p;
+
+public class CustomSecurityManager extends SecurityManager {
+    public CustomSecurityManager() {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/SecurityManager/modules/test.policy	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,3 @@
+grant {
+        permission java.util.PropertyPermission "*", "read";
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/StackTraceElement/ModuleFrames.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Stack trace should have module information
+ * @run testng ModuleFrames
+ */
+
+import java.util.Arrays;
+
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+public class ModuleFrames {
+
+    @Test
+    public void testModuleName() {
+        try {
+            Integer.parseInt("a");
+        } catch (NumberFormatException e) {
+
+            StackTraceElement[] stack = e.getStackTrace();
+            StackTraceElement topFrame = stack[0];
+            StackTraceElement thisFrame = findFrame(this.getClass().getName(), stack);
+
+            assertEquals(topFrame.getModuleName(), "java.base",
+                    "Expected top frame to be in module java.base");
+
+            assertTrue(topFrame.toString().contains("java.base"),
+                    "Expected toString of top frame to include java.base");
+
+            assertNull(thisFrame.getModuleName(),
+                    "Expected frame for test not to have a module name");
+        }
+    }
+
+    private static StackTraceElement findFrame(String cn, StackTraceElement[] stack) {
+        return Arrays.stream(stack)
+                .filter(s -> s.getClassName().equals(cn))
+                .findFirst()
+                .get();
+    }
+}
--- a/test/java/lang/StackTraceElement/PublicConstructor.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/lang/StackTraceElement/PublicConstructor.java	Thu Mar 17 19:04:16 2016 +0000
@@ -41,9 +41,25 @@
             throw new RuntimeException("1");
         if (ste.isNativeMethod())
             throw new RuntimeException("2");
-        StackTraceElement ste2 = new StackTraceElement("com.acme.Widget",
+        StackTraceElement ste2
+            = new StackTraceElement("jdk.module",
+                                    "9.0",
+                                    "com.acme.Widget",
+                                    "frobnicate",
+                                    "Widget.java",
+                                    42);
+        if (!(ste2.getClassName().equals("com.acme.Widget")  &&
+                ste2.getModuleName().equals("jdk.module") &&
+                ste2.getModuleVersion().equals("9.0") &&
+                ste2.getFileName().equals("Widget.java") &&
+                ste2.getMethodName().equals("frobnicate") &&
+                ste2.getLineNumber() == 42))
+            throw new RuntimeException("3");
+        if (ste2.isNativeMethod())
+            throw new RuntimeException("4");
+        StackTraceElement ste3 = new StackTraceElement("com.acme.Widget",
             "frobnicate", "Widget.java", -2);
-        if (!ste2.isNativeMethod())
-            throw new RuntimeException("3");
+        if (!ste3.isNativeMethod())
+            throw new RuntimeException("5");
     }
 }
--- a/test/java/lang/StackWalker/VerifyStackTrace.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/lang/StackWalker/VerifyStackTrace.java	Thu Mar 17 19:04:16 2016 +0000
@@ -72,7 +72,7 @@
             "3: VerifyStackTrace$Handle.run(VerifyStackTrace.java:158)\n" +
             "4: VerifyStackTrace.invoke(VerifyStackTrace.java:188)\n" +
             "5: VerifyStackTrace$1.run(VerifyStackTrace.java:218)\n" +
-            "6: java.security.AccessController.doPrivileged(Native Method)\n" +
+            "6: java.security.AccessController.doPrivileged(java.base/Native Method)\n" +
             "7: VerifyStackTrace.test(VerifyStackTrace.java:227)\n" +
             "8: VerifyStackTrace.main(VerifyStackTrace.java:182)\n";
 
@@ -101,12 +101,12 @@
             "2: VerifyStackTrace$Handle.execute(VerifyStackTrace.java:147)\n" +
             "3: VerifyStackTrace$Handle.run(VerifyStackTrace.java:160)\n" +
             "4: VerifyStackTrace.invoke(VerifyStackTrace.java:190)\n" +
-            "5: sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n" +
-            "6: sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\n" +
-            "7: sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n" +
-            "8: java.lang.reflect.Method.invoke(Method.java:520)\n" +
+            "5: sun.reflect.NativeMethodAccessorImpl.invoke0(java.base/Native Method)\n" +
+            "6: sun.reflect.NativeMethodAccessorImpl.invoke(java.base/NativeMethodAccessorImpl.java:62)\n" +
+            "7: sun.reflect.DelegatingMethodAccessorImpl.invoke(java.base/DelegatingMethodAccessorImpl.java:43)\n" +
+            "8: java.lang.reflect.Method.invoke(java.base/Method.java:520)\n" +
             "9: VerifyStackTrace$1.run(VerifyStackTrace.java:220)\n" +
-            "10: java.security.AccessController.doPrivileged(Native Method)\n" +
+            "10: java.security.AccessController.doPrivileged(java.base/Native Method)\n" +
             "11: VerifyStackTrace.test(VerifyStackTrace.java:229)\n" +
             "12: VerifyStackTrace.main(VerifyStackTrace.java:185)\n";
 
@@ -134,16 +134,16 @@
             "1: VerifyStackTrace.lambda$test$1(VerifyStackTrace.java:213)\n" +
             "2: VerifyStackTrace$$Lambda$1/662441761.run(Unknown Source)\n" +
             "3: VerifyStackTrace$Handle.execute(VerifyStackTrace.java:149)\n" +
-            "4: java.lang.invoke.LambdaForm$DMH/2008017533.invokeVirtual_LL_V(LambdaForm$DMH)\n" +
-            "5: java.lang.invoke.LambdaForm$MH/1395089624.invoke_MT(LambdaForm$MH)\n" +
+            "4: java.lang.invoke.LambdaForm$DMH/2008017533.invokeVirtual_LL_V(java.base/LambdaForm$DMH)\n" +
+            "5: java.lang.invoke.LambdaForm$MH/1395089624.invoke_MT(java.base/LambdaForm$MH)\n" +
             "6: VerifyStackTrace$Handle.run(VerifyStackTrace.java:162)\n" +
             "7: VerifyStackTrace.invoke(VerifyStackTrace.java:192)\n" +
-            "8: sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n" +
-            "9: sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\n" +
-            "10: sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n" +
-            "11: java.lang.reflect.Method.invoke(Method.java:520)\n" +
+            "8: sun.reflect.NativeMethodAccessorImpl.invoke0(java.base/Native Method)\n" +
+            "9: sun.reflect.NativeMethodAccessorImpl.invoke(java.base/NativeMethodAccessorImpl.java:62)\n" +
+            "10: sun.reflect.DelegatingMethodAccessorImpl.invoke(java.base/DelegatingMethodAccessorImpl.java:43)\n" +
+            "11: java.lang.reflect.Method.invoke(java.base/Method.java:520)\n" +
             "12: VerifyStackTrace$1.run(VerifyStackTrace.java:222)\n" +
-            "13: java.security.AccessController.doPrivileged(Native Method)\n" +
+            "13: java.security.AccessController.doPrivileged(java.base/Native Method)\n" +
             "14: VerifyStackTrace.test(VerifyStackTrace.java:231)\n" +
             "15: VerifyStackTrace.main(VerifyStackTrace.java:188)\n";
 
@@ -202,6 +202,8 @@
             // out before comparing. We also erase the hash-like names of
             // synthetic frames introduced by lambdas & method handles
             return produced.replaceAll(":[1-9][0-9]*\\)", ":00)")
+                    .replaceAll("-internal/", "/").replaceAll("-ea/", "/")
+                    .replaceAll("java.base@[0-9]+/", "java.base/")
                     .replaceAll("/[0-9]+\\.run", "/xxxxxxxx.run")
                     .replaceAll("/[0-9]+\\.invoke", "/xxxxxxxx.invoke")
                     .replaceAll("\\$[0-9]+", "\\$??");
--- a/test/java/lang/instrument/ATransformerManagementTestCase.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/lang/instrument/ATransformerManagementTestCase.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,7 @@
 import java.io.*;
 import java.lang.instrument.*;
 
+import java.lang.reflect.Module;
 import java.security.ProtectionDomain;
 import java.util.*;
 
@@ -291,7 +292,25 @@
             // The transform testing is triggered by redefine, ignore others
             if (classBeingRedefined != null) checkInTransformer(MyClassFileTransformer.this);
 
-            return super.transform(    loader,
+            return super.transform(     loader,
+                                        className,
+                                        classBeingRedefined,
+                                        protectionDomain,
+                                        classfileBuffer);
+        }
+
+        public byte[]
+        transform(
+            Module module,
+            String className,
+            Class<?> classBeingRedefined,
+            ProtectionDomain    protectionDomain,
+            byte[] classfileBuffer) {
+
+            // The transform testing is triggered by redefine, ignore others
+            if (classBeingRedefined != null) checkInTransformer(MyClassFileTransformer.this);
+
+            return super.transform(     module,
                                         className,
                                         classBeingRedefined,
                                         protectionDomain,
--- a/test/java/lang/instrument/BootClassPath/Agent.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/lang/instrument/BootClassPath/Agent.java	Thu Mar 17 19:04:16 2016 +0000
@@ -33,10 +33,7 @@
 
 public class Agent {
     public static void premain(String options, Instrumentation ins) throws Exception {
-        String bootclasspath = System.getProperty("sun.boot.class.path");
-        System.out.println("bootclasspath: " + bootclasspath);
-
-        Class c = Class.forName("AgentSupport");
+        Class<?> c = Class.forName("AgentSupport");
         ClassLoader cl = c.getClassLoader();
         if (cl != null) {
             System.err.println("AgentSupport loaded by: " + cl);
--- a/test/java/lang/instrument/MakeJAR2.sh	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/lang/instrument/MakeJAR2.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -86,7 +86,8 @@
 ${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} bootreporter/*.java
 cd ..
 
-${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -XDignore.symbol.file ${AGENT}.java asmlib/*.java
+${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \
+    -XaddExports:java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED ${AGENT}.java asmlib/*.java
 ${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -classpath .${PATHSEP}bootpath ${APP}.java
 
 echo "Manifest-Version: 1.0"    >  ${AGENT}.mf
--- a/test/java/lang/instrument/RedefineClassWithNativeMethodAgent.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/lang/instrument/RedefineClassWithNativeMethodAgent.java	Thu Mar 17 19:04:16 2016 +0000
@@ -21,10 +21,12 @@
  * questions.
  */
 
-import java.lang.instrument.*;
-import java.net.*;
-import java.util.*;
-import java.io.*;
+import java.io.InputStream;
+import java.lang.instrument.ClassDefinition;
+import java.lang.instrument.Instrumentation;
+import java.lang.reflect.Module;
+import java.util.Timer;
+import java.util.TimerTask;
 
 public class RedefineClassWithNativeMethodAgent {
     static Class clz;
@@ -33,29 +35,20 @@
     public static void premain(String agentArgs, final Instrumentation inst) throws Exception {
         String s = agentArgs.substring(0, agentArgs.indexOf(".class"));
         clz = Class.forName(s.replace('/', '.'));
-        ClassLoader loader =
-            RedefineClassWithNativeMethodAgent.class.getClassLoader();
-        URL classURL = loader.getResource(agentArgs);
-        if (classURL == null) {
+        InputStream in;
+        Module m = clz.getModule();
+        if (m != null) {
+            in = m.getResourceAsStream(agentArgs);
+        } else {
+            ClassLoader loader =
+                RedefineClassWithNativeMethodAgent.class.getClassLoader();
+            in = loader.getResourceAsStream(agentArgs);
+        }
+        if (in == null) {
             throw new Exception("Cannot find class: " + agentArgs);
         }
-
-        int         redefineLength;
-        InputStream redefineStream;
+        byte[] buffer = in.readAllBytes();
 
-        System.out.println("Reading test class from " + classURL);
-        if (classURL.getProtocol().equals("file")) {
-            File f = new File(classURL.getFile());
-            redefineStream = new FileInputStream(f);
-            redefineLength = (int) f.length();
-        } else {
-            URLConnection conn = classURL.openConnection();
-            redefineStream = conn.getInputStream();
-            redefineLength = conn.getContentLength();
-        }
-
-        final byte[] buffer = new byte[redefineLength];
-        new BufferedInputStream(redefineStream).read(buffer);
         new Timer(true).schedule(new TimerTask() {
             public void run() {
                 try {
--- a/test/java/lang/instrument/RetransformAgent.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/lang/instrument/RetransformAgent.java	Thu Mar 17 19:04:16 2016 +0000
@@ -34,6 +34,7 @@
  */
 
 import java.lang.instrument.*;
+import java.lang.reflect.Module;
 import java.security.ProtectionDomain;
 import java.io.*;
 import asmlib.*;
@@ -67,12 +68,13 @@
             this.nname = nname;
         }
 
-        public byte[] transform(ClassLoader loader,
+        public byte[] transform(Module module,
                                 String className,
                                 Class<?> classBeingRedefined,
                                 ProtectionDomain    protectionDomain,
                                 byte[] classfileBuffer) {
             boolean redef = classBeingRedefined != null;
+
             // System.err.println("hook " + trname + ": " + className +
             //                    (redef? " REDEF" : " LOAD"));
             if ((redef? onRedef : onLoad) && className != null && className.equals(cname)) {
--- a/test/java/lang/instrument/SimpleIdentityTransformer.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/lang/instrument/SimpleIdentityTransformer.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,6 +24,7 @@
 import java.lang.instrument.Instrumentation;
 import java.lang.instrument.ClassFileTransformer;
 
+import java.lang.reflect.Module;
 import java.security.*;
 
 /*
@@ -59,4 +60,16 @@
         return newBuffer;
     }
 
+    public byte[]
+    transform(
+        Module module,
+        String className,
+        Class<?> classBeingRedefined,
+        ProtectionDomain    protectionDomain,
+        byte[] classfileBuffer) {
+        byte[] newBuffer = new byte[classfileBuffer.length];
+        System.arraycopy(classfileBuffer, 0, newBuffer, 0, classfileBuffer.length);
+
+        return newBuffer;
+    }
 }
--- a/test/java/lang/invoke/AccessControlTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/lang/invoke/AccessControlTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,6 +31,7 @@
 
 import java.lang.invoke.*;
 import java.lang.reflect.*;
+import java.lang.reflect.Modifier;
 import java.util.*;
 import org.testng.*;
 import org.testng.annotations.*;
@@ -117,11 +118,13 @@
                 suffix = "/noaccess";
             else if (lookupModes == PUBLIC)
                 suffix = "/public";
-            else if (lookupModes == (PUBLIC|PACKAGE))
+            else if (lookupModes == (PUBLIC|MODULE))
+                suffix = "/module";
+            else if (lookupModes == (PUBLIC|MODULE|PACKAGE))
                 suffix = "/package";
-            else if (lookupModes == (PUBLIC|PACKAGE|PRIVATE))
+            else if (lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE))
                 suffix = "/private";
-            else if (lookupModes == (PUBLIC|PACKAGE|PRIVATE|PROTECTED))
+            else if (lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED))
                 suffix = "";
             else
                 suffix = "/#"+Integer.toHexString(lookupModes);
@@ -147,16 +150,26 @@
          * <li>[A6] If the new lookup class is not accessible to the old lookup class,
          * using the original access modes,
          * then no members, not even public members, will be accessible.
-         * [A7] (In all other cases, public members will continue to be accessible.)
+         * <li>[A7] If the new lookup class for this {@code Lookup} is in the unnamed module,
+         * and the new lookup class is in a named module {@code M}, then no members in
+         * {@code M}'s non-exported packages will be accessible.
+         * <li>[A8] If the lookup for this {@code Lookup} is in a named module, and the
+         * new lookup class is in a different module, then no members, not even
+         * public members in {@code M}'s exported packages, will be accessible.
+         * [A8] (In all other cases, public members will continue to be accessible.)
          * </ul>
          * Other than the above cases, the new lookup will have the same
-         * access capabilities as the original. [A8]
+         * access capabilities as the original. [A10]
          * <hr>
          */
         public LookupCase in(Class<?> c2) {
             Class<?> c1 = lookupClass();
             int m1 = lookupModes();
             int changed = 0;
+            // for the purposes of access control then treat classes in different unnamed
+            // modules as being in the same module.
+            boolean sameModule = (c1.getModule() == c2.getModule()) ||
+                                 (!c1.getModule().isNamed() && !c2.getModule().isNamed());
             boolean samePackage = (c1.getClassLoader() == c2.getClassLoader() &&
                                    packagePrefix(c1).equals(packagePrefix(c2)));
             boolean sameTopLevel = (topLevelClass(c1) == topLevelClass(c2));
@@ -166,12 +179,20 @@
             boolean accessible = sameClass;  // [A6]
             if ((m1 & PACKAGE) != 0)  accessible |= samePackage;
             if ((m1 & PUBLIC ) != 0)  accessible |= (c2.getModifiers() & PUBLIC) != 0;
+            if (!sameModule) {
+                if (c1.getModule().isNamed()) {
+                    accessible = false;  // [A8]
+                } else {
+                    // Different module; loose MODULE and lower access.
+                    changed |= (MODULE|PACKAGE|PRIVATE|PROTECTED);  // [A7]
+                }
+            }
             if (!accessible) {
                 // Different package and no access to c2; lose all access.
-                changed |= (PUBLIC|PACKAGE|PRIVATE|PROTECTED);  // [A6]
+                changed |= (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED);  // [A6]
             }
             if (!samePackage) {
-                // Different package; lose PACKAGE and lower access.
+                // Different package; loose PACKAGE and lower access.
                 changed |= (PACKAGE|PRIVATE|PROTECTED);  // [A4]
             }
             if (!sameTopLevel) {
@@ -181,9 +202,9 @@
             if (!sameClass) {
                 changed |= (PROTECTED);     // [A3]
             } else {
-                assert(changed == 0);       // [A8] (no deprivation if same class)
+                assert(changed == 0);       // [A10] (no deprivation if same class)
             }
-            if (accessible)  assert((changed & PUBLIC) == 0);  // [A7]
+            if (accessible)  assert((changed & PUBLIC) == 0);  // [A9]
             int m2 = m1 & ~changed;
             LookupCase l2 = new LookupCase(c2, m2);
             assert(l2.lookupClass() == c2); // [A1]
@@ -206,6 +227,16 @@
         public boolean willAccess(Method m) {
             Class<?> c1 = lookupClass();
             Class<?> c2 = m.getDeclaringClass();
+
+            // if the lookup class is in a loose module with PUBLIC access then
+            // public members of public types in all unnamed modules can be accessed
+            if (isLooseModule(c1.getModule())
+                && (lookupModes & PUBLIC) != 0
+                && (!c2.getModule().isNamed())
+                && Modifier.isPublic(c2.getModifiers())
+                && Modifier.isPublic(m.getModifiers()))
+                return true;
+
             LookupCase lc = this.in(c2);
             int m1 = lc.lookupModes();
             int m2 = fixMods(m.getModifiers());
@@ -227,9 +258,25 @@
         /** Predict the success or failure of accessing this class. */
         public boolean willAccessClass(Class<?> c2, boolean load) {
             Class<?> c1 = lookupClass();
-            if (load && c1.getClassLoader() == null) {
+            if (load && c2.getClassLoader() != null) {
+                if (c1.getClassLoader() == null) {
+                    // not visible
                 return false;
             }
+                if (c1 == publicLookup().lookupClass()) {
+                    // not visible as lookup class is defined by child of the boot loader
+                    return false;
+                }
+            }
+
+            // if the lookup class is in a loose module with PUBLIC access then
+            // public types in all unnamed modules can be accessed
+            if (isLooseModule(c1.getModule())
+                && (lookupModes & PUBLIC) != 0
+                && (!c2.getModule().isNamed())
+                && Modifier.isPublic(c2.getModifiers()))
+                return true;
+
             LookupCase lc = this.in(c2);
             int m1 = lc.lookupModes();
             boolean r = false;
@@ -248,6 +295,11 @@
             }
             return r;
         }
+
+        private boolean isLooseModule(Module m) {
+            ClassLoader cl = new ClassLoader() { };
+            return m.canRead(cl.getUnnamedModule());
+        }
     }
 
     private static Class<?> topLevelClass(Class<?> cls) {
@@ -303,7 +355,7 @@
             LookupCase expect = l1.in(c2);
             if (!expect.equals(l2))
                 System.out.println("*** expect "+l1+" => "+expect+" but got "+l2);
-            assertEquals(expect, l2);
+            assertEquals(l2, expect);
         }
     }
 
@@ -420,6 +472,7 @@
     }
 
     static Method targetMethod(Class<?> targetClass, int targetAccess, MethodType methodType) {
+        assert targetAccess != MODULE;
         String methodName = accessName(targetAccess)+placeName(targetClass);
         if (verbosity >= 2)
             System.out.println(targetClass.getSimpleName()+"."+methodName+methodType);
@@ -453,6 +506,7 @@
         assert(false);
         return "?";
     }
+    // MODULE not a test case at this time
     private static final int[] ACCESS_CASES = {
         PUBLIC, PACKAGE, PRIVATE, PROTECTED
     };
--- a/test/java/lang/invoke/CustomizedLambdaFormTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/lang/invoke/CustomizedLambdaFormTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -21,21 +21,25 @@
  * questions.
  */
 
-package java.lang.invoke;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandleHelper;
+import java.lang.invoke.MethodType;
 
 /* @test
  * @summary Assertion in LambdaFormEditor.bindArgumentType is too strong
  *
- * @run main/bootclasspath -esa java.lang.invoke.CustomizedLambdaFormTest
+ * @compile/module=java.base java/lang/invoke/MethodHandleHelper.java
+ * @run main/othervm -esa CustomizedLambdaFormTest
  */
+
 public class CustomizedLambdaFormTest {
 
     static void testExtendCustomizedBMH() throws Exception {
         // Construct BMH
-        MethodHandle mh = MethodHandles.Lookup.IMPL_LOOKUP.findVirtual(String.class, "concat",
+        MethodHandle mh = MethodHandleHelper.IMPL_LOOKUP.findVirtual(String.class, "concat",
                 MethodType.methodType(String.class, String.class))
                 .bindTo("a");
-        mh.customize();
+        MethodHandleHelper.customize(mh);
         mh.bindTo("b"); // Try to extend customized BMH
     }
 
--- a/test/java/lang/invoke/MethodHandlesTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/lang/invoke/MethodHandlesTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -386,7 +386,7 @@
     static final Lookup PACKAGE = PackageSibling.lookup();
     // This lookup is good for public members and protected members of PubExample
     static final Lookup SUBCLASS = RemoteExample.lookup();
-    // This lookup is good only for public members.
+    // This lookup is good only for public members in exported packages.
     static final Lookup PUBLIC  = MethodHandles.publicLookup();
 
     // Subject methods...
@@ -634,10 +634,15 @@
     public void testFindVirtualClone0() throws Throwable {
         // test some ad hoc system methods
         testFindVirtual(false, PUBLIC, Object.class, Object.class, "clone");
+
+        // ##### FIXME - disable tests for clone until we figure out how they should work with modules
+
+        /*
         testFindVirtual(true, PUBLIC, Object[].class, Object.class, "clone");
         testFindVirtual(true, PUBLIC, int[].class, Object.class, "clone");
         for (Class<?> cls : new Class<?>[]{ boolean[].class, long[].class, float[].class, char[].class })
             testFindVirtual(true, PUBLIC, cls, Object.class, "clone");
+         */
     }
 
     void testFindVirtual(Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
--- a/test/java/lang/invoke/VarargsArrayTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/lang/invoke/VarargsArrayTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -21,8 +21,10 @@
  * questions.
  */
 
-package java.lang.invoke;
 
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandleHelper;
+import java.lang.invoke.MethodType;
 import sun.invoke.util.Wrapper;
 import java.util.Arrays;
 import java.util.Collections;
@@ -31,14 +33,16 @@
 /* @test
  * @summary unit tests for varargs array methods: MethodHandleInfo.varargsArray(int),
  *          MethodHandleInfo.varargsArray(Class,int) & MethodHandleInfo.varargsList(int)
+ * @modules java.base/sun.invoke.util
  * @library /lib/testlibrary /lib/testlibrary/jsr292
- * @run main/bootclasspath java.lang.invoke.VarargsArrayTest
+ * @compile/module=java.base java/lang/invoke/MethodHandleHelper.java
+ * @run main/bootclasspath VarargsArrayTest
  * @run main/bootclasspath -DVarargsArrayTest.MAX_ARITY=255 -DVarargsArrayTest.START_ARITY=250
- *                         java.lang.invoke.VarargsArrayTest
+ *                         VarargsArrayTest
  */
 
 /* This might take a while and burn lots of metadata:
- * @run main/bootclasspath -DVarargsArrayTest.MAX_ARITY=255 -DVarargsArrayTest.EXHAUSTIVE=true java.lang.invoke.VarargsArrayTest
+ * @run main/bootclasspath -DVarargsArrayTest.MAX_ARITY=255 -DVarargsArrayTest.EXHAUSTIVE=true VarargsArrayTest
  */
 public class VarargsArrayTest {
     private static final Class<?> CLASS = VarargsArrayTest.class;
@@ -60,7 +64,7 @@
         final int MIN = START_ARITY;
         final int MAX = MAX_ARITY-2;  // 253+1 would cause parameter overflow with 'this' added
         for (int nargs = MIN; nargs <= MAX; nargs = nextArgCount(nargs, 17, MAX)) {
-            MethodHandle target = MethodHandleImpl.varargsArray(nargs);
+            MethodHandle target = MethodHandleHelper.varargsArray(nargs);
             Object[] args = new Object[nargs];
             for (int i = 0; i < nargs; i++)
                 args[i] = "#"+i;
@@ -110,7 +114,7 @@
         if (elemType == long.class || elemType == double.class) { MAX /= 2; MIN /= 2; }
         for (int nargs = MIN; nargs <= MAX; nargs = nextArgCount(nargs, density, MAX)) {
             Object[] args = makeTestArray(elemType, nargs);
-            MethodHandle varargsArray = MethodHandleImpl.varargsArray(arrayType, nargs);
+            MethodHandle varargsArray = MethodHandleHelper.varargsArray(arrayType, nargs);
             MethodType vaType = varargsArray.type();
             assertEquals(arrayType, vaType.returnType());
             if (nargs != 0) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/invoke/java.base/java/lang/invoke/MethodHandleHelper.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+import java.lang.invoke.MethodHandles.Lookup;
+
+/**
+ * Helper class to inject into java.lang.invoke that provides access to
+ * package-private methods in this package.
+ */
+
+public class MethodHandleHelper {
+
+    private MethodHandleHelper() { }
+
+    public static final Lookup IMPL_LOOKUP = Lookup.IMPL_LOOKUP;
+
+    public static void customize(MethodHandle mh) {
+        mh.customize();
+    }
+
+    public static MethodHandle varargsArray(int nargs) {
+        return MethodHandleImpl.varargsArray(nargs);
+    }
+
+    public static MethodHandle varargsArray(Class<?> arrayType, int nargs) {
+        return MethodHandleImpl.varargsArray(arrayType, nargs);
+    }
+
+}
+
--- a/test/java/lang/invoke/lambda/LambdaAccessControlDoPrivilegedTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/lang/invoke/lambda/LambdaAccessControlDoPrivilegedTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -54,8 +54,6 @@
         scratch.clear();
         scratch.add("public class Bar {");
         scratch.add("public static void main(String... args) {");
-        scratch.add("System.out.println(\"sun.boot.class.path\" + \"=\" +");
-        scratch.add("    System.getProperty(\"sun.boot.class.path\", \"\"));");
         scratch.add("System.setSecurityManager(new SecurityManager());");
         scratch.add("DoPriv.main();");
         scratch.add("}");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/invoke/modules/ModuleAccessControlTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.List;
+
+import static jdk.testlibrary.ProcessTools.executeTestJava;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/**
+ * @test
+ * @library /lib/testlibrary
+ * @modules jdk.compiler
+ * @build CompilerUtils jdk.testlibrary.*
+ * @run testng ModuleAccessControlTest
+ * @summary Driver for testing module access checking by MethodHandles.Lookup
+ */
+
+public class ModuleAccessControlTest {
+
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path MODS_DIR = Paths.get("mods");
+
+    // the names of the modules in this test
+    private static List<String> modules = Arrays.asList("m1", "m2");
+
+
+    /**
+     * Compiles all modules used by the test
+     */
+    @BeforeTest
+    public void compileAll() throws Exception {
+        for (String mn : modules) {
+            Path msrc = SRC_DIR.resolve(mn);
+            assertTrue(CompilerUtils
+                .compile(msrc, MODS_DIR, "-modulesourcepath", SRC_DIR.toString()));
+        }
+    }
+
+    /**
+     * Launch the test
+     */
+    @Test
+    public void runTest() throws Exception {
+        int exitValue = executeTestJava("-mp", MODS_DIR.toString(),
+                                        "-m", "m1/p1.Main")
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
+
+        assertTrue(exitValue == 0);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/invoke/modules/src/m1/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+module m1 {
+    requires m2;
+    exports p1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/invoke/modules/src/m1/p1/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p1;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+import java.lang.invoke.MethodType;
+
+/**
+ * Basic test case for module access check, supplements AccessControlTest.
+ *
+ * The tests consists of two modules:
+ *
+ * module m1 { requires m2; exports p1; }
+ * module m2 { exports q1; }
+ *
+ * Both modules read java.base (as every module reads java.base)
+ *
+ * module m1 has public types in packages p1 and p2, p2 is not exported.
+ * module m2 has public types in packages q1 and q2, q2 is not exported.
+ */
+
+public class Main {
+
+    static final int MODULE = Lookup.MODULE;
+
+    // Use Class.forName to get classes for test because some
+    // are not accessible at compile-time
+
+    static final Class<?> p1_Type1;        // m1, exported
+    static final Class<?> p2_Type2;        // m1, not exported
+    static final Class<?> q1_Type1;        // m2, exported, m1 reads m2
+    static final Class<?> q2_Type2;        // m2, not exported, m1 reads m2
+    static final Class<?> x500NameClass;   // java.base, not exported
+
+    static {
+        try {
+            p1_Type1 = Class.forName("p1.Type1");
+            p2_Type2 = Class.forName("p2.Type2");
+            q1_Type1 = Class.forName("q1.Type1");
+            q2_Type2 = Class.forName("q2.Type2");
+            x500NameClass = Class.forName("sun.security.x509.X500Name");
+        } catch (ClassNotFoundException e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        Lookup lookup, lookup2;
+
+        /**
+         * MethodHandles.lookup()
+         * has module access [A0]
+         * can access all public types in m1 [A1]
+         * can access public types in packages exported by modules that m1 reads [A2]
+         * cannot access public types in non-exported modules of modules that m1 reads [A3]
+         */
+        lookup = MethodHandles.lookup();
+        assertTrue((lookup.lookupModes() & MODULE) == MODULE); // [A0]
+        findConstructor(lookup, p1_Type1, void.class); // [A1]
+        findConstructor(lookup, p2_Type2, void.class); // [A1]
+        findConstructor(lookup, q1_Type1, void.class); // [A2]
+        findConstructorExpectingIAE(lookup, q2_Type2, void.class); // [A3]
+        findConstructor(lookup, Object.class, void.class); // [A2]
+        findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); // [A3]
+
+        /**
+         * Teleport from MethodHandles.lookup() to lookup class in the same module
+         * module access is retained [A0]
+         * can access all public types in m1 [A1]
+         * can access public types in packages exported by modules that m1 reads [A2]
+         * cannot access public types in non-exported modules of modules that m1 reads [A3]
+         */
+        lookup2 = lookup.in(p2_Type2);
+        assertTrue((lookup2.lookupModes() & MODULE) == MODULE); // [A0]
+        findConstructor(lookup2, p1_Type1, void.class); // [A1]
+        findConstructor(lookup2, p2_Type2, void.class); // [A1]
+        findConstructor(lookup2, q1_Type1, void.class); // [A2]
+        findConstructorExpectingIAE(lookup2, q2_Type2, void.class); // [A3]
+        findConstructor(lookup2, Object.class, void.class); // [A2]
+        findConstructorExpectingIAE(lookup2, x500NameClass, void.class, String.class); // [A3]
+
+        /**
+         * Teleport from MethodHandles.lookup() to lookup class in another named module
+         * has no access [A0]
+         */
+        lookup2 = lookup.in(Object.class);
+        assertTrue(lookup2.lookupModes() == 0); // [A0]
+        findConstructorExpectingIAE(lookup2, Object.class, void.class);  // [A0]
+
+        /**
+         * Teleport from MethodHandles.lookup() to lookup class in an unnamed module
+         * has no access [A0]
+         */
+        Class<?> c = MethodHandles.publicLookup().lookupClass();
+        assertTrue(!c.getModule().isNamed());
+        lookup2 = lookup.in(c);
+        assertTrue(lookup2.lookupModes() == 0); // [A0]
+        findConstructorExpectingIAE(lookup2, Object.class, void.class);
+
+        /**
+         * MethodHandles.publicLookup()
+         * has no module access [A0]
+         * can access public types in exported packages [A1]
+         * cannot access public types in non-exported packages [A2]
+         */
+        lookup = MethodHandles.publicLookup();
+        assertTrue((lookup.lookupModes() & MODULE) == 0); // [A0]
+        findConstructor(lookup, p1_Type1, void.class); // [A1]
+        findConstructorExpectingIAE(lookup, p2_Type2, void.class); // [A1]
+        findConstructor(lookup, q1_Type1, void.class); // [A1]
+        findConstructorExpectingIAE(lookup, q2_Type2, void.class); // [A2]
+        findConstructor(lookup, Object.class, void.class); // [A1]
+        findConstructorExpectingIAE(lookup, x500NameClass, void.class); // [A2]
+
+        /**
+         * Teleport from MethodHandles.publicLookup() to lookup class in java.base
+         * has no module access [A0]
+         * can access public types in packages exported by java.base [A1]
+         * cannot access public types in non-exported packages [A2]
+         * no access to types in other named modules [A3]
+         */
+        lookup2 = lookup.in(Object.class);
+        assertTrue((lookup2.lookupModes() & MODULE) == 0); // [A0]
+        findConstructor(lookup2, String.class, void.class); // [A1]
+        findConstructorExpectingIAE(lookup2, x500NameClass, void.class, String.class); // [A2]
+        findConstructorExpectingIAE(lookup2, p1_Type1, void.class); // [A3]
+        findConstructorExpectingIAE(lookup2, q1_Type1, void.class); // [A3]
+
+        /**
+         * Teleport from MethodHandles.publicLookup() to lookup class in m1
+         * has no module access [A0]
+         * can access public types in packages exported by m1, m2 and java.base [A1]
+         * cannot access public types is non-exported packages [A2]
+         */
+        lookup2 = lookup.in(p1_Type1);
+        assertTrue((lookup2.lookupModes() & MODULE) == 0); // [A0]
+        findConstructor(lookup2, p1_Type1, void.class);  // [A1]
+        findConstructor(lookup2, q1_Type1, void.class);  // [A1]
+        findConstructor(lookup2, Object.class, void.class);  // [A1]
+        findConstructorExpectingIAE(lookup, p2_Type2, void.class); // [A2]
+        findConstructorExpectingIAE(lookup, q2_Type2, void.class); // [A2]
+        findConstructorExpectingIAE(lookup2, x500NameClass, void.class, String.class); // [A2]
+
+        /**
+         * Teleport from MethodHandles.publicLookup() to lookup class in m2
+         * has no module access [A0]
+         * can access public types in packages exported by m2 and java.base [A1]
+         * cannot access public types is non-exported packages or modules that m2 does
+         *   not read [A2]
+         */
+        lookup2 = lookup.in(q1_Type1);
+        assertTrue((lookup2.lookupModes() & MODULE) == 0); // [A0]
+        findConstructor(lookup2, q1_Type1, void.class); // [A1]
+        findConstructor(lookup2, Object.class, void.class); // [A1]
+        findConstructorExpectingIAE(lookup2, p1_Type1, void.class); // [A2]
+        findConstructorExpectingIAE(lookup, q2_Type2, void.class); // [A2]
+        findConstructorExpectingIAE(lookup2, x500NameClass, void.class, String.class);  // [A2]
+
+        /**
+         * Teleport from MethodHandles.publicLookup() to lookup class that is not
+         * in an exported package, should get no access [A0]
+         */
+        lookup2 = lookup.in(p2_Type2);
+        assertTrue(lookup2.lookupModes()  == 0); // [A0]
+        findConstructorExpectingIAE(lookup, q2_Type2, void.class); // [A0]
+    }
+
+    /**
+     * Invokes Lookup findConstructor with a method type constructored from the
+     * given return and parameter types, expecting IllegalAccessException to be
+     * thrown.
+     */
+    static MethodHandle findConstructorExpectingIAE(Lookup lookup,
+                                                    Class<?> clazz,
+                                                    Class<?> rtype,
+                                                    Class<?>... ptypes) throws Exception {
+        try {
+            findConstructor(lookup, clazz, rtype, ptypes);
+            throw new RuntimeException("IllegalAccessError expected");
+        } catch (IllegalAccessException expected) {
+            return null;
+        }
+    }
+
+    /**
+     * Invokes Lookup findConstructor with a method type constructored from the
+     * given return and parameter types.
+     */
+    static MethodHandle findConstructor(Lookup lookup,
+                                        Class<?> clazz,
+                                        Class<?> rtype,
+                                        Class<?>... ptypes) throws Exception {
+        MethodType mt = MethodType.methodType(rtype, ptypes);
+        return lookup.findConstructor(clazz, mt);
+    }
+
+    static void assertTrue(boolean condition) {
+        if (!condition)
+            throw new RuntimeException();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/invoke/modules/src/m1/p1/Type1.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package p1;
+
+public class Type1 {
+    public Type1() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/invoke/modules/src/m1/p2/Type2.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package p2;
+
+public class Type2 {
+    public Type2() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/invoke/modules/src/m2/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+module m2 {
+    exports q1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/invoke/modules/src/m2/q1/Type1.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package q1;
+
+public class Type1 {
+    public Type1() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/invoke/modules/src/m2/q2/Type2.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package q2;
+
+public class Type2 {
+    public Type2() { }
+}
--- a/test/java/lang/management/CompositeData/ThreadInfoCompositeData.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/lang/management/CompositeData/ThreadInfoCompositeData.java	Thu Mar 17 19:04:16 2016 +0000
@@ -39,6 +39,7 @@
 import java.lang.management.LockInfo;
 import java.lang.management.MonitorInfo;
 import java.lang.management.ThreadInfo;
+import java.util.Objects;
 
 public class ThreadInfoCompositeData {
     private static StackTraceElement[] ste = new StackTraceElement[1];
@@ -173,6 +174,14 @@
             throw new RuntimeException("Class name = " +
                 s2.getClassName() + " expected = " + s1.getClassName());
         }
+        if (!Objects.equals(s1.getModuleName(), s2.getModuleName())) {
+            throw new RuntimeException("Module name = " +
+                s2.getModuleName() + " expected = " + s1.getModuleName());
+        }
+        if (!Objects.equals(s1.getModuleVersion(), s2.getModuleVersion())) {
+            throw new RuntimeException("Module version = " +
+                s2.getModuleVersion() + " expected = " + s1.getModuleVersion());
+        }
         if (!s1.getMethodName().equals(s2.getMethodName())) {
             throw new RuntimeException("Method name = " +
                 s2.getMethodName() + " expected = " + s1.getMethodName());
@@ -329,6 +338,8 @@
 
     private static final String[] steItemNames = {
         "className",
+        "moduleName",
+        "moduleVersion",
         "methodName",
         "fileName",
         "lineNumber",
@@ -352,6 +363,8 @@
 
             final Object[] steValue = {
                 ste[0].getClassName(),
+                ste[0].getModuleName(),
+                ste[0].getModuleVersion(),
                 ste[0].getMethodName(),
                 ste[0].getFileName(),
                 new Integer(ste[0].getLineNumber()),
--- a/test/java/lang/management/MemoryMXBean/PendingAllGC.sh	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/lang/management/MemoryMXBean/PendingAllGC.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -27,7 +27,8 @@
 # @summary 
 # @author  Mandy Chung
 # @requires vm.gc=="null"
-# @modules java.base/sun.misc
+# @modules java.base/jdk.internal.misc
+#          java.management
 # @run compile Pending.java
 # @run shell PendingAllGC.sh
 #
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/module/AutomaticModulesTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,572 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @library /lib/testlibrary
+ * @build AutomaticModulesTest ModuleUtils
+ * @run testng AutomaticModulesTest
+ * @summary Basic tests for automatic modules
+ */
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.module.Configuration;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Exports;
+import java.lang.module.ModuleDescriptor.Requires.Modifier;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReference;
+import java.lang.module.ResolvedModule;
+import java.lang.reflect.Layer;
+import java.lang.reflect.Module;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Optional;
+import java.util.Set;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import java.util.stream.Collectors;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+@Test
+public class AutomaticModulesTest {
+
+    private static final Path USER_DIR
+         = Paths.get(System.getProperty("user.dir"));
+
+
+    @DataProvider(name = "names")
+    public Object[][] createNames() {
+
+        return new Object[][] {
+
+            // JAR file name                module-name[/version]
+
+            { "foo.jar",                    "foo" },
+
+            { "foo-1.jar",                  "foo/1" },
+            { "foo-1.2.jar",                "foo/1.2" },
+            { "foo-1.2.3.jar",              "foo/1.2.3" },
+            { "foo-1.2.3.4.jar",            "foo/1.2.3.4" },
+
+            { "foo-10.jar",                 "foo/10" },
+            { "foo-10.20.jar",              "foo/10.20" },
+            { "foo-10.20.30.jar",           "foo/10.20.30" },
+            { "foo-10.20.30.40.jar",        "foo/10.20.30.40" },
+
+            { "foo-bar.jar",                "foo.bar" },
+            { "foo-bar-1.jar",              "foo.bar/1" },
+            { "foo-bar-1.2.jar",            "foo.bar/1.2"},
+            { "foo-bar-10.jar",             "foo.bar/10" },
+            { "foo-bar-10.20.jar",          "foo.bar/10.20" },
+
+            { "foo-1.2-SNAPSHOT.jar",       "foo/1.2-SNAPSHOT" },
+            { "foo-bar-1.2-SNAPSHOT.jar",   "foo.bar/1.2-SNAPSHOT" },
+
+            { "foo--bar-1.0.jar",           "foo.bar/1.0" },
+            { "-foo-bar-1.0.jar",           "foo.bar/1.0" },
+            { "foo-bar--1.0.jar",           "foo.bar/1.0" },
+
+        };
+    }
+
+    /**
+     * Test mapping of JAR file names to module names
+     */
+    @Test(dataProvider = "names")
+    public void testNames(String fn, String mid) throws IOException {
+
+        String[] s = mid.split("/");
+        String mn = s[0];
+        String vs = (s.length == 2) ? s[1] : null;
+
+        Path dir = Files.createTempDirectory(USER_DIR, "mods");
+        Path jf = dir.resolve(fn);
+
+        // create empty JAR file
+        createJarFile(jf);
+
+        // create a ModuleFinder to find modules in the directory
+        ModuleFinder finder = ModuleFinder.of(dir);
+
+        // a module with the expected name should be found
+        Optional<ModuleReference> mref = finder.find(mn);
+        assertTrue(mref.isPresent(), mn + " not found");
+
+        ModuleDescriptor descriptor = mref.get().descriptor();
+        assertEquals(descriptor.name(), mn);
+        if (vs == null) {
+            assertFalse(descriptor.version().isPresent());
+        } else {
+            assertEquals(descriptor.version().get().toString(), vs);
+        }
+
+    }
+
+
+    /**
+     * Test all packages are exported
+     */
+    public void testExports() throws IOException {
+        Path dir = Files.createTempDirectory(USER_DIR, "mods");
+        createJarFile(dir.resolve("m1.jar"),
+                      "p/C1.class", "p/C2.class", "q/C1.class");
+
+        ModuleFinder finder = ModuleFinder.of(dir);
+
+        Configuration parent = Layer.boot().configuration();
+        Configuration cf = resolve(parent, finder, "m1");
+
+        ModuleDescriptor m1 = findDescriptor(cf, "m1");
+
+        Set<String> exports
+            = m1.exports().stream().map(Exports::source).collect(Collectors.toSet());
+
+        assertTrue(exports.size() == 2);
+        assertTrue(exports.contains("p"));
+        assertTrue(exports.contains("q"));
+        assertTrue(m1.conceals().isEmpty());
+    }
+
+
+    /**
+     * Test that a JAR file with a Main-Class attribute results
+     * in a module with a main class.
+     */
+    public void testMainClass() throws IOException {
+        String mainClass = "p.Main";
+
+        Manifest man = new Manifest();
+        Attributes attrs = man.getMainAttributes();
+        attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0.0");
+        attrs.put(Attributes.Name.MAIN_CLASS, mainClass);
+
+        Path dir = Files.createTempDirectory(USER_DIR, "mods");
+        createJarFile(dir.resolve("m1.jar"), man);
+
+        ModuleFinder finder = ModuleFinder.of(dir);
+
+        Configuration parent = Layer.boot().configuration();
+        Configuration cf = resolve(parent, finder, "m1");
+
+        ModuleDescriptor m1 = findDescriptor(cf, "m1");
+
+        assertTrue(m1.mainClass().isPresent());
+        assertEquals(m1.mainClass().get(), mainClass);
+    }
+
+
+    /**
+     * Basic test of a configuration created with automatic modules.
+     *   m1 requires m2*
+     *   m1 requires m3*
+     *   m2*
+     *   m3*
+     */
+    public void testConfiguration1() throws Exception {
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .requires("m2")
+                .requires("m3")
+                .requires("java.base")
+                .build();
+
+        // m2 and m3 are automatic modules
+        Path dir = Files.createTempDirectory(USER_DIR, "mods");
+        createJarFile(dir.resolve("m2.jar"), "p/T.class");
+        createJarFile(dir.resolve("m3.jar"), "q/T.class");
+
+        // module finder locates m1 and the modules in the directory
+        ModuleFinder finder
+            = ModuleFinder.compose(ModuleUtils.finderOf(descriptor1),
+                ModuleFinder.of(dir));
+
+        Configuration parent = Layer.boot().configuration();
+        Configuration cf = resolve(parent, finder, "m1");
+
+        assertTrue(cf.modules().size() == 3);
+        assertTrue(cf.findModule("m1").isPresent());
+        assertTrue(cf.findModule("m2").isPresent());
+        assertTrue(cf.findModule("m3").isPresent());
+
+        ResolvedModule base = cf.findModule("java.base").get();
+        assertTrue(base.configuration() == Layer.boot().configuration());
+        ResolvedModule m1 = cf.findModule("m1").get();
+        ResolvedModule m2 = cf.findModule("m2").get();
+        ResolvedModule m3 = cf.findModule("m3").get();
+
+        // m2 && m3 only require java.base
+        assertTrue(m2.reference().descriptor().requires().size() == 1);
+        assertTrue(m3.reference().descriptor().requires().size() == 1);
+
+        // readability
+
+        assertTrue(m1.reads().size() == 3);
+        assertTrue(m1.reads().contains(base));
+        assertTrue(m1.reads().contains(m2));
+        assertTrue(m1.reads().contains(m3));
+
+        assertTrue(m2.reads().contains(m1));
+        assertTrue(m2.reads().contains(m3));
+        testReadAllBootModules(cf, "m2");  // m2 reads all modules in boot layer
+
+        assertTrue(m3.reads().contains(m1));
+        assertTrue(m3.reads().contains(m2));
+        testReadAllBootModules(cf, "m3");  // m3 reads all modules in boot layer
+
+    }
+
+    /**
+     * Basic test of a configuration created with automatic modules
+     *   m1 requires m2
+     *   m2 requires m3*
+     *   m3*
+     *   m4*
+     */
+    public void testInConfiguration2() throws IOException {
+
+        ModuleDescriptor descriptor1
+            =  new ModuleDescriptor.Builder("m1")
+                .requires("m2")
+                .requires("java.base")
+                .build();
+
+        ModuleDescriptor descriptor2
+            =  new ModuleDescriptor.Builder("m2")
+                .requires("m3")
+                .requires("java.base")
+                .build();
+
+        // m3 and m4 are automatic modules
+        Path dir = Files.createTempDirectory(USER_DIR, "mods");
+        createJarFile(dir.resolve("m3.jar"), "p/T.class");
+        createJarFile(dir.resolve("m4.jar"), "q/T.class");
+
+        // module finder locates m1 and the modules in the directory
+        ModuleFinder finder
+            = ModuleFinder.compose(ModuleUtils.finderOf(descriptor1, descriptor2),
+                                   ModuleFinder.of(dir));
+
+        Configuration parent = Layer.boot().configuration();
+        Configuration cf = resolve(parent, finder, "m1", "m4");
+
+        assertTrue(cf.modules().size() == 4);
+        assertTrue(cf.findModule("m1").isPresent());
+        assertTrue(cf.findModule("m2").isPresent());
+        assertTrue(cf.findModule("m3").isPresent());
+        assertTrue(cf.findModule("m4").isPresent());
+
+        // m3 && m4 should only require java.base
+        assertTrue(findDescriptor(cf, "m3").requires().size() == 1);
+        assertTrue(findDescriptor(cf, "m4").requires().size() == 1);
+
+        // readability
+
+        ResolvedModule base = cf.findModule("java.base").get();
+        assertTrue(base.configuration() == Layer.boot().configuration());
+        ResolvedModule m1 = cf.findModule("m1").get();
+        ResolvedModule m2 = cf.findModule("m2").get();
+        ResolvedModule m3 = cf.findModule("m3").get();
+        ResolvedModule m4 = cf.findModule("m4").get();
+
+        assertTrue(m1.reads().size() == 2);
+        assertTrue(m1.reads().contains(m2));
+        assertTrue(m1.reads().contains(base));
+
+        assertTrue(m2.reads().size() == 3);
+        assertTrue(m2.reads().contains(m3));
+        assertTrue(m2.reads().contains(m4));
+        assertTrue(m2.reads().contains(base));
+
+        assertTrue(m3.reads().contains(m1));
+        assertTrue(m3.reads().contains(m2));
+        assertTrue(m3.reads().contains(m4));
+        testReadAllBootModules(cf, "m3");   // m3 reads all modules in boot layer
+
+        assertTrue(m4.reads().contains(m1));
+        assertTrue(m4.reads().contains(m2));
+        assertTrue(m4.reads().contains(m3));
+        testReadAllBootModules(cf, "m4");    // m4 reads all modules in boot layer
+
+    }
+
+
+    /**
+     * Basic test of a configuration created with automatic modules
+     *   m1 requires m2
+     *   m2 requires public m3*
+     *   m3*
+     *   m4*
+     */
+    public void testInConfiguration3() throws IOException {
+
+        ModuleDescriptor descriptor1
+            =  new ModuleDescriptor.Builder("m1")
+                .requires("m2")
+                .requires("java.base")
+                .build();
+
+        ModuleDescriptor descriptor2
+            =  new ModuleDescriptor.Builder("m2")
+                .requires(Modifier.PUBLIC, "m3")
+                .requires("java.base")
+                .build();
+
+        // m3 and m4 are automatic modules
+        Path dir = Files.createTempDirectory(USER_DIR, "mods");
+        createJarFile(dir.resolve("m3.jar"), "p/T.class");
+        createJarFile(dir.resolve("m4.jar"), "q/T.class");
+
+        // module finder locates m1 and the modules in the directory
+        ModuleFinder finder
+            = ModuleFinder.compose(ModuleUtils.finderOf(descriptor1, descriptor2),
+                ModuleFinder.of(dir));
+
+        Configuration parent = Layer.boot().configuration();
+        Configuration cf = resolve(parent, finder, "m1", "m4");
+
+        assertTrue(cf.modules().size() == 4);
+        assertTrue(cf.findModule("m1").isPresent());
+        assertTrue(cf.findModule("m2").isPresent());
+        assertTrue(cf.findModule("m3").isPresent());
+        assertTrue(cf.findModule("m4").isPresent());
+
+        ResolvedModule base = cf.findModule("java.base").get();
+        assertTrue(base.configuration() == Layer.boot().configuration());
+        ResolvedModule m1 = cf.findModule("m1").get();
+        ResolvedModule m2 = cf.findModule("m2").get();
+        ResolvedModule m3 = cf.findModule("m3").get();
+        ResolvedModule m4 = cf.findModule("m4").get();
+
+        // m3 && m4 should only require java.base
+        assertTrue(findDescriptor(cf, "m3").requires().size() == 1);
+        assertTrue(findDescriptor(cf, "m4").requires().size() == 1);
+
+        // readability
+
+        assertTrue(m1.reads().size() == 4);
+        assertTrue(m1.reads().contains(m2));
+        assertTrue(m1.reads().contains(m3));
+        assertTrue(m1.reads().contains(m4));
+        assertTrue(m1.reads().contains(base));
+
+        assertTrue(m2.reads().size() == 3);
+        assertTrue(m2.reads().contains(m3));
+        assertTrue(m2.reads().contains(m4));
+        assertTrue(m2.reads().contains(base));
+
+        assertTrue(reads(cf, "m2", "m3"));
+        assertTrue(reads(cf, "m2", "m4"));
+        assertTrue(reads(cf, "m2", "java.base"));
+
+        assertTrue(m3.reads().contains(m1));
+        assertTrue(m3.reads().contains(m2));
+        assertTrue(m3.reads().contains(m4));
+        testReadAllBootModules(cf, "m3");   // m3 reads all modules in boot layer
+
+        assertTrue(m4.reads().contains(m1));
+        assertTrue(m4.reads().contains(m2));
+        assertTrue(m4.reads().contains(m3));
+        testReadAllBootModules(cf, "m4");    // m4 reads all modules in boot layer
+
+    }
+
+
+    /**
+     * Basic test of Layer containing automatic modules
+     */
+    public void testInLayer() throws IOException {
+        ModuleDescriptor descriptor
+            =  new ModuleDescriptor.Builder("m1")
+                .requires("m2")
+                .requires("m3")
+                .build();
+
+        // m2 and m3 are simple JAR files
+        Path dir = Files.createTempDirectory(USER_DIR, "mods");
+        createJarFile(dir.resolve("m2.jar"), "p/T.class");
+        createJarFile(dir.resolve("m3.jar"), "q/T2.class");
+
+        // module finder locates m1 and the modules in the directory
+        ModuleFinder finder
+            = ModuleFinder.compose(ModuleUtils.finderOf(descriptor),
+                ModuleFinder.of(dir));
+
+        Configuration parent = Layer.boot().configuration();
+        Configuration cf = resolve(parent, finder, "m1");
+        assertTrue(cf.modules().size() == 3);
+
+        // each module gets its own loader
+        Layer layer = Layer.boot().defineModules(cf, mn -> new ClassLoader() { });
+
+        // an unnamed module
+        Module unnamed = (new ClassLoader() { }).getUnnamedModule();
+
+        Module m2 = layer.findModule("m2").get();
+        assertTrue(m2.isNamed());
+        assertTrue(m2.canRead(unnamed));
+        testsReadsAll(m2, layer);
+
+        Module m3 = layer.findModule("m3").get();
+        assertTrue(m3.isNamed());
+        assertTrue(m2.canRead(unnamed));
+        testsReadsAll(m3, layer);
+    }
+
+
+    /**
+     * Test miscellaneous methods.
+     */
+    public void testMisc() throws IOException {
+        Path dir = Files.createTempDirectory(USER_DIR, "mods");
+        Path m1_jar = createJarFile(dir.resolve("m1.jar"), "p/T.class");
+
+        ModuleFinder finder = ModuleFinder.of(m1_jar);
+
+        assertTrue(finder.find("m1").isPresent());
+        ModuleDescriptor m1 = finder.find("m1").get().descriptor();
+
+        // test miscellaneous methods
+        assertTrue(m1.isAutomatic());
+        assertFalse(m1.isSynthetic());
+        assertFalse(m1.osName().isPresent());
+        assertFalse(m1.osArch().isPresent());
+        assertFalse(m1.osVersion().isPresent());
+    }
+
+
+    /**
+     * Invokes parent.resolveRequires to resolve the given root modules.
+     */
+    static Configuration resolve(Configuration parent,
+                                 ModuleFinder finder,
+                                 String... roots) {
+        return parent.resolveRequires(finder, ModuleFinder.empty(), Set.of(roots));
+    }
+
+    /**
+     * Finds a module in the given configuration or its parents, returning
+     * the module descriptor (or null if not found)
+     */
+    static ModuleDescriptor findDescriptor(Configuration cf, String name) {
+        Optional<ResolvedModule> om = cf.findModule(name);
+        if (om.isPresent()) {
+            return om.get().reference().descriptor();
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Test that a module in a configuration reads all modules in the boot
+     * configuration.
+     */
+    static void testReadAllBootModules(Configuration cf, String mn) {
+
+        Set<String> bootModules = Layer.boot().modules().stream()
+                .map(Module::getName)
+                .collect(Collectors.toSet());
+
+        bootModules.forEach(other -> assertTrue(reads(cf, mn, other)));
+
+    }
+
+    /**
+     * Test that the given Module reads all module in the given Layer
+     * and its parent Layers.
+     */
+    static void testsReadsAll(Module m, Layer layer) {
+        while (layer != Layer.empty()) {
+
+            // check that m reads all module in the layer
+            layer.configuration().modules().stream()
+                .map(ResolvedModule::name)
+                .map(layer::findModule)
+                .map(Optional::get)
+                .forEach(m2 -> assertTrue(m.canRead(m2)));
+
+            layer = layer.parent().get();
+        }
+    }
+
+    /**
+     * Returns {@code true} if the configuration contains module mn1
+     * that reads module mn2.
+     */
+    static boolean reads(Configuration cf, String mn1, String mn2) {
+        Optional<ResolvedModule> om1 = cf.findModule(mn1);
+        if (!om1.isPresent())
+            return false;
+
+        return om1.get().reads().stream()
+                .map(ResolvedModule::name)
+                .anyMatch(mn2::equals);
+    }
+
+    /**
+     * Creates a JAR file, optionally with a manifest, and with the given
+     * entries. The entries will be empty in the resulting JAR file.
+     */
+    static Path createJarFile(Path file, Manifest man, String... entries)
+        throws IOException
+    {
+        try (OutputStream out = Files.newOutputStream(file)) {
+            try (JarOutputStream jos = new JarOutputStream(out)) {
+
+                if (man != null) {
+                    JarEntry je = new JarEntry(JarFile.MANIFEST_NAME);
+                    jos.putNextEntry(je);
+                    man.write(jos);
+                    jos.closeEntry();
+                }
+
+                for (String entry : entries) {
+                    JarEntry je = new JarEntry(entry);
+                    jos.putNextEntry(je);
+                    jos.closeEntry();
+                }
+
+            }
+        }
+        return file;
+    }
+
+    /**
+     * Creates a JAR file and with the given entries. The entries will be empty
+     * in the resulting JAR file.
+     */
+    static Path createJarFile(Path file, String... entries)
+        throws IOException
+    {
+        return createJarFile(file, null, entries);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/module/ConfigurationTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,1554 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @library /lib/testlibrary
+ * @build ConfigurationTest ModuleUtils
+ * @run testng ConfigurationTest
+ * @summary Basic tests for java.lang.module.Configuration
+ */
+
+import java.lang.module.Configuration;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Requires.Modifier;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ResolutionException;
+import java.lang.module.ResolvedModule;
+import java.lang.reflect.Layer;
+import java.util.Optional;
+import java.util.Set;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+@Test
+public class ConfigurationTest {
+
+
+    /**
+     * Basic test of resolver
+     *     m1 requires m2, m2 requires m3
+     */
+    public void testBasic() {
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .requires("m2")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2")
+                .requires("m3")
+                .build();
+
+        ModuleDescriptor descriptor3
+            = new ModuleDescriptor.Builder("m3")
+                .build();
+
+        ModuleFinder finder
+            = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3);
+
+        Configuration cf = resolveRequires(finder, "m1");
+
+        assertTrue(cf.modules().size() == 3);
+
+        assertTrue(cf.findModule("m1").isPresent());
+        assertTrue(cf.findModule("m2").isPresent());
+        assertTrue(cf.findModule("m3").isPresent());
+
+        assertTrue(cf.parent().get() == Configuration.empty());
+
+        ResolvedModule m1 = cf.findModule("m1").get();
+        ResolvedModule m2 = cf.findModule("m2").get();
+        ResolvedModule m3 = cf.findModule("m3").get();
+
+        // m1 reads m2
+        assertTrue(m1.reads().size() == 1);
+        assertTrue(m1.reads().contains(m2));
+
+        // m2 reads m3
+        assertTrue(m2.reads().size() == 1);
+        assertTrue(m2.reads().contains(m3));
+
+        // m3 reads nothing
+        assertTrue(m3.reads().size() == 0);
+
+        // toString
+        assertTrue(cf.toString().contains("m1"));
+        assertTrue(cf.toString().contains("m2"));
+        assertTrue(cf.toString().contains("m3"));
+    }
+
+
+    /**
+     * Basic test of "requires public":
+     *     m1 requires m2, m2 requires public m3
+     */
+    public void testRequiresPublic1() {
+        // m1 requires m2, m2 requires public m3
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .requires("m2")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2")
+                .requires(Modifier.PUBLIC, "m3")
+                .build();
+
+        ModuleDescriptor descriptor3
+            = new ModuleDescriptor.Builder("m3")
+                .build();
+
+        ModuleFinder finder
+            = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3);
+
+        Configuration cf = resolveRequires(finder, "m1");
+
+        assertTrue(cf.modules().size() == 3);
+
+        assertTrue(cf.findModule("m1").isPresent());
+        assertTrue(cf.findModule("m2").isPresent());
+        assertTrue(cf.findModule("m3").isPresent());
+
+        assertTrue(cf.parent().get() == Configuration.empty());
+
+        ResolvedModule m1 = cf.findModule("m1").get();
+        ResolvedModule m2 = cf.findModule("m2").get();
+        ResolvedModule m3 = cf.findModule("m3").get();
+
+        // m1 reads m2 and m3
+        assertTrue(m1.reads().size() == 2);
+        assertTrue(m1.reads().contains(m2));
+        assertTrue(m1.reads().contains(m3));
+
+        // m2 reads m3
+        assertTrue(m2.reads().size() == 1);
+        assertTrue(m2.reads().contains(m3));
+
+        // m3 reads nothing
+        assertTrue(m3.reads().size() == 0);
+    }
+
+
+    /**
+     * Basic test of "requires public" with configurations.
+     *
+     * The test consists of three configurations:
+     * - Configuration cf1: m1, m2 requires public m1
+     * - Configuration cf2: m3 requires m1
+     */
+    public void testRequiresPublic2() {
+
+        // cf1: m1 and m2, m2 requires public m1
+
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2")
+                .requires(Modifier.PUBLIC, "m1")
+                .build();
+
+        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
+
+        Configuration cf1 = resolveRequires(finder1, "m2");
+
+        assertTrue(cf1.modules().size() == 2);
+        assertTrue(cf1.findModule("m1").isPresent());
+        assertTrue(cf1.findModule("m2").isPresent());
+        assertTrue(cf1.parent().get() == Configuration.empty());
+
+        ResolvedModule m1 = cf1.findModule("m1").get();
+        ResolvedModule m2 = cf1.findModule("m2").get();
+
+        assertTrue(m1.reads().size() == 0);
+        assertTrue(m2.reads().size() == 1);
+        assertTrue(m2.reads().contains(m1));
+
+
+        // cf2: m3, m3 requires m2
+
+        ModuleDescriptor descriptor3
+            = new ModuleDescriptor.Builder("m3")
+                .requires("m2")
+                .build();
+
+        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3);
+
+        Configuration cf2 = resolveRequires(cf1, finder2, "m3");
+
+        assertTrue(cf2.modules().size() == 1);
+        assertTrue(cf2.findModule("m1").isPresent());  // in parent
+        assertTrue(cf2.findModule("m2").isPresent());  // in parent
+        assertTrue(cf2.findModule("m3").isPresent());
+        assertTrue(cf2.parent().get() == cf1);
+
+        ResolvedModule m3 = cf2.findModule("m3").get();
+        assertTrue(m3.configuration() == cf2);
+        assertTrue(m3.reads().size() == 2);
+        assertTrue(m3.reads().contains(m1));
+        assertTrue(m3.reads().contains(m2));
+    }
+
+
+    /**
+     * Basic test of "requires public" with configurations.
+     *
+     * The test consists of three configurations:
+     * - Configuration cf1: m1
+     * - Configuration cf2: m2 requires public m3, m3 requires m2
+     */
+    public void testRequiresPublic3() {
+
+        // cf1: m1
+
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .build();
+
+        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
+
+        Configuration cf1 = resolveRequires(finder1, "m1");
+
+        assertTrue(cf1.modules().size() == 1);
+        assertTrue(cf1.findModule("m1").isPresent());
+        assertTrue(cf1.parent().get() == Configuration.empty());
+
+        ResolvedModule m1 = cf1.findModule("m1").get();
+        assertTrue(m1.reads().size() == 0);
+
+
+        // cf2: m2, m3: m2 requires public m1, m3 requires m2
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2")
+                .requires(Modifier.PUBLIC, "m1")
+                .build();
+
+        ModuleDescriptor descriptor3
+            = new ModuleDescriptor.Builder("m3")
+                .requires("m2")
+                .build();
+
+        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2, descriptor3);
+
+        Configuration cf2 = resolveRequires(cf1, finder2, "m3");
+
+        assertTrue(cf2.modules().size() == 2);
+        assertTrue(cf2.findModule("m1").isPresent());   // in parent
+        assertTrue(cf2.findModule("m2").isPresent());
+        assertTrue(cf2.findModule("m3").isPresent());
+        assertTrue(cf2.parent().get() == cf1);
+
+        ResolvedModule m2 = cf2.findModule("m2").get();
+        ResolvedModule m3 = cf2.findModule("m3").get();
+
+        assertTrue(m2.configuration() == cf2);
+        assertTrue(m2.reads().size() == 1);
+        assertTrue(m2.reads().contains(m1));
+
+        assertTrue(m3.configuration() == cf2);
+        assertTrue(m3.reads().size() == 2);
+        assertTrue(m3.reads().contains(m1));
+        assertTrue(m3.reads().contains(m2));
+    }
+
+
+    /**
+     * Basic test of "requires public" with configurations.
+     *
+     * The test consists of three configurations:
+     * - Configuration cf1: m1
+     * - Configuration cf2: m2 requires public m1
+     * - Configuraiton cf3: m3 requires m3
+     */
+    public void testRequiresPublic4() {
+
+        // cf1: m1
+
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .build();
+
+        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
+
+        Configuration cf1 = resolveRequires(finder1, "m1");
+
+        assertTrue(cf1.modules().size() == 1);
+        assertTrue(cf1.findModule("m1").isPresent());
+        assertTrue(cf1.parent().get() == Configuration.empty());
+
+        ResolvedModule m1 = cf1.findModule("m1").get();
+        assertTrue(m1.reads().size() == 0);
+
+
+        // cf2: m2 requires public m1
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2")
+                .requires(Modifier.PUBLIC, "m1")
+                .build();
+
+        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2);
+
+        Configuration cf2 = resolveRequires(cf1, finder2, "m2");
+
+        assertTrue(cf2.modules().size() == 1);
+        assertTrue(cf2.findModule("m1").isPresent());  // in parent
+        assertTrue(cf2.findModule("m2").isPresent());
+        assertTrue(cf2.parent().get() == cf1);
+
+        ResolvedModule m2 = cf2.findModule("m2").get();
+
+        assertTrue(m2.configuration() == cf2);
+        assertTrue(m2.reads().size() == 1);
+        assertTrue(m2.reads().contains(m1));
+
+
+        // cf3: m3 requires m2
+
+        ModuleDescriptor descriptor3
+            = new ModuleDescriptor.Builder("m3")
+                .requires("m2")
+                .build();
+
+        ModuleFinder finder3 = ModuleUtils.finderOf(descriptor3);
+
+        Configuration cf3 = resolveRequires(cf2, finder3, "m3");
+
+        assertTrue(cf3.modules().size() == 1);
+        assertTrue(cf3.findModule("m1").isPresent());  // in parent
+        assertTrue(cf3.findModule("m2").isPresent());  // in parent
+        assertTrue(cf3.findModule("m3").isPresent());
+        assertTrue(cf3.parent().get() == cf2);
+
+        ResolvedModule m3 = cf3.findModule("m3").get();
+
+        assertTrue(m3.configuration() == cf3);
+        assertTrue(m3.reads().size() == 2);
+        assertTrue(m3.reads().contains(m1));
+        assertTrue(m3.reads().contains(m2));
+    }
+
+
+    /**
+     * Basic test of "requires public" with configurations.
+     *
+     * The test consists of two configurations:
+     * - Configuration cf1: m1, m2 requires public m1
+     * - Configuration cf2: m3 requires public m2, m4 requires m3
+     */
+    public void testRequiresPublic5() {
+
+        // cf1: m1, m2 requires public m1
+
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2")
+                .requires(Modifier.PUBLIC, "m1")
+                .build();
+
+        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
+
+        Configuration cf1 = resolveRequires(finder1, "m2");
+
+        assertTrue(cf1.modules().size() == 2);
+        assertTrue(cf1.findModule("m1").isPresent());
+        assertTrue(cf1.findModule("m2").isPresent());
+        assertTrue(cf1.parent().get() == Configuration.empty());
+
+        ResolvedModule m1 = cf1.findModule("m1").get();
+        ResolvedModule m2 = cf1.findModule("m2").get();
+
+        assertTrue(m1.configuration() == cf1);
+        assertTrue(m1.reads().size() == 0);
+
+        assertTrue(m2.configuration() == cf1);
+        assertTrue(m2.reads().size() == 1);
+        assertTrue(m2.reads().contains(m1));
+
+
+        // cf2: m3 requires public m2, m4 requires m3
+
+        ModuleDescriptor descriptor3
+            = new ModuleDescriptor.Builder("m3")
+                .requires(Modifier.PUBLIC, "m2")
+                .build();
+
+        ModuleDescriptor descriptor4
+            = new ModuleDescriptor.Builder("m4")
+                .requires("m3")
+                .build();
+
+
+        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3, descriptor4);
+
+        Configuration cf2 = resolveRequires(cf1, finder2, "m3", "m4");
+
+        assertTrue(cf2.modules().size() == 2);
+        assertTrue(cf2.findModule("m1").isPresent());   // in parent
+        assertTrue(cf2.findModule("m2").isPresent());   // in parent
+        assertTrue(cf2.findModule("m3").isPresent());
+        assertTrue(cf2.findModule("m4").isPresent());
+        assertTrue(cf2.parent().get() == cf1);
+
+        ResolvedModule m3 = cf2.findModule("m3").get();
+        ResolvedModule m4 = cf2.findModule("m4").get();
+
+        assertTrue(m3.configuration() == cf2);
+        assertTrue(m3.reads().size() == 2);
+        assertTrue(m3.reads().contains(m1));
+        assertTrue(m3.reads().contains(m2));
+
+        assertTrue(m4.configuration() == cf2);
+        assertTrue(m4.reads().size() == 3);
+        assertTrue(m4.reads().contains(m1));
+        assertTrue(m4.reads().contains(m2));
+        assertTrue(m4.reads().contains(m3));
+    }
+
+
+    /**
+     * Basic test of binding services
+     *     m1 uses p.S
+     *     m2 provides p.S
+     */
+    public void testServiceBinding1() {
+
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .exports("p")
+                .uses("p.S")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2")
+                .requires("m1")
+                .conceals("q")
+                .provides("p.S", "q.T")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
+
+        Configuration cf = resolveRequiresAndUses(finder, "m1");
+
+        assertTrue(cf.modules().size() == 2);
+        assertTrue(cf.findModule("m1").isPresent());
+        assertTrue(cf.findModule("m2").isPresent());
+        assertTrue(cf.parent().get() == Configuration.empty());
+
+        ResolvedModule m1 = cf.findModule("m1").get();
+        ResolvedModule m2 = cf.findModule("m2").get();
+
+        assertTrue(m1.configuration() == cf);
+        assertTrue(m1.reads().size() == 0);
+
+        assertTrue(m2.configuration() == cf);
+        assertTrue(m2.reads().size() == 1);
+        assertTrue(m2.reads().contains(m1));
+    }
+
+
+    /**
+     * Basic test of binding services
+     *     m1 uses p.S1
+     *     m2 provides p.S1, m2 uses p.S2
+     *     m3 provides p.S2
+     */
+    public void testServiceBinding2() {
+
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .exports("p")
+                .uses("p.S1")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2")
+                .requires("m1")
+                .uses("p.S2")
+                .conceals("q")
+                .provides("p.S1", "q.Service1Impl")
+                .build();
+
+        ModuleDescriptor descriptor3
+            = new ModuleDescriptor.Builder("m3")
+                .requires("m1")
+                .conceals("q")
+                .provides("p.S2", "q.Service2Impl")
+                .build();
+
+        ModuleFinder finder
+            = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3);
+
+        Configuration cf = resolveRequiresAndUses(finder, "m1");
+
+        assertTrue(cf.modules().size() == 3);
+        assertTrue(cf.findModule("m1").isPresent());
+        assertTrue(cf.findModule("m2").isPresent());
+        assertTrue(cf.findModule("m3").isPresent());
+        assertTrue(cf.parent().get() == Configuration.empty());
+
+        ResolvedModule m1 = cf.findModule("m1").get();
+        ResolvedModule m2 = cf.findModule("m2").get();
+        ResolvedModule m3 = cf.findModule("m3").get();
+
+        assertTrue(m1.configuration() == cf);
+        assertTrue(m1.reads().size() == 0);
+
+        assertTrue(m2.configuration() == cf);
+        assertTrue(m2.reads().size() == 1);
+        assertTrue(m2.reads().contains(m1));
+
+        assertTrue(m3.configuration() == cf);
+        assertTrue(m3.reads().size() == 1);
+        assertTrue(m3.reads().contains(m1));
+    }
+
+
+    /**
+     * Basic test of binding services with configurations.
+     *
+     * The test consists of two configurations:
+     * - Configuration cf1: m1 uses p.S
+     * - Configuration cf2: m2 provides p.S
+     */
+    public void testServiceBindingWithConfigurations1() {
+
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .exports("p")
+                .uses("p.S")
+                .build();
+
+        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
+
+        Configuration cf1 = resolveRequires(finder1, "m1");
+
+        assertTrue(cf1.modules().size() == 1);
+        assertTrue(cf1.findModule("m1").isPresent());
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2")
+                .requires("m1")
+                .conceals("q")
+                .provides("p.S", "q.T")
+                .build();
+
+        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2);
+
+        Configuration cf2 = resolveRequiresAndUses(cf1, finder2); // no roots
+
+        assertTrue(cf2.parent().get() == cf1);
+        assertTrue(cf2.modules().size() == 1);
+        assertTrue(cf2.findModule("m2").isPresent());
+
+        ResolvedModule m1 = cf1.findModule("m1").get();
+        ResolvedModule m2 = cf2.findModule("m2").get();
+
+        assertTrue(m2.reads().size() == 1);
+        assertTrue(m2.reads().contains(m1));
+    }
+
+
+    /**
+     * Basic test of binding services with configurations.
+     *
+     * The test consists of two configurations:
+     * - Configuration cf1: m1 uses p.S && provides p.S,
+     *                      m2 provides p.S
+     * - Configuration cf2: m3 provides p.S
+     *                      m4 provides p.S
+     */
+    public void testServiceBindingWithConfigurations2() {
+
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .exports("p")
+                .uses("p.S")
+                .conceals("p1")
+                .provides("p.S", "p1.ServiceImpl")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2")
+                .requires("m1")
+                .conceals("p2")
+                .provides("p.S", "p2.ServiceImpl")
+                .build();
+
+        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
+
+        Configuration cf1 = resolveRequiresAndUses(finder1, "m1");
+
+        assertTrue(cf1.modules().size() == 2);
+        assertTrue(cf1.findModule("m1").isPresent());
+        assertTrue(cf1.findModule("m2").isPresent());
+
+
+        ModuleDescriptor descriptor3
+            = new ModuleDescriptor.Builder("m3")
+                .requires("m1")
+                .conceals("p3")
+                .provides("p.S", "p3.ServiceImpl")
+                .build();
+
+        ModuleDescriptor descriptor4
+            = new ModuleDescriptor.Builder("m4")
+                .requires("m1")
+                .conceals("p4")
+                .provides("p.S", "p4.ServiceImpl")
+                .build();
+
+        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3, descriptor4);
+
+        Configuration cf2 = resolveRequiresAndUses(cf1, finder2); // no roots
+
+        assertTrue(cf2.parent().get() == cf1);
+        assertTrue(cf2.modules().size() == 2);
+        assertTrue(cf2.findModule("m3").isPresent());
+        assertTrue(cf2.findModule("m4").isPresent());
+
+        ResolvedModule m1 = cf2.findModule("m1").get();  // should find in parent
+        ResolvedModule m2 = cf2.findModule("m2").get();
+        ResolvedModule m3 = cf2.findModule("m3").get();
+        ResolvedModule m4 = cf2.findModule("m4").get();
+
+        assertTrue(m1.reads().size() == 0);
+
+        assertTrue(m2.reads().size() == 1);
+        assertTrue(m2.reads().contains(m1));
+
+        assertTrue(m3.reads().size() == 1);
+        assertTrue(m3.reads().contains(m1));
+
+        assertTrue(m4.reads().size() == 1);
+        assertTrue(m4.reads().contains(m1));
+    }
+
+
+    /**
+     * Basic test of binding services with configurations.
+     *
+     * Configuration cf1: p@1.0 provides p.S
+     * Test configuration cf2: m1 uses p.S
+     * Test configuration cf2: m1 uses p.S, p@2.0 uses p.S
+     */
+    public void testServiceBindingWithConfigurations3() {
+
+        ModuleDescriptor service
+            = new ModuleDescriptor.Builder("s")
+                .exports("p")
+                .build();
+
+        ModuleDescriptor provider_v1
+            = new ModuleDescriptor.Builder("p")
+                .version("1.0")
+                .requires("s")
+                .conceals("q")
+                .provides("p.S", "q.T")
+                .build();
+
+        ModuleFinder finder1 = ModuleUtils.finderOf(service, provider_v1);
+
+        Configuration cf1 = resolveRequires(finder1, "p");
+
+        assertTrue(cf1.modules().size() == 2);
+        assertTrue(cf1.findModule("s").isPresent());
+        assertTrue(cf1.findModule("p").isPresent());
+
+        // p@1.0 in cf1
+        ResolvedModule p = cf1.findModule("p").get();
+        assertEquals(p.reference().descriptor(), provider_v1);
+
+
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .requires("s")
+                .uses("p.S")
+                .build();
+
+        ModuleDescriptor provider_v2
+            = new ModuleDescriptor.Builder("p")
+                .version("2.0")
+                .requires("s")
+                .conceals("q")
+                .provides("p.S", "q.T")
+                .build();
+
+        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, provider_v2);
+
+
+        // finder2 is the before ModuleFinder and so p@2.0 should be located
+
+        Configuration cf2 = resolveRequiresAndUses(cf1, finder2, "m1");
+
+        assertTrue(cf2.parent().get() == cf1);
+        assertTrue(cf2.modules().size() == 2);
+
+        // p should be found in cf2
+        p = cf2.findModule("p").get();
+        assertTrue(p.configuration() == cf2);
+        assertEquals(p.reference().descriptor(), provider_v2);
+
+
+        // finder2 is the after ModuleFinder and so p@2.0 should not be located
+        // as module p is in parent configuration.
+
+        cf2 = resolveRequiresAndUses(cf1, ModuleFinder.empty(), finder2, "m1");
+
+        assertTrue(cf2.parent().get() == cf1);
+        assertTrue(cf2.modules().size() == 1);
+
+        // p should be found in cf1
+        p = cf2.findModule("p").get();
+        assertTrue(p.configuration() == cf1);
+        assertEquals(p.reference().descriptor(), provider_v1);
+    }
+
+
+    /**
+     * Basic test with two module finders.
+     *
+     * Module m2 can be found by both the before and after finders.
+     */
+    public void testWithTwoFinders1() {
+
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .requires("m2")
+                .build();
+
+        ModuleDescriptor descriptor2_v1
+            = new ModuleDescriptor.Builder("m2")
+                .version("1.0")
+                .build();
+
+        ModuleDescriptor descriptor2_v2
+            = new ModuleDescriptor.Builder("m2")
+                .version("2.0")
+                .build();
+
+        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor2_v1);
+        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, descriptor2_v2);
+
+        Configuration cf = resolveRequires(finder1, finder2, "m1");
+
+        assertTrue(cf.modules().size() == 2);
+        assertTrue(cf.findModule("m1").isPresent());
+        assertTrue(cf.findModule("m2").isPresent());
+
+        ResolvedModule m1 = cf.findModule("m1").get();
+        ResolvedModule m2 = cf.findModule("m2").get();
+
+        assertEquals(m1.reference().descriptor(), descriptor1);
+        assertEquals(m2.reference().descriptor(), descriptor2_v1);
+    }
+
+
+    /**
+     * Basic test with two modules finders and service binding.
+     *
+     * The before and after ModuleFinders both locate a service provider module
+     * named "m2" that provide implementations of the same service type.
+     */
+    public void testWithTwoFinders2() {
+
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .exports("p")
+                .uses("p.S")
+                .build();
+
+        ModuleDescriptor descriptor2_v1
+            = new ModuleDescriptor.Builder("m2")
+                .requires("m1")
+                .conceals("q")
+                .provides("p.S", "q.T")
+                .build();
+
+        ModuleDescriptor descriptor2_v2
+            = new ModuleDescriptor.Builder("m2")
+                .requires("m1")
+                .conceals("q")
+                .provides("p.S", "q.T")
+                .build();
+
+        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2_v1);
+        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2_v2);
+
+        Configuration cf = resolveRequiresAndUses(finder1, finder2, "m1");
+
+        assertTrue(cf.modules().size() == 2);
+        assertTrue(cf.findModule("m1").isPresent());
+        assertTrue(cf.findModule("m2").isPresent());
+
+        ResolvedModule m1 = cf.findModule("m1").get();
+        ResolvedModule m2 = cf.findModule("m2").get();
+
+        assertEquals(m1.reference().descriptor(), descriptor1);
+        assertEquals(m2.reference().descriptor(), descriptor2_v1);
+    }
+
+
+    /**
+     * Basic test for resolving a module that is located in the parent
+     * configuration.
+     */
+    public void testResolvedInParent1() {
+
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
+
+        Configuration cf1 = resolveRequires(finder, "m1");
+
+        assertTrue(cf1.modules().size() == 1);
+        assertTrue(cf1.findModule("m1").isPresent());
+
+        Configuration cf2 = resolveRequires(cf1, finder, "m1");
+
+        assertTrue(cf2.modules().size() == 1);
+    }
+
+
+    /**
+     * Basic test for resolving a module that has a dependency on a module
+     * in the parent configuration.
+     */
+    public void testResolvedInParent2() {
+
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .build();
+
+        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
+
+        Configuration cf1 = resolveRequires(finder1, "m1");
+
+        assertTrue(cf1.modules().size() == 1);
+        assertTrue(cf1.findModule("m1").isPresent());
+
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2")
+                .requires("m1")
+                .build();
+
+        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2);
+
+        Configuration cf2 = resolveRequires(cf1, ModuleFinder.empty(), finder2, "m2");
+
+        assertTrue(cf2.modules().size() == 1);
+        assertTrue(cf2.findModule("m2").isPresent());
+
+        ResolvedModule m1 = cf2.findModule("m1").get();   // find in parent
+        ResolvedModule m2 = cf2.findModule("m2").get();
+
+        assertTrue(m1.reads().size() == 0);
+        assertTrue(m2.reads().size() == 1);
+        assertTrue(m2.reads().contains(m1));
+    }
+
+
+    /**
+     * Basic test of using the beforeFinder to override a module in the parent
+     * configuration.
+     */
+    public void testOverriding1() {
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
+
+        Configuration cf1 = resolveRequires(finder, "m1");
+        assertTrue(cf1.modules().size() == 1);
+        assertTrue(cf1.findModule("m1").isPresent());
+
+        Configuration cf2 = resolveRequires(cf1, finder, "m1");
+        assertTrue(cf2.modules().size() == 1);
+        assertTrue(cf1.findModule("m1").isPresent());
+    }
+
+
+    /**
+     * Basic test of using the beforeFinder to override a module in the parent
+     * configuration but where implied readability in the picture so that the
+     * module in the parent is read.
+     *
+     * The test consists of two configurations:
+     * - Configuration cf1: m1, m2 requires public m1
+     * - Configuration cf2: m1, m3 requires m2
+     */
+    public void testOverriding2() {
+
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2")
+                .requires(Modifier.PUBLIC, "m1")
+                .build();
+
+        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
+
+        Configuration cf1 = resolveRequires(finder1, "m2");
+
+        assertTrue(cf1.modules().size() == 2);
+        assertTrue(cf1.findModule("m1").isPresent());
+        assertTrue(cf1.findModule("m2").isPresent());
+
+        // cf2: m3 requires m2, m1
+
+        ModuleDescriptor descriptor3
+            = new ModuleDescriptor.Builder("m3")
+                .requires("m2")
+                .build();
+
+        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, descriptor3);
+
+        Configuration cf2 = resolveRequires(cf1, finder2, "m1", "m3");
+
+        assertTrue(cf2.parent().get() == cf1);
+
+        assertTrue(cf2.modules().size() == 2);
+        assertTrue(cf2.findModule("m1").isPresent());
+        assertTrue(cf2.findModule("m3").isPresent());
+
+        ResolvedModule m1_1 = cf1.findModule("m1").get();
+        ResolvedModule m1_2 = cf2.findModule("m1").get();
+        ResolvedModule m2 = cf1.findModule("m2").get();
+        ResolvedModule m3 = cf2.findModule("m3").get();
+
+        assertTrue(m1_1.configuration() == cf1);
+        assertTrue(m1_2.configuration() == cf2);
+        assertTrue(m3.configuration() == cf2);
+
+
+        // check that m3 reads cf1/m1 and cf2/m2
+        assertTrue(m3.reads().size() == 2);
+        assertTrue(m3.reads().contains(m1_1));
+        assertTrue(m3.reads().contains(m2));
+    }
+
+
+    /**
+     * Root module not found
+     */
+    @Test(expectedExceptions = { ResolutionException.class })
+    public void testRootNotFound() {
+        resolveRequires(ModuleFinder.empty(), "m1");
+    }
+
+
+    /**
+     * Direct dependency not found
+     */
+    @Test(expectedExceptions = { ResolutionException.class })
+    public void testDirectDependencyNotFound() {
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1").requires("m2").build();
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
+        resolveRequires(finder, "m1");
+    }
+
+
+    /**
+     * Transitive dependency not found
+     */
+    @Test(expectedExceptions = { ResolutionException.class })
+    public void testTransitiveDependencyNotFound() {
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1").requires("m2").build();
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2").requires("m3").build();
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
+        resolveRequires(finder, "m1");
+    }
+
+
+    /**
+     * Service provider dependency not found
+     */
+    @Test(expectedExceptions = { ResolutionException.class })
+    public void testServiceProviderDependencyNotFound() {
+
+        // service provider dependency (on m3) not found
+
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .exports("p")
+                .uses("p.S")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2")
+                .requires("m1")
+                .requires("m3")
+                .conceals("q")
+                .provides("p.S", "q.T")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
+
+        // should throw ResolutionException because m3 is not found
+        Configuration cf = resolveRequiresAndUses(finder, "m1");
+    }
+
+
+    /**
+     * Simple cycle.
+     */
+    @Test(expectedExceptions = { ResolutionException.class })
+    public void testSimpleCycle() {
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1").requires("m2").build();
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2").requires("m3").build();
+        ModuleDescriptor descriptor3
+            = new ModuleDescriptor.Builder("m3").requires("m1").build();
+        ModuleFinder finder
+            = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3);
+        resolveRequires(finder, "m1");
+    }
+
+    /**
+     * Basic test for detecting cycles involving a service provider module
+     */
+    @Test(expectedExceptions = { ResolutionException.class })
+    public void testCycleInProvider() {
+
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .exports("p")
+                .uses("p.S")
+                .build();
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2")
+                .requires("m1")
+                .requires("m3")
+                .conceals("q")
+                .provides("p.S", "q.T")
+                .build();
+        ModuleDescriptor descriptor3
+            = new ModuleDescriptor.Builder("m3")
+                .requires("m2")
+                .build();
+
+        ModuleFinder finder
+            = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3);
+
+        // should throw ResolutionException because of the m2 <--> m3 cycle
+        resolveRequiresAndUses(finder, "m1");
+    }
+
+
+    /**
+     * Test two modules exporting package p to a module that reads both.
+     */
+    @Test(expectedExceptions = { ResolutionException.class })
+    public void testPackageSuppliedByTwoOthers() {
+
+        ModuleDescriptor descriptor1
+            =  new ModuleDescriptor.Builder("m1")
+                .requires("m2")
+                .requires("m3")
+                .build();
+
+        ModuleDescriptor descriptor2
+            =  new ModuleDescriptor.Builder("m2")
+                .exports("p")
+                .build();
+
+        ModuleDescriptor descriptor3
+            =  new ModuleDescriptor.Builder("m3")
+                .exports("p", "m1")
+                .build();
+
+        ModuleFinder finder
+            = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3);
+
+        // m2 and m3 export package p to module m1
+        resolveRequires(finder, "m1");
+    }
+
+
+    /**
+     * Test the scenario where a module has a concealed package p and reads
+     * a module that exports package p.
+     */
+    @Test(expectedExceptions = { ResolutionException.class })
+    public void testPackageSuppliedBySelfAndOther() {
+
+        ModuleDescriptor descriptor1
+            =  new ModuleDescriptor.Builder("m1")
+                .requires("m2")
+                .conceals("p")
+                .build();
+
+        ModuleDescriptor descriptor2
+            =  new ModuleDescriptor.Builder("m2")
+                .exports("p")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
+
+        //  m1 contains package p, module m2 exports package p to m1
+        resolveRequires(finder, "m1");
+    }
+
+
+    /**
+     * Test the scenario where a module has a concealed package p and reads
+     * a module that also has a concealed package p.
+     */
+    public void testPackagePrivateToSelfAndOther() {
+
+        ModuleDescriptor descriptor1
+            =  new ModuleDescriptor.Builder("m1")
+                .requires("m2")
+                .conceals("p")
+                .build();
+
+        ModuleDescriptor descriptor2
+            =  new ModuleDescriptor.Builder("m2")
+                .conceals("p")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
+
+        Configuration cf = resolveRequires(finder, "m1");
+
+        assertTrue(cf.modules().size() == 2);
+        assertTrue(cf.findModule("m1").isPresent());
+        assertTrue(cf.findModule("m2").isPresent());
+
+        // m1 reads m2, m2 reads nothing
+        ResolvedModule m1 = cf.findModule("m1").get();
+        ResolvedModule m2 = cf.findModule("m2").get();
+        assertTrue(m1.reads().size() == 1);
+        assertTrue(m1.reads().contains(m2));
+        assertTrue(m2.reads().size() == 0);
+    }
+
+
+    /**
+     * Test the scenario where a module that exports a package that is also
+     * exported by a module that it reads in a parent layer.
+     */
+    @Test(expectedExceptions = { ResolutionException.class })
+    public void testExportSamePackageAsBootLayer() {
+        ModuleDescriptor descriptor
+            =  new ModuleDescriptor.Builder("m1")
+                .requires("java.base")
+                .exports("java.lang")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor);
+
+        Configuration bootConfiguration = Layer.boot().configuration();
+
+        // m1 contains package java.lang, java.base exports package java.lang to m1
+        resolveRequires(bootConfiguration, finder, "m1");
+    }
+
+
+    /**
+     * Test "uses p.S" where p is a concealed package in the same module.
+     */
+    public void testConcealedService1() {
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .conceals("p")
+                .uses("p.S")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
+
+        Configuration cf = resolveRequires(finder, "m1");
+
+        assertTrue(cf.modules().size() == 1);
+        assertTrue(cf.findModule("m1").isPresent());
+    }
+
+
+    /**
+     * Test "uses p.S" where p is a concealed package in a different module.
+     */
+    @Test(expectedExceptions = { ResolutionException.class })
+    public void testConcealedService2() {
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .conceals("p")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2")
+                .requires("m1")
+                .uses("p.S")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
+
+        // m2 does not read a module that exports p
+        resolveRequires(finder, "m2");
+    }
+
+
+    /**
+     * Test "provides p.S" where p is a concealed package in the same module.
+     */
+    public void testConcealedService3() {
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .conceals("p")
+                .conceals("q")
+                .provides("p.S", "q.S1")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
+
+        Configuration cf = resolveRequires(finder, "m1");
+
+        assertTrue(cf.modules().size() == 1);
+        assertTrue(cf.findModule("m1").isPresent());
+    }
+
+
+    /**
+     * Test "provides p.S" where p is a concealed package in a different module.
+     */
+    @Test(expectedExceptions = { ResolutionException.class })
+    public void testConcealedService4() {
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .conceals("p")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2")
+                .requires("m1")
+                .conceals("q")
+                .provides("p.S", "q.S1")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
+
+        // m2 does not read a module that exports p
+        resolveRequires(finder, "m2");
+    }
+
+
+    /**
+     * Test "uses p.S" where p is not exported to the module.
+     */
+    @Test(expectedExceptions = { ResolutionException.class })
+    public void testServiceTypePackageNotExported1() {
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .uses("p.S")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
+
+        // m1 does not read a module that exports p
+        resolveRequires(finder, "m1");
+    }
+
+
+    /**
+     * Test "provides p.S" where p is not exported to the module.
+     */
+    @Test(expectedExceptions = { ResolutionException.class })
+    public void testServiceTypePackageNotExported2() {
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .conceals("q")
+                .provides("p.S", "q.T")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
+
+        // m1 does not read a module that exports p
+        resolveRequires(finder, "m1");
+    }
+
+
+    /**
+     * Test "provides p.S" where p is not local
+     */
+    @Test(expectedExceptions = { ResolutionException.class })
+    public void testProviderPackageNotLocal() {
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .exports("p")
+                .exports("q")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2")
+                .requires("m1")
+                .provides("p.S", "q.T")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
+
+        // q.T not in module m2
+        resolveRequires(finder, "m2");
+    }
+
+
+    /**
+     * Test the empty configuration.
+     */
+    public void testEmptyConfiguration() {
+        Configuration cf = Configuration.empty();
+
+        assertFalse(cf.parent().isPresent());
+
+        assertTrue(cf.modules().isEmpty());
+        assertFalse(cf.findModule("java.base").isPresent());
+    }
+
+
+    // platform specific modules
+
+    @DataProvider(name = "platformmatch")
+    public Object[][] createPlatformMatches() {
+        return new Object[][]{
+
+            { "linux-*-*",       "*-*-*" },
+            { "*-arm-*",         "*-*-*" },
+            { "*-*-2.6",         "*-*-*" },
+
+            { "linux-arm-*",     "*-*-*" },
+            { "linux-*-2.6",     "*-*-*" },
+            { "*-arm-2.6",       "*-*-*" },
+
+            { "linux-arm-2.6",   "*-*-*" },
+
+            { "linux-*-*",       "linux-*-*" },
+            { "*-arm-*",         "*-arm-*"   },
+            { "*-*-2.6",         "*-*-2.6"   },
+
+            { "linux-arm-*",     "linux-arm-*" },
+            { "linux-arm-*",     "linux-*-*"   },
+            { "linux-*-2.6",     "linux-*-2.6" },
+            { "linux-*-2.6",     "linux-arm-*" },
+
+            { "linux-arm-2.6",   "linux-arm-2.6" },
+
+        };
+
+    };
+
+    @DataProvider(name = "platformmismatch")
+    public Object[][] createBad() {
+        return new Object[][] {
+
+            { "linux-*-*",        "solaris-*-*"   },
+            { "linux-x86-*",      "linux-arm-*"   },
+            { "linux-*-2.4",      "linux-x86-2.6" },
+        };
+    }
+
+    /**
+     * Test creating a configuration containing platform specific modules.
+     */
+    @Test(dataProvider = "platformmatch")
+    public void testPlatformMatch(String s1, String s2) {
+
+        ModuleDescriptor.Builder builder
+            = new ModuleDescriptor.Builder("m1").requires("m2");
+
+        String[] s = s1.split("-");
+        if (!s[0].equals("*"))
+            builder.osName(s[0]);
+        if (!s[1].equals("*"))
+            builder.osArch(s[1]);
+        if (!s[2].equals("*"))
+            builder.osVersion(s[2]);
+
+        ModuleDescriptor descriptor1 = builder.build();
+
+        builder = new ModuleDescriptor.Builder("m2");
+
+        s = s2.split("-");
+        if (!s[0].equals("*"))
+            builder.osName(s[0]);
+        if (!s[1].equals("*"))
+            builder.osArch(s[1]);
+        if (!s[2].equals("*"))
+            builder.osVersion(s[2]);
+
+        ModuleDescriptor descriptor2 = builder.build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
+
+        Configuration cf = resolveRequires(finder, "m1");
+
+        assertTrue(cf.modules().size() == 2);
+        assertTrue(cf.findModule("m1").isPresent());
+        assertTrue(cf.findModule("m2").isPresent());
+    }
+
+    /**
+     * Test attempting to create a configuration with modules for different
+     * platforms.
+     */
+    @Test(dataProvider = "platformmismatch",
+          expectedExceptions = ResolutionException.class )
+    public void testPlatformMisMatch(String s1, String s2) {
+        testPlatformMatch(s1, s2);
+    }
+
+
+    // null handling
+
+    // finder1, finder2, roots
+
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testResolveRequiresWithNull1() {
+        resolveRequires((ModuleFinder)null, ModuleFinder.empty());
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testResolveRequiresWithNull2() {
+        resolveRequires(ModuleFinder.empty(), (ModuleFinder)null);
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testResolveRequiresAndUsesWithNull1() {
+        resolveRequiresAndUses((ModuleFinder) null, ModuleFinder.empty());
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testResolveRequiresAndUsesWithNull2() {
+        resolveRequiresAndUses(ModuleFinder.empty(), (ModuleFinder) null);
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testFindModuleWithNull() {
+        Configuration.empty().findModule(null);
+    }
+
+    // immutable sets
+
+    @Test(expectedExceptions = { UnsupportedOperationException.class })
+    public void testImmutableSet1() {
+        Configuration cf = Layer.boot().configuration();
+        ResolvedModule base = cf.findModule("java.base").get();
+        cf.modules().add(base);
+    }
+
+    @Test(expectedExceptions = { UnsupportedOperationException.class })
+    public void testImmutableSet2() {
+        Configuration cf = Layer.boot().configuration();
+        ResolvedModule base = cf.findModule("java.base").get();
+        base.reads().add(base);
+    }
+
+
+    /**
+     * Invokes parent.resolveRequires(...)
+     */
+    private Configuration resolveRequires(Configuration parent,
+                                          ModuleFinder before,
+                                          ModuleFinder after,
+                                          String... roots) {
+        return parent.resolveRequires(before, after, Set.of(roots));
+    }
+
+    private Configuration resolveRequires(Configuration parent,
+                                          ModuleFinder before,
+                                          String... roots) {
+        return resolveRequires(parent, before, ModuleFinder.empty(), roots);
+    }
+
+    private Configuration resolveRequires(ModuleFinder before,
+                                          ModuleFinder after,
+                                          String... roots) {
+        return resolveRequires(Configuration.empty(), before, after, roots);
+    }
+
+    private Configuration resolveRequires(ModuleFinder before,
+                                          String... roots) {
+        return resolveRequires(Configuration.empty(), before, roots);
+    }
+
+
+    /**
+     * Invokes parent.resolveRequiresAndUses(...)
+     */
+    private Configuration resolveRequiresAndUses(Configuration parent,
+                                                 ModuleFinder before,
+                                                 ModuleFinder after,
+                                                 String... roots) {
+        return parent.resolveRequiresAndUses(before, after, Set.of(roots));
+    }
+
+    private Configuration resolveRequiresAndUses(Configuration parent,
+                                                 ModuleFinder before,
+                                                 String... roots) {
+        return resolveRequiresAndUses(parent, before, ModuleFinder.empty(), roots);
+    }
+
+    private Configuration resolveRequiresAndUses(ModuleFinder before,
+                                                 ModuleFinder after,
+                                                 String... roots) {
+        return resolveRequiresAndUses(Configuration.empty(), before, after, roots);
+    }
+
+    private Configuration resolveRequiresAndUses(ModuleFinder before,
+                                                 String... roots) {
+        return resolveRequiresAndUses(Configuration.empty(), before, roots);
+    }
+
+
+    /**
+     * Returns {@code true} if the configuration contains module mn1
+     * that reads module mn2.
+     */
+    static boolean reads(Configuration cf, String mn1, String mn2) {
+        Optional<ResolvedModule> om1 = cf.findModule(mn1);
+        if (!om1.isPresent())
+            return false;
+
+        return om1.get().reads().stream()
+                .map(ResolvedModule::name)
+                .anyMatch(mn2::equals);
+    }
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/module/ModuleDescriptorTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,727 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @run testng ModuleDescriptorTest
+ * @summary Basic test for java.lang.module.ModuleDescriptor and its builder
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.module.InvalidModuleDescriptorException;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Builder;
+import java.lang.module.ModuleDescriptor.Exports;
+import java.lang.module.ModuleDescriptor.Requires;
+import java.lang.module.ModuleDescriptor.Provides;
+import java.lang.module.ModuleDescriptor.Requires.Modifier;
+import java.lang.module.ModuleDescriptor.Version;
+import java.lang.reflect.Module;
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import static java.lang.module.ModuleDescriptor.Requires.Modifier.*;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+@Test
+public class ModuleDescriptorTest {
+
+    @DataProvider(name = "invalidjavaidentifiers")
+    public Object[][] invalidJavaIdentifiers() {
+        return new Object[][]{
+
+            { null,         null },
+            { ".foo",       null },
+            { "foo.",       null },
+            { "[foo]",      null },
+
+        };
+    }
+
+
+    // requires
+
+    private Requires requires(Set<Modifier> mods, String mn) {
+        return new Builder("m")
+            .requires(mods, mn)
+            .build()
+            .requires()
+            .iterator()
+            .next();
+    }
+
+    public void testRequiresWithRequires() {
+        Requires r1 = requires(null, "foo");
+        ModuleDescriptor descriptor = new Builder("m").requires(r1).build();
+        Requires r2 = descriptor.requires().iterator().next();
+        assertEquals(r1, r2);
+    }
+
+    public void testRequiresWithNullModifiers() {
+        Requires r = requires(null, "foo");
+        assertEquals(r, r);
+        assertTrue(r.compareTo(r) == 0);
+        assertTrue(r.modifiers().isEmpty());
+        assertEquals(r.name(), "foo");
+    }
+
+    public void testRequiresWithNoModifiers() {
+        Requires r = requires(EnumSet.noneOf(Requires.Modifier.class), "foo");
+        assertEquals(r, r);
+        assertTrue(r.compareTo(r) == 0);
+        assertTrue(r.modifiers().isEmpty());
+        assertEquals(r.name(), "foo");
+    }
+
+    public void testRequiresWithOneModifier() {
+        Requires r = requires(EnumSet.of(PUBLIC), "foo");
+        assertEquals(r, r);
+        assertTrue(r.compareTo(r) == 0);
+        assertEquals(r.modifiers(), EnumSet.of(PUBLIC));
+        assertEquals(r.name(), "foo");
+    }
+
+    public void testRequiresWithTwoModifiers() {
+        Requires r = requires(EnumSet.of(PUBLIC, SYNTHETIC), "foo");
+        assertEquals(r, r);
+        assertTrue(r.compareTo(r) == 0);
+        assertEquals(r.modifiers(), EnumSet.of(PUBLIC, SYNTHETIC));
+        assertEquals(r.name(), "foo");
+    }
+
+    public void testRequiresWithAllModifiers() {
+        Requires r = requires(EnumSet.allOf(Modifier.class), "foo");
+        assertEquals(r, r);
+        assertTrue(r.compareTo(r) == 0);
+        assertEquals(r.modifiers(), EnumSet.allOf(Modifier.class));
+        assertEquals(r.name(), "foo");
+    }
+
+    @Test(expectedExceptions = IllegalStateException.class)
+    public void testRequiresWithDuplicatesRequires() {
+        Requires r = requires(null, "foo");
+        new Builder("m").requires(r).requires(r);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testRequiresSelfWithRequires() {
+        Requires r = requires(null, "m");
+        new Builder("m").requires(r);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testRequiresSelfWithNoModifier() {
+        new Builder("m").requires("m");
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testRequiresSelfWithOneModifier() {
+        new Builder("m").requires(PUBLIC, "m");
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testRequiresSelfWithAllModifiers() {
+        new Builder("m").requires(EnumSet.allOf(Modifier.class), "m");
+    }
+
+    @Test(dataProvider = "invalidjavaidentifiers",
+          expectedExceptions = IllegalArgumentException.class )
+    public void testRequiresWithBadModuleName(String mn, String ignore) {
+        requires(EnumSet.noneOf(Modifier.class), mn);
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testRequiresWithNullRequires() {
+        new Builder("m").requires((Requires) null);
+    }
+
+    public void testRequiresCompare() {
+        Requires r1 = requires(EnumSet.noneOf(Modifier.class), "foo");
+        Requires r2 = requires(EnumSet.noneOf(Modifier.class), "bar");
+        int n = "foo".compareTo("bar");
+        assertTrue(r1.compareTo(r2) == n);
+        assertTrue(r2.compareTo(r1) == -n);
+    }
+
+    public void testRequiresToString() {
+        Requires r = requires(EnumSet.noneOf(Modifier.class), "foo");
+        assertTrue(r.toString().contains("foo"));
+    }
+
+
+    // exports
+
+    private Exports exports(String pn) {
+        return new Builder("foo")
+            .exports(pn)
+            .build()
+            .exports()
+            .iterator()
+            .next();
+    }
+
+    private Exports exports(String pn, String target) {
+        return new Builder("foo")
+            .exports(pn, target)
+            .build()
+            .exports()
+            .iterator()
+            .next();
+    }
+
+    public void testExportsExports() {
+        Exports e1 = exports("p");
+        ModuleDescriptor descriptor = new Builder("m").exports(e1).build();
+        Exports e2 = descriptor.exports().iterator().next();
+        assertEquals(e1, e2);
+    }
+
+    public void testExportsToAll() {
+        Exports e = exports("p");
+        assertEquals(e, e);
+        assertEquals(e.source(), "p");
+        assertFalse(e.isQualified());
+        assertTrue(e.targets().isEmpty());
+    }
+
+    public void testExportsToTarget() {
+        Exports e = exports("p", "bar");
+        assertEquals(e, e);
+        assertEquals(e.source(), "p");
+        assertTrue(e.isQualified());
+        assertTrue(e.targets().size() == 1);
+        assertTrue(e.targets().contains("bar"));
+    }
+
+    public void testExportsToTargets() {
+        Set<String> targets = new HashSet<>();
+        targets.add("bar");
+        targets.add("gus");
+        Exports e
+            = new Builder("foo")
+                .exports("p", targets)
+                .build()
+                .exports()
+                .iterator()
+                .next();
+        assertEquals(e, e);
+        assertEquals(e.source(), "p");
+        assertTrue(e.isQualified());
+        assertTrue(e.targets().size() == 2);
+        assertTrue(e.targets().contains("bar"));
+        assertTrue(e.targets().contains("gus"));
+    }
+
+    @Test(expectedExceptions = IllegalStateException.class)
+    public void testExportsWithDuplicate1() {
+        Exports e = exports("p");
+        new Builder("foo").exports(e).exports(e);
+    }
+
+    @Test(expectedExceptions = IllegalStateException.class)
+    public void testExportsWithDuplicate2() {
+        new Builder("foo").exports("p").exports("p");
+    }
+
+    @Test(expectedExceptions = IllegalStateException.class)
+    public void testExportsWithConcealedPackage() {
+        new Builder("foo").conceals("p").exports("p");
+    }
+
+    @Test(expectedExceptions = IllegalStateException.class)
+    public void testExportsToTargetWithConcealedPackage() {
+        new Builder("foo").conceals("p").exports("p", "bar");
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class )
+    public void testExportsWithEmptySet() {
+        new Builder("foo").exports("p", Collections.emptySet());
+    }
+
+    @Test(dataProvider = "invalidjavaidentifiers",
+          expectedExceptions = IllegalArgumentException.class )
+    public void testExportsWithBadName(String pn, String ignore) {
+        new Builder("foo").exports(pn);
+    }
+
+    @Test(expectedExceptions = NullPointerException.class )
+    public void testExportsWithNullExports() {
+        new Builder("foo").exports((Exports)null);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class )
+    public void testExportsWithNullTarget() {
+        new Builder("foo").exports("p", (String) null);
+    }
+
+    @Test(expectedExceptions = NullPointerException.class )
+    public void testExportsWithNullTargets() {
+        new Builder("foo").exports("p", (Set<String>) null);
+    }
+
+    public void testExportsToString() {
+        String s = new Builder("foo")
+            .exports("p1", "bar")
+            .build()
+            .exports()
+            .iterator()
+            .next()
+            .toString();
+        assertTrue(s.contains("p1"));
+        assertTrue(s.contains("bar"));
+    }
+
+
+    // uses
+
+    public void testUses() {
+        Set<String> uses
+            = new Builder("foo")
+                .uses("p.S")
+                .uses("q.S")
+                .build()
+                .uses();
+        assertTrue(uses.size() == 2);
+        assertTrue(uses.contains("p.S"));
+        assertTrue(uses.contains("q.S"));
+    }
+
+    @Test(expectedExceptions = IllegalStateException.class)
+    public void testUsesWithDuplicate() {
+        new Builder("foo").uses("p.S").uses("p.S");
+    }
+
+    @Test(dataProvider = "invalidjavaidentifiers",
+          expectedExceptions = IllegalArgumentException.class )
+    public void testUsesWithBadName(String service, String ignore) {
+        new Builder("foo").uses(service);
+    }
+
+
+    // provides
+
+    private Provides provides(String st, String pc) {
+        return new Builder("foo")
+            .provides("p.S", pc)
+            .build()
+            .provides()
+            .values()
+            .iterator()
+            .next();
+    }
+
+    public void testProvidesWithProvides() {
+        Provides p1 = provides("p.S", "q.S1");
+        ModuleDescriptor descriptor = new Builder("m").provides(p1).build();
+        Provides p2 = descriptor.provides().get("p.S");
+        assertEquals(p1, p2);
+    }
+
+    public void testProvides() {
+        Set<String> pns = new HashSet<>();
+        pns.add("q.P1");
+        pns.add("q.P2");
+
+        Map<String, Provides> map
+            = new Builder("foo")
+                .provides("p.S", pns)
+                .build()
+                .provides();
+        assertTrue(map.size() == 1);
+
+        Provides p = map.values().iterator().next();
+        assertEquals(p, p);
+        assertTrue(p.providers().size() == 2);
+        assertTrue(p.providers().contains("q.P1"));
+        assertTrue(p.providers().contains("q.P2"));
+    }
+
+    @Test(expectedExceptions = IllegalStateException.class )
+    public void testProvidesWithDuplicateProvides() {
+        Provides p = provides("p.S", "q.S2");
+        new Builder("m").provides("p.S", "q.S1").provides(p);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class )
+    public void testProvidesWithEmptySet() {
+        new Builder("foo").provides("p.Service", Collections.emptySet());
+    }
+
+    @Test(dataProvider = "invalidjavaidentifiers",
+          expectedExceptions = IllegalArgumentException.class )
+    public void testProvidesWithBadService(String service, String ignore) {
+        new Builder("foo").provides(service, "p.Provider");
+    }
+
+    @Test(dataProvider = "invalidjavaidentifiers",
+          expectedExceptions = IllegalArgumentException.class )
+    public void testProvidesWithBadProvider(String provider, String ignore) {
+        new Builder("foo").provides("p.Service", provider);
+    }
+
+    @Test(expectedExceptions = NullPointerException.class )
+    public void testProvidesWithNullProvides() {
+        new Builder("foo").provides((Provides)null);
+    }
+
+    @Test(expectedExceptions = NullPointerException.class )
+    public void testProvidesWithNullProviders() {
+        new Builder("foo").provides("p.S", (Set<String>) null);
+    }
+
+
+    // conceals
+
+    public void testConceals() {
+        Set<String> conceals
+            = new Builder("foo").conceals("p").conceals("q").build().conceals();
+        assertTrue(conceals.size() == 2);
+        assertTrue(conceals.contains("p"));
+        assertTrue(conceals.contains("q"));
+    }
+
+    public void testConcealsWithEmptySet() {
+        Set<String> conceals
+            = new Builder("foo").conceals(Collections.emptySet()).build().conceals();
+        assertTrue(conceals.size() == 0);
+    }
+
+    @Test(expectedExceptions = IllegalStateException.class)
+    public void testConcealsWithDuplicate() {
+        new Builder("foo").conceals("p").conceals("p");
+    }
+
+    @Test(expectedExceptions = IllegalStateException.class)
+    public void testConcealsWithExportedPackage() {
+        new Builder("foo").exports("p").conceals("p");
+    }
+
+    @Test(dataProvider = "invalidjavaidentifiers",
+          expectedExceptions = IllegalArgumentException.class )
+    public void testConcealsWithBadName(String pn, String ignore) {
+        new Builder("foo").conceals(pn);
+    }
+
+
+    // packages
+
+    public void testPackages() {
+        Set<String> packages
+            = new Builder("foo").exports("p").conceals("q").build().packages();
+        assertTrue(packages.size() == 2);
+        assertTrue(packages.contains("p"));
+        assertTrue(packages.contains("q"));
+    }
+
+
+    // name
+
+    public void testModuleName() {
+        String mn = new Builder("foo").build().name();
+        assertEquals(mn, "foo");
+    }
+
+    @Test(dataProvider = "invalidjavaidentifiers",
+          expectedExceptions = IllegalArgumentException.class )
+    public void testBadModuleName(String mn, String ignore) {
+        new Builder(mn);
+    }
+
+
+    // version
+
+    public void testVersion1() {
+        Version v1 = Version.parse("1.0");
+        Version v2 = new Builder("foo").version(v1).build().version().get();
+        assertEquals(v1, v2);
+    }
+
+    public void testVersion2() {
+        String vs = "1.0";
+        Version v1 = new Builder("foo").version(vs).build().version().get();
+        Version v2 = Version.parse(vs);
+        assertEquals(v1, v2);
+    }
+
+    @Test(expectedExceptions = NullPointerException.class )
+    public void testNullVersion1() {
+        new Builder("foo").version((Version)null);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class )
+    public void testNullVersion2() {
+        new Builder("foo").version((String)null);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class )
+    public void testEmptyVersion() {
+        new Builder("foo").version("");
+    }
+
+    @Test(expectedExceptions = IllegalStateException.class)
+    public void testDuplicateVersion1() {
+        Version v = Version.parse("2.0");
+        new Builder("foo").version("1.0").version(v);
+    }
+
+    @Test(expectedExceptions = IllegalStateException.class)
+    public void testDuplicateVersion2() {
+        new Builder("foo").version("1.0").version("2.0");
+    }
+
+
+    // toNameAndVersion
+
+    public void testToNameAndVersion() {
+        ModuleDescriptor md1 = new Builder("foo").build();
+        assertEquals(md1.toNameAndVersion(), "foo");
+
+        ModuleDescriptor md2 = new Builder("foo").version("1.0").build();
+        assertEquals(md2.toNameAndVersion(), "foo@1.0");
+    }
+
+
+    // isAutomatic
+    public void testIsAutomatic() {
+        ModuleDescriptor descriptor = new Builder("foo").build();
+        assertFalse(descriptor.isAutomatic());
+    }
+
+    // isSynthetic
+    public void testIsSynthetic() {
+        assertFalse(Object.class.getModule().getDescriptor().isSynthetic());
+
+        ModuleDescriptor descriptor = new Builder("foo").build();
+        assertFalse(descriptor.isSynthetic());
+    }
+
+
+    // mainClass
+
+    public void testMainClass() {
+        String mainClass
+            = new Builder("foo").mainClass("p.Main").build().mainClass().get();
+        assertEquals(mainClass, "p.Main");
+    }
+
+    @Test(dataProvider = "invalidjavaidentifiers",
+          expectedExceptions = IllegalArgumentException.class )
+    public void testMainClassWithBadName(String mainClass, String ignore) {
+        Builder builder = new Builder("foo");
+        builder.mainClass(mainClass);
+    }
+
+    @Test(expectedExceptions = IllegalStateException.class)
+    public void testDuplicateMainClass() {
+        new Builder("foo").mainClass("p.Main").mainClass("p.Main");
+    }
+
+
+    // osName
+
+    public void testOsName() {
+        String osName = new Builder("foo").osName("Linux").build().osName().get();
+        assertEquals(osName, "Linux");
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testNullOsName() {
+        new Builder("foo").osName(null);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testEmptyOsName() {
+        new Builder("foo").osName("");
+    }
+
+    @Test(expectedExceptions = IllegalStateException.class)
+    public void testDuplicateOsName() {
+        new Builder("foo").osName("Linux").osName("Linux");
+    }
+
+
+    // osArch
+
+    public void testOsArch() {
+        String osArch = new Builder("foo").osName("arm").build().osName().get();
+        assertEquals(osArch, "arm");
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testNullOsArch() {
+        new Builder("foo").osArch(null);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testEmptyOsArch() {
+        new Builder("foo").osArch("");
+    }
+
+    @Test(expectedExceptions = IllegalStateException.class)
+    public void testDuplicateOsArch() {
+        new Builder("foo").osArch("arm").osArch("arm");
+    }
+
+
+    // osVersion
+
+    public void testOsVersion() {
+        String osVersion = new Builder("foo").osName("11.2").build().osName().get();
+        assertEquals(osVersion, "11.2");
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testNullOsVersion() {
+        new Builder("foo").osVersion(null);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testEmptyOsVersion() {
+        new Builder("foo").osVersion("");
+    }
+
+    @Test(expectedExceptions = IllegalStateException.class)
+    public void testDuplicateOsVersion() {
+        new Builder("foo").osVersion("11.2").osVersion("11.2");
+    }
+
+
+    // reads
+
+    private static InputStream EMPTY_INPUT_STREAM = new InputStream() {
+        @Override
+        public int read() {
+            return -1;
+        }
+    };
+
+    private static InputStream FAILING_INPUT_STREAM = new InputStream() {
+        @Override
+        public int read() throws IOException {
+            throw new IOException();
+        }
+    };
+
+    public void testRead() throws Exception {
+        Module base = Object.class.getModule();
+
+        try (InputStream in = base.getResourceAsStream("module-info.class")) {
+            ModuleDescriptor descriptor = ModuleDescriptor.read(in);
+            assertTrue(in.read() == -1); // all bytes read
+            assertEquals(descriptor.name(), "java.base");
+        }
+
+        try (InputStream in = base.getResourceAsStream("module-info.class")) {
+            ByteBuffer bb = ByteBuffer.wrap(in.readAllBytes());
+            ModuleDescriptor descriptor = ModuleDescriptor.read(bb);
+            assertFalse(bb.hasRemaining()); // no more remaining bytes
+            assertEquals(descriptor.name(), "java.base");
+        }
+    }
+
+    public void testReadsWithPackageFinder() {
+        // TBD: Need way to write a module-info.class without a
+        // ConcealedPackages attribute
+    }
+
+    @Test(expectedExceptions = InvalidModuleDescriptorException.class)
+    public void testReadFromEmptyInputStream() throws Exception {
+        ModuleDescriptor.read(EMPTY_INPUT_STREAM);
+    }
+
+    @Test(expectedExceptions = IOException.class)
+    public void testReadFromFailingInputStream() throws Exception {
+        ModuleDescriptor.read(FAILING_INPUT_STREAM);
+    }
+
+    @Test(expectedExceptions = InvalidModuleDescriptorException.class)
+    public void testReadFromEmptyBuffer() {
+        ByteBuffer bb = ByteBuffer.allocate(0);
+        ModuleDescriptor.read(bb);
+    }
+
+    public void testReadWithNull() throws Exception {
+        Module base = Object.class.getModule();
+
+        try {
+            ModuleDescriptor.read((InputStream)null);
+            assertTrue(false);
+        } catch (NullPointerException expected) { }
+
+
+        try (InputStream in = base.getResourceAsStream("module-info.class")) {
+            try {
+                ModuleDescriptor.read(in, null);
+                assertTrue(false);
+            } catch (NullPointerException expected) { }
+        }
+
+        try {
+            ModuleDescriptor.read((ByteBuffer)null);
+            assertTrue(false);
+        } catch (NullPointerException expected) { }
+
+
+        try (InputStream in = base.getResourceAsStream("module-info.class")) {
+            ByteBuffer bb = ByteBuffer.wrap(in.readAllBytes());
+            try {
+                ModuleDescriptor.read(bb, null);
+                assertTrue(false);
+            } catch (NullPointerException expected) { }
+        }
+    }
+
+
+    // equals/hashCode/compareTo/toString
+
+    public void testEqualsAndHashCode() {
+        ModuleDescriptor md1 = new Builder("foo").build();
+        ModuleDescriptor md2 = new Builder("foo").build();
+        assertEquals(md1, md1);
+        assertEquals(md1.hashCode(), md2.hashCode());
+    }
+
+    public void testCompare() {
+        ModuleDescriptor md1 = new Builder("foo").build();
+        ModuleDescriptor md2 = new Builder("bar").build();
+        int n = "foo".compareTo("bar");
+        assertTrue(md1.compareTo(md2) == n);
+        assertTrue(md2.compareTo(md1) == -n);
+    }
+
+    public void testToString() {
+        String s = new Builder("m1").requires("m2").exports("p1").build().toString();
+        assertTrue(s.contains("m1"));
+        assertTrue(s.contains("m2"));
+        assertTrue(s.contains("p1"));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/module/ModuleFinderTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,568 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @modules java.base/jdk.internal.module
+ * @build ModuleFinderTest
+ * @run testng ModuleFinderTest
+ * @summary Basic tests for java.lang.module.ModuleFinder
+ */
+
+import java.io.OutputStream;
+import java.lang.module.FindException;
+import java.lang.module.InvalidModuleDescriptorException;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReference;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
+import java.util.stream.Collectors;
+
+import jdk.internal.module.ModuleInfoWriter;
+
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+@Test
+public class ModuleFinderTest {
+
+    private static final Path USER_DIR
+        = Paths.get(System.getProperty("user.dir"));
+
+
+    /**
+     * Test ModuleFinder.ofSystem
+     */
+    public void testOfSystem() {
+        ModuleFinder finder = ModuleFinder.ofSystem();
+
+        assertTrue(finder.find("java.se").isPresent());
+        assertTrue(finder.find("java.base").isPresent());
+        assertFalse(finder.find("java.rhubarb").isPresent());
+
+        Set<String> names = finder.findAll().stream()
+            .map(ModuleReference::descriptor)
+            .map(ModuleDescriptor::name)
+            .collect(Collectors.toSet());
+        assertTrue(names.contains("java.se"));
+        assertTrue(names.contains("java.base"));
+        assertFalse(names.contains("java.rhubarb"));
+    }
+
+
+    /**
+     * Test ModuleFinder.of with zero entries
+     */
+    public void testOfZeroEntries() {
+        ModuleFinder finder = ModuleFinder.of();
+        assertTrue(finder.findAll().isEmpty());
+        assertFalse(finder.find("java.rhubarb").isPresent());
+    }
+
+
+    /**
+     * Test ModuleFinder.of with one directory of modules
+     */
+    public void testOfOneDirectory() throws Exception {
+        Path dir = Files.createTempDirectory(USER_DIR, "mods");
+        createExplodedModule(dir.resolve("m1"), "m1");
+        createModularJar(dir.resolve("m2.jar"), "m2");
+
+        ModuleFinder finder = ModuleFinder.of(dir);
+        assertTrue(finder.findAll().size() == 2);
+        assertTrue(finder.find("m1").isPresent());
+        assertTrue(finder.find("m2").isPresent());
+        assertFalse(finder.find("java.rhubarb").isPresent());
+    }
+
+
+    /**
+     * Test ModuleFinder.of with two directories
+     */
+    public void testOfTwoDirectories() throws Exception {
+        Path dir1 = Files.createTempDirectory(USER_DIR, "mods1");
+        createExplodedModule(dir1.resolve("m1"), "m1@1.0");
+        createModularJar(dir1.resolve("m2.jar"), "m2@1.0");
+
+        Path dir2 = Files.createTempDirectory(USER_DIR, "mods2");
+        createExplodedModule(dir2.resolve("m1"), "m1@2.0");
+        createModularJar(dir2.resolve("m2.jar"), "m2@2.0");
+        createExplodedModule(dir2.resolve("m3"), "m3");
+        createModularJar(dir2.resolve("m4.jar"), "m4");
+
+        ModuleFinder finder = ModuleFinder.of(dir1, dir2);
+        assertTrue(finder.findAll().size() == 4);
+        assertTrue(finder.find("m1").isPresent());
+        assertTrue(finder.find("m2").isPresent());
+        assertTrue(finder.find("m3").isPresent());
+        assertTrue(finder.find("m4").isPresent());
+        assertFalse(finder.find("java.rhubarb").isPresent());
+
+        // check that m1@1.0 (and not m1@2.0) is found
+        ModuleDescriptor m1 = finder.find("m1").get().descriptor();
+        assertEquals(m1.version().get().toString(), "1.0");
+
+        // check that m2@1.0 (and not m2@2.0) is found
+        ModuleDescriptor m2 = finder.find("m2").get().descriptor();
+        assertEquals(m2.version().get().toString(), "1.0");
+    }
+
+
+    /**
+     * Test ModuleFinder.of with one JAR file
+     */
+    public void testOfOneJarFile() throws Exception {
+        Path dir = Files.createTempDirectory(USER_DIR, "mods");
+        Path jar1 = createModularJar(dir.resolve("m1.jar"), "m1");
+
+        ModuleFinder finder = ModuleFinder.of(jar1);
+        assertTrue(finder.findAll().size() == 1);
+        assertTrue(finder.find("m1").isPresent());
+        assertFalse(finder.find("java.rhubarb").isPresent());
+    }
+
+
+    /**
+     * Test ModuleFinder.of with two JAR files
+     */
+    public void testOfTwoJarFiles() throws Exception {
+        Path dir = Files.createTempDirectory(USER_DIR, "mods");
+
+        Path jar1 = createModularJar(dir.resolve("m1.jar"), "m1");
+        Path jar2 = createModularJar(dir.resolve("m2.jar"), "m2");
+
+        ModuleFinder finder = ModuleFinder.of(jar1, jar2);
+        assertTrue(finder.findAll().size() == 2);
+        assertTrue(finder.find("m1").isPresent());
+        assertTrue(finder.find("m2").isPresent());
+        assertFalse(finder.find("java.rhubarb").isPresent());
+    }
+
+
+    /**
+     * Test ModuleFinder.of with many JAR files
+     */
+    public void testOfManyJarFiles() throws Exception {
+        Path dir = Files.createTempDirectory(USER_DIR, "mods");
+
+        Path jar1 = createModularJar(dir.resolve("m1@1.0.jar"), "m1@1.0");
+        Path jar2 = createModularJar(dir.resolve("m2@1.0.jar"), "m2");
+        Path jar3 = createModularJar(dir.resolve("m1@2.0.jar"), "m1@2.0"); // shadowed
+        Path jar4 = createModularJar(dir.resolve("m3@1.0.jar"), "m3");
+
+        ModuleFinder finder = ModuleFinder.of(jar1, jar2, jar3, jar4);
+        assertTrue(finder.findAll().size() == 3);
+        assertTrue(finder.find("m1").isPresent());
+        assertTrue(finder.find("m2").isPresent());
+        assertTrue(finder.find("m3").isPresent());
+        assertFalse(finder.find("java.rhubarb").isPresent());
+
+        // check that m1@1.0 (and not m1@2.0) is found
+        ModuleDescriptor m1 = finder.find("m1").get().descriptor();
+        assertEquals(m1.version().get().toString(), "1.0");
+    }
+
+
+    /**
+     * Test ModuleFinder.of with one exploded module.
+     */
+    public void testOfOneExplodedModule() throws Exception {
+        Path dir = Files.createTempDirectory(USER_DIR, "mods");
+        Path m1_dir = createExplodedModule(dir.resolve("m1"), "m1");
+
+        ModuleFinder finder = ModuleFinder.of(m1_dir);
+        assertTrue(finder.findAll().size() == 1);
+        assertTrue(finder.find("m1").isPresent());
+        assertFalse(finder.find("java.rhubarb").isPresent());
+    }
+
+
+    /**
+     * Test ModuleFinder.of with two exploded modules.
+     */
+    public void testOfTwoExplodedModules() throws Exception {
+        Path dir = Files.createTempDirectory(USER_DIR, "mods");
+        Path m1_dir = createExplodedModule(dir.resolve("m1"), "m1");
+        Path m2_dir = createExplodedModule(dir.resolve("m2"), "m2");
+
+        ModuleFinder finder = ModuleFinder.of(m1_dir, m2_dir);
+        assertTrue(finder.findAll().size() == 2);
+        assertTrue(finder.find("m1").isPresent());
+        assertTrue(finder.find("m2").isPresent());
+        assertFalse(finder.find("java.rhubarb").isPresent());
+    }
+
+
+    /**
+     * Test ModuleFinder.of with a mix of module directories and JAR files.
+     */
+    public void testOfMixDirectoriesAndJars() throws Exception {
+
+        // directory with m1@1.0 and m2@1.0
+        Path dir1 = Files.createTempDirectory(USER_DIR, "mods1");
+        createExplodedModule(dir1.resolve("m1"), "m1@1.0");
+        createModularJar(dir1.resolve("m2.jar"), "m2@1.0");
+
+        // JAR files: m1@2.0, m2@2.0, m3@2.0, m4@2.0
+        Path dir2 = Files.createTempDirectory(USER_DIR, "mods2");
+        Path jar1 = createModularJar(dir2.resolve("m1.jar"), "m1@2.0");
+        Path jar2 = createModularJar(dir2.resolve("m2.jar"), "m2@2.0");
+        Path jar3 = createModularJar(dir2.resolve("m3.jar"), "m3@2.0");
+        Path jar4 = createModularJar(dir2.resolve("m4.jar"), "m4@2.0");
+
+        // directory with m3@3.0 and m4@3.0
+        Path dir3 = Files.createTempDirectory(USER_DIR, "mods3");
+        createExplodedModule(dir3.resolve("m3"), "m3@3.0");
+        createModularJar(dir3.resolve("m4.jar"), "m4@3.0");
+
+        // JAR files: m5 and m6
+        Path dir4 = Files.createTempDirectory(USER_DIR, "mods4");
+        Path jar5 = createModularJar(dir4.resolve("m5.jar"), "m5@4.0");
+        Path jar6 = createModularJar(dir4.resolve("m6.jar"), "m6@4.0");
+
+
+        ModuleFinder finder
+            = ModuleFinder.of(dir1, jar1, jar2, jar3, jar4, dir3, jar5, jar6);
+        assertTrue(finder.findAll().size() == 6);
+        assertTrue(finder.find("m1").isPresent());
+        assertTrue(finder.find("m2").isPresent());
+        assertTrue(finder.find("m3").isPresent());
+        assertTrue(finder.find("m4").isPresent());
+        assertTrue(finder.find("m5").isPresent());
+        assertTrue(finder.find("m6").isPresent());
+        assertFalse(finder.find("java.rhubarb").isPresent());
+
+        // m1 and m2 should be located in dir1
+        ModuleDescriptor m1 = finder.find("m1").get().descriptor();
+        assertEquals(m1.version().get().toString(), "1.0");
+        ModuleDescriptor m2 = finder.find("m2").get().descriptor();
+        assertEquals(m2.version().get().toString(), "1.0");
+
+        // m3 and m4 should be located in JAR files
+        ModuleDescriptor m3 = finder.find("m3").get().descriptor();
+        assertEquals(m3.version().get().toString(), "2.0");
+        ModuleDescriptor m4 = finder.find("m4").get().descriptor();
+        assertEquals(m4.version().get().toString(), "2.0");
+
+        // m5 and m6 should be located in JAR files
+        ModuleDescriptor m5 = finder.find("m5").get().descriptor();
+        assertEquals(m5.version().get().toString(), "4.0");
+        ModuleDescriptor m6 = finder.find("m6").get().descriptor();
+        assertEquals(m6.version().get().toString(), "4.0");
+    }
+
+
+    /**
+     * Test ModuleFinder.of with a mix of module directories and exploded
+     * modules.
+     */
+    public void testOfMixDirectoriesAndExplodedModules() throws Exception {
+        // directory with m1@1.0 and m2@1.0
+        Path dir1 = Files.createTempDirectory(USER_DIR, "mods1");
+        createExplodedModule(dir1.resolve("m1"), "m1@1.0");
+        createModularJar(dir1.resolve("m2.jar"), "m2@1.0");
+
+        // exploded modules: m1@2.0, m2@2.0, m3@2.0, m4@2.0
+        Path dir2 = Files.createTempDirectory(USER_DIR, "mods2");
+        Path m1_dir = createExplodedModule(dir2.resolve("m1"), "m1@2.0");
+        Path m2_dir = createExplodedModule(dir2.resolve("m2"), "m2@2.0");
+        Path m3_dir = createExplodedModule(dir2.resolve("m3"), "m3@2.0");
+        Path m4_dir = createExplodedModule(dir2.resolve("m4"), "m4@2.0");
+
+        ModuleFinder finder = ModuleFinder.of(dir1, m1_dir, m2_dir, m3_dir, m4_dir);
+        assertTrue(finder.findAll().size() == 4);
+        assertTrue(finder.find("m1").isPresent());
+        assertTrue(finder.find("m2").isPresent());
+        assertTrue(finder.find("m3").isPresent());
+        assertTrue(finder.find("m4").isPresent());
+        assertFalse(finder.find("java.rhubarb").isPresent());
+
+        // m1 and m2 should be located in dir1
+        ModuleDescriptor m1 = finder.find("m1").get().descriptor();
+        assertEquals(m1.version().get().toString(), "1.0");
+        ModuleDescriptor m2 = finder.find("m2").get().descriptor();
+        assertEquals(m2.version().get().toString(), "1.0");
+
+        // m3 and m4 should be located in dir2
+        ModuleDescriptor m3 = finder.find("m3").get().descriptor();
+        assertEquals(m3.version().get().toString(), "2.0");
+        ModuleDescriptor m4 = finder.find("m4").get().descriptor();
+        assertEquals(m4.version().get().toString(), "2.0");
+    }
+
+
+    /**
+     * Test ModuleFinder.of with a path to a file that does not exist.
+     */
+    public void testOfWithDoesNotExistEntry() throws Exception {
+        Path dir1 = Files.createTempDirectory(USER_DIR, "mods1");
+
+        Path dir2 = Files.createTempDirectory(USER_DIR, "mods2");
+        createModularJar(dir2.resolve("m2.jar"), "m2@1.0");
+
+        Files.delete(dir1);
+
+        ModuleFinder finder = ModuleFinder.of(dir1, dir2);
+
+        assertTrue(finder.find("m2").isPresent());
+        assertTrue(finder.findAll().size() == 1);
+        assertFalse(finder.find("java.rhubarb").isPresent());
+    }
+
+
+    /**
+     * Test ModuleFinder.of with a file path to an unrecognized file type.
+     */
+    public void testOfWithUnrecognizedEntry() throws Exception {
+        Path dir = Files.createTempDirectory(USER_DIR, "mods");
+        Path mod = Files.createTempFile(dir, "m", "mod");
+
+        ModuleFinder finder = ModuleFinder.of(mod);
+        try {
+            finder.find("java.rhubarb");
+            assertTrue(false);
+        } catch (FindException e) {
+            // expected
+        }
+
+        finder = ModuleFinder.of(mod);
+        try {
+            finder.findAll();
+            assertTrue(false);
+        } catch (FindException e) {
+            // expected
+        }
+    }
+
+
+    /**
+     * Test ModuleFinder.of with a directory that contains two
+     * versions of the same module
+     */
+    public void testOfDuplicateModulesInDirectory() throws Exception {
+        Path dir = Files.createTempDirectory(USER_DIR, "mods");
+        createModularJar(dir.resolve("m1@1.0.jar"), "m1");
+        createModularJar(dir.resolve("m1@2.0.jar"), "m1");
+
+        ModuleFinder finder = ModuleFinder.of(dir);
+        try {
+            finder.find("m1");
+            assertTrue(false);
+        } catch (FindException expected) { }
+
+        finder = ModuleFinder.of(dir);
+        try {
+            finder.findAll();
+            assertTrue(false);
+        } catch (FindException expected) { }
+    }
+
+
+    /**
+     * Test ModuleFinder.of with a truncated module-info.class
+     */
+    public void testOfWithTruncatedModuleInfo() throws Exception {
+        Path dir = Files.createTempDirectory(USER_DIR, "mods");
+
+        // create an empty <dir>/rhubarb/module-info.class
+        Path subdir = Files.createDirectory(dir.resolve("rhubarb"));
+        Files.createFile(subdir.resolve("module-info.class"));
+
+        ModuleFinder finder = ModuleFinder.of(dir);
+        try {
+            finder.find("rhubarb");
+            assertTrue(false);
+        } catch (FindException e) {
+            assertTrue(e.getCause() instanceof InvalidModuleDescriptorException);
+        }
+
+        finder = ModuleFinder.of(dir);
+        try {
+            finder.findAll();
+            assertTrue(false);
+        } catch (FindException e) {
+            assertTrue(e.getCause() instanceof InvalidModuleDescriptorException);
+        }
+    }
+
+
+    /**
+     * Test ModuleFinder.compose
+     */
+    public void testCompose() throws Exception {
+        Path dir1 = Files.createTempDirectory(USER_DIR, "mods1");
+        createExplodedModule(dir1.resolve("m1"), "m1@1.0");
+        createExplodedModule(dir1.resolve("m2"), "m2@1.0");
+
+        Path dir2 = Files.createTempDirectory(USER_DIR, "mods2");
+        createExplodedModule(dir2.resolve("m1"), "m1@2.0");
+        createExplodedModule(dir2.resolve("m2"), "m2@2.0");
+        createExplodedModule(dir2.resolve("m3"), "m3");
+        createExplodedModule(dir2.resolve("m4"), "m4");
+
+        ModuleFinder finder1 = ModuleFinder.of(dir1);
+        ModuleFinder finder2 = ModuleFinder.of(dir2);
+
+        ModuleFinder finder = ModuleFinder.compose(finder1, finder2);
+        assertTrue(finder.findAll().size() == 4);
+        assertTrue(finder.find("m1").isPresent());
+        assertTrue(finder.find("m2").isPresent());
+        assertTrue(finder.find("m3").isPresent());
+        assertTrue(finder.find("m4").isPresent());
+        assertFalse(finder.find("java.rhubarb").isPresent());
+
+        // check that m1@1.0 (and not m1@2.0) is found
+        ModuleDescriptor m1 = finder.find("m1").get().descriptor();
+        assertEquals(m1.version().get().toString(), "1.0");
+
+        // check that m2@1.0 (and not m2@2.0) is found
+        ModuleDescriptor m2 = finder.find("m2").get().descriptor();
+        assertEquals(m2.version().get().toString(), "1.0");
+    }
+
+
+    /**
+     * Test ModuleFinder.empty
+     */
+    public void testEmpty() {
+        ModuleFinder finder = ModuleFinder.empty();
+        assertTrue(finder.findAll().isEmpty());
+        assertFalse(finder.find("java.rhubarb").isPresent());
+    }
+
+
+    /**
+     * Test null handling
+     */
+    public void testNulls() {
+
+        try {
+            ModuleFinder.ofSystem().find(null);
+            assertTrue(false);
+        } catch (NullPointerException expected) { }
+
+        try {
+            ModuleFinder.of().find(null);
+            assertTrue(false);
+        } catch (NullPointerException expected) { }
+
+        try {
+            ModuleFinder.empty().find(null);
+            assertTrue(false);
+        } catch (NullPointerException expected) { }
+
+        try {
+            ModuleFinder.of((Path[])null);
+            assertTrue(false);
+        } catch (NullPointerException expected) { }
+
+        try {
+            ModuleFinder.of((Path)null);
+            assertTrue(false);
+        } catch (NullPointerException expected) { }
+
+        // compose
+        ModuleFinder finder = ModuleFinder.of();
+        try {
+            ModuleFinder.compose(finder, null);
+            assertTrue(false);
+        } catch (NullPointerException expected) { }
+        try {
+            ModuleFinder.compose(null, finder);
+            assertTrue(false);
+        } catch (NullPointerException expected) { }
+
+    }
+
+
+    /**
+     * Parses a string of the form {@code name[@version]} and returns a
+     * ModuleDescriptor with that name and version. The ModuleDescriptor
+     * will have a requires on java.base.
+     */
+    static ModuleDescriptor newModuleDescriptor(String mid) {
+        String mn;
+        String vs;
+        int i = mid.indexOf("@");
+        if (i == -1) {
+            mn = mid;
+            vs = null;
+        } else {
+            mn = mid.substring(0, i);
+            vs = mid.substring(i+1);
+        }
+        ModuleDescriptor.Builder builder
+                = new ModuleDescriptor.Builder(mn).requires("java.base");
+        if (vs != null)
+            builder.version(vs);
+        return builder.build();
+    }
+
+    /**
+     * Creates an exploded module in the given directory and containing a
+     * module descriptor with the given module name/version.
+     */
+    static Path createExplodedModule(Path dir, String mid) throws Exception {
+        ModuleDescriptor descriptor = newModuleDescriptor(mid);
+        Files.createDirectories(dir);
+        Path mi = dir.resolve("module-info.class");
+        try (OutputStream out = Files.newOutputStream(mi)) {
+            ModuleInfoWriter.write(descriptor, out);
+        }
+        return dir;
+    }
+
+    /**
+     * Creates a JAR file with the given file path and containing a module
+     * descriptor with the given module name/version.
+     */
+    static Path createModularJar(Path file, String mid, String ... entries)
+        throws Exception
+    {
+        ModuleDescriptor descriptor = newModuleDescriptor(mid);
+        try (OutputStream out = Files.newOutputStream(file)) {
+            try (JarOutputStream jos = new JarOutputStream(out)) {
+
+                JarEntry je = new JarEntry("module-info.class");
+                jos.putNextEntry(je);
+                ModuleInfoWriter.write(descriptor, jos);
+                jos.closeEntry();
+
+                for (String entry : entries) {
+                    je = new JarEntry(entry);
+                    jos.putNextEntry(je);
+                    jos.closeEntry();
+                }
+            }
+
+        }
+        return file;
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/module/ModuleReader/ModuleReaderTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @library /lib/testlibrary
+ * @modules java.base/jdk.internal.module
+ *          jdk.jlink/jdk.tools.jmod
+ *          jdk.compiler
+ * @build ModuleReaderTest CompilerUtils JarUtils
+ * @run testng ModuleReaderTest
+ * @summary Basic tests for java.lang.module.ModuleReader
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReader;
+import java.lang.module.ModuleReference;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLConnection;
+import java.nio.ByteBuffer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.Optional;
+
+import jdk.internal.module.ConfigurableModuleFinder;
+import jdk.internal.module.ConfigurableModuleFinder.Phase;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+@Test
+public class ModuleReaderTest {
+
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    private static final Path USER_DIR   = Paths.get(System.getProperty("user.dir"));
+    private static final Path SRC_DIR    = Paths.get(TEST_SRC, "src");
+    private static final Path MODS_DIR   = Paths.get("mods");
+
+    // the module name of the test module
+    private static final String TEST_MODULE = "m";
+
+    // resources in test module (can't use module-info.class as a test
+    // resource as it will be modified by the jmod tool)
+    private static final String[] RESOURCES = {
+        "p/Main.class"
+    };
+
+    // a resource that is not in the test module
+    private static final String NOT_A_RESOURCE = "NotAResource";
+
+
+    @BeforeTest
+    public void compileTestModule() throws Exception {
+
+        // javac -d mods/$TESTMODULE src/$TESTMODULE/**
+        boolean compiled
+            = CompilerUtils.compile(SRC_DIR.resolve(TEST_MODULE),
+                                    MODS_DIR.resolve(TEST_MODULE));
+        assertTrue(compiled, "test module did not compile");
+    }
+
+
+    /**
+     * Test exploded module
+     */
+    public void testExplodedModule() throws Exception {
+        test(MODS_DIR);
+    }
+
+
+    /**
+     * Test modular JAR
+     */
+    public void testModularJar() throws Exception {
+        Path dir = Files.createTempDirectory(USER_DIR, "mlib");
+
+        // jar cf mlib/${TESTMODULE}.jar -C mods .
+        JarUtils.createJarFile(dir.resolve("m.jar"),
+                               MODS_DIR.resolve(TEST_MODULE));
+
+        test(dir);
+    }
+
+
+    /**
+     * Test JMOD
+     */
+    public void testJMod() throws Exception {
+        Path dir = Files.createTempDirectory(USER_DIR, "mlib");
+
+        // jmod create --class-path mods/${TESTMODULE}  mlib/${TESTMODULE}.jmod
+        String cp = MODS_DIR.resolve(TEST_MODULE).toString();
+        String jmod = dir.resolve("m.jmod").toString();
+        String[] args = { "create", "--class-path", cp, jmod };
+        jdk.tools.jmod.JmodTask task = new jdk.tools.jmod.JmodTask();
+        assertEquals(task.run(args), 0);
+
+        test(dir);
+    }
+
+
+    /**
+     * The test module is found on the given module path. Open a ModuleReader
+     * to the test module and test the reader.
+     */
+    void test(Path mp) throws Exception {
+
+        ModuleFinder finder = ModuleFinder.of(mp);
+        if (finder instanceof ConfigurableModuleFinder) {
+            // need ModuleFinder to be in the phase to find JMOD files
+            ((ConfigurableModuleFinder)finder).configurePhase(Phase.LINK_TIME);
+        }
+
+        ModuleReference mref = finder.find(TEST_MODULE).get();
+        ModuleReader reader = mref.open();
+
+        try (reader) {
+
+            // test each of the known resources in the module
+            for (String name : RESOURCES) {
+                byte[] expectedBytes
+                    = Files.readAllBytes(MODS_DIR
+                        .resolve(TEST_MODULE)
+                        .resolve(name.replace('/', File.separatorChar)));
+
+                testFind(reader, name, expectedBytes);
+                testOpen(reader, name, expectedBytes);
+                testRead(reader, name, expectedBytes);
+            }
+
+            // test "not found"
+            assertFalse(reader.open(NOT_A_RESOURCE).isPresent());
+            assertFalse(reader.read(NOT_A_RESOURCE).isPresent());
+
+            // test nulls
+            try {
+                reader.find(null);
+                assertTrue(false);
+            } catch (NullPointerException expected) { }
+
+            try {
+                reader.open(null);
+                assertTrue(false);
+            } catch (NullPointerException expected) { }
+
+            try {
+                reader.read(null);
+                assertTrue(false);
+            } catch (NullPointerException expected) { }
+
+            // should release(null) throw NPE?
+
+        }
+
+        // test closed ModuleReader
+        try {
+            reader.open(RESOURCES[0]);
+            assertTrue(false);
+        } catch (IOException expected) { }
+
+
+        try {
+            reader.read(RESOURCES[0]);
+            assertTrue(false);
+        } catch (IOException expected) { }
+    }
+
+    /**
+     * Test ModuleReader#find
+     */
+    void testFind(ModuleReader reader, String name, byte[] expectedBytes)
+        throws Exception
+    {
+        Optional<URI> ouri = reader.find(name);
+        assertTrue(ouri.isPresent());
+
+        URL url = ouri.get().toURL();
+        if (!url.getProtocol().equalsIgnoreCase("jmod")) {
+            URLConnection uc = url.openConnection();
+            uc.setUseCaches(false);
+            try (InputStream in = uc.getInputStream()) {
+                byte[] bytes = in.readAllBytes();
+                assertTrue(Arrays.equals(bytes, expectedBytes));
+            }
+        }
+    }
+
+    /**
+     * Test ModuleReader#open
+     */
+    void testOpen(ModuleReader reader, String name, byte[] expectedBytes)
+        throws Exception
+    {
+        Optional<InputStream> oin = reader.open(name);
+        assertTrue(oin.isPresent());
+
+        InputStream in = oin.get();
+        try (in) {
+            byte[] bytes = in.readAllBytes();
+            assertTrue(Arrays.equals(bytes, expectedBytes));
+        }
+    }
+
+    /**
+     * Test ModuleReader#read
+     */
+    void testRead(ModuleReader reader, String name, byte[] expectedBytes)
+        throws Exception
+    {
+        Optional<ByteBuffer> obb = reader.read(name);
+        assertTrue(obb.isPresent());
+
+        ByteBuffer bb = obb.get();
+        try {
+            int rem = bb.remaining();
+            assertTrue(rem == expectedBytes.length);
+            byte[] bytes = new byte[rem];
+            bb.get(bytes);
+            assertTrue(Arrays.equals(bytes, expectedBytes));
+        } finally {
+            reader.release(bb);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/module/ModuleReader/src/m/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/module/ModuleReader/src/m/p/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p;
+
+/**
+ * Main class for dummy module.
+ */
+
+public class Main {
+    public static void main(String[] args) {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/module/ModuleReferenceTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @run testng ModuleReferenceTest
+ * @summary Basic tests for java.lang.module.ModuleReference
+ */
+
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleReader;
+import java.lang.module.ModuleReference;
+import java.net.URI;
+import java.util.function.Supplier;
+
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+@Test
+public class ModuleReferenceTest {
+
+    private Supplier<ModuleReader> makeSupplier() {
+        return () -> { throw new UnsupportedOperationException(); };
+    }
+
+    public void testBasic() throws Exception {
+        ModuleDescriptor descriptor
+            = new ModuleDescriptor.Builder("m")
+                .exports("p")
+                .exports("q")
+                .conceals("p.internal")
+                .build();
+
+        URI uri = URI.create("module:/m");
+
+        Supplier<ModuleReader> supplier = makeSupplier();
+
+        ModuleReference mref = new ModuleReference(descriptor, uri, supplier);
+
+        assertTrue(mref.descriptor().equals(descriptor));
+        assertTrue(mref.location().get().equals(uri));
+
+        // check that the supplier is called
+        try {
+            mref.open();
+            assertTrue(false);
+        } catch (UnsupportedOperationException expected) { }
+    }
+
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testNullDescriptor() throws Exception {
+        URI location = URI.create("module:/m");
+        new ModuleReference(null, location, makeSupplier());
+    }
+
+    public void testNullLocation() {
+        ModuleDescriptor descriptor
+            = new ModuleDescriptor.Builder("m")
+                .exports("p")
+                .build();
+        Supplier<ModuleReader> supplier = makeSupplier();
+        ModuleReference mref = new ModuleReference(descriptor, null, supplier);
+        assertTrue(!mref.location().isPresent());
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testNullSupplier() throws Exception {
+        ModuleDescriptor descriptor = new ModuleDescriptor.Builder("m").build();
+        URI location = URI.create("module:/m");
+        new ModuleReference(descriptor, location, null);
+    }
+
+
+    public void testEqualsAndHashCode() {
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .exports("p")
+                .build();
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m1")
+                .exports("p")
+                .build();
+
+        URI uri = URI.create("module:/m1");
+        Supplier<ModuleReader> supplier = makeSupplier();
+
+        ModuleReference mref1 = new ModuleReference(descriptor1, uri, supplier);
+        ModuleReference mref2 = new ModuleReference(descriptor2, uri, supplier);
+        ModuleReference mref3 = new ModuleReference(descriptor1, null, supplier);
+
+        assertTrue(mref1.equals(mref1));
+        assertTrue(mref1.equals(mref1));
+        assertTrue(mref2.equals(mref1));
+        assertTrue(mref1.hashCode() == mref2.hashCode());
+
+        assertTrue(mref3.equals(mref3));
+        assertFalse(mref3.equals(mref1));
+        assertFalse(mref1.equals(mref3));
+    }
+
+
+    public void testToString() {
+        ModuleDescriptor descriptor = new ModuleDescriptor.Builder("m1").build();
+        URI uri = URI.create("module:/m1");
+        Supplier<ModuleReader> supplier = makeSupplier();
+        ModuleReference mref = new ModuleReference(descriptor, uri, supplier);
+        String s = mref.toString();
+        assertTrue(s.contains("m1"));
+        assertTrue(s.contains(uri.toString()));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/module/VersionTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @run testng VersionTest
+ * @summary Basic tests for java.lang.module.ModuleDescriptor.Version.
+ */
+
+import java.lang.module.ModuleDescriptor.Version;
+
+import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+import static org.testng.Assert.*;
+
+@Test
+public class VersionTest {
+
+    // valid version strings
+    @DataProvider(name = "validVersions")
+    public Object[][] validVersions() {
+        return new Object[][]{
+
+            { "1.0",            null },
+            { "1.0.0",          null },
+            { "1.0.0.0",        null },
+
+            { "99",             null },
+            { "99.99",          null },
+            { "99.99.99",       null },
+
+            { "1-SNAPSHOT",     null },
+            { "1.0-SNAPSHOT",   null },
+            { "1.0.0-SNAPSHOT", null },
+
+            { "9-ea",           null },
+            { "9-ea+110",       null },
+            { "9.3.2.1+42-8839942", null}
+
+        };
+    }
+
+    // invalid version strings
+    @DataProvider(name = "invalidVersions")
+    public Object[][] invalidVersions() {
+        return new Object[][]{
+
+            { null,            null },
+            { "",              null },
+            { "A1",            null },  // does not start with number
+            { "1.0-",          null },  // empty branch
+
+        };
+    }
+
+    // Test parsing valid version strings
+    @Test(dataProvider = "validVersions")
+    public void testParseValidVersions(String vs, String ignore) {
+        Version v = Version.parse(vs);
+        assertEquals(v.toString(), vs);
+    }
+
+    // Test parsing an invalid version strings
+    @Test(dataProvider = "invalidVersions",
+          expectedExceptions = IllegalArgumentException.class )
+    public void testParseInvalidVersions(String vs, String ignore) {
+        Version.parse(vs);
+    }
+
+    // Test equals and hashCode
+    @Test(dataProvider = "validVersions")
+    public void testEqualsAndHashCode(String vs, String ignore) {
+
+        Version v1 = Version.parse(vs);
+        Version v2 = Version.parse(vs);
+        assertEquals(v1, v2);
+        assertEquals(v2, v1);
+        assertEquals(v1.hashCode(), v2.hashCode());
+
+        Version v3 = Version.parse("1.0-rhubarb");
+        assertNotEquals(v1, v3);
+        assertNotEquals(v2, v3);
+        assertNotEquals(v3, v1);
+        assertNotEquals(v3, v2);
+
+    }
+
+    // ordered version strings
+    @DataProvider(name = "orderedVersions")
+    public Object[][] orderedVersions() {
+        return new Object[][]{
+
+            { "1.0",     "2.0" },
+            { "1.0-SNAPSHOT", "1.0" },
+            { "1.0-SNAPSHOT2", "1.0" },
+            { "1.2.3-ea", "1.2.3" },
+            { "1.2.3-ea+104", "1.2.3-ea+105" },
+            { "1.2.3-ea+104-4084552", "1.2.3-ea+104-4084552+8849330" },
+            { "1+104", "1+105" },
+            { "1.0-alpha1", "1.0-alpha2" }
+
+        };
+    }
+
+    /**
+     * Test compareTo with ordered versions.
+     */
+    @Test(dataProvider = "orderedVersions")
+    public void testCompareOrderedVersions(String vs1, String vs2) {
+
+        Version v1 = Version.parse(vs1);
+        assertTrue(v1.compareTo(v1) == 0);
+
+        Version v2 = Version.parse(vs2);
+        assertTrue(v2.compareTo(v2) == 0);
+
+        // v1 < v2
+        assertTrue(v1.compareTo(v2) < 0);
+        assertTrue(v2.compareTo(v1) > 0);
+
+    }
+
+    // equal version strings
+    @DataProvider(name = "equalVersions")
+    public Object[][] equalVersions() {
+        return new Object[][]{
+
+            { "1",             "1.0.0" },
+            { "1.0",           "1.0.0" },
+            { "1.0-beta",      "1.0.0-beta" },
+
+        };
+    }
+
+    /**
+     * Test compareTo with equal versions.
+     */
+    @Test(dataProvider = "equalVersions")
+    public void testCompareEqualsVersions(String vs1, String vs2) {
+
+        Version v1 = Version.parse(vs1);
+        assertTrue(v1.compareTo(v1) == 0);
+
+        Version v2 = Version.parse(vs2);
+        assertTrue(v2.compareTo(v2) == 0);
+
+        assertTrue(v1.compareTo(v2) == 0);
+        assertTrue(v2.compareTo(v1) == 0);
+        assertEquals(v1, v2);
+        assertEquals(v2, v1);
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @build ModuleSetAccessibleTest
+ * @modules java.base/sun.misc
+ * @run testng ModuleSetAccessibleTest
+ * @summary Test java.lang.reflect.AccessibleObject with modules
+ */
+
+import java.lang.module.ModuleDescriptor;
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InaccessibleObjectException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Module;
+
+import sun.misc.Unsafe;
+
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+@Test
+public class ModuleSetAccessibleTest {
+
+    /**
+     * Invoke a private constructor on a public class in an exported package
+     */
+    public void testPrivateConstructorInExportedPackage() throws Exception {
+        Constructor<?> ctor = Unsafe.class.getDeclaredConstructor();
+
+        try {
+            ctor.newInstance();
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+
+        ctor.setAccessible(true);
+        Unsafe unsafe = (Unsafe) ctor.newInstance();
+    }
+
+
+    /**
+     * Invoke a private method on a public class in an exported package
+     */
+    public void testPrivateMethodInExportedPackage() throws Exception {
+        Method m = Unsafe.class.getDeclaredMethod("throwIllegalAccessError");
+        try {
+            m.invoke(null);
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+
+        m.setAccessible(true);
+        try {
+            m.invoke(null);
+            assertTrue(false);
+        } catch (InvocationTargetException e) {
+            // thrown by throwIllegalAccessError
+            assertTrue(e.getCause() instanceof IllegalAccessError);
+        }
+    }
+
+
+    /**
+     * Access a private field in a public class that is an exported package
+     */
+    public void testPrivateFieldInExportedPackage() throws Exception {
+        Field f = Unsafe.class.getDeclaredField("theUnsafe");
+
+        try {
+            f.get(null);
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+
+        f.setAccessible(true);
+        Unsafe unsafe = (Unsafe) f.get(null);
+    }
+
+
+    /**
+     * Invoke a public constructor on a public class in a non-exported package
+     */
+    public void testPublicConstructorInNonExportedPackage() throws Exception {
+        Class<?> clazz = Class.forName("sun.security.x509.X500Name");
+        Constructor<?> ctor = clazz.getConstructor(String.class);
+
+        try {
+            ctor.newInstance("cn=duke");
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+
+        try {
+            ctor.setAccessible(true);
+            assertTrue(false);
+        } catch (InaccessibleObjectException expected) { }
+
+        ctor.setAccessible(false); // should succeed
+    }
+
+
+    /**
+     * Access a public field in a public class that in a non-exported package
+     */
+    public void testPublicFieldInNonExportedPackage() throws Exception {
+        Class<?> clazz = Class.forName("sun.security.x509.X500Name");
+        Field f = clazz.getField("SERIALNUMBER_OID");
+
+        try {
+            f.get(null);
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+
+        try {
+            f.setAccessible(true);
+            assertTrue(false);
+        } catch (InaccessibleObjectException expected) { }
+
+        f.setAccessible(false); // should succeed
+    }
+
+
+    /**
+     * Test that only public members of java.lang.reflect.Module can be make
+     * accessible.
+     */
+    public void testJavaLangReflectModule() throws Exception {
+
+        // non-public constructor
+        Constructor<?> ctor
+            = Module.class.getDeclaredConstructor(ClassLoader.class,
+                                                  ModuleDescriptor.class);
+        AccessibleObject[] ctors = { ctor };
+
+        try {
+            ctor.setAccessible(true);
+            assertTrue(false);
+        } catch (InaccessibleObjectException expected) { }
+
+        try {
+            AccessibleObject.setAccessible(ctors, true);
+            assertTrue(false);
+        } catch (InaccessibleObjectException expected) { }
+
+        // should succeed
+        ctor.setAccessible(false);
+        AccessibleObject.setAccessible(ctors, false);
+
+
+        // public method
+        Method method = Module.class.getMethod("addReads", Module.class);
+        AccessibleObject[] methods = { method };
+        method.setAccessible(true);
+        AccessibleObject.setAccessible(methods, true);
+        method.setAccessible(false);
+        AccessibleObject.setAccessible(methods, false);
+
+        // non-public method
+        method = Module.class.getDeclaredMethod("implAddReadsNoSync", Module.class);
+        methods[0] = method;
+
+        try {
+            method.setAccessible(true);
+            assertTrue(false);
+        } catch (InaccessibleObjectException expected) { }
+
+        try {
+            AccessibleObject.setAccessible(methods, true);
+            assertTrue(false);
+        } catch (InaccessibleObjectException expected) { }
+
+        // should succeed
+        method.setAccessible(false);
+        AccessibleObject.setAccessible(methods, false);
+
+
+        // non-public field
+        Field field = Module.class.getDeclaredField("name");
+        AccessibleObject[] fields = { field };
+
+        try {
+            field.setAccessible(true);
+            assertTrue(false);
+        } catch (InaccessibleObjectException expected) { }
+
+        try {
+            AccessibleObject.setAccessible(fields, true);
+            assertTrue(false);
+        } catch (InaccessibleObjectException expected) { }
+
+        // should succeed
+        field.setAccessible(false);
+        AccessibleObject.setAccessible(fields, false);
+
+    }
+
+
+    /**
+     * Test that the Class constructor cannot be make accessible.
+     */
+    public void testJavaLangClass() throws Exception {
+
+        // non-public constructor
+        Constructor<?> ctor
+            = Class.class.getDeclaredConstructor(ClassLoader.class, Class.class);
+        AccessibleObject[] ctors = { ctor };
+
+        try {
+            ctor.setAccessible(true);
+            assertTrue(false);
+        } catch (SecurityException expected) { }
+
+        try {
+            AccessibleObject.setAccessible(ctors, true);
+            assertTrue(false);
+        } catch (SecurityException expected) { }
+
+        // should succeed
+        ctor.setAccessible(false);
+        AccessibleObject.setAccessible(ctors, false);
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Layer/BasicLayerTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,867 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @library /lib/testlibrary
+ * @build BasicLayerTest ModuleUtils
+ * @compile layertest/Test.java
+ * @run testng BasicLayerTest
+ * @summary Basic tests for java.lang.reflect.Layer
+ */
+
+import java.lang.module.Configuration;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleFinder;
+import static java.lang.module.ModuleFinder.empty;
+import java.lang.reflect.Layer;
+import java.lang.reflect.LayerInstantiationException;
+import java.lang.reflect.Module;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+@Test
+public class BasicLayerTest {
+
+    /**
+     * Exercise Layer.empty()
+     */
+    public void testEmpty() {
+        Layer emptyLayer = Layer.empty();
+
+        assertFalse(emptyLayer.parent().isPresent());
+
+        assertTrue(emptyLayer.configuration() == Configuration.empty());
+
+        assertTrue(emptyLayer.modules().isEmpty());
+
+        assertFalse(emptyLayer.findModule("java.base").isPresent());
+
+        try {
+            emptyLayer.findLoader("java.base");
+            assertTrue(false);
+        } catch (IllegalArgumentException expected) { }
+    }
+
+
+    /**
+     * Exercise Layer.boot()
+     */
+    public void testBoot() {
+        Layer bootLayer = Layer.boot();
+
+        // configuration
+        Configuration cf = bootLayer.configuration();
+        assertTrue(cf.findModule("java.base").get()
+                .reference()
+                .descriptor()
+                .exports()
+                .stream().anyMatch(e -> (e.source().equals("java.lang")
+                                         && !e.isQualified())));
+
+        // modules
+        Set<Module> modules = bootLayer.modules();
+        assertTrue(modules.contains(Object.class.getModule()));
+        int count = (int) modules.stream().map(Module::getName).count();
+        assertEquals(count, modules.size()); // module names are unique
+
+        // findModule
+        Module base = Object.class.getModule();
+        assertTrue(bootLayer.findModule("java.base").get() == base);
+        assertTrue(base.getLayer() == bootLayer);
+
+        // findLoader
+        assertTrue(bootLayer.findLoader("java.base") == null);
+
+        // parent
+        assertTrue(bootLayer.parent().get() == Layer.empty());
+    }
+
+
+    /**
+     * Exercise Layer.create, created on an empty layer
+     */
+    public void testLayerOnEmpty() {
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .requires("m2")
+                .exports("p1")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2")
+                .requires("m3")
+                .build();
+
+        ModuleDescriptor descriptor3
+            = new ModuleDescriptor.Builder("m3")
+                .build();
+
+        ModuleFinder finder
+            = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3);
+
+        Configuration cf = resolveRequires(finder, "m1");
+
+        // map each module to its own class loader for this test
+        ClassLoader loader1 = new ClassLoader() { };
+        ClassLoader loader2 = new ClassLoader() { };
+        ClassLoader loader3 = new ClassLoader() { };
+        Map<String, ClassLoader> map = new HashMap<>();
+        map.put("m1", loader1);
+        map.put("m2", loader2);
+        map.put("m3", loader3);
+
+        Layer layer = Layer.empty().defineModules(cf, map::get);
+
+        // configuration
+        assertTrue(layer.configuration() == cf);
+        assertTrue(layer.configuration().modules().size() == 3);
+
+        // modules
+        Set<Module> modules = layer.modules();
+        assertTrue(modules.size() == 3);
+        Set<String> names = modules.stream()
+            .map(Module::getName)
+            .collect(Collectors.toSet());
+        assertTrue(names.contains("m1"));
+        assertTrue(names.contains("m2"));
+        assertTrue(names.contains("m3"));
+
+        // findModule
+        Module m1 = layer.findModule("m1").get();
+        Module m2 = layer.findModule("m2").get();
+        Module m3 = layer.findModule("m3").get();
+        assertEquals(m1.getName(), "m1");
+        assertEquals(m2.getName(), "m2");
+        assertEquals(m3.getName(), "m3");
+        assertTrue(m1.getDescriptor() == descriptor1);
+        assertTrue(m2.getDescriptor() == descriptor2);
+        assertTrue(m3.getDescriptor() == descriptor3);
+        assertTrue(m1.getLayer() == layer);
+        assertTrue(m2.getLayer() == layer);
+        assertTrue(m3.getLayer() == layer);
+        assertTrue(modules.contains(m1));
+        assertTrue(modules.contains(m2));
+        assertTrue(modules.contains(m3));
+        assertFalse(layer.findModule("godot").isPresent());
+
+        // findLoader
+        assertTrue(layer.findLoader("m1") == loader1);
+        assertTrue(layer.findLoader("m2") == loader2);
+        assertTrue(layer.findLoader("m3") == loader3);
+        try {
+            ClassLoader loader = layer.findLoader("godot");
+            assertTrue(false);
+        } catch (IllegalArgumentException ignore) { }
+
+        // parent
+        assertTrue(layer.parent().get() == Layer.empty());
+    }
+
+
+    /**
+     * Exercise Layer.create, created over the boot layer
+     */
+    public void testLayerOnBoot() {
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .requires("m2")
+                .requires("java.base")
+                .exports("p1")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2")
+                .requires("java.base")
+                .build();
+
+        ModuleFinder finder
+            = ModuleUtils.finderOf(descriptor1, descriptor2);
+
+        Configuration parent = Layer.boot().configuration();
+        Configuration cf = resolveRequires(parent, finder, "m1");
+
+        ClassLoader loader = new ClassLoader() { };
+
+        Layer layer = Layer.boot().defineModules(cf, mn -> loader);
+
+        // configuration
+        assertTrue(layer.configuration() == cf);
+        assertTrue(layer.configuration().modules().size() == 2);
+
+        // modules
+        Set<Module> modules = layer.modules();
+        assertTrue(modules.size() == 2);
+        Set<String> names = modules.stream()
+            .map(Module::getName)
+            .collect(Collectors.toSet());
+        assertTrue(names.contains("m1"));
+        assertTrue(names.contains("m2"));
+
+        // findModule
+        Module m1 = layer.findModule("m1").get();
+        Module m2 = layer.findModule("m2").get();
+        assertEquals(m1.getName(), "m1");
+        assertEquals(m2.getName(), "m2");
+        assertTrue(m1.getDescriptor() == descriptor1);
+        assertTrue(m2.getDescriptor() == descriptor2);
+        assertTrue(m1.getLayer() == layer);
+        assertTrue(m2.getLayer() == layer);
+        assertTrue(modules.contains(m1));
+        assertTrue(modules.contains(m2));
+        assertTrue(layer.findModule("java.base").get() == Object.class.getModule());
+        assertFalse(layer.findModule("godot").isPresent());
+
+        // findLoader
+        assertTrue(layer.findLoader("m1") == loader);
+        assertTrue(layer.findLoader("m2") == loader);
+        assertTrue(layer.findLoader("java.base") == null);
+
+        // parent
+        assertTrue(layer.parent().get() == Layer.boot());
+    }
+
+
+    /**
+     * Layer.create with a configuration of two modules that have the same
+     * module-private package.
+     */
+    public void testSameConcealedPackage() {
+        ModuleDescriptor descriptor1
+            =  new ModuleDescriptor.Builder("m1")
+                .requires("m2")
+                .conceals("p")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2")
+                .conceals("p")
+                .build();
+
+        ModuleFinder finder
+            = ModuleUtils.finderOf(descriptor1, descriptor2);
+
+        Configuration cf = resolveRequires(finder, "m1");
+        assertTrue(cf.modules().size() == 2);
+
+        // one loader per module, should be okay
+        Layer.empty().defineModules(cf, mn -> new ClassLoader() { });
+
+        // same class loader
+        try {
+            ClassLoader loader = new ClassLoader() { };
+            Layer.empty().defineModules(cf, mn -> loader);
+            assertTrue(false);
+        } catch (LayerInstantiationException expected) { }
+    }
+
+
+    /**
+     * Layer.create with a configuration with a partitioned graph. The same
+     * package is exported in both partitions.
+     */
+    public void testSameExportInPartitionedGraph() {
+
+        // m1 reads m2, m2 exports p to m1
+        ModuleDescriptor descriptor1
+            =  new ModuleDescriptor.Builder("m1")
+                .requires("m2")
+                .build();
+        ModuleDescriptor descriptor2
+            =  new ModuleDescriptor.Builder("m2")
+                .exports("p", "m1")
+                .build();
+
+        // m3 reads m4, m4 exports p to m3
+        ModuleDescriptor descriptor3
+            =  new ModuleDescriptor.Builder("m3")
+                .requires("m4")
+                .build();
+        ModuleDescriptor descriptor4
+            =  new ModuleDescriptor.Builder("m4")
+                .exports("p", "m3")
+                .build();
+
+        ModuleFinder finder
+            = ModuleUtils.finderOf(descriptor1,
+                                   descriptor2,
+                                   descriptor3,
+                                   descriptor4);
+
+        Configuration cf = resolveRequires(finder, "m1", "m3");
+        assertTrue(cf.modules().size() == 4);
+
+        // one loader per module
+        Layer.empty().defineModules(cf, mn -> new ClassLoader() { });
+
+        // m1 & m2 in one loader, m3 & m4 in another loader
+        ClassLoader loader1 = new ClassLoader() { };
+        ClassLoader loader2 = new ClassLoader() { };
+        Map<String, ClassLoader> map = new HashMap<>();
+        map.put("m1", loader1);
+        map.put("m2", loader1);
+        map.put("m3", loader2);
+        map.put("m3", loader2);
+        Layer.empty().defineModules(cf, map::get);
+
+        // same loader
+        try {
+            ClassLoader loader = new ClassLoader() { };
+            Layer.empty().defineModules(cf, mn -> loader);
+            assertTrue(false);
+        } catch (LayerInstantiationException expected) { }
+    }
+
+
+    /**
+     * Layer.create with a configuration that contains a module that has a
+     * concealed package that is the same name as a non-exported package
+     * in a parent layer.
+     */
+    public void testConcealSamePackageAsBootLayer() {
+
+        // check assumption that java.base contains sun.launcher
+        ModuleDescriptor base = Object.class.getModule().getDescriptor();
+        assertTrue(base.conceals().contains("sun.launcher"));
+
+        ModuleDescriptor descriptor
+            = new ModuleDescriptor.Builder("m1")
+               .requires("java.base")
+               .conceals("sun.launcher")
+               .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor);
+
+        Configuration parent = Layer.boot().configuration();
+        Configuration cf = parent.resolveRequires(finder, empty(), Set.of("m1"));
+        assertTrue(cf.modules().size() == 1);
+
+        ClassLoader loader = new ClassLoader() { };
+        Layer layer = Layer.boot().defineModules(cf, mn -> loader);
+        assertTrue(layer.modules().size() == 1);
+   }
+
+
+    /**
+     * Test layers with implied readability.
+     *
+     * The test consists of three configurations:
+     * - Configuration/layer1: m1, m2 requires public m1
+     * - Configuration/layer2: m3 requires m1
+     */
+    public void testImpliedReadabilityWithLayers1() {
+
+        // cf1: m1 and m2, m2 requires public m1
+
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2")
+                .requires(ModuleDescriptor.Requires.Modifier.PUBLIC, "m1")
+                .build();
+
+        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
+
+        Configuration cf1 = resolveRequires(finder1, "m2");
+
+        ClassLoader cl1 = new ClassLoader() { };
+        Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1);
+
+
+        // cf2: m3, m3 requires m2
+
+        ModuleDescriptor descriptor3
+            = new ModuleDescriptor.Builder("m3")
+                .requires("m2")
+                .build();
+
+        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3);
+
+        Configuration cf2 = resolveRequires(cf1, finder2, "m3");
+
+        ClassLoader cl2 = new ClassLoader() { };
+        Layer layer2 = layer1.defineModules(cf2, mn -> cl2);
+
+        assertTrue(layer1.parent().get() == Layer.empty());
+        assertTrue(layer2.parent().get() == layer1);
+
+        Module m1 = layer2.findModule("m1").get();
+        Module m2 = layer2.findModule("m2").get();
+        Module m3 = layer2.findModule("m3").get();
+
+        assertTrue(m1.getLayer() == layer1);
+        assertTrue(m2.getLayer() == layer1);
+        assertTrue(m3.getLayer() == layer2);
+
+        assertTrue(m1.getClassLoader() == cl1);
+        assertTrue(m2.getClassLoader() == cl1);
+        assertTrue(m3.getClassLoader() == cl2);
+
+        assertTrue(m1.canRead(m1));
+        assertFalse(m1.canRead(m2));
+        assertFalse(m1.canRead(m3));
+
+        assertTrue(m2.canRead(m1));
+        assertTrue(m2.canRead(m2));
+        assertFalse(m2.canRead(m3));
+
+        assertTrue(m3.canRead(m1));
+        assertTrue(m3.canRead(m2));
+        assertTrue(m3.canRead(m3));
+    }
+
+
+    /**
+     * Test layers with implied readability.
+     *
+     * The test consists of three configurations:
+     * - Configuration/layer1: m1
+     * - Configuration/layer2: m2 requires public m3, m3 requires m2
+     */
+    public void testImpliedReadabilityWithLayers2() {
+
+        // cf1: m1
+
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .build();
+
+        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
+
+        Configuration cf1 = resolveRequires(finder1, "m1");
+
+        ClassLoader cl1 = new ClassLoader() { };
+        Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1);
+
+
+        // cf2: m2, m3: m2 requires public m1, m3 requires m2
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2")
+                .requires(ModuleDescriptor.Requires.Modifier.PUBLIC, "m1")
+                .build();
+
+        ModuleDescriptor descriptor3
+            = new ModuleDescriptor.Builder("m3")
+                .requires("m2")
+                .build();
+
+        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2, descriptor3);
+
+        Configuration cf2 = resolveRequires(cf1, finder2, "m3");
+
+        ClassLoader cl2 = new ClassLoader() { };
+        Layer layer2 = layer1.defineModules(cf2, mn -> cl2);
+
+        assertTrue(layer1.parent().get() == Layer.empty());
+        assertTrue(layer2.parent().get() == layer1);
+
+        Module m1 = layer2.findModule("m1").get();
+        Module m2 = layer2.findModule("m2").get();
+        Module m3 = layer2.findModule("m3").get();
+
+        assertTrue(m1.getLayer() == layer1);
+        assertTrue(m2.getLayer() == layer2);
+        assertTrue(m3.getLayer() == layer2);
+
+        assertTrue(m1.canRead(m1));
+        assertFalse(m1.canRead(m2));
+        assertFalse(m1.canRead(m3));
+
+        assertTrue(m2.canRead(m1));
+        assertTrue(m2.canRead(m2));
+        assertFalse(m2.canRead(m3));
+
+        assertTrue(m3.canRead(m1));
+        assertTrue(m3.canRead(m2));
+        assertTrue(m3.canRead(m3));
+    }
+
+
+    /**
+     * Test layers with implied readability.
+     *
+     * The test consists of three configurations:
+     * - Configuration/layer1: m1
+     * - Configuration/layer2: m2 requires public m1
+     * - Configuration/layer3: m3 requires m1
+     */
+    public void testImpliedReadabilityWithLayers3() {
+
+        // cf1: m1
+
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .build();
+
+        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
+
+        Configuration cf1 = resolveRequires(finder1, "m1");
+
+        ClassLoader cl1 = new ClassLoader() { };
+        Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1);
+
+
+        // cf2: m2 requires public m1
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2")
+                .requires(ModuleDescriptor.Requires.Modifier.PUBLIC, "m1")
+                .build();
+
+        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2);
+
+        Configuration cf2 = resolveRequires(cf1, finder2, "m2");
+
+        ClassLoader cl2 = new ClassLoader() { };
+        Layer layer2 = layer1.defineModules(cf2, mn -> cl2);
+
+
+        // cf3: m3 requires m2
+
+        ModuleDescriptor descriptor3
+            = new ModuleDescriptor.Builder("m3")
+                .requires("m2")
+                .build();
+
+        ModuleFinder finder3 = ModuleUtils.finderOf(descriptor3);
+
+        Configuration cf3 = resolveRequires(cf2, finder3, "m3");
+
+        ClassLoader cl3 = new ClassLoader() { };
+        Layer layer3 = layer2.defineModules(cf3, mn -> cl3);
+
+        assertTrue(layer1.parent().get() == Layer.empty());
+        assertTrue(layer2.parent().get() == layer1);
+        assertTrue(layer3.parent().get() == layer2);
+
+        Module m1 = layer3.findModule("m1").get();
+        Module m2 = layer3.findModule("m2").get();
+        Module m3 = layer3.findModule("m3").get();
+
+        assertTrue(m1.getLayer() == layer1);
+        assertTrue(m2.getLayer() == layer2);
+        assertTrue(m3.getLayer() == layer3);
+
+        assertTrue(m1.canRead(m1));
+        assertFalse(m1.canRead(m2));
+        assertFalse(m1.canRead(m3));
+
+        assertTrue(m2.canRead(m1));
+        assertTrue(m2.canRead(m2));
+        assertFalse(m2.canRead(m3));
+
+        assertTrue(m3.canRead(m1));
+        assertTrue(m3.canRead(m2));
+        assertTrue(m3.canRead(m3));
+    }
+
+
+    /**
+     * Test layers with implied readability.
+     *
+     * The test consists of two configurations:
+     * - Configuration/layer1: m1, m2 requires public m1
+     * - Configuration/layer2: m3 requires public m2, m4 requires m3
+     */
+    public void testImpliedReadabilityWithLayers4() {
+
+        // cf1: m1, m2 requires public m1
+
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2")
+                .requires(ModuleDescriptor.Requires.Modifier.PUBLIC, "m1")
+                .build();
+
+        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
+
+        Configuration cf1 = resolveRequires(finder1, "m2");
+
+        ClassLoader cl1 = new ClassLoader() { };
+        Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1);
+
+
+        // cf2: m3 requires public m2, m4 requires m3
+
+        ModuleDescriptor descriptor3
+            = new ModuleDescriptor.Builder("m3")
+                .requires(ModuleDescriptor.Requires.Modifier.PUBLIC, "m2")
+                .build();
+
+        ModuleDescriptor descriptor4
+            = new ModuleDescriptor.Builder("m4")
+                .requires("m3")
+                .build();
+
+
+        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3, descriptor4);
+
+        Configuration cf2 = resolveRequires(cf1, finder2, "m3", "m4");
+
+        ClassLoader cl2 = new ClassLoader() { };
+        Layer layer2 = layer1.defineModules(cf2, mn -> cl2);
+
+        assertTrue(layer1.parent().get() == Layer.empty());
+        assertTrue(layer2.parent().get() == layer1);
+
+        Module m1 = layer2.findModule("m1").get();
+        Module m2 = layer2.findModule("m2").get();
+        Module m3 = layer2.findModule("m3").get();
+        Module m4 = layer2.findModule("m4").get();
+
+        assertTrue(m1.getLayer() == layer1);
+        assertTrue(m2.getLayer() == layer1);
+        assertTrue(m3.getLayer() == layer2);
+        assertTrue(m4.getLayer() == layer2);
+
+        assertTrue(m1.canRead(m1));
+        assertFalse(m1.canRead(m2));
+        assertFalse(m1.canRead(m3));
+        assertFalse(m1.canRead(m4));
+
+        assertTrue(m2.canRead(m1));
+        assertTrue(m2.canRead(m2));
+        assertFalse(m1.canRead(m3));
+        assertFalse(m1.canRead(m4));
+
+        assertTrue(m3.canRead(m1));
+        assertTrue(m3.canRead(m2));
+        assertTrue(m3.canRead(m3));
+        assertFalse(m3.canRead(m4));
+
+        assertTrue(m4.canRead(m1));
+        assertTrue(m4.canRead(m2));
+        assertTrue(m4.canRead(m3));
+        assertTrue(m4.canRead(m4));
+    }
+
+
+    /**
+     * Attempt to use Layer.create to create a layer with a module defined to a
+     * class loader that already has a module of the same name defined to the
+     * class loader.
+     */
+    @Test(expectedExceptions = { LayerInstantiationException.class })
+    public void testModuleAlreadyDefinedToLoader() {
+
+        ModuleDescriptor md
+            = new ModuleDescriptor.Builder("m")
+                .requires("java.base")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(md);
+
+        Configuration parent = Layer.boot().configuration();
+
+        Configuration cf = parent.resolveRequires(finder, empty(), Set.of("m"));
+
+        ClassLoader loader = new ClassLoader() { };
+
+        Layer.boot().defineModules(cf, mn -> loader);
+
+        // should throw LayerInstantiationException as m1 already defined to loader
+        Layer.boot().defineModules(cf, mn -> loader);
+
+    }
+
+
+    /**
+     * Attempt to use Layer.create to create a Layer with a module containing
+     * package {@code p} where the class loader already has a module defined
+     * to it containing package {@code p}.
+     */
+    @Test(expectedExceptions = { LayerInstantiationException.class })
+    public void testPackageAlreadyInNamedModule() {
+
+        ModuleDescriptor md1
+            = new ModuleDescriptor.Builder("m1")
+                .conceals("p")
+                .requires("java.base")
+                .build();
+
+        ModuleDescriptor md2
+            = new ModuleDescriptor.Builder("m2")
+                .conceals("p")
+                .requires("java.base")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(md1, md2);
+
+        ClassLoader loader = new ClassLoader() { };
+
+        // define m1 containing package p to class loader
+
+        Configuration parent = Layer.boot().configuration();
+
+        Configuration cf1 = parent.resolveRequires(finder, empty(), Set.of("m1"));
+
+        Layer layer1 = Layer.boot().defineModules(cf1, mn -> loader);
+
+        // attempt to define m2 containing package p to class loader
+
+        Configuration cf2 = parent.resolveRequires(finder, empty(), Set.of("m2"));
+
+        // should throw exception because p already in m1
+        Layer layer2 = Layer.boot().defineModules(cf2, mn -> loader);
+
+    }
+
+
+    /**
+     * Attempt to use Layer.create to create a Layer with a module containing
+     * a package in which a type is already loaded by the class loader.
+     */
+    @Test(expectedExceptions = { LayerInstantiationException.class })
+    public void testPackageAlreadyInUnnamedModule() throws Exception {
+
+        Class<?> c = layertest.Test.class;
+        assertFalse(c.getModule().isNamed());  // in unnamed module
+
+        ModuleDescriptor md
+            = new ModuleDescriptor.Builder("m")
+                .conceals(c.getPackageName())
+                .requires("java.base")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(md);
+
+        Configuration parent = Layer.boot().configuration();
+        Configuration cf = parent.resolveRequires(finder, empty(), Set.of("m"));
+
+        Layer.boot().defineModules(cf, mn -> c.getClassLoader());
+    }
+
+
+    /**
+     * Parent of configuration != configuration of parent Layer
+     */
+    @Test(expectedExceptions = { IllegalArgumentException.class })
+    public void testIncorrectParent1() {
+
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .requires("java.base")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
+
+        Configuration parent = Layer.boot().configuration();
+        Configuration cf = parent.resolveRequires(finder, empty(), Set.of("m1"));
+
+        ClassLoader loader = new ClassLoader() { };
+        Layer.empty().defineModules(cf, mn -> loader);
+    }
+
+
+    /**
+     * Parent of configuration != configuration of parent Layer
+     */
+    @Test(expectedExceptions = { IllegalArgumentException.class })
+    public void testIncorrectParent2() {
+
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
+
+        Configuration cf = resolveRequires(finder, "m1");
+
+        ClassLoader loader = new ClassLoader() { };
+        Layer.boot().defineModules(cf, mn -> loader);
+    }
+
+
+    // null handling
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testCreateWithNull1() {
+        ClassLoader loader = new ClassLoader() { };
+        Layer.empty().defineModules(null, mn -> loader);
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testCreateWithNull2() {
+        ClassLoader loader = new ClassLoader() { };
+        Configuration cf = resolveRequires(Layer.boot().configuration(), empty());
+        Layer.boot().defineModules(cf, null);
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testCreateWithNull3() {
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+        Layer.empty().defineModulesWithOneLoader(null, scl);
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testCreateWithNull4() {
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+        Layer.empty().defineModulesWithManyLoaders(null, scl);
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testFindModuleWithNull() {
+        Layer.boot().findModule(null);
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testFindLoaderWithNull() {
+        Layer.boot().findLoader(null);
+    }
+
+
+    // immutable sets
+
+    @Test(expectedExceptions = { UnsupportedOperationException.class })
+    public void testImmutableSet() {
+        Module base = Object.class.getModule();
+        Layer.boot().modules().add(base);
+    }
+
+
+    /**
+     * Resolve the given modules, by name, and returns the resulting
+     * Configuration.
+     */
+    private static Configuration resolveRequires(Configuration cf,
+                                                 ModuleFinder finder,
+                                                 String... roots) {
+        return cf.resolveRequires(finder, empty(), Set.of(roots));
+    }
+
+    private static Configuration resolveRequires(ModuleFinder finder,
+                                                 String... roots) {
+        return resolveRequires(Configuration.empty(), finder, roots);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Layer/LayerAndLoadersTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,673 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @library /lib/testlibrary
+ * @build LayerAndLoadersTest CompilerUtils ModuleUtils
+ * @run testng LayerAndLoadersTest
+ * @summary Tests for java.lang.reflect.Layer@createWithXXX methods
+ */
+
+import java.lang.module.Configuration;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleFinder;
+import static java.lang.module.ModuleFinder.empty;
+import java.lang.module.ModuleReference;
+import java.lang.reflect.Layer;
+import java.lang.reflect.LayerInstantiationException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Module;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Optional;
+import java.util.ServiceLoader;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+@Test
+public class LayerAndLoadersTest {
+
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path MODS_DIR = Paths.get("mods");
+
+    @BeforeTest
+    public void setup() throws Exception {
+
+        // javac -d mods -modulesourcepath src src/**
+        assertTrue(CompilerUtils.compile(SRC_DIR, MODS_DIR,
+                "-modulesourcepath", SRC_DIR.toString()));
+    }
+
+
+    /**
+     * Basic test of Layer.createWithOneLoader
+     *
+     * Test scenario:
+     *   m1 requires m2 and m3
+     */
+    public void testWithOneLoader() throws Exception {
+
+        Configuration cf = resolveRequires("m1");
+
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+
+        Layer layer = Layer.boot().defineModulesWithOneLoader(cf, scl);
+
+        checkLayer(layer, "m1", "m2", "m3");
+
+        ClassLoader cl1 = layer.findLoader("m1");
+        ClassLoader cl2 = layer.findLoader("m2");
+        ClassLoader cl3 = layer.findLoader("m3");
+
+        assertTrue(cl1.getParent() == scl);
+        assertTrue(cl2 == cl1);
+        assertTrue(cl3 == cl1);
+
+        invoke(layer, "m1", "p.Main");
+
+    }
+
+
+    /**
+     * Basic test of Layer.createWithManyLoaders
+     *
+     * Test scenario:
+     *   m1 requires m2 and m3
+     */
+    public void testWithManyLoaders() throws Exception {
+
+        Configuration cf = resolveRequires("m1");
+
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+
+        Layer layer = Layer.boot().defineModulesWithManyLoaders(cf, scl);
+
+        checkLayer(layer, "m1", "m2", "m3");
+
+        ClassLoader cl1 = layer.findLoader("m1");
+        ClassLoader cl2 = layer.findLoader("m2");
+        ClassLoader cl3 = layer.findLoader("m3");
+
+        assertTrue(cl1.getParent() == scl);
+        assertTrue(cl2.getParent() == scl);
+        assertTrue(cl3.getParent() == scl);
+        assertTrue(cl2 != cl1);
+        assertTrue(cl3 != cl1);
+        assertTrue(cl3 != cl2);
+
+        invoke(layer, "m1", "p.Main");
+
+    }
+
+
+    /**
+     * Basic test of Layer.createWithOneLoader where one of the modules
+     * is a service provider module.
+     *
+     * Test scenario:
+     *    m1 requires m2 and m3
+     *    m1 uses S
+     *    m4 provides S with ...
+     */
+    public void testServicesWithOneLoader() throws Exception {
+
+        Configuration cf = resolveRequiresAndUses("m1");
+
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+
+        Layer layer = Layer.boot().defineModulesWithOneLoader(cf, scl);
+
+        checkLayer(layer, "m1", "m2", "m3", "m4");
+
+        ClassLoader cl1 = layer.findLoader("m1");
+        ClassLoader cl2 = layer.findLoader("m2");
+        ClassLoader cl3 = layer.findLoader("m3");
+        ClassLoader cl4 = layer.findLoader("m4");
+
+        assertTrue(cl1.getParent() == scl);
+        assertTrue(cl2 == cl1);
+        assertTrue(cl3 == cl1);
+        assertTrue(cl4 == cl1);
+
+        Class<?> serviceType = cl1.loadClass("p.Service");
+        assertTrue(serviceType.getClassLoader() == cl1);
+
+        Iterator<?> iter = ServiceLoader.load(serviceType, cl1).iterator();
+        Object provider = iter.next();
+        assertTrue(serviceType.isInstance(provider));
+        assertTrue(provider.getClass().getClassLoader() == cl1);
+        assertFalse(iter.hasNext());
+
+    }
+
+
+    /**
+     * Basic test of Layer.createWithManyLoaders where one of the modules
+     * is a service provider module.
+     *
+     * Test scenario:
+     *    m1 requires m2 and m3
+     *    m1 uses S
+     *    m4 provides S with ...
+     */
+    public void testServicesWithManyLoaders() throws Exception {
+
+        Configuration cf = resolveRequiresAndUses("m1");
+
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+
+        Layer layer = Layer.boot().defineModulesWithManyLoaders(cf, scl);
+
+        checkLayer(layer, "m1", "m2", "m3", "m4");
+
+        ClassLoader cl1 = layer.findLoader("m1");
+        ClassLoader cl2 = layer.findLoader("m2");
+        ClassLoader cl3 = layer.findLoader("m3");
+        ClassLoader cl4 = layer.findLoader("m4");
+
+        assertTrue(cl1.getParent() == scl);
+        assertTrue(cl2.getParent() == scl);
+        assertTrue(cl3.getParent() == scl);
+        assertTrue(cl4.getParent() == scl);
+        assertTrue(cl2 != cl1);
+        assertTrue(cl3 != cl1);
+        assertTrue(cl3 != cl2);
+        assertTrue(cl4 != cl1);
+        assertTrue(cl4 != cl2);
+        assertTrue(cl4 != cl3);
+
+        Class<?> serviceType = cl1.loadClass("p.Service");
+        assertTrue(serviceType.getClassLoader() == cl1);
+
+        // Test that the service provider can be located via any of
+        // the class loaders in the layer
+        for (Module m : layer.modules()) {
+            ClassLoader loader = m.getClassLoader();
+            Iterator<?> iter = ServiceLoader.load(serviceType, loader).iterator();
+            Object provider = iter.next();
+            assertTrue(serviceType.isInstance(provider));
+            assertTrue(provider.getClass().getClassLoader() == cl4);
+            assertFalse(iter.hasNext());
+        }
+
+    }
+
+
+    /**
+     * Tests that the class loaders created by Layer.createWithXXX delegate
+     * to the given parent class loader.
+     */
+    public void testDelegationToParent() throws Exception {
+
+        Configuration cf = resolveRequires("m1");
+
+        ClassLoader parent = this.getClass().getClassLoader();
+        String cn = this.getClass().getName();
+
+        // one loader
+        Layer layer = Layer.boot().defineModulesWithOneLoader(cf, parent);
+        testLoad(layer, cn);
+
+         // one loader with boot loader as parent
+        layer = Layer.boot().defineModulesWithOneLoader(cf, null);
+        testLoadFail(layer, cn);
+
+        // many loaders
+        layer = Layer.boot().defineModulesWithManyLoaders(cf, parent);
+        testLoad(layer, cn);
+
+        // many loader with boot loader as parent
+        layer = Layer.boot().defineModulesWithManyLoaders(cf, null);
+        testLoadFail(layer, cn);
+
+    }
+
+
+    /**
+     * Test Layer.createWithXXX when modules that have overlapping packages.
+     *
+     * Test scenario:
+     *   m1 exports p
+     *   m2 exports p
+     */
+    public void testOverlappingPackages() {
+
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1").exports("p").build();
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2").exports("p").build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
+
+        Configuration cf = Layer.boot()
+            .configuration()
+            .resolveRequires(finder, empty(), Set.of("m1", "m2"));
+
+        // cannot define both module m1 and m2 to the same class loader
+        try {
+            Layer.boot().defineModulesWithOneLoader(cf, null);
+            assertTrue(false);
+        } catch (LayerInstantiationException expected) { }
+
+        // should be okay to have one module per class loader
+        Layer layer = Layer.boot().defineModulesWithManyLoaders(cf, null);
+        checkLayer(layer, "m1", "m2");
+
+    }
+
+
+    /**
+     * Test Layer.createWithXXX with split delegation.
+     *
+     * Test scenario:
+     *   layer1: m1 exports p, m2 exports p
+     *   layer2: m3 reads m1, m4 reads m2
+     */
+    public void testSplitDelegation() {
+
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1").exports("p").build();
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2").exports("p").build();
+
+        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
+
+        Configuration cf1 = Layer.boot()
+            .configuration()
+            .resolveRequires(finder1, empty(), Set.of("m1", "m2"));
+
+        Layer layer1 = Layer.boot().defineModulesWithManyLoaders(cf1, null);
+        checkLayer(layer1, "m1", "m2");
+
+        ModuleDescriptor descriptor3
+            = new ModuleDescriptor.Builder("m3").requires("m1").build();
+
+        ModuleDescriptor descriptor4
+            = new ModuleDescriptor.Builder("m4").requires("m2").build();
+
+        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3, descriptor4);
+
+        Configuration cf2 = cf1.resolveRequires(finder2, empty(), Set.of("m3", "m4"));
+
+        // package p cannot be supplied by two class loaders
+        try {
+            layer1.defineModulesWithOneLoader(cf2, null);
+            assertTrue(false);
+        } catch (LayerInstantiationException expected) { }
+
+        // no split delegation when modules have their own class loader
+        Layer layer2 = layer1.defineModulesWithManyLoaders(cf2, null);
+        checkLayer(layer2, "m3", "m4");
+
+    }
+
+
+    /**
+     * Test Layer.createWithXXX when the modules that override same named
+     * modules in the parent layer.
+     *
+     * Test scenario:
+     *   layer1: m1, m2, m3 => same loader
+     *   layer2: m1, m2, m4 => same loader
+     */
+    public void testOverriding1() throws Exception {
+
+        Configuration cf1 = resolveRequires("m1");
+
+        Layer layer1 = Layer.boot().defineModulesWithOneLoader(cf1, null);
+        checkLayer(layer1, "m1", "m2", "m3");
+
+        ModuleFinder finder = ModuleFinder.of(MODS_DIR);
+        Configuration cf2 = cf1.resolveRequires(finder, empty(), Set.of("m1"));
+
+        Layer layer2 = layer1.defineModulesWithOneLoader(cf2, null);
+        checkLayer(layer2, "m1", "m2", "m3");
+        invoke(layer1, "m1", "p.Main");
+
+        ClassLoader loader1 = layer1.findLoader("m1");
+        ClassLoader loader2 = layer1.findLoader("m2");
+        ClassLoader loader3 = layer1.findLoader("m3");
+
+        ClassLoader loader4 = layer2.findLoader("m1");
+        ClassLoader loader5 = layer2.findLoader("m2");
+        ClassLoader loader6 = layer2.findLoader("m3");
+
+        assertTrue(loader1 == loader2);
+        assertTrue(loader1 == loader3);
+
+        assertTrue(loader4 == loader5);
+        assertTrue(loader4 == loader6);
+        assertTrue(loader4 != loader1);
+
+        assertTrue(loader1.loadClass("p.Main").getClassLoader() == loader1);
+        assertTrue(loader1.loadClass("q.Hello").getClassLoader() == loader1);
+        assertTrue(loader1.loadClass("w.Hello").getClassLoader() == loader1);
+
+        assertTrue(loader4.loadClass("p.Main").getClassLoader() == loader4);
+        assertTrue(loader4.loadClass("q.Hello").getClassLoader() == loader4);
+        assertTrue(loader4.loadClass("w.Hello").getClassLoader() == loader4);
+
+    }
+
+
+    /**
+     * Test Layer.createWithXXX when the modules that override same named
+     * modules in the parent layer.
+     *
+     * Test scenario:
+     *   layer1: m1, m2, m3 => loader pool
+     *   layer2: m1, m2, m3 => loader pool
+     */
+    public void testOverriding2() throws Exception {
+
+        Configuration cf1 = resolveRequires("m1");
+
+        Layer layer1 = Layer.boot().defineModulesWithManyLoaders(cf1, null);
+        checkLayer(layer1, "m1", "m2", "m3");
+
+        ModuleFinder finder = ModuleFinder.of(MODS_DIR);
+        Configuration cf2 = cf1.resolveRequires(finder, empty(), Set.of("m1"));
+
+        Layer layer2 = layer1.defineModulesWithManyLoaders(cf2, null);
+        checkLayer(layer2, "m1", "m2", "m3");
+        invoke(layer1, "m1", "p.Main");
+
+        ClassLoader loader1 = layer1.findLoader("m1");
+        ClassLoader loader2 = layer1.findLoader("m2");
+        ClassLoader loader3 = layer1.findLoader("m3");
+
+        ClassLoader loader4 = layer2.findLoader("m1");
+        ClassLoader loader5 = layer2.findLoader("m2");
+        ClassLoader loader6 = layer2.findLoader("m3");
+
+        assertTrue(loader4 != loader1);
+        assertTrue(loader5 != loader2);
+        assertTrue(loader6 != loader3);
+
+        assertTrue(loader1.loadClass("p.Main").getClassLoader() == loader1);
+        assertTrue(loader1.loadClass("q.Hello").getClassLoader() == loader2);
+        assertTrue(loader1.loadClass("w.Hello").getClassLoader() == loader3);
+
+        // p.Main is not visible via loader2
+        try {
+            loader2.loadClass("p.Main");
+            assertTrue(false);
+        } catch (ClassNotFoundException expected) { }
+
+        // w.Hello is not visible via loader2
+        try {
+            loader2.loadClass("w.Hello");
+            assertTrue(false);
+        } catch (ClassNotFoundException expected) { }
+
+        // p.Main is not visible via loader3
+        try {
+            loader3.loadClass("p.Main");
+            assertTrue(false);
+        } catch (ClassNotFoundException expected) { }
+
+        // q.Hello is not visible via loader3
+        try {
+            loader3.loadClass("q.Hello");
+            assertTrue(false);
+        } catch (ClassNotFoundException expected) { }
+
+
+        assertTrue(loader4.loadClass("p.Main").getClassLoader() == loader4);
+        assertTrue(loader5.loadClass("q.Hello").getClassLoader() == loader5);
+        assertTrue(loader6.loadClass("w.Hello").getClassLoader() == loader6);
+
+        // p.Main is not visible via loader5
+        try {
+            loader5.loadClass("p.Main");
+            assertTrue(false);
+        } catch (ClassNotFoundException expected) { }
+
+        // w.Hello is not visible via loader5
+        try {
+            loader5.loadClass("w.Hello");
+            assertTrue(false);
+        } catch (ClassNotFoundException expected) { }
+
+        // p.Main is not visible via loader6
+        try {
+            loader6.loadClass("p.Main");
+            assertTrue(false);
+        } catch (ClassNotFoundException expected) { }
+
+        // q.Hello is not visible via loader6
+        try {
+            loader6.loadClass("q.Hello");
+            assertTrue(false);
+        } catch (ClassNotFoundException expected) { }
+
+    }
+
+
+    /**
+     * Test Layer.createWithXXX when the modules that override same named
+     * modules in the parent layer.
+     *
+     * layer1: m1, m2, m3 => same loader
+     * layer2: m1, m3 => same loader
+     */
+    public void testOverriding3() throws Exception {
+
+        Configuration cf1 = resolveRequires("m1");
+
+        Layer layer1 = Layer.boot().defineModulesWithOneLoader(cf1, null);
+        checkLayer(layer1, "m1", "m2", "m3");
+
+        ModuleFinder finder = finderFor("m1", "m3");
+
+        Configuration cf2 = cf1.resolveRequires(finder, empty(), Set.of("m1"));
+
+        Layer layer2 = layer1.defineModulesWithOneLoader(cf2, null);
+        checkLayer(layer2, "m1", "m3");
+        invoke(layer1, "m1", "p.Main");
+
+        ClassLoader loader1 = layer1.findLoader("m1");
+        ClassLoader loader2 = layer2.findLoader("m1");
+
+        assertTrue(loader1.loadClass("p.Main").getClassLoader() == loader1);
+        assertTrue(loader1.loadClass("q.Hello").getClassLoader() == loader1);
+        assertTrue(loader1.loadClass("w.Hello").getClassLoader() == loader1);
+
+        assertTrue(loader2.loadClass("p.Main").getClassLoader() == loader2);
+        assertTrue(loader2.loadClass("q.Hello").getClassLoader() == loader1);
+        assertTrue(loader2.loadClass("w.Hello").getClassLoader() == loader2);
+
+    }
+
+
+    /**
+     * Test Layer.createWithXXX when the modules that override same named
+     * modules in the parent layer.
+     *
+     * layer1: m1, m2, m3 => loader pool
+     * layer2: m1, m3 => loader pool
+     */
+    public void testOverriding4() throws Exception {
+
+        Configuration cf1 = resolveRequires("m1");
+
+        Layer layer1 = Layer.boot().defineModulesWithManyLoaders(cf1, null);
+        checkLayer(layer1, "m1", "m2", "m3");
+
+        ModuleFinder finder = finderFor("m1", "m3");
+
+        Configuration cf2 = cf1.resolveRequires(finder, empty(), Set.of("m1"));
+
+        Layer layer2 = layer1.defineModulesWithManyLoaders(cf2, null);
+        checkLayer(layer2, "m1", "m3");
+        invoke(layer1, "m1", "p.Main");
+
+        ClassLoader loader1 = layer1.findLoader("m1");
+        ClassLoader loader2 = layer1.findLoader("m2");
+        ClassLoader loader3 = layer1.findLoader("m3");
+
+        ClassLoader loader4 = layer2.findLoader("m1");
+        ClassLoader loader5 = layer2.findLoader("m2");
+        ClassLoader loader6 = layer2.findLoader("m3");
+
+        assertTrue(loader4 != loader1);
+        assertTrue(loader5 == loader2);  // m2 not overridden
+        assertTrue(loader6 != loader3);
+
+        assertTrue(loader1.loadClass("p.Main").getClassLoader() == loader1);
+        assertTrue(loader1.loadClass("q.Hello").getClassLoader() == loader2);
+        assertTrue(loader1.loadClass("w.Hello").getClassLoader() == loader3);
+
+        assertTrue(loader2.loadClass("q.Hello").getClassLoader() == loader2);
+
+        assertTrue(loader3.loadClass("w.Hello").getClassLoader() == loader3);
+
+        assertTrue(loader4.loadClass("p.Main").getClassLoader() == loader4);
+        assertTrue(loader4.loadClass("q.Hello").getClassLoader() == loader2);
+        assertTrue(loader4.loadClass("w.Hello").getClassLoader() == loader6);
+
+        assertTrue(loader6.loadClass("w.Hello").getClassLoader() == loader6);
+
+    }
+
+
+    // -- supporting methods --
+
+
+    /**
+     * Resolve the given modules, by name, and returns the resulting
+     * Configuration.
+     */
+    private static Configuration resolveRequires(String... roots) {
+        ModuleFinder finder = ModuleFinder.of(MODS_DIR);
+        return Layer.boot()
+            .configuration()
+            .resolveRequires(finder, empty(), Set.of(roots));
+    }
+
+    /**
+     * Resolve the given modules, by name, and returns the resulting
+     * Configuration.
+     */
+    private static Configuration resolveRequiresAndUses(String... roots) {
+        ModuleFinder finder = ModuleFinder.of(MODS_DIR);
+        return Layer.boot()
+            .configuration()
+            .resolveRequiresAndUses(finder, empty(), Set.of(roots));
+    }
+
+
+    /**
+     * Invokes the static void main(String[]) method on the given class
+     * in the given module.
+     */
+    private static void invoke(Layer layer, String mn, String mc) throws Exception {
+        ClassLoader loader = layer.findLoader(mn);
+        Class<?> c = loader.loadClass(mc);
+        Method mainMethod = c.getMethod("main", String[].class);
+        mainMethod.invoke(null, (Object)new String[0]);
+    }
+
+
+    /**
+     * Checks that the given layer contains exactly the expected modules
+     * (by name).
+     */
+    private void checkLayer(Layer layer, String ... expected) {
+        Set<String> names = layer.modules().stream()
+                .map(Module::getName)
+                .collect(Collectors.toSet());
+        assertTrue(names.size() == expected.length);
+        for (String name : expected) {
+            assertTrue(names.contains(name));
+        }
+    }
+
+
+    /**
+     * Test that a class can be loaded via the class loader of all modules
+     * in the given layer.
+     */
+    static void testLoad(Layer layer, String cn) throws Exception {
+        for (Module m : layer.modules()) {
+            ClassLoader l = m.getClassLoader();
+            l.loadClass(cn);
+        }
+    }
+
+
+    /**
+     * Test that a class cannot be loaded via any of the class loaders of
+     * the modules in the given layer.
+     */
+    static void testLoadFail(Layer layer, String cn) throws Exception {
+        for (Module m : layer.modules()) {
+            ClassLoader l = m.getClassLoader();
+            try {
+                l.loadClass(cn);
+                assertTrue(false);
+            } catch (ClassNotFoundException expected) { }
+        }
+    }
+
+
+    /**
+     * Returns a ModuleFinder that only finds the given test modules
+     */
+    static ModuleFinder finderFor(String... names) {
+
+        ModuleFinder finder = ModuleFinder.of(MODS_DIR);
+
+        Map<String, ModuleReference> mrefs = new HashMap<>();
+        for (String name : names) {
+            Optional<ModuleReference> omref = finder.find(name);
+            assert omref.isPresent();
+            mrefs.put(name, omref.get());
+        }
+
+        return new ModuleFinder() {
+            @Override
+            public Optional<ModuleReference> find(String name) {
+                ModuleReference mref = mrefs.get(name);
+                return Optional.ofNullable(mref);
+            }
+            @Override
+            public Set<ModuleReference> findAll() {
+                return mrefs.values().stream().collect(Collectors.toSet());
+            }
+        };
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Layer/layertest/Test.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Supporting class for tests of java.lang.reflect.Layer.
+ */
+
+package layertest;
+
+public class Test { }
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Layer/src/m1/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m1 {
+    requires m2;
+    requires m3;
+    exports p;
+    uses p.Service;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Layer/src/m1/p/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p;
+
+import java.net.URL;
+
+public class Main {
+    public static void main(String[] args) {
+
+        URL url1 = Main.class.getResource("Main.class");
+        if (url1 == null) throw new RuntimeException();
+        URL url2 = Main.class.getResource("/p/Main.class");
+        if (url2 == null) throw new RuntimeException();
+
+        q.Hello.hello();
+        w.Hello.hello();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Layer/src/m1/p/Service.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p;
+
+public interface Service { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Layer/src/m2/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m2 {
+    exports q;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Layer/src/m2/q/Hello.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package q;
+
+import java.net.URL;
+
+public class Hello {
+
+    public static void hello() {
+
+        URL url1 = Hello.class.getResource("Hello.class");
+        if (url1 == null) throw new RuntimeException();
+        URL url2 = Hello.class.getResource("/q/Hello.class");
+        if (url2 == null) throw new RuntimeException();
+
+        System.out.println("Hello!");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Layer/src/m3/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m3 {
+    // qualified export
+    exports w to m1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Layer/src/m3/w/Hello.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package w;
+
+import java.net.URL;
+
+public class Hello {
+
+    public static void hello() {
+
+        URL url1 = Hello.class.getResource("Hello.class");
+        if (url1 == null) throw new RuntimeException();
+        URL url2 = Hello.class.getResource("/w/Hello.class");
+        if (url2 == null) throw new RuntimeException();
+
+        System.out.println("Hello!");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Layer/src/m4/impl/ServiceImpl.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package impl;
+
+public class ServiceImpl implements p.Service {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Layer/src/m4/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m4 {
+    requires m1;
+    provides p.Service with impl.ServiceImpl;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Module/AddExportsTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @run main/othervm -XaddExports:java.desktop/sun.awt=java.base AddExportsTest
+ * @run main/othervm -XaddExports:java.desktop/sun.awt=ALL-UNNAMED AddExportsTest
+ * @summary Test Module isExported methods with exports changed by -AddExportsTest
+ */
+
+import java.lang.reflect.Layer;
+import java.lang.reflect.Module;
+import java.util.Optional;
+
+public class AddExportsTest {
+
+    public static void main(String[] args) {
+
+        String addExports = System.getProperty("jdk.launcher.addexports.0");
+        assertTrue(addExports != null, "Expected to be run with -XaddExports");
+
+        Layer bootLayer = Layer.boot();
+
+        Module unnamedModule = AddExportsTest.class.getModule();
+        assertFalse(unnamedModule.isNamed());
+
+        for (String expr : addExports.split(",")) {
+
+            String[] s = expr.split("=");
+            assertTrue(s.length == 2);
+
+            // $MODULE/$PACKAGE
+            String[] moduleAndPackage = s[0].split("/");
+            assertTrue(moduleAndPackage.length == 2);
+
+            String mn = moduleAndPackage[0];
+            String pn = moduleAndPackage[1];
+
+            // source module
+            Module source;
+            Optional<Module> om = bootLayer.findModule(mn);
+            assertTrue(om.isPresent(), mn + " not in boot layer");
+            source = om.get();
+
+            // package should not be exported unconditionally
+            assertFalse(source.isExported(pn),
+                        pn + " should not be exported unconditionally");
+
+            // $TARGET
+            String tn = s[1];
+            if ("ALL-UNNAMED".equals(tn)) {
+
+                // package is exported to all unnamed modules
+                assertTrue(source.isExported(pn, unnamedModule),
+                           pn + " should be exported to all unnamed modules");
+
+            } else {
+
+                om = bootLayer.findModule(tn);
+                assertTrue(om.isPresent());
+                Module target = om.get();
+
+                // package should be exported to target module
+                assertTrue(source.isExported(pn, target),
+                           pn + " should be exported to " + target);
+
+                // package should not be exported to unnamed modules
+                assertFalse(source.isExported(pn, unnamedModule),
+                            pn + " should not be exported to unnamed modules");
+
+            }
+
+        }
+    }
+
+    static void assertTrue(boolean cond) {
+        if (!cond) throw new RuntimeException();
+    }
+
+    static void assertTrue(boolean cond, String msg) {
+        if (!cond) throw new RuntimeException(msg);
+    }
+
+    static void assertFalse(boolean cond) {
+        if (cond) throw new RuntimeException();
+    }
+
+    static void assertFalse(boolean cond, String msg) {
+        if (cond) throw new RuntimeException(msg);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Module/BasicModuleTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.lang.module.ModuleDescriptor.Exports;
+import java.lang.module.ResolvedModule;
+import java.lang.reflect.Layer;
+import java.lang.reflect.Module;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/*
+ * @test
+ * @summary Basic test of java.lang.reflect.Module
+ * @modules java.desktop java.xml
+ * @run testng BasicModuleTest
+ */
+
+public class BasicModuleTest {
+
+    /**
+     * Tests that the given module reads all modules in the boot Layer.
+     */
+    private void testReadsAllBootModules(Module m) {
+        Layer bootLayer = Layer.boot();
+        bootLayer.configuration()
+            .modules()
+            .stream()
+            .map(ResolvedModule::name)
+            .map(bootLayer::findModule)
+            .forEach(target -> assertTrue(m.canRead(target.get())));
+    }
+
+    /**
+     * Returns {@code true} if the array contains the given object.
+     */
+    private <T> boolean contains(T[] array, T obj) {
+        return Stream.of(array).anyMatch(obj::equals);
+    }
+
+    /**
+     * Returns a {@code Predicate} to test if a package is exported.
+     */
+    private Predicate<Exports> doesExport(String pn) {
+        return e -> (e.source().equals(pn) && !e.isQualified());
+    }
+
+
+
+    @Test
+    public void testThisModule() {
+        Module thisModule = BasicModuleTest.class.getModule();
+        Module baseModule = Object.class.getModule();
+
+        assertFalse(thisModule.isNamed());
+        assertTrue(thisModule.getName() == null);
+        assertTrue(thisModule.getDescriptor() == null);
+        assertTrue(thisModule.getLayer() == null);
+        assertTrue(thisModule.toString().startsWith("unnamed module "));
+
+        ClassLoader thisLoader = BasicModuleTest.class.getClassLoader();
+        assertTrue(thisLoader == thisModule.getClassLoader());
+        assertTrue(thisLoader.getUnnamedModule() == thisModule);
+
+        // unnamed modules read all other modules
+        ClassLoader cl;
+        cl = ClassLoader.getPlatformClassLoader();
+        assertTrue(thisModule.canRead(cl.getUnnamedModule()));
+        cl = ClassLoader.getSystemClassLoader();
+        assertTrue(thisModule.canRead(cl.getUnnamedModule()));
+        testReadsAllBootModules(thisModule);
+
+        // unnamed modules export all packages
+        assertTrue(thisModule.isExported(""));
+        assertTrue(thisModule.isExported("", thisModule));
+        assertTrue(thisModule.isExported("", baseModule));
+        assertTrue(thisModule.isExported("p"));
+        assertTrue(thisModule.isExported("p", thisModule));
+        assertTrue(thisModule.isExported("p", baseModule));
+
+        // this test is in the unnamed package
+        assertTrue(contains(thisModule.getPackages(), ""));
+    }
+
+
+    @Test
+    public void testUnnamedModules() {
+        Module thisModule = BasicModuleTest.class.getModule();
+        Module baseModule = Object.class.getModule();
+
+        ClassLoader loader1 = ClassLoader.getSystemClassLoader();
+        ClassLoader loader2 = loader1.getParent();
+
+        Module m1 = loader1.getUnnamedModule();
+        Module m2 = loader2.getUnnamedModule();
+
+        assertTrue(m1 != m2);
+
+        assertFalse(m1.isNamed());
+        assertFalse(m2.isNamed());
+
+        assertTrue(m1.getLayer() == null);
+        assertTrue(m2.getLayer() == null);
+
+        assertTrue(m1.toString().startsWith("unnamed module "));
+        assertTrue(m2.toString().startsWith("unnamed module "));
+
+        // unnamed module reads all modules
+        assertTrue(m1.canRead(m2));
+        assertTrue(m2.canRead(m1));
+
+        testReadsAllBootModules(m1);
+        testReadsAllBootModules(m2);
+
+        assertTrue(m1.isExported(""));
+        assertTrue(m1.isExported("", thisModule));
+        assertTrue(m1.isExported("", baseModule));
+        assertTrue(m1.isExported("p"));
+        assertTrue(m1.isExported("p", thisModule));
+        assertTrue(m1.isExported("p", baseModule));
+    }
+
+
+
+    @Test
+    public void testBaseModule() {
+        Module base = Object.class.getModule();
+        Module thisModule = BasicModuleTest.class.getModule();
+
+        // getName
+        assertTrue(base.getName().equals("java.base"));
+
+        // getDescriptor
+        assertTrue(base.getDescriptor().exports().stream()
+                .anyMatch(doesExport("java.lang")));
+
+        // getClassLoader
+        assertTrue(base.getClassLoader() == null);
+
+        // getLayer
+        assertTrue(base.getLayer() == Layer.boot());
+
+        // toString
+        assertEquals(base.toString(), "module java.base");
+
+        // getPackages
+        assertTrue(contains(base.getPackages(), "java.lang"));
+
+        // canRead
+        assertTrue(base.canRead(base));
+
+        // isExported
+        assertTrue(base.isExported("java.lang"));
+        assertTrue(base.isExported("java.lang", thisModule));
+        assertFalse(base.isExported("java.wombat"));
+        assertFalse(base.isExported("java.wombat", thisModule));
+    }
+
+
+    @Test
+    public void testDesktopModule() {
+        Module desktop = java.awt.Component.class.getModule();
+        Module base = Object.class.getModule();
+        Module xml = javax.xml.XMLConstants.class.getModule();
+        Module thisModule = BasicModuleTest.class.getModule();
+
+        // name
+        assertTrue(desktop.getName().equals("java.desktop"));
+
+        // descriptor
+        assertTrue(desktop.getDescriptor().exports().stream()
+                   .anyMatch(doesExport("java.awt")));
+
+        // getClassLoader
+        assertTrue(desktop.getClassLoader() == null);
+
+        // getLayer
+        assertTrue(desktop.getLayer() == Layer.boot());
+
+        // toString
+        assertEquals(desktop.toString(), "module java.desktop");
+
+        // getPackages
+        assertTrue(contains(desktop.getPackages(), "java.awt"));
+        assertTrue(contains(desktop.getPackages(), "sun.awt"));
+
+        // canRead
+        assertTrue(desktop.canRead(base));
+        assertTrue(desktop.canRead(xml));
+
+        // isExported
+        assertTrue(desktop.isExported("java.awt"));
+        assertTrue(desktop.isExported("java.awt", thisModule));
+        assertFalse(desktop.isExported("java.wombat"));
+        assertFalse(desktop.isExported("java.wombat", thisModule));
+    }
+
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testIsExportedNull() {
+        Module thisModule = this.getClass().getModule();
+        thisModule.isExported(null, thisModule);
+    }
+
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testIsExportedToNull() {
+        Module thisModule = this.getClass().getModule();
+        thisModule.isExported("", null);
+    }
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Module/access/AccessTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.List;
+
+import static jdk.testlibrary.ProcessTools.executeTestJava;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/**
+ * @test
+ * @library /lib/testlibrary
+ * @modules java.compiler
+ * @build AccessTest CompilerUtils jdk.testlibrary.*
+ * @run testng AccessTest
+ * @summary Driver for test that checks access to public members in exported
+ *          and non-exported packages.
+ */
+
+@Test
+public class AccessTest {
+
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path MODS_DIR = Paths.get("mods");
+
+
+    // the names of the modules in this test
+    private static List<String> modules = Arrays.asList("test", "target");
+
+
+    /**
+     * Compiles all modules used by the test
+     */
+    @BeforeTest
+    public void compileAll() throws Exception {
+        for (String mn : modules) {
+            Path src = SRC_DIR.resolve(mn);
+            Path mods = MODS_DIR.resolve(mn);
+            assertTrue(CompilerUtils.compile(src, mods));
+        }
+    }
+
+    /**
+     * Run the test
+     */
+    public void runTest() throws Exception {
+        int exitValue
+            = executeTestJava("-mp", MODS_DIR.toString(),
+                              "-addmods", "target",
+                              "-m", "test/test.Main")
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
+
+        assertTrue(exitValue == 0);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Module/access/src/target/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module target {
+    exports p;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Module/access/src/target/p/Exported.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p;
+
+public class Exported {
+
+    /**
+     * Public constructor
+     */
+    public Exported() { }
+
+    /**
+     * Public field
+     */
+    public static Object field;
+
+    /**
+     * Public method
+     */
+    public static void run() {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Module/access/src/target/p/Helper.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p;
+
+import java.lang.reflect.Module;
+
+public class Helper {
+    Helper() { }
+
+    public static void exportPackage(String pn, Module who) {
+        Helper.class.getModule().addExports(pn, who);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Module/access/src/target/q/Internal.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package q;
+
+public class Internal {
+
+    /**
+     * Public constructor
+     */
+    public Internal() { }
+
+    /**
+     * Public field
+     */
+    public static Object field;
+
+    /**
+     * Public method
+     */
+    public static void run() {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Module/access/src/test/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module test { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Module/access/src/test/test/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package test;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InaccessibleObjectException;
+import java.lang.reflect.Layer;
+import java.lang.reflect.Method;
+import java.lang.reflect.Module;
+import java.util.Optional;
+
+/**
+ * Test access to public members in exported and non-exported packages.
+ */
+
+public class Main {
+
+    public static void main(String[] args) throws Exception {
+
+        Module thisModule = Main.class.getModule();
+        assertTrue(thisModule.isNamed());
+
+        Optional<Module> om = Layer.boot().findModule("target");
+        assertTrue(om.isPresent());
+
+        Module target = om.get();
+
+        assertTrue(target.isExported("p"));
+        assertTrue(target.isExported("p", thisModule));
+
+        assertFalse(target.isExported("q"));
+        assertFalse(target.isExported("q", thisModule));
+
+
+        // thisModule does not read the target module
+
+        assertFalse(thisModule.canRead(target));
+
+        tryAccessPublicMembers("p.Exported", true);
+        tryAccessPublicMembers("q.Internal", false);
+
+
+
+        // thisModule reads the target module
+
+        thisModule.addReads(target);
+        assertTrue(thisModule.canRead(target));
+
+        tryAccessPublicMembers("p.Exported", true);
+        tryAccessPublicMembers("q.Internal", false);
+
+
+
+        // change target module to export its internal package to thisModule
+
+        targetAddExports("q", thisModule);
+        assertFalse(target.isExported("q"));
+        assertTrue(target.isExported("q", thisModule));
+
+        tryAccessPublicMembers("p.Exported", true);
+        tryAccessPublicMembers("q.Internal", true);
+    }
+
+
+    /**
+     * Attempt to access public members in a target class.
+     */
+    static void tryAccessPublicMembers(String cn, boolean shouldSucceed)
+        throws Exception
+    {
+
+        Class<?> clazz = Class.forName(cn);
+
+        Module thisModule = Main.class.getModule();
+        Module targetModule = clazz.getModule();
+
+        // check if the target class is in an exported package
+        String pn = cn.substring(0, cn.lastIndexOf('.'));
+        boolean exported = targetModule.isExported(pn, thisModule);
+        assertTrue(exported == shouldSucceed);
+        boolean shouldFail = !shouldSucceed;
+
+
+        // Class.newInstance
+
+        try {
+            clazz.newInstance();
+            assertTrue(shouldSucceed);
+        } catch (IllegalAccessException e) {
+            assertTrue(shouldFail);
+        }
+
+
+        // Constructor.newInstance and Constructor.setAccessible
+
+        Constructor<?> ctor = clazz.getConstructor();
+        try {
+            ctor.newInstance();
+            assertTrue(shouldSucceed);
+        } catch (IllegalAccessException e) {
+            assertTrue(shouldFail);
+        }
+        try {
+            ctor.setAccessible(true);
+            assertTrue(shouldSucceed);
+            ctor.newInstance();
+        } catch (InaccessibleObjectException e) {
+            assertTrue(shouldFail);
+        }
+
+
+        // Method.invoke and Method.setAccessible
+
+        Method m = clazz.getDeclaredMethod("run");
+        try {
+            m.invoke(null);
+            assertTrue(shouldSucceed);
+        } catch (IllegalAccessException e) {
+            assertTrue(shouldFail);
+        }
+        try {
+            m.setAccessible(true);
+            assertTrue(shouldSucceed);
+            m.invoke(null);
+        } catch (InaccessibleObjectException e) {
+            assertTrue(shouldFail);
+        }
+
+        // Field.get, Field.set and Field.setAccessible
+
+        Field f = clazz.getDeclaredField("field");
+        try {
+            f.get(null);
+            assertTrue(shouldSucceed);
+        } catch (IllegalAccessException e) {
+            assertTrue(shouldFail);
+        }
+        try {
+            f.set(null, 100);
+            assertTrue(shouldSucceed);
+        } catch (IllegalAccessException e) {
+            assertTrue(shouldFail);
+        }
+        try {
+            f.setAccessible(true);
+            f.get(null);
+            f.set(null, 100);
+            assertTrue(shouldSucceed);
+        } catch (InaccessibleObjectException e) {
+            assertTrue(shouldFail);
+        }
+
+    }
+
+    /**
+     * Update target module to export a package to the given module.
+     */
+    static void targetAddExports(String pn, Module who) throws Exception {
+        Class<?> helper = Class.forName("p.Helper");
+        Method m = helper.getMethod("exportPackage", String.class, Module.class);
+        m.invoke(null, pn, who);
+    }
+
+
+    static void assertTrue(boolean expr) {
+        if (!expr) throw new RuntimeException();
+    }
+
+    static void assertFalse(boolean expr) {
+        assertTrue(!expr);
+    }
+}
--- a/test/java/lang/reflect/Proxy/Basic1.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/lang/reflect/Proxy/Basic1.java	Thu Mar 17 19:04:16 2016 +0000
@@ -108,7 +108,7 @@
              * Verify that its protection domain is the bootstrap domain.
              */
             ProtectionDomain pd = proxyClass.getProtectionDomain();
-            System.err.println("+ proxy class's protextion domain: " + pd);
+            System.err.println("+ proxy class's protection domain: " + pd);
             if (!pd.implies(new AllPermission())) {
                 throw new RuntimeException(
                     "proxy class does not have AllPermission");
@@ -143,7 +143,7 @@
             /*
              * Invoke a method on a proxy instance.
              */
-            Method m = Runnable.class.getMethod("run", null);
+            Method m = Runnable.class.getMethod("run");
             ((Runnable) proxy).run();
             if (!handler.lastMethod.equals(m)) {
                 throw new RuntimeException(
--- a/test/java/lang/reflect/Proxy/NullClassLoader.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/lang/reflect/Proxy/NullClassLoader.java	Thu Mar 17 19:04:16 2016 +0000
@@ -42,8 +42,8 @@
             "\nTest creating proxy class with the null class loader.\n");
 
         try {
-            Class p = Proxy.getProxyClass(null,
-                new Class[] { Runnable.class, Observer.class });
+            ClassLoader ld = null;
+            Class p = Proxy.getProxyClass(ld, new Class[] { Runnable.class, Observer.class });
             System.err.println("proxy class: " + p);
 
             ClassLoader loader = p.getClassLoader();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Proxy/ProxyClassAccessTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.lang.module.Configuration;
+import java.lang.module.ModuleFinder;
+import java.lang.reflect.Layer;
+import java.lang.reflect.Proxy;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.List;
+
+import static jdk.testlibrary.ProcessTools.executeTestJava;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/**
+ * @test
+ * @library /lib/testlibrary
+ * @modules jdk.compiler
+ * @build ProxyClassAccessTest q.NP CompilerUtils jdk.testlibrary.*
+ * @run testng ProxyClassAccessTest
+ * @summary Driver for testing proxy class doesn't have access to
+ *          types referenced by proxy interfaces
+ */
+
+public class ProxyClassAccessTest {
+
+    private static final String TEST_SRC = System.getProperty("test.src");
+    private static final String TEST_CLASSES = System.getProperty("test.classes");
+
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path MODS_DIR = Paths.get("mods");
+
+    // the names of the modules in this test
+    private static List<String> modules = Arrays.asList("m1", "m2", "m3", "test");
+
+    /**
+     * Compiles all modules used by the test
+     */
+    @BeforeTest
+    public void compileAll() throws Exception {
+        for (String mn : modules) {
+            Path msrc = SRC_DIR.resolve(mn);
+            assertTrue(CompilerUtils.compile(msrc, MODS_DIR, "-modulesourcepath", SRC_DIR.toString()));
+        }
+    }
+
+    /**
+     * Run the modular test
+     */
+    @Test
+    public void runTest() throws Exception {
+        int exitValue = executeTestJava("-mp", MODS_DIR.toString(),
+                                        "-m", "test/jdk.test.ProxyClassAccess")
+                            .outputTo(System.out)
+                            .errorTo(System.out)
+                            .getExitValue();
+
+        assertTrue(exitValue == 0);
+    }
+
+    /**
+     * Test unnamed module has no access to other proxy interface
+     */
+    @Test
+    public void testNoReadAccess() throws Exception {
+        ModuleFinder finder = ModuleFinder.of(MODS_DIR);
+        Layer bootLayer = Layer.boot();
+        Configuration cf = bootLayer
+                .configuration()
+                .resolveRequiresAndUses(ModuleFinder.empty(), finder, modules);
+        ClassLoader parentLoader = this.getClass().getClassLoader();
+        Layer layer = bootLayer.defineModulesWithOneLoader(cf, parentLoader);
+
+        ClassLoader loader = layer.findLoader("m1");
+        Class<?>[] interfaces = new Class<?>[] {
+                Class.forName("p.one.I", false, loader),
+                Class.forName("q.NP", false, loader)     // non-public interface in unnamed module
+        };
+        checkIAE(loader, interfaces);
+    }
+
+    private void checkIAE(ClassLoader loader, Class<?>[] interfaces) {
+        try {
+            Proxy.getProxyClass(loader, interfaces);
+            throw new RuntimeException("Expected IllegalArgumentException thrown");
+        } catch (IllegalArgumentException e) {}
+
+        try {
+            Proxy.newProxyInstance(loader, interfaces,
+                (proxy, m, params) -> { throw new RuntimeException(m.toString()); });
+            throw new RuntimeException("Expected IllegalArgumentException thrown");
+        } catch (IllegalArgumentException e) {}
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Proxy/ProxyForMethodHandle.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandleProxies;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Module;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/**
+ * @test
+ * @summary test MethodHandleProxies that adds qualified export of sun.invoke
+ * from java.base to a dynamic module
+ * @run testng ProxyForMethodHandle
+ */
+public class ProxyForMethodHandle {
+    /**
+     * MethodHandleProxies will add qualified export of sun.invoke from java.base
+     * to a dynamic module
+     */
+    @Test
+    static void testRunnableMethodHandle() throws Exception {
+        MethodHandles.Lookup lookup = MethodHandles.lookup();
+        MethodType mt = MethodType.methodType(void.class);
+        MethodHandle mh = lookup.findStatic(ProxyForMethodHandle.class, "runForRunnable", mt);
+        Runnable proxy = MethodHandleProxies.asInterfaceInstance(Runnable.class, mh);
+        proxy.run();
+
+        Class<?> proxyClass = proxy.getClass();
+        Module target = proxyClass.getModule();
+        assertDynamicModule(target, proxyClass.getClassLoader(), proxyClass);
+    }
+
+    static void runForRunnable() {
+        System.out.println("runForRunnable");
+    }
+
+    public static void assertDynamicModule(Module m, ClassLoader ld, Class<?> proxyClass) {
+        if (!m.isNamed() || !m.getName().startsWith("jdk.proxy")) {
+            throw new RuntimeException(m.getName() + " not dynamic module");
+        }
+
+        if (ld != m.getClassLoader() || proxyClass.getClassLoader() != ld) {
+            throw new RuntimeException("unexpected class loader");
+        }
+
+        try {
+            Constructor<?> cons = proxyClass.getConstructor(InvocationHandler.class);
+            cons.newInstance(handler);
+            throw new RuntimeException("Expected IllegalAccessException: " + proxyClass);
+        } catch (IllegalAccessException e) {
+            // expected
+        } catch (NoSuchMethodException|InstantiationException|InvocationTargetException e) {
+            throw new RuntimeException(e);
+        }
+    }
+    private final static InvocationHandler handler =
+            (proxy, m, params) -> { throw new RuntimeException(m.toString()); };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Proxy/ProxyLayerTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.lang.module.Configuration;
+import java.lang.module.ModuleFinder;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Layer;
+import java.lang.reflect.Proxy;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+
+import static jdk.testlibrary.ProcessTools.executeTestJava;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/**
+ * @test
+ * @library /lib/testlibrary
+ * @modules jdk.compiler
+ * @build ProxyTest CompilerUtils jdk.testlibrary.ProcessTools
+ * @run testng ProxyLayerTest
+ * @summary Test proxies to implement interfaces in a layer
+ */
+
+public class ProxyLayerTest {
+
+    private static final String TEST_SRC = System.getProperty("test.src");
+    private static final String TEST_CLASSES = System.getProperty("test.classes");
+
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path MODS_DIR = Paths.get("mods");
+    private static final Path CPATH_DIR = Paths.get(TEST_CLASSES);
+
+    // the names of the modules in this test
+    private static String[] modules = new String[] {"m1", "m2", "m3"};
+
+
+    /**
+     * Compiles all modules used by the test
+     */
+    @BeforeTest
+    public void compileAll() throws Exception {
+        for (String mn : modules) {
+            Path msrc = SRC_DIR.resolve(mn);
+            assertTrue(CompilerUtils.compile(msrc, MODS_DIR, "-modulesourcepath", SRC_DIR.toString()));
+        }
+    }
+
+    /**
+     * Test proxy implementing interfaces in a Layer defined in
+     * an unnamed module
+     */
+    @Test
+    public void testProxyInUnnamed() throws Exception {
+        ModuleFinder finder = ModuleFinder.of(MODS_DIR);
+        Layer bootLayer = Layer.boot();
+        Configuration cf = bootLayer
+                .configuration()
+                .resolveRequiresAndUses(ModuleFinder.empty(), finder, Arrays.asList(modules));
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+        Layer layer = bootLayer.defineModulesWithOneLoader(cf, scl);
+
+        ClassLoader loader = layer.findLoader("m1");
+
+        assertTrue(layer.findModule("m1").isPresent());
+        assertTrue(layer.findModule("m2").isPresent());
+        assertTrue(layer.findModule("m3").isPresent());
+
+        Class<?>[] interfaces = new Class<?>[] {
+            Class.forName("p.one.I", false, loader),
+            Class.forName("p.two.A", false, loader),
+            Class.forName("p.three.P", false, loader),
+        };
+        Object o = Proxy.newProxyInstance(loader, interfaces, handler);
+
+        Class<?> proxyClass = o.getClass();
+        Package pkg = proxyClass.getPackage();
+        assertFalse(proxyClass.getModule().isNamed());
+        assertFalse(pkg.isSealed());
+        assertEquals(proxyClass.getModule().getLayer(), null);
+    }
+
+    /**
+     * Test proxy implementing interfaces in a Layer and defined in a
+     * dynamic module
+     */
+    @Test
+    public void testProxyInDynamicModule() throws Exception {
+        ModuleFinder finder = ModuleFinder.of(MODS_DIR);
+        Layer bootLayer = Layer.boot();
+        Configuration cf = bootLayer
+                .configuration()
+                .resolveRequiresAndUses(ModuleFinder.empty(), finder, Arrays.asList(modules));
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+        Layer layer = bootLayer.defineModulesWithOneLoader(cf, scl);
+
+        ClassLoader loader = layer.findLoader("m1");
+
+        assertTrue(layer.findModule("m1").isPresent());
+        assertTrue(layer.findModule("m2").isPresent());
+        assertTrue(layer.findModule("m3").isPresent());
+
+        Class<?>[] interfaces = new Class<?>[] {
+            Class.forName("p.one.internal.J", false, loader),
+        };
+        Object o = Proxy.newProxyInstance(loader, interfaces, handler);
+        Class<?> proxyClass = o.getClass();
+        Package pkg = proxyClass.getPackage();
+        assertTrue(proxyClass.getModule().isNamed());
+        assertTrue(pkg.isSealed());
+        assertEquals(proxyClass.getModule().getLayer(), null);
+    }
+
+    /**
+     * Test proxy implementing interfaces that the target module has no access
+     */
+    @Test
+    public void testNoReadAccess() throws Exception {
+        ModuleFinder finder = ModuleFinder.of(MODS_DIR);
+        Layer bootLayer = Layer.boot();
+        Configuration cf = bootLayer
+                .configuration()
+                .resolveRequiresAndUses(ModuleFinder.empty(), finder, Arrays.asList(modules));
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+        Layer layer = bootLayer.defineModulesWithOneLoader(cf, scl);
+
+        ClassLoader loader = layer.findLoader("m1");
+
+        assertTrue(layer.findModule("m1").isPresent());
+        assertTrue(layer.findModule("m2").isPresent());
+        assertTrue(layer.findModule("m3").isPresent());
+
+        Class<?>[] interfaces = new Class<?>[] {
+                Class.forName("p.one.I", false, loader),
+                Class.forName("p.two.B", false, loader)   // non-public interface but exported package
+        };
+        checkIAE(loader, interfaces);
+    }
+
+    private void checkIAE(ClassLoader loader, Class<?>[] interfaces) {
+        try {
+            Proxy.getProxyClass(loader, interfaces);
+            throw new RuntimeException("Expected IllegalArgumentException thrown");
+        } catch (IllegalArgumentException e) {}
+
+        try {
+            Proxy.newProxyInstance(loader, interfaces, handler);
+            throw new RuntimeException("Expected IllegalArgumentException thrown");
+        } catch (IllegalArgumentException e) {}
+    }
+
+    private final static InvocationHandler handler =
+            (proxy, m, params) -> { throw new RuntimeException(m.toString()); };
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Proxy/ProxyModuleMapping.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Module;
+import java.lang.reflect.Proxy;
+
+/*
+ * @test
+ * @summary Basic test of proxy module mapping and the access to Proxy class
+ * @modules java.base/sun.invoke
+ */
+
+public class ProxyModuleMapping {
+    public static void main(String... args) throws Exception {
+        ClassLoader ld = ProxyModuleMapping.class.getClassLoader();
+        Module unnamed = ld.getUnnamedModule();
+        new ProxyModuleMapping(unnamed, Runnable.class).test();
+
+        // unnamed module gets access to sun.invoke package (e.g. via -XaddExports)
+        new ProxyModuleMapping(sun.invoke.WrapperInstance.class).test();
+
+        Class<?> modulePrivateIntf = Class.forName("sun.net.ProgressListener");
+        new ProxyModuleMapping(modulePrivateIntf).test();
+    }
+
+    final Module target;
+    final ClassLoader loader;
+    final Class<?>[] interfaces;
+    ProxyModuleMapping(Module m, Class<?>... interfaces) {
+        this.target = m;
+        this.loader = m.getClassLoader();
+        this.interfaces = interfaces;
+    }
+
+    ProxyModuleMapping(Class<?>... interfaces) {
+        this.target = null;  // expected to be dynamic module
+        this.loader = interfaces[0].getClassLoader();   // same class loader
+        this.interfaces = interfaces;
+    }
+
+    void test() throws Exception {
+        verifyProxyClass();
+        verifyNewProxyInstance();
+    }
+
+    void verifyProxyClass() throws Exception {
+        Class<?> c = Proxy.getProxyClass(loader, interfaces);
+        Module m = c.getModule();
+        if (target != null && m != target) {
+            throw new RuntimeException(c.getModule() + " not expected: " + target);
+        }
+        // expect dynamic module
+        if (target == null && (!m.isNamed() || !m.getName().startsWith("jdk.proxy"))) {
+            throw new RuntimeException("Unexpected:" + m);
+        }
+
+        Module module = c.getModule();
+        try {
+            Constructor<?> cons = c.getConstructor(InvocationHandler.class);
+            cons.newInstance(ih);
+            if (module.isNamed()) {
+                throw new RuntimeException("expected IAE not thrown");
+            }
+        } catch (IllegalAccessException e) {
+            if (!module.isNamed()) {
+                throw e;
+            }
+        }
+    }
+
+    void verifyNewProxyInstance() throws Exception {
+        Object o = Proxy.newProxyInstance(loader, interfaces, ih);
+        Module m = o.getClass().getModule();
+        if (target != null && m != target) {
+            throw new RuntimeException(m + " not expected: " + target);
+        }
+        if (target == null && (!m.isNamed() || !m.getName().startsWith("jdk.proxy"))) {
+            throw new RuntimeException(m + " not expected: dynamic module");
+        }
+    }
+    private final static InvocationHandler ih =
+        (proxy, m, params) -> { System.out.println(m); return null; };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Proxy/ProxyTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.List;
+
+import static jdk.testlibrary.ProcessTools.executeTestJava;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/**
+ * @test
+ * @library /lib/testlibrary
+ * @modules jdk.compiler
+ * @build ProxyTest q.U CompilerUtils jdk.testlibrary.*
+ * @run testng ProxyTest
+ * @summary Driver for testing proxies accessing interfaces in named modules
+ */
+
+public class ProxyTest {
+
+    private static final String TEST_SRC = System.getProperty("test.src");
+    private static final String TEST_CLASSES = System.getProperty("test.classes");
+
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path MODS_DIR = Paths.get("mods");
+    private static final Path CPATH_DIR = Paths.get(TEST_CLASSES);
+
+    // the names of the modules in this test
+    private static List<String> modules = Arrays.asList("test", "m1", "m2", "m3");
+
+
+    /**
+     * Compiles all modules used by the test
+     */
+    @BeforeTest
+    public void compileAll() throws Exception {
+        for (String mn : modules) {
+            Path msrc = SRC_DIR.resolve(mn);
+            assertTrue(CompilerUtils.compile(msrc, MODS_DIR, "-modulesourcepath", SRC_DIR.toString()));
+        }
+    }
+
+    /**
+     * Run the modular test
+     */
+    @Test
+    public void runTest() throws Exception {
+        int exitValue = executeTestJava("-cp", CPATH_DIR.toString(),
+                                        "-mp", MODS_DIR.toString(),
+                                        "-m", "test/jdk.test.Main")
+                            .outputTo(System.out)
+                            .errorTo(System.out)
+                            .getExitValue();
+
+        assertTrue(exitValue == 0);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Proxy/q/NP.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package q;
+
+interface NP {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Proxy/q/U.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package q;
+
+public interface U {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Proxy/src/m1/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m1 {
+    exports p.one;
+    exports p.one.internal to test;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Proxy/src/m1/p/one/I.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p.one;
+
+public interface I {
+    void run();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Proxy/src/m1/p/one/internal/J.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p.one.internal;
+
+public interface J {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Proxy/src/m2/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m2 {
+    exports p.two;
+    exports p.two.internal to test;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Proxy/src/m2/p/two/A.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p.two;
+
+public interface A {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Proxy/src/m2/p/two/B.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p.two;
+
+interface B {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Proxy/src/m2/p/two/Bar.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p.two;
+
+public class Bar {
+    public Bar() {
+    }
+
+    @Override
+    public String toString() {
+        return this.getClass().getName();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Proxy/src/m2/p/two/internal/C.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p.two.internal;
+
+public interface C {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Proxy/src/m3/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m3 {
+    requires public m2;
+    exports p.three;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Proxy/src/m3/p/three/P.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p.three;
+
+import p.two.Bar;
+
+public interface P {
+    public Bar bar();
+
+    public Bar[][][] barArrays();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Proxy/src/m3/p/three/internal/Q.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p.three.internal;
+
+public interface Q {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Proxy/src/test/jdk/test/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.lang.reflect.Module;
+import static jdk.test.ProxyTest.*;
+
+public class Main {
+    public static void main(String... args) {
+        ProxyTest ptest = new jdk.test.ProxyTest();
+        for (Data d : proxiesForExportedTypes()) {
+            ptest.test(d);
+        }
+
+        for (Data d : proxiesForPackagePrivateTypes()) {
+            ptest.test(d);
+        }
+
+        for (Data d : proxiesForModulePrivateTypes()) {
+            ptest.test(d);
+        }
+
+        for (Data d : proxiesWithAddReads()) {
+            ptest.test(d);
+        }
+
+        for (Data d : proxiesWithAddExports()) {
+            ptest.test(d);
+        }
+    }
+
+    private final static Module m1 = p.one.I.class.getModule();
+    private final static Module m2 = p.two.A.class.getModule();
+    private final static Module m3 = p.three.P.class.getModule();
+    private final static Module test = Main.class.getModule();
+    private final static Class<?> unnamedModuleClass = classForName("q.U");
+    private final static Class<?> m3InternalType = classForName("p.three.internal.Q");
+
+    /*
+     * Test cases for proxy class to implement exported proxy interfaces
+     * will result in the unnamed module.
+     *
+     * The proxy class is accessible to unnamed module.
+     */
+    static Data[] proxiesForExportedTypes() {
+        ClassLoader ld = Main.class.getClassLoader();
+        Module unnamed = ld.getUnnamedModule();
+        ClassLoader ld2 = new URLClassLoader(new URL[0], ld);
+        Module unnamed2 = ld2.getUnnamedModule();
+
+        return new Data[] {
+            new Data(unnamed,  ld, Runnable.class),
+            new Data(unnamed,  ld, p.one.I.class),
+            new Data(unnamed,  ld, p.one.I.class, p.two.A.class),
+            new Data(unnamed,  ld, p.one.I.class, unnamedModuleClass),
+            new Data(unnamed2, ld2, Runnable.class),
+            new Data(unnamed2, ld2, p.one.I.class),
+            new Data(unnamed2, ld2, p.one.I.class, p.two.A.class),
+            new Data(unnamed2, ld2, p.one.I.class, unnamedModuleClass),
+            new Data(unnamed, m1.getClassLoader(), p.one.I.class),
+            new Data(unnamed, m2.getClassLoader(), p.two.A.class),
+            new Data(unnamed, m3.getClassLoader(), p.three.P.class),
+        };
+    }
+
+    /*
+     * Test cases for proxy class to implement package-private proxy interface
+     * will result in same runtime package and same module as the proxy interface
+     *
+     * The proxy class is accessible to classes in the same runtime package
+     */
+    static Data[] proxiesForPackagePrivateTypes() {
+        Class<?> bClass = classForName("p.two.B");  // package-private type
+
+        return new Data[] {
+            new Data(m2, m2.getClassLoader(), p.two.A.class, bClass),
+            new Data(m2, m2.getClassLoader(), p.two.A.class, bClass, p.two.internal.C.class)
+        };
+    }
+
+    /*
+     * Test cases for proxy class to implement one or more module-private types.
+     *
+     * This will result in a dynamic module which can read the modules of the interfaces
+     * and their dependences and also qualified exports to the module-private packages.
+     * The proxy class is not accessible to any module.
+     */
+    static Data[] proxiesForModulePrivateTypes() {
+        ClassLoader ld = Main.class.getClassLoader();
+        ClassLoader customLoader = new URLClassLoader(new URL[0], ld);
+        return new Data[] {
+            // different loaders
+            new Data(m1.getClassLoader(), p.one.internal.J.class),
+            new Data(customLoader, p.one.internal.J.class),
+            new Data(m2.getClassLoader(), p.two.internal.C.class, Runnable.class),
+            // interfaces from m2 only
+            new Data(m2.getClassLoader(), p.two.internal.C.class, p.two.A.class),
+            // p.two.A is accessible to m3
+            new Data(m3.getClassLoader(), m3InternalType, p.two.A.class),
+            new Data(customLoader, unnamedModuleClass, jdk.test.internal.R.class, p.one.I.class),
+            // two module-private types in two different modules
+            new Data(m3.getClassLoader(), p.two.internal.C.class, m3InternalType),
+            new Data(m3.getClassLoader(), p.three.P.class, m3InternalType, jdk.test.internal.R.class),
+        };
+    }
+
+    /*
+     * Test cases for proxy class to implement accessible proxy interfaces
+     * after addReads. That does not change the target module.
+     */
+    static Data[] proxiesWithAddReads() {
+        Module unnamed = test.getClassLoader().getUnnamedModule();
+        test.addReads(unnamed);
+        return new Data[] {
+             new Data(test.getClassLoader(),
+                      unnamedModuleClass, p.one.I.class,
+                      jdk.test.internal.R.class), // module-private interface in test
+        };
+    }
+
+    /*
+     * Test cases for proxy class to implement accessible proxy interfaces
+     * after addExports.  That does not change the target module.
+     */
+    static Data[] proxiesWithAddExports() {
+        return new Data[] {
+                new Data(test.getClassLoader(),
+                         p.one.internal.J.class,
+                         p.two.internal.C.class), // module-private interfaces in m2 and m3
+        };
+    }
+
+    static Class<?> classForName(String cn) {
+        try {
+            return Class.forName(cn);
+        } catch (ClassNotFoundException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Proxy/src/test/jdk/test/NP.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test;
+
+/*
+ * Non-public interface
+ */
+interface NP {
+    void test();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Proxy/src/test/jdk/test/ProxyClassAccess.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test;
+
+import jdk.test.internal.*;
+import jdk.test.internal.foo.*;
+import p.two.Bar;
+import p.three.P;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.net.URL;
+import java.net.URLClassLoader;
+
+/**
+ * Test proxy class to have access to types referenced in the public methods.
+ */
+public class ProxyClassAccess {
+    public static void main(String... args) throws Exception {
+        testImplClass();
+        testProxyClass1();
+        testProxyClass2();
+        testNonPublicProxy();
+    }
+
+    /*
+     * Invoke methods from implementation class
+     */
+    static void testImplClass() {
+        R impl = new RImpl();
+        impl.foo();
+        Bar[][] bars = new Bar[0][0];
+        impl.setBarArray(bars);
+        try {
+            impl.throwException();
+            throw new RuntimeException("FooException not thrown");
+        } catch (FooException e) { }
+    }
+
+    /*
+     * Invoke methods via proxy
+     */
+    static void testProxyClass1() {
+        R proxy = (R) Proxy.newProxyInstance(R.class.getClassLoader(),
+                                             new Class<?>[] { R.class }, handler);
+        proxy.foo();
+        Bar[][] bars = new Bar[0][0];
+        proxy.setBarArray(bars);
+    }
+
+    /*
+     * Invoke methods via proxy defined with a custom class loader
+     */
+    static void testProxyClass2() {
+        URLClassLoader loader = new URLClassLoader(new URL[0]);
+        P proxy = (P) Proxy.newProxyInstance(loader,
+                new Class<?>[] { R.class, P.class }, handler);
+        proxy.bar();
+        proxy.barArrays();
+    }
+
+    static void testNonPublicProxy() {
+        NP proxy = (NP) Proxy.newProxyInstance(NP.class.getClassLoader(),
+                                               new Class<?>[]{NP.class}, handler);
+        proxy.test();
+
+        try {
+            URLClassLoader loader = new URLClassLoader(new URL[0]);
+            proxy = (NP) Proxy.newProxyInstance(loader,
+                    new Class<?>[]{NP.class}, handler);
+            throw new RuntimeException("IllegalArgumentException not thrown");
+        } catch (IllegalArgumentException e) {
+        }
+    }
+
+    static InvocationHandler handler = new InvocationHandler() {
+        final R impl = new RImpl();
+        @Override
+        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+            if (method.getDeclaringClass() == R.class) {
+                return method.invoke(impl, args);
+            } else {
+                return null;
+            }
+        }
+    };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Proxy/src/test/jdk/test/ProxyTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Module;
+import java.lang.reflect.Proxy;
+import java.util.Arrays;
+
+public class ProxyTest {
+    public static class Data {
+        private static int count = 0;
+        final int testcase;
+        final ClassLoader loader;
+        final Module module;
+        final Class<?>[] interfaces;
+        // Expected the proxy class in the specified module
+        public Data(Module m, ClassLoader loader, Class<?>... interfaces) {
+            this.module = m;
+            this.loader = loader;
+            this.interfaces = interfaces;
+            this.testcase = ++count;
+        }
+        // Expected the proxy class in a dynamic module
+        public Data(ClassLoader loader, Class<?>... interfaces) {
+            this(null, loader, interfaces);
+        }
+
+        @Override
+        public String toString() {
+            String expected = module != null
+                    ? (module.isNamed() ? module.getName() : "unnamed")
+                    : "dynamic";
+            return String.format("%2d: Expected: %s %s loader: %s", testcase, expected,
+                    Arrays.toString(interfaces), loader);
+        }
+    }
+
+    public void test(Data d) {
+        System.out.println(d);
+
+        if (d.module != null) {
+            testProxyClass(d.module, d.loader, d.interfaces);
+        } else {
+            testDynamicModule(d);
+        }
+    }
+
+    private void testDynamicModule(Data d) {
+        Class<?> proxyClass = Proxy.getProxyClass(d.loader, d.interfaces);
+        assertDynamicModule(proxyClass.getModule(), d.loader, proxyClass);
+
+        Object proxy = Proxy.newProxyInstance(d.loader, d.interfaces, handler);
+        assertDynamicModule(proxy.getClass().getModule(), d.loader, proxy.getClass());
+    }
+
+    private static void testProxyClass(Module module, ClassLoader ld, Class<?>... interfaces) {
+        Class<?> proxyClass = Proxy.getProxyClass(ld, interfaces);
+        assertEquals(proxyClass.getModule(), module);
+
+        Object proxy = Proxy.newProxyInstance(ld, interfaces, handler);
+        assertEquals(proxy.getClass().getModule(), module);
+    }
+
+    public static void assertDynamicModule(Module m, ClassLoader ld, Class<?> proxyClass) {
+        if (!m.isNamed() || !m.getName().startsWith("jdk.proxy")) {
+            throw new RuntimeException(m.getName() + " not dynamic module");
+        }
+
+        if (ld != m.getClassLoader() || proxyClass.getClassLoader() != ld) {
+            throw new RuntimeException("unexpected class loader");
+        }
+
+        try {
+            Constructor<?> cons = proxyClass.getConstructor(InvocationHandler.class);
+            cons.newInstance(handler);
+            throw new RuntimeException("Expected IllegalAccessException: " + proxyClass);
+        } catch (IllegalAccessException e) {
+            // expected
+        } catch (NoSuchMethodException|InstantiationException|InvocationTargetException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static void assertEquals(Object o1, Object o2) {
+        if (o1 != o2) {
+            throw new RuntimeException(o1 + " != " + o2);
+        }
+    }
+    private final static InvocationHandler handler =
+        (proxy, m, params) -> { throw new RuntimeException(m.toString()); };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Proxy/src/test/jdk/test/internal/R.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.internal;
+
+import jdk.test.internal.foo.*;
+import p.two.Bar;
+
+public interface R {
+    public Foo foo();
+    public void throwException() throws FooException;
+
+    public void setBarArray(Bar[][] array);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Proxy/src/test/jdk/test/internal/RImpl.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.internal;
+
+import jdk.test.internal.foo.*;
+import p.two.Bar;
+
+public class RImpl implements R {
+    public Foo foo() {
+        return new Foo();
+    }
+    public void throwException() throws FooException {
+        throw new FooException();
+    }
+    public void setBarArray(Bar[][] array) {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Proxy/src/test/jdk/test/internal/foo/Foo.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.internal.foo;
+
+public class Foo {
+    @Override
+    public String toString() {
+        return this.getClass().getName();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Proxy/src/test/jdk/test/internal/foo/FooException.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.internal.foo;
+
+public class FooException extends RuntimeException {
+    public FooException() {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/reflect/Proxy/src/test/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module test {
+    requires m1;
+    requires m3;   // requires public m2
+
+    exports jdk.test;
+}
--- a/test/java/net/Authenticator/B4933582.sh	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/net/Authenticator/B4933582.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -43,8 +43,12 @@
     exit 1;
     ;;
 esac
-${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . \
+
+EXTRAOPTS="-XaddExports:java.base/sun.net.www=ALL-UNNAMED,java.base/sun.net.www.protocol.http=ALL-UNNAMED"
+export EXTRAOPTS
+
+${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ${EXTRAOPTS} -d . \
     -classpath "${TESTSRC}${FS}..${FS}..${FS}..${FS}sun${FS}net${FS}www${FS}httptest" ${TESTSRC}${FS}B4933582.java
 rm -f cache.ser auth.save
-${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -classpath "${TESTSRC}${FS}..${FS}..${FS}..${FS}sun${FS}net${FS}www${FS}httptest${PS}." B4933582 first
-${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -classpath "${TESTSRC}${FS}..${FS}..${FS}..${FS}sun${FS}net${FS}www${FS}httptest${PS}." B4933582 second
+${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${EXTRAOPTS} -classpath "${TESTSRC}${FS}..${FS}..${FS}..${FS}sun${FS}net${FS}www${FS}httptest${PS}." B4933582 first
+${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${EXTRAOPTS} -classpath "${TESTSRC}${FS}..${FS}..${FS}..${FS}sun${FS}net${FS}www${FS}httptest${PS}." B4933582 second
--- a/test/java/net/DatagramSocket/SetDatagramSocketImplFactory/ADatagramSocket.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/net/DatagramSocket/SetDatagramSocketImplFactory/ADatagramSocket.java	Thu Mar 17 19:04:16 2016 +0000
@@ -25,8 +25,8 @@
  * @bug 4132931
  * @summary DatagramSocket should use a factory for its impl
  *
- * @build ADatagramSocket
- * @run shell ADatagramSocket.sh
+ * @compile/module=java.base java/net/MyDatagramSocketImplFactory.java
+ * @run main ADatagramSocket
  */
 import java.io.*;
 import java.net.*;
--- a/test/java/net/DatagramSocket/SetDatagramSocketImplFactory/ADatagramSocket.sh	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-#! /bin/sh
-
-#
-# Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-
-# set platform-dependent variables
-OS=`uname -s`
-case "$OS" in
-  SunOS | Darwin | AIX )
-    PATHSEP=":"
-    FILESEP="/"
-    ;;
-  Linux )
-    PATHSEP=":"
-    FILESEP="/"
-    ;;
-  CYGWIN* )
-    PATHSEP=";"
-    FILESEP="/"
-    ;;
-  Windows* )
-    PATHSEP=";"
-    FILESEP="\\"
-    ;;
-  * )
-    echo "Unrecognized system!"
-    exit 1;
-    ;;
-esac
-
-${TESTJAVA}${FILESEP}bin${FILESEP}java ${TESTVMOPTS} -Xbootclasspath/p:${TESTCLASSES} ADatagramSocket true
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/net/DatagramSocket/SetDatagramSocketImplFactory/java.base/java/net/MyDatagramSocketImplFactory.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+public class MyDatagramSocketImplFactory implements DatagramSocketImplFactory {
+  public DatagramSocketImpl createDatagramSocketImpl() {
+    try {
+        return DefaultDatagramSocketImplFactory.createDatagramSocketImpl(false);
+    } catch (SocketException se) {
+        assert false;
+    }
+
+    return null;
+  }
+}
--- a/test/java/net/DatagramSocket/SetDatagramSocketImplFactory/java/net/MyDatagramSocketImplFactory.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package java.net;
-
-public class MyDatagramSocketImplFactory implements DatagramSocketImplFactory {
-  public DatagramSocketImpl createDatagramSocketImpl() {
-    try {
-        return DefaultDatagramSocketImplFactory.createDatagramSocketImpl(false);
-    } catch (SocketException se) {
-        assert false;
-    }
-
-    return null;
-  }
-}
--- a/test/java/net/NetworkInterface/NetworkInterfaceStreamTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/net/NetworkInterface/NetworkInterfaceStreamTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -24,8 +24,8 @@
 /* @test
  * @bug 8081678 8131155
  * @summary Tests for stream returning methods
- * @library ../../util/stream/bootlib/java.base
- * @build java.util.stream.OpTestCase
+ * @library ../../util/stream/bootlib
+ * @build java.base/java.util.stream.OpTestCase
  * @run testng/othervm NetworkInterfaceStreamTest
  * @run testng/othervm -Djava.net.preferIPv4Stack=true NetworkInterfaceStreamTest
  * @key intermittent
--- a/test/java/net/URI/URItoURLTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/net/URI/URItoURLTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -38,9 +38,7 @@
 
     public static void main(String args[]) throws Exception {
 
-        URItoURLTest testClass = new URItoURLTest();
-        URL classUrl = testClass.getClass().
-                                    getResource("/java/lang/Object.class");
+        URL classUrl = new URL("jrt:/java.base/java/lang/Object.class");
 
         String[] uris = {
                         "mailto:xyz@abc.de",
--- a/test/java/net/URLPermission/nstest/lookup.sh	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/net/URLPermission/nstest/lookup.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -24,6 +24,7 @@
 
 # @test
 # @library /lib/testlibrary
+# @modules java.base/sun.net.spi.nameservice
 # @build jdk.testlibrary.*
 # @compile -XDignore.symbol.file=true SimpleNameService.java
 #            LookupTest.java SimpleNameServiceDescriptor.java
@@ -57,6 +58,7 @@
 POLICY
 
 ${TESTJAVA}/bin/java ${TESTVMOPTS} \
+    -XaddExports:java.base/sun.net.spi.nameservice=ALL-UNNAMED \
     -Djava.security.policy=file:./policy \
     -Dsun.net.spi.nameservice.provider.1=simple,sun \
     -cp ${TESTCLASSPATH}${PS}${TESTSRC} LookupTest -runtest ${port}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/net/httpclient/whitebox/Driver.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8151299
+ * @run testng java.httpclient/java.net.http.SelectorTest
+ */
--- a/test/java/net/httpclient/whitebox/TEST.properties	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-TestNG.dirs = .
-
-bootclasspath.dirs = /java/net/httpclient
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/net/httpclient/whitebox/java.httpclient/java/net/http/SelectorTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net.http;
+
+import java.net.*;
+import java.io.*;
+import java.nio.channels.*;
+import java.nio.ByteBuffer;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicInteger;
+import static java.lang.System.out;
+import static java.nio.charset.StandardCharsets.US_ASCII;
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import org.testng.annotations.Test;
+
+/**
+ * Whitebox test of selector mechanics. Currently only a simple test
+ * setting one read and one write event is done. It checks that the
+ * write event occurs first, followed by the read event and then no
+ * further events occur despite the conditions actually still existing.
+ */
+@Test
+public class SelectorTest {
+
+    AtomicInteger counter = new AtomicInteger();
+    volatile boolean error;
+    static final CountDownLatch finishingGate = new CountDownLatch(1);
+
+    String readSomeBytes(RawChannel chan) {
+        try {
+            ByteBuffer buf = ByteBuffer.allocate(1024);
+            int t = chan.read(buf);
+            if (t <= 0) {
+                out.printf("chan read returned %d\n", t);
+                return null;
+            }
+            byte[] bb = new byte[t];
+            buf.get(bb);
+            return new String(bb, US_ASCII);
+        } catch (IOException ioe) {
+            throw new UncheckedIOException(ioe);
+        }
+    }
+
+    @Test(timeOut = 10000)
+    public void test() throws Exception {
+
+        try (ServerSocket server = new ServerSocket(0)) {
+            int port = server.getLocalPort();
+
+            out.println("Listening on port " + server.getLocalPort());
+
+            TestServer t = new TestServer(server);
+            t.start();
+            out.println("Started server thread");
+
+            final RawChannel chan = getARawChannel(port);
+
+            chan.registerEvent(new RawChannel.NonBlockingEvent() {
+                @Override
+                public int interestOps() {
+                    return SelectionKey.OP_READ;
+                }
+
+                @Override
+                public void handle() {
+                    readSomeBytes(chan);
+                    out.printf("OP_READ\n");
+                    if (counter.get() != 1) {
+                        out.printf("OP_READ error counter = %d\n", counter);
+                        error = true;
+                    }
+                }
+            });
+
+            chan.registerEvent(new RawChannel.NonBlockingEvent() {
+                @Override
+                public int interestOps() {
+                    return SelectionKey.OP_WRITE;
+                }
+
+                @Override
+                public void handle() {
+                    out.printf("OP_WRITE\n");
+                    if (counter.get() != 0) {
+                        out.printf("OP_WRITE error counter = %d\n", counter);
+                        error = true;
+                    } else {
+                        ByteBuffer bb = ByteBuffer.wrap(TestServer.INPUT);
+                        counter.incrementAndGet();
+                        try {
+                            chan.write(bb);
+                        } catch (IOException e) {
+                            throw new UncheckedIOException(e);
+                        }
+                    }
+                }
+
+            });
+            out.println("Events registered. Waiting");
+            finishingGate.await(30, SECONDS);
+            if (error)
+                throw new RuntimeException("Error");
+            else
+                out.println("No error");
+        }
+    }
+
+    static RawChannel getARawChannel(int port) throws Exception {
+        URI uri = URI.create("http://127.0.0.1:" + port + "/");
+        out.println("client connecting to " + uri.toString());
+        HttpRequest req = HttpRequest.create(uri).GET();
+        HttpResponse r = req.response();
+        r.body(HttpResponse.ignoreBody());
+        return ((HttpResponseImpl) r).rawChannel();
+    }
+
+    static class TestServer extends Thread {
+        static final byte[] INPUT = "Hello world".getBytes(US_ASCII);
+        static final byte[] OUTPUT = "Goodbye world".getBytes(US_ASCII);
+        static final String FIRST_RESPONSE = "HTTP/1.1 200 OK\r\nContent-length: 0\r\n\r\n";
+        final ServerSocket server;
+
+        TestServer(ServerSocket server) throws IOException {
+            this.server = server;
+        }
+
+        public void run() {
+            try (Socket s = server.accept();
+                 InputStream is = s.getInputStream();
+                 OutputStream os = s.getOutputStream()) {
+
+                out.println("Got connection");
+                readRequest(is);
+                os.write(FIRST_RESPONSE.getBytes());
+                read(is);
+                write(os);
+                Thread.sleep(1000);
+                // send some more data, and make sure WRITE op does not get called
+                write(os);
+                out.println("TestServer exiting");
+                SelectorTest.finishingGate.countDown();
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+
+        // consumes the HTTP request
+        static void readRequest(InputStream is) throws IOException {
+            out.println("starting readRequest");
+            byte[] buf = new byte[1024];
+            String s = "";
+            while (true) {
+                int n = is.read(buf);
+                if (n <= 0)
+                    throw new IOException("Error");
+                s = s + new String(buf, 0, n);
+                if (s.indexOf("\r\n\r\n") != -1)
+                    break;
+            }
+            out.println("returning from readRequest");
+        }
+
+        static void read(InputStream is) throws IOException {
+            out.println("starting read");
+            for (int i = 0; i < INPUT.length; i++) {
+                int c = is.read();
+                if (c == -1)
+                    throw new IOException("closed");
+                if (INPUT[i] != (byte) c)
+                    throw new IOException("Error. Expected:" + INPUT[i] + ", got:" + c);
+            }
+            out.println("returning from read");
+        }
+
+        static void write(OutputStream os) throws IOException {
+            out.println("doing write");
+            os.write(OUTPUT);
+        }
+    }
+}
--- a/test/java/net/httpclient/whitebox/java/net/http/SelectorTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,208 +0,0 @@
-/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/**
- * @test
- * @bug 8151299
- * @summary Http client SelectorManager overwriting read and write events
- */
-package java.net.http;
-
-import java.net.*;
-import java.io.*;
-import java.nio.channels.*;
-import java.nio.ByteBuffer;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.atomic.AtomicInteger;
-import static java.lang.System.out;
-import static java.nio.charset.StandardCharsets.US_ASCII;
-import static java.util.concurrent.TimeUnit.SECONDS;
-
-import org.testng.annotations.Test;
-
-/**
- * Whitebox test of selector mechanics. Currently only a simple test
- * setting one read and one write event is done. It checks that the
- * write event occurs first, followed by the read event and then no
- * further events occur despite the conditions actually still existing.
- */
-@Test
-public class SelectorTest {
-
-    AtomicInteger counter = new AtomicInteger();
-    volatile boolean error;
-    static final CountDownLatch finishingGate = new CountDownLatch(1);
-
-    String readSomeBytes(RawChannel chan) {
-        try {
-            ByteBuffer buf = ByteBuffer.allocate(1024);
-            int t = chan.read(buf);
-            if (t <= 0) {
-                out.printf("chan read returned %d\n", t);
-                return null;
-            }
-            byte[] bb = new byte[t];
-            buf.get(bb);
-            return new String(bb, US_ASCII);
-        } catch (IOException ioe) {
-            throw new UncheckedIOException(ioe);
-        }
-    }
-
-    @Test(timeOut = 10000)
-    public void test() throws Exception {
-
-        try (ServerSocket server = new ServerSocket(0)) {
-            int port = server.getLocalPort();
-
-            out.println("Listening on port " + server.getLocalPort());
-
-            TestServer t = new TestServer(server);
-            t.start();
-            out.println("Started server thread");
-
-            final RawChannel chan = getARawChannel(port);
-
-            chan.registerEvent(new RawChannel.NonBlockingEvent() {
-                @Override
-                public int interestOps() {
-                    return SelectionKey.OP_READ;
-                }
-
-                @Override
-                public void handle() {
-                    readSomeBytes(chan);
-                    out.printf("OP_READ\n");
-                    if (counter.get() != 1) {
-                        out.printf("OP_READ error counter = %d\n", counter);
-                        error = true;
-                    }
-                }
-            });
-
-            chan.registerEvent(new RawChannel.NonBlockingEvent() {
-                @Override
-                public int interestOps() {
-                    return SelectionKey.OP_WRITE;
-                }
-
-                @Override
-                public void handle() {
-                    out.printf("OP_WRITE\n");
-                    if (counter.get() != 0) {
-                        out.printf("OP_WRITE error counter = %d\n", counter);
-                        error = true;
-                    } else {
-                        ByteBuffer bb = ByteBuffer.wrap(TestServer.INPUT);
-                        counter.incrementAndGet();
-                        try {
-                            chan.write(bb);
-                        } catch (IOException e) {
-                            throw new UncheckedIOException(e);
-                        }
-                    }
-                }
-
-            });
-            out.println("Events registered. Waiting");
-            finishingGate.await(30, SECONDS);
-            if (error)
-                throw new RuntimeException("Error");
-            else
-                out.println("No error");
-        }
-    }
-
-    static RawChannel getARawChannel(int port) throws Exception {
-        URI uri = URI.create("http://127.0.0.1:" + port + "/");
-        out.println("client connecting to " + uri.toString());
-        HttpRequest req = HttpRequest.create(uri).GET();
-        HttpResponse r = req.response();
-        r.body(HttpResponse.ignoreBody());
-        return ((HttpResponseImpl) r).rawChannel();
-    }
-
-    static class TestServer extends Thread {
-        static final byte[] INPUT = "Hello world".getBytes(US_ASCII);
-        static final byte[] OUTPUT = "Goodbye world".getBytes(US_ASCII);
-        static final String FIRST_RESPONSE = "HTTP/1.1 200 OK\r\nContent-length: 0\r\n\r\n";
-        final ServerSocket server;
-
-        TestServer(ServerSocket server) throws IOException {
-            this.server = server;
-        }
-
-        public void run() {
-            try (Socket s = server.accept();
-                 InputStream is = s.getInputStream();
-                 OutputStream os = s.getOutputStream()) {
-
-                out.println("Got connection");
-                readRequest(is);
-                os.write(FIRST_RESPONSE.getBytes());
-                read(is);
-                write(os);
-                Thread.sleep(1000);
-                // send some more data, and make sure WRITE op does not get called
-                write(os);
-                out.println("TestServer exiting");
-                SelectorTest.finishingGate.countDown();
-            } catch (Exception e) {
-                e.printStackTrace();
-            }
-        }
-
-        // consumes the HTTP request
-        static void readRequest(InputStream is) throws IOException {
-            out.println("starting readRequest");
-            byte[] buf = new byte[1024];
-            String s = "";
-            while (true) {
-                int n = is.read(buf);
-                if (n <= 0)
-                    throw new IOException("Error");
-                s = s + new String(buf, 0, n);
-                if (s.indexOf("\r\n\r\n") != -1)
-                    break;
-            }
-            out.println("returning from readRequest");
-        }
-
-        static void read(InputStream is) throws IOException {
-            out.println("starting read");
-            for (int i = 0; i < INPUT.length; i++) {
-                int c = is.read();
-                if (c == -1)
-                    throw new IOException("closed");
-                if (INPUT[i] != (byte) c)
-                    throw new IOException("Error. Expected:" + INPUT[i] + ", got:" + c);
-            }
-            out.println("returning from read");
-        }
-
-        static void write(OutputStream os) throws IOException {
-            out.println("doing write");
-            os.write(OUTPUT);
-        }
-    }
-}
--- a/test/java/nio/Buffer/LimitDirectMemory.sh	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/nio/Buffer/LimitDirectMemory.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -27,8 +27,8 @@
 # @bug 4627316 6743526
 # @summary Test option to limit direct memory allocation
 #
+# @requires (os.arch == "x86_64") | (os.arch == "amd64") | (os.arch == "sparcv9")
 # @build LimitDirectMemory
-# @ignore JDK-8129343
 # @run shell LimitDirectMemory.sh
 
 TMP1=tmp_$$
--- a/test/java/nio/channels/spi/SelectorProvider/inheritedChannel/run_tests.sh	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/nio/channels/spi/SelectorProvider/inheritedChannel/run_tests.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -109,7 +109,8 @@
 
 go() {
     echo ''
-    sh -xc "$JAVA ${TESTVMOPTS} $DFLAG $1 $2 $3 $4 $5 $6 $7 $8" 2>&1
+    sh -xc "$JAVA ${TESTVMOPTS} -XaddExports:java.base/sun.nio.ch=ALL-UNNAMED $DFLAG \
+        $1 $2 $3 $4 $5 $6 $7 $8" 2>&1
     if [ $? != 0 ]; then failures=`expr $failures + 1`; fi
 }
 
--- a/test/java/nio/file/Files/StreamLinesTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/nio/file/Files/StreamLinesTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -23,8 +23,8 @@
 
 /* @test
  * @bug 8072773
- * @library /lib/testlibrary/ ../../../util/stream/bootlib/java.base
- * @build java.util.stream.OpTestCase
+ * @library /lib/testlibrary/ ../../../util/stream/bootlib
+ * @build java.base/java.util.stream.OpTestCase
  * @build jdk.testlibrary.RandomFactory
  * @run testng/othervm StreamLinesTest
  * @summary Tests streams returned from Files.lines, primarily focused on
--- a/test/java/nio/file/spi/SetDefaultProvider.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/nio/file/spi/SetDefaultProvider.java	Thu Mar 17 19:04:16 2016 +0000
@@ -25,7 +25,6 @@
  * @bug 4313887 7006126
  * @summary Unit test for java.nio.file.spi.FileSystemProvider
  * @build TestProvider SetDefaultProvider
- * @ignore JDK-8129343
  * @run main/othervm -Djava.nio.file.spi.DefaultFileSystemProvider=TestProvider SetDefaultProvider
  */
 
--- a/test/java/nio/file/spi/TestProvider.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/nio/file/spi/TestProvider.java	Thu Mar 17 19:04:16 2016 +0000
@@ -21,20 +21,34 @@
  * questions.
  */
 
-import java.nio.file.spi.FileSystemProvider;
+import java.io.File;
 import java.nio.file.*;
-import java.nio.file.attribute.*;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.nio.file.attribute.FileAttribute;
+import java.nio.file.attribute.FileAttributeView;
+import java.nio.file.attribute.UserPrincipalLookupService;
+import java.nio.file.spi.FileSystemProvider;
 import java.nio.channels.SeekableByteChannel;
 import java.net.URI;
-import java.util.*;
 import java.io.IOException;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
 
 public class TestProvider extends FileSystemProvider {
 
-    private final FileSystem theFileSystem;
+    private final FileSystemProvider defaultProvider;
+    private final TestFileSystem theFileSystem;
 
     public TestProvider(FileSystemProvider defaultProvider) {
-        theFileSystem = new TestFileSystem(this);
+        this.defaultProvider = defaultProvider;
+        FileSystem fs = defaultProvider.getFileSystem(URI.create("file:/"));
+        this.theFileSystem = new TestFileSystem(fs, this);
+    }
+
+    FileSystemProvider defaultProvider() {
+        return defaultProvider;
     }
 
     @Override
@@ -43,8 +57,8 @@
     }
 
     @Override
-    public FileSystem newFileSystem(URI uri, Map<String,?> env) {
-        throw new RuntimeException("not implemented");
+    public FileSystem newFileSystem(URI uri, Map<String,?> env) throws IOException {
+        return defaultProvider.newFileSystem(uri, env);
     }
 
     @Override
@@ -54,7 +68,8 @@
 
     @Override
     public Path getPath(URI uri) {
-        throw new RuntimeException("not implemented");
+        Path path = defaultProvider.getPath(uri);
+        return theFileSystem.wrap(path);
     }
 
     @Override
@@ -62,7 +77,7 @@
                              LinkOption... options)
         throws IOException
     {
-        throw new RuntimeException("not implemented");
+        throw new ReadOnlyFileSystemException();
     }
 
     @Override
@@ -70,7 +85,8 @@
                                              LinkOption... options)
         throws IOException
     {
-        throw new RuntimeException("not implemented");
+        Path delegate = theFileSystem.unwrap(file);
+        return defaultProvider.readAttributes(delegate, attributes, options);
     }
 
     @Override
@@ -79,7 +95,8 @@
                                                             LinkOption... options)
         throws IOException
     {
-        throw new RuntimeException("not implemented");
+        Path delegate = theFileSystem.unwrap(file);
+        return defaultProvider.readAttributes(delegate, type, options);
     }
 
     @Override
@@ -87,45 +104,46 @@
                                                                 Class<V> type,
                                                                 LinkOption... options)
     {
-        throw new RuntimeException("not implemented");
+        Path delegate = theFileSystem.unwrap(file);
+        return defaultProvider.getFileAttributeView(delegate, type, options);
     }
 
-
     @Override
     public void delete(Path file) throws IOException {
-        throw new RuntimeException("not implemented");
+        throw new ReadOnlyFileSystemException();
     }
 
     @Override
     public void createSymbolicLink(Path link, Path target, FileAttribute<?>... attrs)
         throws IOException
     {
-        throw new RuntimeException("not implemented");
+        throw new ReadOnlyFileSystemException();
     }
 
     @Override
     public void createLink(Path link, Path existing) throws IOException {
-        throw new RuntimeException("not implemented");
+        throw new ReadOnlyFileSystemException();
     }
 
     @Override
     public Path readSymbolicLink(Path link) throws IOException {
-        throw new RuntimeException("not implemented");
+        Path delegate = theFileSystem.unwrap(link);
+        Path target = defaultProvider.readSymbolicLink(delegate);
+        return theFileSystem.wrap(target);
     }
 
-
     @Override
     public void copy(Path source, Path target, CopyOption... options)
         throws IOException
     {
-        throw new RuntimeException("not implemented");
+        throw new ReadOnlyFileSystemException();
     }
 
     @Override
     public void move(Path source, Path target, CopyOption... options)
         throws IOException
     {
-        throw new RuntimeException("not implemented");
+        throw new ReadOnlyFileSystemException();
     }
 
     @Override
@@ -140,7 +158,7 @@
     public void createDirectory(Path dir, FileAttribute<?>... attrs)
         throws IOException
     {
-        throw new RuntimeException("not implemented");
+        throw new ReadOnlyFileSystemException();
     }
 
     @Override
@@ -149,13 +167,18 @@
                                               FileAttribute<?>... attrs)
         throws IOException
     {
+        if (options.contains(StandardOpenOption.READ) && options.size() == 1) {
+            Path delegate = theFileSystem.unwrap(file);
+            options = Collections.singleton(StandardOpenOption.READ);
+            return defaultProvider.newByteChannel(delegate, options, attrs);
+        }
+
         throw new RuntimeException("not implemented");
     }
 
-
     @Override
     public boolean isHidden(Path file) throws IOException {
-        throw new RuntimeException("not implemented");
+        throw new ReadOnlyFileSystemException();
     }
 
     @Override
@@ -176,12 +199,26 @@
     }
 
     static class TestFileSystem extends FileSystem {
+        private final FileSystem delegate;
         private final TestProvider provider;
 
-        TestFileSystem(TestProvider provider) {
+        TestFileSystem(FileSystem delegate, TestProvider provider) {
+            this.delegate = delegate;
             this.provider = provider;
         }
 
+        Path wrap(Path path) {
+            return (path != null) ? new TestPath(this, path) : null;
+        }
+
+        Path unwrap(Path wrapper) {
+            if (wrapper == null)
+                throw new NullPointerException();
+            if (!(wrapper instanceof TestPath))
+                throw new ProviderMismatchException();
+            return ((TestPath)wrapper).unwrap();
+        }
+
         @Override
         public FileSystemProvider provider() {
             return provider;
@@ -194,17 +231,17 @@
 
         @Override
         public boolean isOpen() {
-            throw new RuntimeException("not implemented");
+            return true;
         }
 
         @Override
         public boolean isReadOnly() {
-            throw new RuntimeException("not implemented");
+            return true;
         }
 
         @Override
         public String getSeparator() {
-            throw new RuntimeException("not implemented");
+            return delegate.getSeparator();
         }
 
         @Override
@@ -219,27 +256,209 @@
 
         @Override
         public Set<String> supportedFileAttributeViews() {
-            throw new RuntimeException("not implemented");
+            return delegate.supportedFileAttributeViews();
         }
 
         @Override
         public Path getPath(String first, String... more) {
-            throw new RuntimeException("not implemented");
+            Path path = delegate.getPath(first, more);
+            return wrap(path);
         }
 
         @Override
         public PathMatcher getPathMatcher(String syntaxAndPattern) {
-            throw new RuntimeException("not implemented");
+            return delegate.getPathMatcher(syntaxAndPattern);
         }
 
         @Override
         public UserPrincipalLookupService getUserPrincipalLookupService() {
-            throw new RuntimeException("not implemented");
+            return delegate.getUserPrincipalLookupService();
         }
 
         @Override
         public WatchService newWatchService() throws IOException {
-            throw new RuntimeException("not implemented");
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    static class TestPath implements Path {
+        private final TestFileSystem fs;
+        private final Path delegate;
+
+        TestPath(TestFileSystem fs, Path delegate) {
+            this.fs = fs;
+            this.delegate = delegate;
+        }
+
+        Path unwrap() {
+            return delegate;
+        }
+
+        @Override
+        public FileSystem getFileSystem() {
+            return fs;
+        }
+
+        @Override
+        public boolean isAbsolute() {
+            return delegate.isAbsolute();
+        }
+
+        @Override
+        public Path getRoot() {
+            return fs.wrap(delegate.getRoot());
+        }
+
+        @Override
+        public Path getParent() {
+            return fs.wrap(delegate.getParent());
+        }
+
+        @Override
+        public int getNameCount() {
+            return delegate.getNameCount();
+        }
+
+        @Override
+        public Path getFileName() {
+            return fs.wrap(delegate.getFileName());
+        }
+
+        @Override
+        public Path getName(int index) {
+            return fs.wrap(delegate.getName(index));
+        }
+
+        @Override
+        public Path subpath(int beginIndex, int endIndex) {
+            return fs.wrap(delegate.subpath(beginIndex, endIndex));
+        }
+
+        @Override
+        public boolean startsWith(Path other) {
+            return delegate.startsWith(fs.unwrap(other));
+        }
+
+        @Override
+        public boolean startsWith(String other) {
+            return delegate.startsWith(other);
+        }
+
+        @Override
+        public boolean endsWith(Path other) {
+            return delegate.endsWith(fs.unwrap(other));
+        }
+
+        @Override
+        public boolean endsWith(String other) {
+            return delegate.endsWith(other);
+        }
+
+        @Override
+        public Path normalize() {
+            return fs.wrap(delegate.normalize());
+        }
+
+        @Override
+        public Path resolve(Path other) {
+            return fs.wrap(delegate.resolve(fs.unwrap(other)));
+        }
+
+        @Override
+        public Path resolve(String other) {
+            return fs.wrap(delegate.resolve(other));
+        }
+
+        @Override
+        public Path resolveSibling(Path other) {
+            return fs.wrap(delegate.resolveSibling(fs.unwrap(other)));
+        }
+
+        @Override
+        public Path resolveSibling(String other) {
+            return fs.wrap(delegate.resolveSibling(other));
+        }
+
+        @Override
+        public Path relativize(Path other) {
+            return fs.wrap(delegate.relativize(fs.unwrap(other)));
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (!(other instanceof TestPath))
+                return false;
+            return delegate.equals(fs.unwrap((TestPath) other));
+        }
+
+        @Override
+        public int hashCode() {
+            return delegate.hashCode();
+        }
+
+        @Override
+        public String toString() {
+            return delegate.toString();
+        }
+
+        @Override
+        public URI toUri() {
+            String ssp = delegate.toUri().getSchemeSpecificPart();
+            return URI.create(fs.provider().getScheme() + ":" + ssp);
+        }
+
+        @Override
+        public Path toAbsolutePath() {
+            return fs.wrap(delegate.toAbsolutePath());
+        }
+
+        @Override
+        public Path toRealPath(LinkOption... options) throws IOException {
+            return fs.wrap(delegate.toRealPath(options));
+        }
+
+        @Override
+        public File toFile() {
+            return delegate.toFile();
+        }
+
+        @Override
+        public Iterator<Path> iterator() {
+            final Iterator<Path> itr = delegate.iterator();
+            return new Iterator<Path>() {
+                @Override
+                public boolean hasNext() {
+                    return itr.hasNext();
+                }
+                @Override
+                public Path next() {
+                    return fs.wrap(itr.next());
+                }
+                @Override
+                public void remove() {
+                    itr.remove();
+                }
+            };
+        }
+
+        @Override
+        public int compareTo(Path other) {
+            return delegate.compareTo(fs.unwrap(other));
+        }
+
+        @Override
+        public WatchKey register(WatchService watcher,
+                                 WatchEvent.Kind<?>[] events,
+                                 WatchEvent.Modifier... modifiers)
+        {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public  WatchKey register(WatchService watcher,
+                                  WatchEvent.Kind<?>... events)
+        {
+            throw new UnsupportedOperationException();
         }
     }
 }
--- a/test/java/rmi/activation/Activatable/extLoadedImpl/ext.sh	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/rmi/activation/Activatable/extLoadedImpl/ext.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -51,5 +51,6 @@
 mkdir -p ext
 $COMPILEJAVA/bin/jar ${TESTTOOLVMOPTS} cf ext/ext.jar -C $TESTCLASSES ExtLoadedImpl.class -C $TESTCLASSES ExtLoadedImpl_Stub.class -C $TESTCLASSES CheckLoader.class
 
+TESTVMOPTS="${TESTVMOPTS}  -XaddExports:java.rmi/sun.rmi.registry=ALL-UNNAMED,java.rmi/sun.rmi.server=ALL-UNNAMED,java.rmi/sun.rmi.transport=ALL-UNNAMED,java.rmi/sun.rmi.transport.tcp=ALL-UNNAMED"
 $TESTJAVA/bin/java ${TESTVMOPTS} -cp classes -Dtest.src=$TESTSRC -Dtest.classes=$TESTCLASSES -Djava.security.policy=$TESTSRC/security.policy -Djava.ext.dirs=ext ExtLoadedImplTest
 
--- a/test/java/rmi/activation/ActivationGroup/downloadActivationGroup/DownloadActivationGroup.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/rmi/activation/ActivationGroup/downloadActivationGroup/DownloadActivationGroup.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -41,13 +41,19 @@
  * @run main/othervm/policy=security.policy/timeout=240 DownloadActivationGroup
  */
 
-import java.io.*;
-import java.rmi.*;
-import java.net.*;
-import java.rmi.activation.*;
-import java.rmi.server.*;
-import java.rmi.registry.*;
-import java.util.Vector;
+import java.net.URL;
+import java.rmi.MarshalledObject;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.rmi.activation.Activatable;
+import java.rmi.activation.ActivationDesc;
+import java.rmi.activation.ActivationException;
+import java.rmi.activation.ActivationGroup;
+import java.rmi.activation.ActivationGroupDesc;
+import java.rmi.activation.ActivationGroupDesc.CommandEnvironment;
+import java.rmi.activation.ActivationGroupID;
+import java.rmi.activation.ActivationID;
+import java.rmi.server.UnicastRemoteObject;
 import java.util.Properties;
 
 public class DownloadActivationGroup
@@ -130,11 +136,16 @@
 
             Properties p = new Properties();
             p.put("java.security.policy", TestParams.defaultGroupPolicy);
+            CommandEnvironment cmd = new ActivationGroupDesc.CommandEnvironment(
+                    null,
+                    new String[] { "-XaddExports:java.rmi/sun.rmi.registry=ALL-UNNAMED,"
+                            + "java.rmi/sun.rmi.server=ALL-UNNAMED,java.rmi/sun.rmi.transport=ALL-UNNAMED,"
+                            + "java.rmi/sun.rmi.transport.tcp=ALL-UNNAMED" });
 
             ActivationGroupDesc groupDesc =
                 new ActivationGroupDesc("MyActivationGroupImpl",
                                         groupURL.toExternalForm(),
-                                        null, p, null);
+                                        null, p, cmd);
             ActivationGroupID groupID =
                 ActivationGroup.getSystem().registerGroup(groupDesc);
 
--- a/test/java/rmi/activation/ActivationSystem/stubClassesPermitted/StubClassesPermitted.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/rmi/activation/ActivationSystem/stubClassesPermitted/StubClassesPermitted.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -37,14 +37,20 @@
  * @run main/othervm/java.security.policy=security.policy/secure=java.lang.SecurityManager/timeout=240 StubClassesPermitted
  */
 
-import java.io.*;
-import java.rmi.*;
-import java.rmi.server.*;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.rmi.MarshalledObject;
+import java.rmi.RemoteException;
+import java.rmi.activation.Activatable;
+import java.rmi.activation.ActivationDesc;
+import java.rmi.activation.ActivationGroup;
+import java.rmi.activation.ActivationGroupDesc;
+import java.rmi.activation.ActivationGroupDesc.CommandEnvironment;
+import java.rmi.activation.ActivationGroupID;
+import java.rmi.activation.ActivationID;
+import java.rmi.activation.ActivationSystem;
 import java.rmi.registry.Registry;
-import java.rmi.activation.*;
-import java.security.CodeSource;
 import java.util.Properties;
-import java.util.StringTokenizer;
 
 /**
  * The RMI activation system needs to explicitly allow itself to
@@ -113,8 +119,13 @@
             // sun.rmi.server.Activation$ActivationMonitorImpl_Stub
             //
             System.err.println("Create activation group, in a new VM");
+            CommandEnvironment cmd = new ActivationGroupDesc.CommandEnvironment(null,
+                    new String[] { "-XaddExports:java.base/sun.security.provider=ALL-UNNAMED,"
+                            + "java.rmi/sun.rmi.registry=ALL-UNNAMED,java.rmi/sun.rmi.server=ALL-UNNAMED,"
+                            + "java.rmi/sun.rmi.transport=ALL-UNNAMED,java.rmi/sun.rmi.transport.tcp=ALL-UNNAMED" });
+
             ActivationGroupDesc groupDesc =
-                new ActivationGroupDesc(p, null);
+                new ActivationGroupDesc(p, cmd);
             ActivationSystem system = ActivationGroup.getSystem();
             ActivationGroupID groupID = system.registerGroup(groupDesc);
 
--- a/test/java/rmi/activation/ActivationSystem/stubClassesPermitted/rmid.security.policy	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/rmi/activation/ActivationSystem/stubClassesPermitted/rmid.security.policy	Thu Mar 17 19:04:16 2016 +0000
@@ -1,4 +1,7 @@
 grant {
     permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.manager=java.lang.SecurityManager";
     permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.policy=*";
+
+    // test needs to export a set of internal APIs to access them from unamed module
+    permission com.sun.rmi.rmid.ExecOptionPermission "*";
 };
--- a/test/java/rmi/activation/rmidViaInheritedChannel/InheritedChannelNotServerSocket.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/rmi/activation/rmidViaInheritedChannel/InheritedChannelNotServerSocket.java	Thu Mar 17 19:04:16 2016 +0000
@@ -105,9 +105,9 @@
             RMID.removeLog();
             rmid = RMID.createRMID(System.out, System.err, true, true,
                                    TestLibrary.INHERITEDCHANNELNOTSERVERSOCKET_ACTIVATION_PORT);
-            rmid.addOptions(new String[]{
-                "-Djava.nio.channels.spi.SelectorProvider=" +
-                "InheritedChannelNotServerSocket$SP"});
+            rmid.addOptions(
+                "-XaddExports:java.base/sun.nio.ch=ALL-UNNAMED",
+                "-Djava.nio.channels.spi.SelectorProvider=InheritedChannelNotServerSocket$SP");
             rmid.start();
 
             /*
--- a/test/java/rmi/activation/rmidViaInheritedChannel/RmidViaInheritedChannel.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/rmi/activation/rmidViaInheritedChannel/RmidViaInheritedChannel.java	Thu Mar 17 19:04:16 2016 +0000
@@ -92,8 +92,9 @@
             RMID.removeLog();
             rmid = RMID.createRMID(System.out, System.err, true, false,
                                    TestLibrary.RMIDVIAINHERITEDCHANNEL_ACTIVATION_PORT);
-            rmid.addOptions(new String[]{
-                "-Djava.nio.channels.spi.SelectorProvider=RmidViaInheritedChannel$RmidSelectorProvider"});
+            rmid.addOptions(
+                "-XaddExports:java.base/sun.nio.ch=ALL-UNNAMED",
+                "-Djava.nio.channels.spi.SelectorProvider=RmidViaInheritedChannel$RmidSelectorProvider");
             if (System.getProperty("os.name").startsWith("Windows") &&
                 System.getProperty("os.version").startsWith("5."))
             {
--- a/test/java/rmi/dgc/dgcAckFailure/DGCAckFailure.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/rmi/dgc/dgcAckFailure/DGCAckFailure.java	Thu Mar 17 19:04:16 2016 +0000
@@ -30,6 +30,7 @@
  * rather than pinning it indefinitely.
  * @author Peter Jones
  *
+ * @modules java.rmi/sun.rmi.transport
  * @build DGCAckFailure DGCAckFailure_Stub
  * @run main/othervm DGCAckFailure
  */
--- a/test/java/rmi/registry/readTest/readTest.sh	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/rmi/registry/readTest/readTest.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -23,6 +23,10 @@
 
 # @test
 # @bug 7102369 7094468 7100592
+# @modules java.rmi/sun.rmi.registry
+#          java.rmi/sun.rmi.server
+#          java.rmi/sun.rmi.transport
+#          java.rmi/sun.rmi.transport.tcp
 # @library ../../testlibrary
 # @build TestLibrary
 # @summary remove java.rmi.server.codebase property parsing from registyimpl
@@ -94,6 +98,7 @@
     ;;
 esac
 # trailing / after code base is important for rmi codebase property.
+TESTVMOPTS="${TESTVMOPTS}  -XaddExports:java.rmi/sun.rmi.registry=ALL-UNNAMED,java.rmi/sun.rmi.server=ALL-UNNAMED,java.rmi/sun.rmi.transport=ALL-UNNAMED,java.rmi/sun.rmi.transport.tcp=ALL-UNNAMED"
 ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -cp $TEST_CLASSPATH ${ARGS} -Djava.rmi.server.codebase=${FILEURL}$CODEBASE/ readTest > OUT.TXT 2>&1 &
 TEST_PID=$!
 #bulk of testcase - let it run for a while
--- a/test/java/rmi/reliability/benchmark/bench/HtmlReporter.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/rmi/reliability/benchmark/bench/HtmlReporter.java	Thu Mar 17 19:04:16 2016 +0000
@@ -41,7 +41,7 @@
     static final int PRECISION = 3;
     static final String[] PROPNAMES = { "os.name", "os.arch", "os.version",
         "java.home", "java.vm.version", "java.vm.vendor", "java.vm.name",
-        "java.compiler", "java.class.path", "sun.boot.class.path" };
+        "java.compiler", "java.class.path" };
 
     OutputStream out;
     String title;
--- a/test/java/rmi/reliability/benchmark/bench/TextReporter.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/rmi/reliability/benchmark/bench/TextReporter.java	Thu Mar 17 19:04:16 2016 +0000
@@ -47,7 +47,7 @@
     static final int PROPNAME_WIDTH = 25;
     static final String[] PROPNAMES = { "os.name", "os.arch", "os.version",
         "java.home", "java.vm.version", "java.vm.vendor", "java.vm.name",
-        "java.compiler", "java.class.path", "sun.boot.class.path" };
+        "java.compiler", "java.class.path" };
 
     OutputStream out;
     String title;
--- a/test/java/rmi/testlibrary/JavaVM.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/rmi/testlibrary/JavaVM.java	Thu Mar 17 19:04:16 2016 +0000
@@ -78,7 +78,7 @@
     }
 
     // Prepends passed opts array to current options
-    public void addOptions(String[] opts) {
+    public void addOptions(String... opts) {
         String newOpts = "";
         for (int i = 0 ; i < opts.length ; i ++) {
             newOpts += " " + opts[i];
@@ -88,7 +88,7 @@
     }
 
     // Prepends passed arguments array to current args
-    public void addArguments(String[] arguments) {
+    public void addArguments(String... arguments) {
         String newArgs = "";
         for (int i = 0 ; i < arguments.length ; i ++) {
             newArgs += " " + arguments[i];
--- a/test/java/rmi/transport/checkFQDN/CheckFQDN.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/rmi/transport/checkFQDN/CheckFQDN.java	Thu Mar 17 19:04:16 2016 +0000
@@ -123,6 +123,9 @@
                                     propOption + property +
                                     equal +
                                     propertyValue + extraProp +
+                                    " -XaddExports:java.rmi/sun.rmi.registry=ALL-UNNAMED,"
+                                    + "java.rmi/sun.rmi.server=ALL-UNNAMED,java.rmi/sun.rmi.transport=ALL-UNNAMED,"
+                                    + "java.rmi/sun.rmi.transport.tcp=ALL-UNNAMED" +
                                     " -Drmi.registry.port=" +
                                     REGISTRY_PORT,
                                     "");
--- a/test/java/rmi/transport/dgcDeadLock/DGCDeadLock.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/rmi/transport/dgcDeadLock/DGCDeadLock.java	Thu Mar 17 19:04:16 2016 +0000
@@ -74,6 +74,10 @@
         try {
             String options = " -Djava.security.policy=" +
                 TestParams.defaultPolicy +
+                " -XaddExports:java.rmi/sun.rmi.registry=ALL-UNNAMED," +
+                "java.rmi/sun.rmi.server=ALL-UNNAMED," +
+                "java.rmi/sun.rmi.transport=ALL-UNNAMED," +
+                "java.rmi/sun.rmi.transport.tcp=ALL-UNNAMED" +
                 " -Djava.rmi.dgc.leaseValue=500000" +
                 "  -Dsun.rmi.dgc.checkInterval=" +
                 (HOLD_TARGET_TIME - 5000) +
--- a/test/java/security/PermissionCollection/PermissionCollectionStreamTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/security/PermissionCollection/PermissionCollectionStreamTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -24,8 +24,8 @@
 /* @test
  * @bug 8081678
  * @summary Tests for stream returning methods
- * @library ../../util/stream/bootlib/java.base
- * @build java.util.stream.OpTestCase
+ * @library ../../util/stream/bootlib
+ * @build java.base/java.util.stream.OpTestCase
  * @run testng/othervm PermissionCollectionStreamTest
  */
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/security/Provider/DefaultProviderList.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 7191662
+ * @summary Ensure non-java.base providers can be found by ServiceLoader
+ * @author Valerie Peng
+ */
+
+import java.util.*;
+import java.security.*;
+
+public class DefaultProviderList {
+
+    public static void main(String[] args) throws Exception {
+        Provider[] defaultProvs = Security.getProviders();
+        System.out.println("Providers: " + Arrays.asList(defaultProvs));
+        System.out.println();
+
+        ServiceLoader<Provider> sl = ServiceLoader.load(Provider.class);
+        boolean failed = false;
+        for (Provider p : defaultProvs) {
+            String pName = p.getName();
+            // only providers outside java.base are loaded by ServiceLoader
+            if (pName.equals("SUN") || pName.equals("SunRsaSign") ||
+                pName.equals("SunJCE") || pName.equals("SunJSSE")) {
+                System.out.println("Skip test for provider " + pName);
+                continue;
+            }
+            String pClassName = p.getClass().getName();
+            // Should be able to find each one through ServiceLoader
+            Iterator<Provider> provIter = sl.iterator();
+            boolean found = false;
+            while (provIter.hasNext()) {
+                Provider pFromSL = provIter.next();
+                if (pFromSL.getClass().getName().equals(pClassName)) {
+                    found = true;
+                    break;
+                }
+            }
+            System.out.println("Found " + p.getName() + " = " + found);
+            if (!found) {
+                failed = true;
+                System.out.println("Error: no provider class " + pClassName +
+                    " found");
+            }
+        }
+        if (!failed) {
+            System.out.println("Test Passed");
+        } else {
+            throw new Exception("One or more provider not loaded by SL");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/security/Provider/SecurityProviderModularTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Arrays;
+import java.io.IOException;
+import java.lang.module.ModuleDescriptor;
+import jdk.testlibrary.ProcessTools;
+import jdk.testlibrary.OutputAnalyzer;
+import org.testng.annotations.BeforeTest;
+
+/**
+ * @test
+ * @bug 8130360
+ * @library /lib/testlibrary
+ * @library /java/security/modules
+ * @modules java.base/jdk.internal.module
+ * @build CompilerUtils JarUtils
+ * @summary Test custom security provider module with all possible modular
+ *          condition. The test includes different combination of security
+ *          client/provider modules interaction with or without service
+ *          description.
+ * @run testng SecurityProviderModularTest
+ */
+public class SecurityProviderModularTest extends ModularTest {
+
+    private static final Path S_SRC = SRC.resolve("TestSecurityProvider.java");
+    private static final String S_PKG = "provider";
+    private static final String S_JAR_NAME = S_PKG + JAR_EXTN;
+    private static final String S_WITH_DESCR_JAR_NAME = S_PKG + DESCRIPTOR
+            + JAR_EXTN;
+    private static final String MS_JAR_NAME = MODULAR + S_PKG + JAR_EXTN;
+    private static final String MS_WITH_DESCR_JAR_NAME = MODULAR + S_PKG
+            + DESCRIPTOR + JAR_EXTN;
+
+    private static final Path C_SRC = SRC.resolve(
+            "TestSecurityProviderClient.java");
+    private static final String C_PKG = "client";
+    private static final String C_JAR_NAME = C_PKG + JAR_EXTN;
+    private static final String MC_DEPENDS_ON_AUTO_SERVICE_JAR_NAME = MODULAR
+            + C_PKG + AUTO + JAR_EXTN;
+    private static final String MC_JAR_NAME = MODULAR + C_PKG + JAR_EXTN;
+
+    private static final Path BUILD_DIR = Paths.get(".").resolve("build");
+    private static final Path COMPILE_DIR = BUILD_DIR.resolve("bin");
+    private static final Path S_BUILD_DIR = COMPILE_DIR.resolve(S_PKG);
+    private static final Path S_WITH_META_DESCR_BUILD_DIR = COMPILE_DIR.resolve(
+            S_PKG + DESCRIPTOR);
+    private static final Path C_BUILD_DIR = COMPILE_DIR.resolve(C_PKG);
+    private static final Path M_BASE_PATH = BUILD_DIR.resolve("mbase");
+    private static final Path ARTIFACTS_DIR = BUILD_DIR.resolve("artifacts");
+
+    private static final Path S_ARTIFACTS_DIR = ARTIFACTS_DIR.resolve(S_PKG);
+    private static final Path S_JAR = S_ARTIFACTS_DIR.resolve(S_JAR_NAME);
+    private static final Path S_WITH_DESCRIPTOR_JAR = S_ARTIFACTS_DIR.resolve(
+            S_WITH_DESCR_JAR_NAME);
+    private static final Path MS_JAR = S_ARTIFACTS_DIR.resolve(
+            MS_JAR_NAME);
+    private static final Path MS_WITH_DESCR_JAR = S_ARTIFACTS_DIR.resolve(
+            MS_WITH_DESCR_JAR_NAME);
+
+    private static final Path C_ARTIFACTS_DIR = ARTIFACTS_DIR.resolve(C_PKG);
+    private static final Path C_JAR = C_ARTIFACTS_DIR.resolve(C_JAR_NAME);
+    private static final Path MC_JAR = C_ARTIFACTS_DIR.resolve(MC_JAR_NAME);
+    private static final Path MC_DEPENDS_ON_AUTO_SERVICE_JAR = C_ARTIFACTS_DIR
+            .resolve(MC_DEPENDS_ON_AUTO_SERVICE_JAR_NAME);
+
+    private static final String MAIN = C_PKG + ".TestSecurityProviderClient";
+    private static final String S_INTERFACE = "java.security.Provider";
+    private static final String S_IMPL = S_PKG + ".TestSecurityProvider";
+    private static final List<String> M_REQUIRED = Arrays.asList("java.base");
+    private static final Path META_DESCR_PATH = Paths.get("META-INF")
+            .resolve("services").resolve(S_INTERFACE);
+    private static final Path S_META_DESCR_FPATH = S_WITH_META_DESCR_BUILD_DIR
+            .resolve(META_DESCR_PATH);
+
+    private static final boolean WITH_S_DESCR = true;
+    private static final boolean WITHOUT_S_DESCR = false;
+    private static final String CLASS_NOT_FOUND_MSG = "NoClassDefFoundError:"
+            + " provider/TestSecurityProvider";
+    private static final String PROVIDER_NOT_FOUND_MSG = "Unable to find Test"
+            + " Security Provider";
+    private static final String CAN_NOT_ACCESS_MSG = "cannot access class";
+    private static final String NO_FAILURE = null;
+    private static final String SERVICE_LOADER = "SERVICE_LOADER";
+    private static final String CLASS_LOADER = "CLASS_LOADER";
+    private static final String SECURITY_PROP = "SECURITY_PROP";
+    private static final List<String> MECHANISMS = Arrays.asList(SERVICE_LOADER,
+            CLASS_LOADER, SECURITY_PROP);
+    private static final Path SECURE_PROP_EXTN = Paths.get("./java.secure.ext");
+
+    /**
+     * Generates Test specific input parameters.
+     */
+    @Override
+    public Object[][] getTestInput() {
+
+        List<List<Object>> params = new ArrayList<>();
+        MECHANISMS.stream().forEach((mechanism) -> {
+            boolean useCLoader = CLASS_LOADER.equals(mechanism);
+            boolean useSLoader = SERVICE_LOADER.equals(mechanism);
+            String[] args = new String[]{mechanism};
+            //PARAMETER ORDERS -
+            //client Module Type, Service Module Type,
+            //Service META Descriptor Required,
+            //Expected Failure message, mech used to find the provider
+            params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.EXPLICIT,
+                    WITH_S_DESCR, NO_FAILURE, args));
+            params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.EXPLICIT,
+                    WITHOUT_S_DESCR, NO_FAILURE, args));
+            params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.AUTO,
+                    WITH_S_DESCR, ((useCLoader) ? CAN_NOT_ACCESS_MSG
+                            : NO_FAILURE), args));
+            params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.AUTO,
+                    WITHOUT_S_DESCR, CLASS_NOT_FOUND_MSG, args));
+            params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.UNNAMED,
+                    WITH_S_DESCR, ((useCLoader) ? CAN_NOT_ACCESS_MSG
+                            : NO_FAILURE), args));
+            params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.UNNAMED,
+                    WITHOUT_S_DESCR, ((useCLoader) ? CAN_NOT_ACCESS_MSG
+                            : ((useSLoader) ? PROVIDER_NOT_FOUND_MSG
+                                    : NO_FAILURE)), args));
+
+            params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.EXPLICIT,
+                    WITH_S_DESCR, NO_FAILURE, args));
+            params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.EXPLICIT,
+                    WITH_S_DESCR, NO_FAILURE, args));
+            params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.AUTO,
+                    WITH_S_DESCR, NO_FAILURE, args));
+            params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.AUTO,
+                    WITHOUT_S_DESCR, CLASS_NOT_FOUND_MSG, args));
+            params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.UNNAMED,
+                    WITH_S_DESCR, NO_FAILURE, args));
+            params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.UNNAMED,
+                    WITHOUT_S_DESCR, ((useSLoader) ? PROVIDER_NOT_FOUND_MSG
+                            : NO_FAILURE), args));
+
+            params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.EXPLICIT,
+                    WITH_S_DESCR, NO_FAILURE, args));
+            params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.EXPLICIT,
+                    WITHOUT_S_DESCR, NO_FAILURE, args));
+            params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.AUTO,
+                    WITH_S_DESCR, NO_FAILURE, args));
+            params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.AUTO,
+                    WITHOUT_S_DESCR, CLASS_NOT_FOUND_MSG, args));
+            params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.UNNAMED,
+                    WITH_S_DESCR, NO_FAILURE, args));
+            params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.UNNAMED,
+                    WITHOUT_S_DESCR, ((useSLoader) ? PROVIDER_NOT_FOUND_MSG
+                            : NO_FAILURE), args));
+        });
+        return params.stream().map(p -> p.toArray()).toArray(Object[][]::new);
+    }
+
+    /**
+     * Pre-compile and generate the artifacts required to run this test before
+     * running each test cases.
+     */
+    @BeforeTest
+    public void buildArtifacts() {
+
+        boolean done = true;
+        try {
+
+            done &= CompilerUtils.compile(S_SRC, S_BUILD_DIR);
+            done &= CompilerUtils.compile(S_SRC, S_WITH_META_DESCR_BUILD_DIR);
+            done &= createMetaInfServiceDescriptor(S_META_DESCR_FPATH, S_IMPL);
+            //Generate regular/modular jars with(out) META-INF
+            //Service descriptor
+            generateJar(true, MODULE_TYPE.EXPLICIT, MS_JAR, S_BUILD_DIR, false);
+            generateJar(true, MODULE_TYPE.EXPLICIT, MS_WITH_DESCR_JAR,
+                    S_WITH_META_DESCR_BUILD_DIR, false);
+            generateJar(true, MODULE_TYPE.UNNAMED, S_JAR, S_BUILD_DIR, false);
+            generateJar(true, MODULE_TYPE.UNNAMED, S_WITH_DESCRIPTOR_JAR,
+                    S_WITH_META_DESCR_BUILD_DIR, false);
+            //Generate regular/modular(depends on explicit/auto Service)
+            //jars for client
+            done &= CompilerUtils.compile(C_SRC, C_BUILD_DIR, "-cp",
+                    S_JAR.toFile().getCanonicalPath());
+            generateJar(false, MODULE_TYPE.EXPLICIT, MC_JAR, C_BUILD_DIR, true);
+            generateJar(false, MODULE_TYPE.EXPLICIT,
+                    MC_DEPENDS_ON_AUTO_SERVICE_JAR, C_BUILD_DIR, false);
+            generateJar(false, MODULE_TYPE.UNNAMED, C_JAR, C_BUILD_DIR, false);
+            System.out.format("%nArtifacts generated successfully? %s", done);
+            if (!done) {
+                throw new RuntimeException("Artifacts generation failed");
+            }
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Generate modular/regular jar based on module type for this test.
+     */
+    private void generateJar(boolean isService, MODULE_TYPE moduleType,
+            Path jar, Path compilePath, boolean depends) throws IOException {
+
+        ModuleDescriptor mDescriptor = null;
+        if (isService) {
+            mDescriptor = generateModuleDescriptor(isService, moduleType, S_PKG,
+                    S_PKG, S_INTERFACE, S_IMPL, null, M_REQUIRED, depends);
+        } else {
+            mDescriptor = generateModuleDescriptor(isService, moduleType, C_PKG,
+                    C_PKG, S_INTERFACE, null, S_PKG, M_REQUIRED, depends);
+        }
+        generateJar(mDescriptor, jar, compilePath);
+    }
+
+    /**
+     * Holds Logic for the test. This method will get called with each test
+     * parameter.
+     */
+    @Override
+    public OutputAnalyzer executeTestClient(MODULE_TYPE cModuleType,
+            Path cJarPath, MODULE_TYPE sModuletype, Path sJarPath,
+            String... args) throws Exception {
+
+        OutputAnalyzer output = null;
+        try {
+
+            //For automated/explicit module type copy the corresponding
+            //jars to module base folder, which will be considered as
+            //module base path during execution.
+            if (!(cModuleType == MODULE_TYPE.UNNAMED
+                    && sModuletype == MODULE_TYPE.UNNAMED)) {
+                copyJarsToModuleBase(cModuleType, cJarPath, M_BASE_PATH);
+                copyJarsToModuleBase(sModuletype, sJarPath, M_BASE_PATH);
+            }
+
+            System.out.format("%nExecuting java client with required"
+                    + " custom security provider in class/module path.");
+            String mName = getModuleName(cModuleType, cJarPath, C_PKG);
+            Path cmBasePath = (cModuleType != MODULE_TYPE.UNNAMED
+                    || sModuletype != MODULE_TYPE.UNNAMED) ? M_BASE_PATH : null;
+            String cPath = buildClassPath(cModuleType, cJarPath, sModuletype,
+                    sJarPath);
+
+            Map<String, String> VM_ARGS = getVMArgs(sModuletype, args);
+            output = ProcessTools.executeTestJava(
+                    getJavaCommand(cmBasePath, cPath, mName, MAIN, VM_ARGS,
+                            args)).outputTo(System.out).errorTo(System.out);
+        } finally {
+            //clean module path so that the modulepath can hold only
+            //the required jars for next run.
+            cleanModuleBasePath(M_BASE_PATH);
+            System.out.println("--------------------------------------------");
+        }
+        return output;
+    }
+
+    /**
+     * Decide the pre-generated client/service jar path for each test case
+     * based on client/service module type.
+     */
+    @Override
+    public Path findJarPath(boolean isService, MODULE_TYPE moduleType,
+            boolean addMetaDesc, boolean dependsOnServiceModule) {
+        if (isService) {
+            if (moduleType == MODULE_TYPE.EXPLICIT) {
+                if (addMetaDesc) {
+                    return MS_WITH_DESCR_JAR;
+                } else {
+                    return MS_JAR;
+                }
+            } else {
+                if (addMetaDesc) {
+                    return S_WITH_DESCRIPTOR_JAR;
+                } else {
+                    return S_JAR;
+                }
+            }
+        } else {
+            if (moduleType == MODULE_TYPE.EXPLICIT) {
+                if (dependsOnServiceModule) {
+                    return MC_JAR;
+                } else {
+                    return MC_DEPENDS_ON_AUTO_SERVICE_JAR;
+                }
+            } else {
+                return C_JAR;
+            }
+        }
+    }
+
+    /**
+     * VM argument required for the test.
+     */
+    private Map<String, String> getVMArgs(MODULE_TYPE sModuletype,
+            String... args) throws IOException {
+        final Map<String, String> VM_ARGS = new LinkedHashMap<>();
+        VM_ARGS.put("-Duser.language=", "en");
+        VM_ARGS.put("-Duser.region=", "US");
+        //If mechanism selected to find the provider through
+        //Security.getProvider() then use providerName/ProviderClassName based
+        //on modular/regular provider jar in security configuration file.
+        if (args != null && args.length > 0 && SECURITY_PROP.equals(args[0])) {
+            if (sModuletype == MODULE_TYPE.UNNAMED) {
+                Files.write(SECURE_PROP_EXTN, ("security.provider.10=" + S_IMPL)
+                        .getBytes());
+            } else {
+                Files.write(SECURE_PROP_EXTN, "security.provider.10=TEST"
+                        .getBytes());
+            }
+            VM_ARGS.put("-Djava.security.properties=", SECURE_PROP_EXTN.toFile()
+                    .getCanonicalPath());
+        }
+        return VM_ARGS;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/security/Provider/TestSecurityProvider.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package provider;
+
+import java.security.Provider;
+
+/**
+ * Custom Security provider for modular test.
+ */
+public final class TestSecurityProvider extends Provider {
+
+    public TestSecurityProvider() {
+        super("TEST", 1.0d, "Test Security provider");
+        System.out.println(String.format("TEST Security provider loaded"
+                + " successfully : %s", this.toString()));
+    }
+
+    @Override
+    public String toString() {
+        return "TestSecurityProvider [getName()=" + getName()
+                + ", getVersion()=" + getVersion() + ", getInfo()="
+                + getInfo() + ", toString()=" + super.toString() + "]";
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/security/Provider/TestSecurityProviderClient.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package client;
+
+import java.security.Provider;
+import java.security.Security;
+import java.util.Iterator;
+import java.util.ServiceLoader;
+
+/**
+ * Modular test for client using different mechanism to find the custom security
+ * provider. It uses ServiceLoader and ClassLoader to find the TEST provider
+ * available in classPath/modulePath. It also tries to find, if the provider is
+ * configured through "java.security" file.
+ */
+public class TestSecurityProviderClient {
+
+    private static final String CUSTOM_PROVIDER_NAME = "TEST";
+    private static final String EXCEPTION_MESSAGE
+            = "Unable to find Test Security Provider";
+    private static final String SERVICE_LOADER = "SERVICE_LOADER";
+    private static final String CLASS_LOADER = "CLASS_LOADER";
+
+    public static void main(String[] args) {
+        Provider provider = null;
+        //Try to find the TEST provider loaded by ServiceLoader.
+        if (args != null && args.length > 0
+                && SERVICE_LOADER.equals(args[0])) {
+            System.out.println(
+                    "Using service loader to find Security provider.");
+            ServiceLoader<Provider> services
+                    = ServiceLoader.load(java.security.Provider.class);
+            Iterator<Provider> iterator = services.iterator();
+            while (iterator.hasNext()) {
+                Provider p = iterator.next();
+                if (p.getName().equals(CUSTOM_PROVIDER_NAME)) {
+                    provider = p;
+                    break;
+                }
+            }
+        } else if (args != null && args.length > 0
+                && CLASS_LOADER.equals(args[0])) {
+            System.out.println("Using class loader to find Security provider.");
+            //Find the TEST provider loaded by ClassLoader.
+            provider = new provider.TestSecurityProvider();
+        } else {
+            //Find the TEST provider configured through Security.getProvider().
+            System.out.println("Finding Security provider through"
+                    + " Security.getProvider().");
+            provider = Security.getProvider(CUSTOM_PROVIDER_NAME);
+        }
+
+        if (provider != null) {
+            System.out.format("%nTest Security provider named '%s' loaded "
+                    + "successfully", CUSTOM_PROVIDER_NAME);
+        } else {
+            throw new RuntimeException(EXCEPTION_MESSAGE);
+        }
+    }
+}
--- a/test/java/security/cert/X509Certificate/EmptySubject.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/security/cert/X509Certificate/EmptySubject.java	Thu Mar 17 19:04:16 2016 +0000
@@ -33,8 +33,6 @@
 import java.security.cert.*;
 import javax.security.auth.x500.X500Principal;
 
-import sun.security.x509.*;
-
 public class EmptySubject {
 
     public static void main(String[] args) throws Exception {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/security/modules/ModularTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.Map;
+import java.util.StringJoiner;
+import java.util.Arrays;
+import java.util.stream.Collectors;
+import java.lang.module.ModuleDescriptor;
+import jdk.testlibrary.OutputAnalyzer;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import jdk.internal.module.ModuleInfoWriter;
+import static java.lang.module.ModuleDescriptor.Builder;
+
+/**
+ * Base class need to be extended by modular test for security.
+ */
+public abstract class ModularTest {
+
+    /**
+     * Enum represents all supported module types supported in JDK9. i.e.
+     * EXPLICIT - Modules have module descriptor(module-info.java)
+     * defining the module.
+     * AUTO - Are regular jar files but provided in MODULE_PATH instead
+     * of CLASS_PATH.
+     * UNNAMED - Are regular jar but provided through CLASS_PATH.
+     */
+    public enum MODULE_TYPE {
+
+        EXPLICIT, AUTO, UNNAMED;
+    }
+
+    public static final String SPACE = " ";
+    public static final Path SRC = Paths.get(System.getProperty("test.src"));
+    public static final String DESCRIPTOR = "MetaService";
+    public static final String MODULAR = "Modular";
+    public static final String AUTO = "AutoServiceType";
+    public static final String JAR_EXTN = ".jar";
+
+    /**
+     * Setup test data for the test.
+     */
+    @DataProvider(name = "TestParams")
+    public Object[][] setUpTestData() {
+        return getTestInput();
+    }
+
+    /**
+     * Test method for TestNG.
+     */
+    @Test(dataProvider = "TestParams")
+    public void runTest(MODULE_TYPE cModuleType, MODULE_TYPE sModuletype,
+            boolean addMetaDesc, String failureMsgExpected, String[] args)
+            throws Exception {
+
+        String testName = new StringJoiner("_").add(cModuleType.toString())
+                .add(sModuletype.toString()).add(
+                        (addMetaDesc) ? "DESCRIPTOR" : "NO_DESCRIPTOR")
+                .toString();
+
+        System.out.format("%nStarting Test case: '%s'", testName);
+        Path cJarPath = findJarPath(false, cModuleType, false,
+                (sModuletype == MODULE_TYPE.EXPLICIT));
+        Path sJarPath = findJarPath(true, sModuletype, addMetaDesc, false);
+        System.out.format("%nClient jar path : %s ", cJarPath);
+        System.out.format("%nService jar path : %s ", sJarPath);
+        OutputAnalyzer output = executeTestClient(cModuleType, cJarPath,
+                sModuletype, sJarPath, args);
+
+        if (output.getExitValue() != 0) {
+            if (failureMsgExpected != null
+                    && output.getOutput().contains(failureMsgExpected)) {
+                System.out.println("PASS: Test is expected to fail here.");
+            } else {
+                System.out.format("%nUnexpected failure occured with exit code"
+                        + " '%s'.", output.getExitValue());
+                throw new RuntimeException("Unexpected failure occured.");
+            }
+        }
+    }
+
+    /**
+     * Abstract method need to be implemented by each Test type to provide
+     * test parameters.
+     */
+    public abstract Object[][] getTestInput();
+
+    /**
+     * Execute the test client to access required service.
+     */
+    public abstract OutputAnalyzer executeTestClient(MODULE_TYPE cModuleType,
+            Path cJarPath, MODULE_TYPE sModuletype, Path sJarPath,
+            String... args) throws Exception;
+
+    /**
+     * Find the Jar for service/client based on module type and if service
+     * descriptor required.
+     */
+    public abstract Path findJarPath(boolean service, MODULE_TYPE moduleType,
+            boolean addMetaDesc, boolean dependsOnServiceModule);
+
+    /**
+     * Constructs a Java Command line string based on modular structure followed
+     * by modular client and service.
+     */
+    public String[] getJavaCommand(Path modulePath, String classPath,
+            String clientModuleName, String mainClass,
+            Map<String, String> vmArgs, String... options) throws IOException {
+
+        final StringJoiner command = new StringJoiner(SPACE, SPACE, SPACE);
+        vmArgs.forEach((key, value) -> command.add(key + value));
+        if (modulePath != null) {
+            command.add("-mp").add(modulePath.toFile().getCanonicalPath());
+        }
+        if (classPath != null && classPath.length() > 0) {
+            command.add("-cp").add(classPath);
+        }
+        if (clientModuleName != null && clientModuleName.length() > 0) {
+            command.add("-m").add(clientModuleName + "/" + mainClass);
+        } else {
+            command.add(mainClass);
+        }
+        command.add(Arrays.stream(options).collect(Collectors.joining(SPACE)));
+        return command.toString().trim().split("[\\s]+");
+    }
+
+    /**
+     * Generate ModuleDescriptor object for explicit/auto based client/Service
+     * modules type.
+     */
+    public ModuleDescriptor generateModuleDescriptor(boolean isService,
+            MODULE_TYPE moduleType, String moduleName, String pkg,
+            String serviceInterface, String serviceImpl,
+            String serviceModuleName, List<String> requiredModules,
+            boolean depends) {
+
+        final Builder builder;
+        if (moduleType == MODULE_TYPE.EXPLICIT) {
+            System.out.format(" %nGenerating ModuleDescriptor object");
+            builder = new Builder(moduleName).exports(pkg);
+            if (isService) {
+                builder.provides(serviceInterface, serviceImpl);
+            } else {
+                builder.uses(serviceInterface);
+                if (depends) {
+                    builder.requires(serviceModuleName);
+                }
+            }
+        } else {
+            System.out.format(" %nModuleDescriptor object not required.");
+            return null;
+        }
+        requiredModules.stream().forEach(reqMod -> builder.requires(reqMod));
+        return builder.build();
+    }
+
+    /**
+     * Generates service descriptor inside META-INF folder.
+     */
+    public boolean createMetaInfServiceDescriptor(
+            Path serviceDescriptorFile, String serviceImpl) {
+        boolean created = true;
+        System.out.format("%nCreating META-INF service descriptor for '%s' "
+                + "at path '%s'", serviceImpl, serviceDescriptorFile);
+        try {
+            Path parent = serviceDescriptorFile.getParent();
+            if (parent != null) {
+                Files.createDirectories(parent);
+            }
+            Files.write(serviceDescriptorFile, serviceImpl.getBytes("UTF-8"));
+            System.out.println(
+                    "META-INF service descriptor generated successfully");
+        } catch (IOException e) {
+            e.printStackTrace(System.out);
+            created = false;
+        }
+        return created;
+    }
+
+    /**
+     * Generate modular/regular jar file.
+     */
+    public void generateJar(ModuleDescriptor mDescriptor, Path jar,
+            Path compilePath) throws IOException {
+        System.out.format("%nCreating jar file '%s'", jar);
+        JarUtils.createJarFile(jar, compilePath);
+        if (mDescriptor != null) {
+            Path dir = Files.createTempDirectory("tmp");
+            Path mi = dir.resolve("module-info.class");
+            try (OutputStream out = Files.newOutputStream(mi)) {
+                ModuleInfoWriter.write(mDescriptor, out);
+            }
+            System.out.format("%nAdding 'module-info.class' to jar '%s'", jar);
+            JarUtils.updateJarFile(jar, dir);
+        }
+    }
+
+    /**
+     * Copy pre-generated jar files to the module base path.
+     */
+    public void copyJarsToModuleBase(MODULE_TYPE moduleType, Path jar,
+            Path mBasePath) throws IOException {
+        if (mBasePath != null) {
+            Files.createDirectories(mBasePath);
+        }
+        if (moduleType != MODULE_TYPE.UNNAMED) {
+            Path artifactName = mBasePath.resolve(jar.getFileName());
+            System.out.format("%nCopy jar path: '%s' to module base path: %s",
+                    jar, artifactName);
+            Files.copy(jar, artifactName);
+        }
+    }
+
+    /**
+     * Construct class path string.
+     */
+    public String buildClassPath(MODULE_TYPE cModuleType,
+            Path cJarPath, MODULE_TYPE sModuletype,
+            Path sJarPath) throws IOException {
+        StringJoiner classPath = new StringJoiner(File.pathSeparator);
+        classPath.add((cModuleType == MODULE_TYPE.UNNAMED)
+                ? cJarPath.toFile().getCanonicalPath() : "");
+        classPath.add((sModuletype == MODULE_TYPE.UNNAMED)
+                ? sJarPath.toFile().getCanonicalPath() : "");
+        return classPath.toString();
+    }
+
+    /**
+     * Construct executable module name for java. It is fixed for explicit
+     * module type while it is same as jar file name for automated module type.
+     */
+    public String getModuleName(MODULE_TYPE moduleType,
+            Path jarPath, String mName) {
+        String jarName = jarPath.toFile().getName();
+        return (moduleType == MODULE_TYPE.EXPLICIT) ? mName
+                : ((moduleType == MODULE_TYPE.AUTO) ? jarName.substring(0,
+                                jarName.indexOf(JAR_EXTN)) : "");
+    }
+
+    /**
+     * Delete all the files inside the base module path.
+     */
+    public void cleanModuleBasePath(Path mBasePath) {
+        Arrays.asList(mBasePath.toFile().listFiles()).forEach(f -> {
+            System.out.println("delete: " + f);
+            f.delete();
+        });
+    }
+
+}
--- a/test/java/security/testlibrary/Proc.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/security/testlibrary/Proc.java	Thu Mar 17 19:04:16 2016 +0000
@@ -33,6 +33,7 @@
 import java.security.Permission;
 import java.util.ArrayList;
 import java.util.Base64;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -182,15 +183,21 @@
             cmd.add(new File(new File(System.getProperty("java.home"), "bin"),
                         "java").getPath());
         }
+
+        int n = 0;
+        String addexports;
+        while ((addexports = System.getProperty("jdk.launcher.addexports." + n)) != null) {
+            prop("jdk.launcher.addexports." + n, addexports);
+            n++;
+        }
+
+        Collections.addAll(cmd, splitProperty("test.vm.opts"));
+        Collections.addAll(cmd, splitProperty("test.java.opts"));
+
         cmd.add("-cp");
-        StringBuilder cp = new StringBuilder();
-        for (URL url: ((URLClassLoader)Proc.class.getClassLoader()).getURLs()) {
-            if (cp.length() != 0) {
-                cp.append(File.pathSeparatorChar);
-            }
-            cp.append(url.getFile());
-        }
-        cmd.add(cp.toString());
+        cmd.add(System.getProperty("test.class.path") + File.pathSeparator +
+                System.getProperty("test.src.path"));
+
         for (Entry<String,String> e: prop.entrySet()) {
             cmd.add("-D" + e.getKey() + "=" + e.getValue());
         }
@@ -322,4 +329,12 @@
     public static void d(Throwable e) throws IOException {
         e.printStackTrace();
     }
+
+    private static String[] splitProperty(String prop) {
+        String s = System.getProperty(prop);
+        if (s == null || s.trim().isEmpty()) {
+            return new String[] {};
+        }
+        return s.trim().split("\\s+");
+    }
 }
--- a/test/java/util/Calendar/GenericTimeZoneNamesTest.sh	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/util/Calendar/GenericTimeZoneNamesTest.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -24,20 +24,22 @@
 # @test
 # @bug 8003267
 # @summary Unit test for generic time zone names support
-# @compile -XDignore.symbol.file GenericTimeZoneNamesTest.java
+# @modules java.base/sun.util.locale.provider
+# @compile GenericTimeZoneNamesTest.java
 # @run shell GenericTimeZoneNamesTest.sh
 
 # This test is locale data-dependent and assumes that both JRE and CLDR
 # have the same geneic time zone names in English.
 
+EXTRAOPTS="-XaddExports:java.base/sun.util.locale.provider=ALL-UNNAMED"
 STATUS=0
 echo "Locale providers: default"
-if ! ${TESTJAVA}/bin/java -esa ${TESTVMOPTS} -cp "${TESTCLASSES}" GenericTimeZoneNamesTest en-US; then
+if ! ${TESTJAVA}/bin/java -esa ${TESTVMOPTS} ${EXTRAOPTS} -cp "${TESTCLASSES}" GenericTimeZoneNamesTest en-US; then
     STATUS=1
 fi
 
 echo "Locale providers: CLDR"
-if ! ${TESTJAVA}/bin/java -esa ${TESTVMOPTS} -cp "${TESTCLASSES}" -Djava.locale.providers=CLDR GenericTimeZoneNamesTest en-US; then
+if ! ${TESTJAVA}/bin/java -esa ${TESTVMOPTS} ${EXTRAOPTS} -cp "${TESTCLASSES}" -Djava.locale.providers=CLDR GenericTimeZoneNamesTest en-US; then
    STATUS=1
 fi
 exit ${STATUS}
--- a/test/java/util/Currency/CheckDataVersion.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/util/Currency/CheckDataVersion.java	Thu Mar 17 19:04:16 2016 +0000
@@ -29,6 +29,7 @@
 import java.io.*;
 import java.lang.reflect.*;
 import java.security.*;
+import java.util.Currency;
 
 class CheckDataVersion {
     static final String datafile = "tablea1.txt";
@@ -63,9 +64,9 @@
             AccessController.doPrivileged(new PrivilegedAction<Object>() {
                 public Object run() {
                     try {
+                        InputStream in = Currency.class.getModule().getResourceAsStream("java/util/currency.data");
                         String sep = File.separator;
-                        DataInputStream dis = new DataInputStream(
-                             new BufferedInputStream(getClass().getResourceAsStream("/java/util/currency.data")));
+                        DataInputStream dis = new DataInputStream(in);
                         int magic = dis.readInt();
                         if (magic != 0x43757244) {
                             throw new RuntimeException("The magic number in the JRE's currency data is incorrect.  Expected: 0x43757244, Got: 0x"+magic);
--- a/test/java/util/Currency/CurrencyTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/util/Currency/CurrencyTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,7 @@
  * @bug 4290801 4692419 4693631 5101540 5104960 6296410 6336600 6371531
  *    6488442 7036905 8008577 8039317 8074350 8074351
  * @summary Basic tests for Currency class.
+ * @modules jdk.localedata
  */
 
 import java.io.ByteArrayInputStream;
--- a/test/java/util/Formatter/Basic.sh	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/util/Formatter/Basic.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -23,7 +23,8 @@
 
 #
 
-${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -cp ${TESTSRC} -d . \
+EXTRAOPTS="-XaddExports:java.base/jdk.internal.math=ALL-UNNAMED"
+${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ${EXTRAOPTS} -cp ${TESTSRC} -d . \
     ${TESTSRC}/Basic.java
 
 expectPass() {
@@ -39,7 +40,7 @@
   echo "Testing:" ${1}
   TZ="${1}"; export TZ
   echo "  " $TZ
-  ${TESTJAVA}/bin/java ${TESTVMOPTS} Basic
+  ${TESTJAVA}/bin/java ${TESTVMOPTS} ${EXTRAOPTS} Basic
   expectPass $?
 }
 
--- a/test/java/util/Locale/LocaleProviders.sh	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/util/Locale/LocaleProviders.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -26,7 +26,9 @@
 # @bug 6336885 7196799 7197573 7198834 8000245 8000615 8001440 8008577
 #      8010666 8013086 8013233 8013903 8015960 8028771 8054482 8062006
 # @summary tests for "java.locale.providers" system property
-# @compile -XDignore.symbol.file LocaleProviders.java
+# @modules java.base/sun.util.locale
+#          java.base/sun.util.locale.provider
+# @compile LocaleProviders.java
 # @run shell/timeout=600 LocaleProviders.sh
 
 if [ "${TESTSRC}" = "" ]
@@ -118,18 +120,21 @@
 tznp
 tznp8013086
 EOF
+
+EXTRAOPTS="-XaddExports:java.base/sun.util.locale=ALL-UNNAMED,java.base/sun.util.locale.provider=ALL-UNNAMED"
+
 ${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d ${SPIDIR}${FS}dest \
     ${SPIDIR}${FS}src${FS}tznp.java \
     ${SPIDIR}${FS}src${FS}tznp8013086.java
 ${COMPILEJAVA}${FS}bin${FS}jar ${TESTTOOLVMOPTS} cvf ${SPIDIR}${FS}tznp.jar -C ${SPIDIR}${FS}dest .
 
 # get the platform default locales
-PLATDEF=`${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -classpath ${TESTCLASSES} LocaleProviders getPlatformLocale display`
+PLATDEF=`${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${EXTRAOPTS} -classpath ${TESTCLASSES} LocaleProviders getPlatformLocale display`
 DEFLANG=`echo ${PLATDEF} | sed -e "s/,.*//"`
 DEFCTRY=`echo ${PLATDEF} | sed -e "s/.*,//"`
 echo "DEFLANG=${DEFLANG}"
 echo "DEFCTRY=${DEFCTRY}"
-PLATDEF=`${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -classpath ${TESTCLASSES} LocaleProviders getPlatformLocale format`
+PLATDEF=`${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${EXTRAOPTS} -classpath ${TESTCLASSES} LocaleProviders getPlatformLocale format`
 DEFFMTLANG=`echo ${PLATDEF} | sed -e "s/,.*//"`
 DEFFMTCTRY=`echo ${PLATDEF} | sed -e "s/.*,//"`
 echo "DEFFMTLANG=${DEFFMTLANG}"
@@ -137,7 +142,7 @@
 
 runTest()
 {
-    RUNCMD="${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -classpath ${TESTCLASSES}${PS}${SPICLASSES} -Djava.locale.providers=$PREFLIST LocaleProviders $METHODNAME $PARAM1 $PARAM2 $PARAM3"
+    RUNCMD="${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${EXTRAOPTS} -classpath ${TESTCLASSES}${PS}${SPICLASSES} -Djava.locale.providers=$PREFLIST LocaleProviders $METHODNAME $PARAM1 $PARAM2 $PARAM3"
     echo ${RUNCMD}
     ${RUNCMD}
     result=$?
--- a/test/java/util/PluggableLocale/ExecTest.sh	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/util/PluggableLocale/ExecTest.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -92,10 +92,13 @@
     ;;
 esac
 
+
+EXTRA_OPTS="-XaddExports:java.base/sun.util.locale.provider=ALL-UNNAMED,java.base/sun.util.resources=ALL-UNNAMED"
+
 # compile
 cp ${TESTSRC}${FS}ProviderTest.java .
 cp ${TESTSRC}${FS}$2.java .
-COMPILE="${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \
+COMPILE="${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ${EXTRA_OPTS} \
     -XDignore.symbol.file -d . -classpath ${CLASSPATHARG} $2.java"
 echo ${COMPILE}
 ${COMPILE}
@@ -120,7 +123,7 @@
 fi
 
 # run
-RUNCMD="${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${SECURITYOPTS} -classpath ${CLASSPATHARG} -Djava.locale.providers=JRE,SPI $2 "
+RUNCMD="${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${EXTRA_OPTS} ${SECURITYOPTS} -classpath ${CLASSPATHARG} -Djava.locale.providers=JRE,SPI $2 "
 
 echo ${RUNCMD}
 ${RUNCMD}
--- a/test/java/util/PluggableLocale/ProviderTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/util/PluggableLocale/ProviderTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -26,7 +26,6 @@
 
 import java.text.*;
 import java.util.*;
-import sun.text.resources.*;
 import sun.util.locale.provider.*;
 
 public class ProviderTest {
--- a/test/java/util/ResourceBundle/Bug4168625Test.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/util/ResourceBundle/Bug4168625Test.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -425,26 +425,36 @@
                 throws ClassNotFoundException {
             Class result;
             synchronized (this) {
-                logln(">>"+threadName()+">load "+className);
-                loadedClasses.addElement(className);
+                try {
+                    logln(">>"+threadName()+">load "+className);
+                    loadedClasses.addElement(className);
 
-                result = findLoadedClass(className);
-                if (result == null) {
-                    final byte[] classData = getClassData(className);
-                    if (classData == null) {
-                        //we don't have a local copy of this one
-                        logln("Loading system class: "+className);
-                        result = loadFromSystem(className);
-                    } else {
-                        result = defineClass(classData, 0, classData.length);
-                        if (result == null) {
-                            //there was an error defining the class
+                    result = findLoadedClass(className);
+                    if (result == null) {
+                        final byte[] classData = getClassData(className);
+                        if (classData == null) {
+                            //we don't have a local copy of this one
+                            logln("Loading system class: "+className);
                             result = loadFromSystem(className);
+                        } else {
+                            result = defineClass(classData, 0, classData.length);
+                            if (result == null) {
+                                //there was an error defining the class
+                                result = loadFromSystem(className);
+                            }
+                        }
+                        if ((result != null) && resolveIt) {
+                            resolveClass(result);
                         }
                     }
-                    if ((result != null) && resolveIt) {
-                        resolveClass(result);
+                } catch (ClassNotFoundException e) {
+                    // Ignore loading of Bug4168625ResourceProvider
+                    if (className.equals("Bug4168625ResourceProvider")) {
+                        logln("Ignoring " + className);
+                        loadedClasses.remove(className);
+                        return null;
                     }
+                    throw e;
                 }
             }
             for (int i = classesToWaitFor.length-1; i >= 0; --i) {
--- a/test/java/util/ResourceBundle/Bug6299235Test.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/util/ResourceBundle/Bug6299235Test.java	Thu Mar 17 19:04:16 2016 +0000
@@ -20,13 +20,9 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-/*
- *
- */
-import java.io.File;
+
+import java.awt.Toolkit;
 import java.util.Locale;
-import java.util.ResourceBundle;
-import sun.util.CoreResourceBundleControl;
 
 /*
  * After introducing CoreResourceBundleControl for Awt/Swing resources
@@ -39,24 +35,26 @@
  */
 
 public class Bug6299235Test {
-
-    public static void main(String args[]) throws Exception {
-        /* Try to load "sun.awt.resources.awt_ru_RU.properties which
-         * is in awtres.jar.
-         */
-        ResourceBundle russionAwtRes = ResourceBundle.getBundle("sun.awt.resources.awt",
-                                                                new Locale("ru", "RU"),
-                                                                CoreResourceBundleControl.getRBControlInstance());
+    static final Locale ru_RU = new Locale("ru", "RU");
 
-        /* If this call throws MissingResourceException, the test fails. */
-        if (russionAwtRes != null) {
-            String result = russionAwtRes.getString("foo");
-            if (result.equals("bar")) {
-                System.out.println("Bug6299235Test passed");
-            } else {
-                System.err.println("Bug6299235Test failed");
-                throw new Exception("Resource found, but value of key foo is not correct\n");
+    public static void main(String args[]) {
+        Locale locale = Locale.getDefault();
+        try {
+            Locale.setDefault(ru_RU);
+            // Get the value for the test key "foo"
+            String value = Toolkit.getProperty("foo", "undefined");
+            if (!value.equals("bar")) {
+                throw new RuntimeException("key = foo, value = " + value);
             }
+            // Get the value for a valid key "AWT.enter"
+            value = Toolkit.getProperty("AWT.enter", "DO NOT ENTER");
+            if (value.equals("DO NOT ENTER")) {
+                throw new RuntimeException("AWT.enter undefined.");
+            }
+        } finally {
+            // Restore the default Locale
+            Locale.setDefault(locale);
         }
+        System.out.println("Bug6299235Test passed");
     }
 }
--- a/test/java/util/ResourceBundle/Bug6299235Test.sh	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/util/ResourceBundle/Bug6299235Test.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -58,11 +58,17 @@
 echo "TESTJAVA=${TESTJAVA}"
 echo "TESTSRC=${TESTSRC}"
 echo "TESTCLASSES=${TESTCLASSES}"
-echo "NEW_EXT_DIR=${NEW_EXT_DIR}"
+
+PATCHDIR=${TESTCLASSES}/patches
+rm -rf $PATCHDIR
+mkdir -p $PATCHDIR/java.desktop
 
-cd ${TESTSRC}
+cd ${PATCHDIR}/java.desktop
+${TESTJAVA}/bin/jar xf ${TESTSRC}/awtres.jar
+
 echo 
-${TESTJAVA}/bin/java ${TESTVMOPTS} -cp ${TESTCLASSES}${PATHSEP}${TESTSRC}${FILESEP}awtres.jar Bug6299235Test
+${TESTJAVA}/bin/java ${TESTVMOPTS} -Xpatch:${PATCHDIR} \
+     -cp ${TESTCLASSES} Bug6299235Test
 
 if [ $? -ne 0 ]
     then
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/appbasic/src/asiabundles/jdk/test/resources/asia/MyResourcesAsia.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources.asia;
+
+import java.io.IOException;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.util.ResourceBundle.Control;
+import jdk.test.resources.MyControl;
+import jdk.test.resources.MyResourcesProvider;
+
+public class MyResourcesAsia extends MyControl implements MyResourcesProvider {
+    @Override
+    public ResourceBundle getBundle(String baseName, Locale locale) {
+        if (isAsiaLocale(locale)) {
+            try {
+                ClassLoader loader = MyResourcesAsia.class.getClassLoader();
+                return newBundle(baseName, locale, "java.properties", loader, false);
+            } catch (IllegalAccessException | InstantiationException | IOException e) {
+                System.out.println(e);
+            }
+        }
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/appbasic/src/asiabundles/jdk/test/resources/asia/MyResources_ja.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+key=ja: message
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/appbasic/src/asiabundles/jdk/test/resources/asia/MyResources_zh.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+key=zh: message
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/appbasic/src/asiabundles/jdk/test/resources/asia/MyResources_zh_TW.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+key=zh-TW: message
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/appbasic/src/asiabundles/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module asiabundles {
+    requires test;
+
+    provides jdk.test.resources.MyResourcesProvider
+        with jdk.test.resources.asia.MyResourcesAsia;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/appbasic/src/eubundles/jdk/test/resources/eu/MyResourcesEU.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources.eu;
+
+import java.io.IOException;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.util.ResourceBundle.Control;
+import jdk.test.resources.MyControl;
+import jdk.test.resources.MyResourcesProvider;
+
+public class MyResourcesEU extends MyControl implements MyResourcesProvider {
+    @Override
+    public ResourceBundle getBundle(String baseName, Locale locale) {
+        if (isEULocale(locale)) {
+            try {
+                ClassLoader loader = MyResourcesEU.class.getClassLoader();
+                return newBundle(baseName, locale, "java.class", loader, false);
+            } catch (IllegalAccessException | InstantiationException | IOException e) {
+                System.out.println(e);
+            }
+        }
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/appbasic/src/eubundles/jdk/test/resources/eu/MyResources_de.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources.eu;
+
+import java.util.ListResourceBundle;
+
+public class MyResources_de extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "de: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/appbasic/src/eubundles/jdk/test/resources/eu/MyResources_fr.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources.eu;
+
+import java.util.ListResourceBundle;
+
+public class MyResources_fr extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "fr: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/appbasic/src/eubundles/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module eubundles {
+    requires test;
+
+    provides jdk.test.resources.MyResourcesProvider
+        with jdk.test.resources.eu.MyResourcesEU;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/appbasic/src/test/jdk/test/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.util.Set;
+
+public class Main {
+    public static void main(String[] args) throws Exception {
+        int errors = 0;
+
+        for (String loctag : args) {
+            Locale locale = Locale.forLanguageTag(loctag);
+            if (locale.equals(Locale.ROOT)) {
+                continue;
+            }
+            ResourceBundle rb = ResourceBundle.getBundle("jdk.test.resources.MyResources", locale);
+            String tag = locale.toLanguageTag(); // normalized
+            String value = rb.getString("key");
+            System.out.println("locale = " + tag + ", value = " + value);
+            if (!value.startsWith(tag + ':')) {
+                errors++;
+            }
+        }
+        if (errors > 0) {
+            throw new RuntimeException(errors + " errors");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/appbasic/src/test/jdk/test/resources/MyControl.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources;
+
+import java.util.*;
+
+public class MyControl extends ResourceBundle.Control {
+    private static final Set<Locale> euLocales, asiaLocales;
+
+    static {
+        euLocales = new HashSet<>(Arrays.asList(Locale.GERMAN, Locale.FRENCH));
+        asiaLocales = new HashSet<>(Arrays.asList(Locale.JAPANESE, Locale.CHINESE, Locale.TAIWAN));
+    }
+
+    @Override
+    public String toBundleName(String baseName, Locale locale) {
+        String bundleName = baseName;
+        if (euLocales.contains(locale)) {
+            bundleName = addRegion(baseName, "eu");
+        } else if (asiaLocales.contains(locale)) {
+            bundleName = addRegion(baseName, "asia");
+        }
+        return super.toBundleName(bundleName, locale);
+    }
+
+    private String addRegion(String baseName, String region) {
+        int index = baseName.lastIndexOf('.');
+        return baseName.substring(0, index + 1) + region + baseName.substring(index);
+    }
+
+    protected static boolean isEULocale(Locale locale) {
+        return euLocales.contains(locale);
+    }
+
+    protected static boolean isAsiaLocale(Locale locale) {
+        return asiaLocales.contains(locale);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/appbasic/src/test/jdk/test/resources/MyResources.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources;
+
+import java.util.ListResourceBundle;
+
+public class MyResources extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "root: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/appbasic/src/test/jdk/test/resources/MyResourcesProvider.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources;
+
+import java.util.spi.ResourceBundleProvider;
+
+public interface MyResourcesProvider extends ResourceBundleProvider {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/appbasic/src/test/jdk/test/resources/MyResourcesProviderImpl.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources;
+
+import java.io.IOException;
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+public class MyResourcesProviderImpl extends MyControl implements MyResourcesProvider {
+    @Override
+    public ResourceBundle getBundle(String baseName, Locale locale) {
+        if (locale.equals(Locale.ENGLISH) || locale.equals(Locale.ROOT)) {
+            try {
+                ClassLoader loader = MyResourcesProviderImpl.class.getClassLoader();
+                return newBundle(baseName, locale, "java.class", loader, false);
+            } catch (IllegalAccessException | InstantiationException | IOException e) {
+            }
+        }
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/appbasic/src/test/jdk/test/resources/MyResources_en.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources;
+
+import java.util.ListResourceBundle;
+
+public class MyResources_en extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "en: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/appbasic/src/test/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module test {
+    exports jdk.test.resources to eubundles, asiabundles;
+    uses jdk.test.resources.MyResourcesProvider;
+    provides jdk.test.resources.MyResourcesProvider with jdk.test.resources.MyResourcesProviderImpl;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/appbasic2/appbasic2.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,68 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+# @test
+# @bug 8044767
+# @summary Basic test for ResourceBundle with modules; named module "test"
+#          contains resource bundles for root and en, and separate named modules
+#          "eubundles" and "asiabundles" contain other resource bundles.
+
+set -e
+
+if [ -z "$TESTJAVA" ]; then
+  if [ $# -lt 1 ]; then exit 1; fi
+  TESTJAVA="$1"; shift
+  COMPILEJAVA="${TESTJAVA}"
+  TESTSRC="`pwd`"
+  TESTCLASSES="`pwd`"
+fi
+
+JAVAC="$COMPILEJAVA/bin/javac"
+JAVA="$TESTJAVA/bin/java"
+
+
+for I in eu asia
+do
+  B=${I}bundles
+  mkdir -p mods/$B
+  CLASSES="`find $TESTSRC/src/$B -name '*.java'`"
+  if [ "x$CLASSES" != x ]; then
+    $JAVAC -g -d mods -modulesourcepath $TESTSRC/src -cp mods/test $CLASSES
+  fi
+  PROPS="`(cd $TESTSRC/src/$B; find . -name '*.properties')`"
+  if [ "x$PROPS" != x ]; then
+      for P in $PROPS
+      do
+        D=`dirname $P`
+        mkdir -p mods/$B/$D
+        cp $TESTSRC/src/$B/$P mods/$B/$D/
+      done
+  fi
+done
+
+mkdir -p mods/test
+$JAVAC -g -d mods -modulesourcepath $TESTSRC/src `find $TESTSRC/src/test -name "*.java"`
+
+$JAVA -mp mods -m test/jdk.test.Main de fr ja zh-tw en de
+
+exit $?
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/appbasic2/src/asiabundles/jdk/test/resources/asia/MyResourcesAsia.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources.asia;
+
+import java.util.Locale;
+import jdk.test.resources.MyResourcesProvider;
+
+public class MyResourcesAsia extends MyResourcesProvider {
+    public MyResourcesAsia() {
+        super("java.properties");
+    }
+
+    @Override
+    protected String toBundleName(String baseName, Locale locale) {
+        // Convert baseName to its properties resource name for the given locale
+        // e.g., jdk.test.resources.MyResources -> jdk/test/resources/asia/MyResources_zh_TW
+        StringBuilder sb = new StringBuilder();
+        int index = baseName.lastIndexOf('.');
+        sb.append(baseName.substring(0, index))
+            .append(".asia")
+            .append(baseName.substring(index));
+        String lang = locale.getLanguage();
+        if (!lang.isEmpty()) {
+            sb.append('_').append(lang);
+            String country = locale.getCountry();
+            if (!country.isEmpty()) {
+                sb.append('_').append(country);
+            }
+        }
+        return sb.toString();
+    }
+
+    @Override
+    protected boolean isSupportedInModule(Locale locale) {
+        return locale.equals(Locale.JAPANESE)
+            || locale.equals(Locale.CHINESE) || locale.equals(Locale.TAIWAN);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/appbasic2/src/asiabundles/jdk/test/resources/asia/MyResources_ja.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+key=ja: message
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/appbasic2/src/asiabundles/jdk/test/resources/asia/MyResources_zh.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+key=zh: message
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/appbasic2/src/asiabundles/jdk/test/resources/asia/MyResources_zh_TW.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+key=zh-TW: message
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/appbasic2/src/asiabundles/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module asiabundles {
+    requires test;
+
+    provides jdk.test.resources.MyResourcesProvider
+        with jdk.test.resources.asia.MyResourcesAsia;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/appbasic2/src/eubundles/jdk/test/resources/eu/MyResourcesEU.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources.eu;
+
+import java.util.Locale;
+import jdk.test.resources.MyResourcesProvider;
+
+public class MyResourcesEU extends MyResourcesProvider {
+    public MyResourcesEU() {
+        super("java.class");
+    }
+
+    @Override
+    protected String toBundleName(String baseName, Locale locale) {
+        int index = baseName.lastIndexOf('.');
+        String bundleName = baseName.substring(0, index) + ".eu" + baseName.substring(index)
+                                + '_' + locale.getLanguage();
+        return bundleName;
+    }
+
+    @Override
+    protected boolean isSupportedInModule(Locale locale) {
+        return locale.equals(Locale.GERMAN) || locale.equals(Locale.FRENCH);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/appbasic2/src/eubundles/jdk/test/resources/eu/MyResources_de.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources.eu;
+
+import java.util.ListResourceBundle;
+
+public class MyResources_de extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "de: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/appbasic2/src/eubundles/jdk/test/resources/eu/MyResources_fr.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources.eu;
+
+import java.util.ListResourceBundle;
+
+public class MyResources_fr extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "fr: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/appbasic2/src/eubundles/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module eubundles {
+    requires test;
+
+    provides jdk.test.resources.MyResourcesProvider
+        with jdk.test.resources.eu.MyResourcesEU;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/appbasic2/src/test/jdk/test/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.util.Set;
+
+public class Main {
+    public static void main(String[] args) throws Exception {
+        int errors = 0;
+
+        for (String loctag : args) {
+            Locale locale = Locale.forLanguageTag(loctag);
+            if (locale.equals(Locale.ROOT)) {
+                continue;
+            }
+            ResourceBundle rb = ResourceBundle.getBundle("jdk.test.resources.MyResources", locale);
+            String tag = locale.toLanguageTag(); // normalized
+            String value = rb.getString("key");
+            System.out.println("locale = " + tag + ", value = " + value);
+            if (!value.startsWith(tag + ':')) {
+                errors++;
+            }
+        }
+        if (errors > 0) {
+            throw new RuntimeException(errors + " errors");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/appbasic2/src/test/jdk/test/resources/MyResources.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources;
+
+import java.util.ListResourceBundle;
+
+public class MyResources extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "root: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/appbasic2/src/test/jdk/test/resources/MyResourcesProvider.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources;
+
+
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.util.spi.AbstractResourceBundleProvider;
+
+public abstract class MyResourcesProvider extends AbstractResourceBundleProvider {
+    protected MyResourcesProvider(String... formats) {
+        super(formats);
+    }
+
+    @Override
+    public ResourceBundle getBundle(String baseName, Locale locale) {
+        if (isSupportedInModule(locale)) {
+            return super.getBundle(baseName, locale);
+        }
+        return null;
+    }
+
+    protected abstract boolean isSupportedInModule(Locale locale);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/appbasic2/src/test/jdk/test/resources/MyResourcesProviderImpl.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources;
+
+import java.util.Locale;
+
+public class MyResourcesProviderImpl extends MyResourcesProvider {
+    public MyResourcesProviderImpl() {
+        super("java.class");
+    }
+
+    @Override
+    protected String toBundleName(String baseName, Locale locale) {
+        return locale.equals(Locale.ROOT) ? baseName : baseName + '_' + locale.getLanguage();
+    }
+
+    @Override
+    protected boolean isSupportedInModule(Locale locale) {
+        return locale.equals(Locale.ENGLISH) || locale.equals(Locale.ROOT);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/appbasic2/src/test/jdk/test/resources/MyResources_en.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources;
+
+import java.util.ListResourceBundle;
+
+public class MyResources_en extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "en: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/appbasic2/src/test/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module test {
+    exports jdk.test.resources to eubundles, asiabundles;
+    uses jdk.test.resources.MyResourcesProvider;
+    provides jdk.test.resources.MyResourcesProvider with jdk.test.resources.MyResourcesProviderImpl;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/basic/basic.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,89 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+# @test
+# @bug 8044767 8139067
+# @summary Basic test case for ResourceBundle with modules;
+#          ResourceBundle.getBundle caller is in module named "test",
+#          resource bundles are grouped in main (module "mainbundles"),
+#          EU (module "eubundles"), and Asia (module "asiabundles").
+#          Also adds a jar file containing resource bundles to the class path.
+
+set -e
+
+if [ -z "$TESTJAVA" ]; then
+  if [ $# -lt 1 ]; then exit 1; fi
+  TESTJAVA="$1"; shift
+  COMPILEJAVA="${TESTJAVA}"
+  TESTSRC="`pwd`"
+  TESTCLASSES="`pwd`"
+fi
+
+JAVAC="$COMPILEJAVA/bin/javac"
+JAR="$COMPILEJAVA/bin/jar"
+JAVA="$TESTJAVA/bin/java"
+
+rm -rf mods
+
+CP=
+for I in main eu asia
+do
+  B=${I}bundles
+  mkdir -p mods/$B
+  CLASSES="`find $TESTSRC/src/$B -name '*.java'`"
+  if [ "x$CLASSES" != x ]; then
+    $JAVAC -g -d mods -modulesourcepath $TESTSRC/src $CP $CLASSES
+  fi
+  PROPS="`(cd $TESTSRC/src/$B; find . -name '*.properties')`"
+  if [ "x$PROPS" != x ]; then
+      for P in $PROPS
+      do
+        D=`dirname $P`
+        mkdir -p mods/$B/$D
+        cp $TESTSRC/src/$B/$P mods/$B/$D/
+      done
+  fi
+  CP="-cp mods/mainbundles"
+done
+
+mkdir -p mods/test
+$JAVAC -g -cp mods/mainbundles -d mods -modulesourcepath $TESTSRC/src \
+    `find $TESTSRC/src/test -name "*.java"`
+
+# Create a jar to be added to the class path. Expected only properties files are
+# picked up from the class path.
+rm -f extra.jar
+mkdir -p classes
+$JAVAC -d classes $TESTSRC/src/extra/jdk/test/resources/eu/*.java
+$JAR -cf extra.jar -C classes jdk/test/resources/eu \
+                   -C $TESTSRC/src/extra jdk/test/resources/asia
+
+STATUS=0
+
+echo "jdk.test.Main should load bundles using ResourceBundleProviders."
+$JAVA -mp mods -m test/jdk.test.Main de fr ja ja-jp zh-tw en de ja-jp || STATUS=1
+
+echo "jdk.test.Main should NOT load bundles from the jar file specified by the class-path."
+$JAVA -cp extra.jar -mp mods -m test/jdk.test.Main es vi && STATUS=1
+
+exit $STATUS
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/basic/src/asiabundles/jdk/test/resources/MyResources_ja_JP.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+# This resource bundle is located at jdk/test/resources to demonstrate
+# the unique package requirement is not applicable to .properties bundles.
+
+key=ja-JP: message
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/basic/src/asiabundles/jdk/test/resources/asia/MyResourcesAsia.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources.asia;
+
+import java.util.Locale;
+import jdk.test.resources.MyResourcesProvider;
+
+/**
+ *
+ */
+public class MyResourcesAsia extends MyResourcesProvider {
+    public MyResourcesAsia() {
+        super("java.properties", "asia",
+              Locale.JAPANESE, Locale.JAPAN, Locale.CHINESE, Locale.TAIWAN,
+              new Locale("vi"));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/basic/src/asiabundles/jdk/test/resources/asia/MyResources_ja.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+key=ja: message
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/basic/src/asiabundles/jdk/test/resources/asia/MyResources_zh.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+key=zh: message
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/basic/src/asiabundles/jdk/test/resources/asia/MyResources_zh_TW.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+key=zh-TW: message
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/basic/src/asiabundles/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module asiabundles {
+    requires mainbundles;
+
+    provides jdk.test.resources.MyResourcesProvider
+        with jdk.test.resources.asia.MyResourcesAsia;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/basic/src/eubundles/jdk/test/resources/eu/MyResourcesEU.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources.eu;
+
+import java.util.Locale;
+import jdk.test.resources.MyResourcesProvider;
+
+/**
+ *
+ */
+public class MyResourcesEU extends MyResourcesProvider {
+    public MyResourcesEU() {
+        super("java.class", "eu",
+              Locale.GERMAN, Locale.FRENCH, new Locale("es"));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/basic/src/eubundles/jdk/test/resources/eu/MyResources_de.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources.eu;
+
+import java.util.ListResourceBundle;
+
+public class MyResources_de extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "de: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/basic/src/eubundles/jdk/test/resources/eu/MyResources_fr.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources.eu;
+
+import java.util.ListResourceBundle;
+
+public class MyResources_fr extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "fr: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/basic/src/eubundles/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module eubundles {
+    requires mainbundles;
+
+    provides jdk.test.resources.MyResourcesProvider
+        with jdk.test.resources.eu.MyResourcesEU;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/basic/src/extra/jdk/test/resources/asia/MyResources_vi.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+key=vi: message
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/basic/src/extra/jdk/test/resources/eu/MyResources_es.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources.eu;
+
+import java.util.ListResourceBundle;
+
+public class MyResources_es extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "es: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/basic/src/mainbundles/jdk/test/resources/MyResources.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources;
+
+import java.util.ListResourceBundle;
+
+public class MyResources extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "root: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/basic/src/mainbundles/jdk/test/resources/MyResourcesMain.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources;
+
+import java.util.Locale;
+
+public class MyResourcesMain extends MyResourcesProvider {
+    public MyResourcesMain() {
+        super("java.class", "", Locale.ROOT, Locale.ENGLISH);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/basic/src/mainbundles/jdk/test/resources/MyResourcesProvider.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.util.ResourceBundle.Control;
+import java.util.Set;
+import java.util.spi.AbstractResourceBundleProvider;
+
+
+public class MyResourcesProvider extends AbstractResourceBundleProvider {
+    private final String region;
+    private final Set<Locale> supportedLocales;
+    private final List<String> formats;
+
+    protected MyResourcesProvider() {
+        region = "";
+        supportedLocales = null;
+        formats = Collections.emptyList();
+    }
+
+    protected MyResourcesProvider(String format, String region, Locale... locales) {
+        super(format);
+        this.region = region;
+        this.supportedLocales = new HashSet<>(Arrays.asList(locales));
+        this.formats = Collections.singletonList(format);
+    }
+
+    @Override
+    public ResourceBundle getBundle(String baseName, Locale locale) {
+        if (isSupportedInModule(locale)) {
+           return super.getBundle(baseName, locale);
+        }
+        return null;
+    }
+
+    @Override
+    protected String toBundleName(String baseName, Locale locale) {
+        // The resource bundle for Locale.JAPAN is loccated at jdk.test.resources
+        // in module "asiabundles".
+        String name = locale.equals(Locale.JAPAN) ? baseName : addRegion(baseName);
+        return Control.getControl(Control.FORMAT_DEFAULT).toBundleName(name, locale);
+    }
+
+    private String addRegion(String baseName) {
+        if (region.isEmpty()) {
+            return baseName;
+        }
+        int index = baseName.lastIndexOf('.');
+        return baseName.substring(0, index + 1) + region + baseName.substring(index);
+    }
+
+    protected boolean isSupportedInModule(Locale locale) {
+        return supportedLocales.contains(locale);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/basic/src/mainbundles/jdk/test/resources/MyResources_en.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources;
+
+import java.util.ListResourceBundle;
+
+public class MyResources_en extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "en: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/basic/src/mainbundles/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module mainbundles {
+    exports jdk.test.resources to test, eubundles, asiabundles;
+    provides jdk.test.resources.MyResourcesProvider
+        with jdk.test.resources.MyResourcesMain;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/basic/src/test/jdk/test/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test;
+
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+public class Main {
+    public static void main(String[] args) throws Exception {
+        int errors = 0;
+
+        for (String loctag : args) {
+            Locale locale = Locale.forLanguageTag(loctag);
+            if (locale.equals(Locale.ROOT)) {
+                continue;
+            }
+            ResourceBundle rb = ResourceBundle.getBundle("jdk.test.resources.MyResources",
+                                                         locale);
+            String tag = locale.toLanguageTag(); // normalized
+            String value = rb.getString("key");
+            System.out.println("locale = " + tag + ", value = " + value);
+            if (!value.startsWith(tag + ':')) {
+                errors++;
+            }
+        }
+        if (errors > 0) {
+            throw new RuntimeException(errors + " errors");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/basic/src/test/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module test {
+    requires mainbundles;
+    uses jdk.test.resources.MyResourcesProvider;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/modlocal/modlocal.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,77 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+# @test
+# @bug 8044767 8139067
+# @summary Test case for having resource bundles in a local named module
+#          with no ResourceBundleProviders.
+
+
+set -e
+
+if [ -z "$TESTJAVA" ]; then
+  if [ $# -lt 1 ]; then exit 1; fi
+  TESTJAVA="$1"; shift
+  COMPILEJAVA="${TESTJAVA}"
+  TESTSRC="`pwd`"
+  TESTCLASSES="`pwd`"
+fi
+
+JAVAC="$COMPILEJAVA/bin/javac"
+JAR="$COMPILEJAVA/bin/jar"
+JAVA="$TESTJAVA/bin/java"
+
+rm -rf mods
+mkdir -p mods/test
+
+#
+# Copy .properties files
+#
+PROPS="`(cd $TESTSRC/src; find . -name '*.properties')`"
+if [ "x$PROPS" != x ]; then
+    for P in $PROPS
+    do
+      D=`dirname $P`
+      mkdir -p mods/$D
+      cp $TESTSRC/src/$P mods/$D/
+    done
+fi
+
+$JAVAC -g -d mods -modulesourcepath $TESTSRC/src \
+       -cp mods/bundles `find $TESTSRC/src/test -name "*.java"`
+
+# Create a jar to be added to the class path. Expected properties files are
+# picked up from the class path.
+rm -f extra.jar
+mkdir -p classes
+$JAR -cf extra.jar -C $TESTSRC/src/extra jdk/test/resources
+
+STATUS=0
+
+echo 'jdk.test.Main should load bundles local to named module "test".'
+$JAVA -mp mods -m test/jdk.test.Main de fr ja zh-tw en de || STATUS=1
+
+echo "jdk.test.Main should NOT load bundles from the jar file specified by the class-path."
+$JAVA -cp extra.jar -mp mods -m test/jdk.test.Main vi && STATUS=1
+
+exit $STATUS
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/modlocal/src/extra/jdk/test/resources/MyResources_vi.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+key=vi: message
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test;
+
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.util.ResourceBundle.Control;
+import java.util.MissingResourceException;
+
+public class Main {
+    public static void main(String[] args) throws Exception {
+        int errors = 0;
+        for (String loctag : args) {
+            Locale locale = Locale.forLanguageTag(loctag);
+            if (locale.equals(Locale.ROOT)) {
+                continue;
+            }
+            ResourceBundle rb = ResourceBundle.getBundle("jdk.test.resources.MyResources",
+                                                         locale);
+            String tag = locale.toLanguageTag(); // normalized
+            String value = rb.getString("key");
+            System.out.println("locale = " + tag + ", value = " + value);
+            if (!value.startsWith(tag + ':')) {
+                System.out.println("ERROR: " + value + " expected: " + tag);
+                errors++;
+            }
+        }
+
+        // Make sure ResourceBundle.getBundle throws an UnsupportedOperationException with
+        // a ResourceBundle.Control.
+        try {
+            ResourceBundle rb;
+            rb = ResourceBundle.getBundle("jdk.test.resources.MyResources",
+                                          Locale.ENGLISH,
+                                          Control.getControl(Control.FORMAT_DEFAULT));
+            System.out.println("ERROR: no UnsupportedOperationException thrown with a ResourceBundle.Control");
+            errors++;
+        } catch (UnsupportedOperationException e) {
+            // OK
+        }
+
+        if (errors > 0) {
+            throw new RuntimeException(errors + " errors");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/resources/MyResources.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources;
+
+import java.util.ListResourceBundle;
+
+public class MyResources extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "root: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/resources/MyResources_de.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources;
+
+import java.util.ListResourceBundle;
+
+public class MyResources_de extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "de: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/resources/MyResources_en.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources;
+
+import java.util.ListResourceBundle;
+
+public class MyResources_en extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "en: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/resources/MyResources_fr.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources;
+
+import java.util.ListResourceBundle;
+
+public class MyResources_fr extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "fr: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/resources/MyResources_ja.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+key=ja: message
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/resources/MyResources_zh.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+key=zh: message
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/resources/MyResources_zh_TW.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+key=zh-TW: message
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/modlocal/src/test/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module test {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/security/TestPermission.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.List;
+
+import static jdk.testlibrary.ProcessTools.executeTestJava;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/**
+ * @test
+ * @library /lib/testlibrary
+ * @modules jdk.compiler
+ * @build TestPermission CompilerUtils jdk.testlibrary.*
+ * @run testng TestPermission
+ * @summary Driver for testing ResourceBundle::getBundle(String, Module)
+ */
+
+public class TestPermission {
+
+    private static final String TEST_SRC = System.getProperty("test.src");
+    private static final String TEST_CLASSES = System.getProperty("test.classes");
+
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path MODS_DIR = Paths.get("mods");
+
+    // the names of the modules in this test
+    private static List<String> modules = Arrays.asList("test", "m1");
+
+    /**
+     * Compiles all modules used by the test
+     */
+    @BeforeTest
+    public void compileAll() throws Exception {
+        for (String mn : modules) {
+            Path msrc = SRC_DIR.resolve(mn);
+            assertTrue(CompilerUtils.compile(msrc, MODS_DIR, "-modulesourcepath", SRC_DIR.toString()));
+        }
+    }
+
+    /**
+     * Run the modular test
+     */
+    @Test
+    public void runTest() throws Exception {
+        int exitValue = executeTestJava("-mp", MODS_DIR.toString(),
+                                        "-m", "test/jdk.test.Main")
+                            .outputTo(System.out)
+                            .errorTo(System.out)
+                            .getExitValue();
+
+        assertTrue(exitValue == 0);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/security/src/m1/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m1 {
+    exports p1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/security/src/m1/p1/Bundle.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p1;
+
+import java.util.ResourceBundle;
+
+public class Bundle {
+    public static ResourceBundle getBundle(String basename) {
+        return ResourceBundle.getBundle(basename);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/security/src/m1/p1/resources/MyResources.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p1.resources;
+
+import java.util.ListResourceBundle;
+
+public class MyResources extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "msg", "m1" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/security/src/test/jdk/test/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test;
+
+import p1.Bundle;
+import java.lang.reflect.Module;
+import java.util.ResourceBundle;
+
+public class Main {
+    private static final String TEST_RESOURCE_BUNDLE_NAME
+            = "jdk.test.resources.TestResources";
+    private static final String M1_RESOURCE_BUNDLE_NAME
+            = "p1.resources.MyResources";
+
+    public static void main(String[] args) {
+        // local resource
+        ResourceBundle.getBundle(TEST_RESOURCE_BUNDLE_NAME, Main.class.getModule());
+
+        // resource in another module
+        Module m1 = p1.Bundle.class.getModule();
+        ResourceBundle rb1 = Bundle.getBundle(M1_RESOURCE_BUNDLE_NAME);
+        ResourceBundle rb2 = ResourceBundle.getBundle(M1_RESOURCE_BUNDLE_NAME, m1);
+        if (rb1 != rb2) {
+            throw new RuntimeException("unexpected resource bundle");
+        }
+
+        System.setSecurityManager(new SecurityManager());
+
+        // no permission needed for local resource
+        ResourceBundle.getBundle(TEST_RESOURCE_BUNDLE_NAME, Main.class.getModule());
+
+        // resource bundle through m1's exported API
+        Bundle.getBundle(M1_RESOURCE_BUNDLE_NAME);
+
+        try {
+            // fail to get resource bundle in another module
+            ResourceBundle.getBundle(M1_RESOURCE_BUNDLE_NAME, m1);
+            throw new RuntimeException("should deny access");
+        } catch (SecurityException e) {}
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/security/src/test/jdk/test/resources/TestResources.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources;
+
+import java.util.ListResourceBundle;
+
+public class TestResources extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "msg", "test" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/security/src/test/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module test {
+    requires m1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/simple/simple.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,70 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+# @test
+# @bug 8044767
+# @summary Simple test case for ResourceBundle with named modules;
+#          ResourceBundle.getBundle caller is in named module "test" and
+#          all resource bundles are in single named module "bundles" with
+#          service providers.
+
+
+set -e
+
+if [ -z "$TESTJAVA" ]; then
+  if [ $# -lt 1 ]; then exit 1; fi
+  TESTJAVA="$1"; shift
+  COMPILEJAVA="${TESTJAVA}"
+  TESTSRC="`pwd`"
+  TESTCLASSES="`pwd`"
+fi
+
+JAVAC="$COMPILEJAVA/bin/javac"
+JAVA="$TESTJAVA/bin/java"
+
+rm -rf mods
+
+mkdir -p mods/test
+
+B=bundles
+mkdir -p mods/$B
+CLASSES="`find $TESTSRC/src/$B -name '*.java'`"
+if [ "x$CLASSES" != x ]; then
+    $JAVAC -g -d mods -modulesourcepath $TESTSRC/src $CLASSES
+fi
+PROPS="`(cd $TESTSRC/src/$B; find . -name '*.properties')`"
+if [ "x$PROPS" != x ]; then
+    for P in $PROPS
+    do
+      D=`dirname $P`
+      mkdir -p mods/$B/$D
+      cp $TESTSRC/src/$B/$P mods/$B/$D/
+    done
+fi
+
+$JAVAC -g -d mods -modulesourcepath $TESTSRC/src \
+       -cp mods/bundles `find $TESTSRC/src/test -name "*.java"`
+
+$JAVA -mp mods -m test/jdk.test.Main de fr ja zh-tw en de
+
+exit $?
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResources.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources;
+
+import java.util.ListResourceBundle;
+
+public class MyResources extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "root: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResourcesProvider.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources;
+
+import java.util.Locale;
+import java.util.spi.AbstractResourceBundleProvider;
+
+public class MyResourcesProvider extends AbstractResourceBundleProvider {
+    public MyResourcesProvider() {
+        super("java.class", "java.properties");
+        System.err.println("MyResourcesProvider called " + this);
+    }
+
+    @Override
+    protected String toBundleName(String baseName, Locale locale) {
+        StringBuilder sb = new StringBuilder(baseName);
+        String lang = locale.getLanguage();
+        if (!lang.isEmpty()) {
+            sb.append('_').append(lang);
+            String country = locale.getCountry();
+            if (!country.isEmpty()) {
+                sb.append('_').append(country);
+            }
+        }
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResources_de.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources;
+
+import java.util.ListResourceBundle;
+
+public class MyResources_de extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "de: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResources_en.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources;
+
+import java.util.ListResourceBundle;
+
+public class MyResources_en extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "en: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResources_fr.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources;
+
+import java.util.ListResourceBundle;
+
+public class MyResources_fr extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "fr: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResources_ja.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+key=ja: message
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResources_zh.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+key=zh: message
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResources_zh_TW.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+key=zh-TW: message
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/simple/src/bundles/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module bundles {
+    exports jdk.test.resources to test;
+    provides jdk.test.resources.MyResourcesProvider with jdk.test.resources.MyResourcesProvider;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/simple/src/test/jdk/test/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test;
+
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+public class Main {
+    public static void main(String[] args) throws Exception {
+        int errors = 0;
+        for (String loctag : args) {
+            Locale locale = Locale.forLanguageTag(loctag);
+            if (locale.equals(Locale.ROOT)) {
+                continue;
+            }
+            ResourceBundle rb = ResourceBundle.getBundle("jdk.test.resources.MyResources",
+                                                         locale);
+            String tag = locale.toLanguageTag(); // normalized
+            String value = rb.getString("key");
+            System.out.println("locale = " + tag + ", value = " + value);
+            if (!value.startsWith(tag + ':')) {
+                System.out.println("ERROR: " + value + " expected: " + tag);
+                errors++;
+            }
+        }
+        if (errors > 0) {
+            throw new RuntimeException(errors + " errors");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/simple/src/test/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module test {
+    requires bundles;
+
+    uses jdk.test.resources.MyResourcesProvider;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/visibility/src/embargo/jdk/embargo/TestWithNoModuleArg.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.embargo;
+
+import java.lang.reflect.Module;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class TestWithNoModuleArg {
+    public static void main(String[] args) throws Exception {
+        if (args.length != 2) {
+            System.out.println("Usage: java ... basename should-be-loaded-flag");
+            System.out.println("  ex. java ... jdk.test.resources.classes.MyResources false");
+            return;
+        }
+
+        String basename = args[0];
+        boolean shouldBeLoaded = "true".equals(args[1]);
+
+        int errors = 0;
+        try {
+            // Set the default Locale to Locale.ROOT to avoid any confusions related to fallback
+            Locale.setDefault(Locale.ROOT);
+            ResourceBundle rb = ResourceBundle.getBundle(basename);
+            if (shouldBeLoaded) {
+                System.out.println("Passed: got resource bundle:");
+            } else {
+                System.out.println("Failed: no MissingResourceException thrown");
+                errors++;
+            }
+            System.out.println("            bundle = " + rb);
+        } catch (MissingResourceException e) {
+            if (!shouldBeLoaded) {
+                System.out.println("Passed: got expected " + e);
+            } else {
+                System.out.println("Failed: got unexpected " + e);
+                errors++;
+            }
+            System.out.println("            cause = " + e.getCause());
+        } catch (Throwable t) {
+            System.out.println("Failed: unexpected throwable: " + t);
+            errors++;
+        }
+
+        if (errors > 0) {
+            throw new RuntimeException(errors + " errors");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/visibility/src/embargo/jdk/embargo/TestWithUnnamedModuleArg.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.embargo;
+
+import java.lang.reflect.Module;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class TestWithUnnamedModuleArg {
+    public static void main(String[] args) throws Exception {
+        if (args.length != 2) {
+            System.out.println("Usage: java ... basename should-be-loaded-flag");
+            System.out.println("  ex. java ... jdk.test.resources.classes.MyResources false");
+            return;
+        }
+
+        String basename = args[0];
+        boolean shouldBeLoaded = "true".equals(args[1]);
+
+        int errors = 0;
+
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        if (cl == null) {
+            cl = ClassLoader.getSystemClassLoader();
+        }
+
+        try {
+            // Set the default Locale to Locale.ROOT to avoid any confusions related to fallback
+            Locale.setDefault(Locale.ROOT);
+            ResourceBundle rb = ResourceBundle.getBundle(basename,
+                                                         cl.getUnnamedModule());
+            if (shouldBeLoaded) {
+                System.out.println("Passed: got resource bundle:");
+            } else {
+                System.out.println("Failed: no MissingResourceException thrown");
+                errors++;
+            }
+            System.out.println("        bundle = " + rb);
+        } catch (MissingResourceException e) {
+            if (!shouldBeLoaded) {
+                System.out.println("Passed: got expected " + e);
+            } else {
+                System.out.println("Failed: got unexpected " + e);
+                errors++;
+            }
+            System.out.println("        cause = " + e.getCause());
+        } catch (Throwable t) {
+            System.out.println("Failed: unexpected throwable: " + t);
+            errors++;
+        }
+
+        if (errors > 0) {
+            throw new RuntimeException(errors + " errors");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/visibility/src/embargo/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module embargo {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/visibility/src/exported.named.bundles/jdk/test/resources/exported/classes/MyResources.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources.exported.classes;
+
+import java.util.ListResourceBundle;
+
+public class MyResources extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "root: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/visibility/src/exported.named.bundles/jdk/test/resources/exported/classes/MyResourcesProvider.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources.exported.classes;
+
+import java.util.Locale;
+import java.util.spi.AbstractResourceBundleProvider;
+
+public class MyResourcesProvider extends AbstractResourceBundleProvider {
+    public MyResourcesProvider() {
+        super("java.class", "java.properties");
+        System.err.println("MyResourcesProvider called " + this);
+    }
+
+    @Override
+    protected String toBundleName(String baseName, Locale locale) {
+        StringBuilder sb = new StringBuilder(baseName);
+        String lang = locale.getLanguage();
+        if (!lang.isEmpty()) {
+            sb.append('_').append(lang);
+            String country = locale.getCountry();
+            if (!country.isEmpty()) {
+                sb.append('_').append(country);
+            }
+        }
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/visibility/src/exported.named.bundles/jdk/test/resources/exported/props/MyResources.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+key=root: message
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/visibility/src/exported.named.bundles/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module exported.named.bundles {
+    // unqualified exports to verify that resource bundles are not picked
+    // up by other named modules
+    exports jdk.test.resources.exported.classes;
+    provides jdk.test.resources.exported.classes.MyResourcesProvider
+        with jdk.test.resources.exported.classes.MyResourcesProvider;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/visibility/src/named.bundles/jdk/test/resources/classes/MyResources.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources.classes;
+
+import java.util.ListResourceBundle;
+
+public class MyResources extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "root: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/visibility/src/named.bundles/jdk/test/resources/classes/MyResourcesProvider.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources.classes;
+
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.util.spi.AbstractResourceBundleProvider;
+
+public class MyResourcesProvider extends AbstractResourceBundleProvider {
+    public MyResourcesProvider() {
+        super("java.class");
+    }
+
+    @Override
+    protected String toBundleName(String baseName, Locale locale) {
+        StringBuilder sb = new StringBuilder(baseName);
+        String lang = locale.getLanguage();
+        if (!lang.isEmpty()) {
+            sb.append('_').append(lang);
+            String country = locale.getCountry();
+            if (!country.isEmpty()) {
+                sb.append('_').append(country);
+            }
+        }
+        return sb.toString();
+    }
+
+    @Override
+    public ResourceBundle getBundle(String baseName, Locale locale) {
+        ResourceBundle rb = super.getBundle(baseName, locale);
+        String tag = locale.toLanguageTag();
+        if (tag.equals("und")) {
+            tag = "ROOT"; // to a human friendly name
+        }
+        System.out.printf("    MyResourcesProvider.getBundle(%s, %s)%n         -> %s%n",
+                          baseName, tag, rb);
+        return rb;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/visibility/src/named.bundles/jdk/test/resources/props/MyResources.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+key=root: message
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/visibility/src/named.bundles/jdk/test/resources/props/MyResourcesProvider.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources.props;
+
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.util.spi.AbstractResourceBundleProvider;
+
+public class MyResourcesProvider extends AbstractResourceBundleProvider {
+    public MyResourcesProvider() {
+        super("java.properties");
+    }
+
+    @Override
+    protected String toBundleName(String baseName, Locale locale) {
+        StringBuilder sb = new StringBuilder(baseName);
+        String lang = locale.getLanguage();
+        if (!lang.isEmpty()) {
+            sb.append('_').append(lang);
+            String country = locale.getCountry();
+            if (!country.isEmpty()) {
+                sb.append('_').append(country);
+            }
+        }
+        return sb.toString();
+    }
+
+    @Override
+    public ResourceBundle getBundle(String baseName, Locale locale) {
+        ResourceBundle rb = super.getBundle(baseName, locale);
+        String tag = locale.toLanguageTag();
+        if (tag.equals("und")) {
+            tag = "ROOT"; // to a human friendly name
+        }
+        System.out.printf("    MyResourcesProvider.getBundle(%s, %s)%n         -> %s%n",
+                          baseName, tag, rb);
+        return rb;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/visibility/src/named.bundles/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module named.bundles {
+    exports jdk.test.resources.classes to test; // exports only to test
+    exports jdk.test.resources.props to test;   // exports only to test
+    provides jdk.test.resources.classes.MyResourcesProvider
+        with jdk.test.resources.classes.MyResourcesProvider;
+    provides jdk.test.resources.props.MyResourcesProvider
+        with jdk.test.resources.props.MyResourcesProvider;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/visibility/src/pkg/jdk/pkg/resources/classes/MyResources.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.pkg.resources.classes;
+
+import java.util.ListResourceBundle;
+
+public class MyResources extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "root: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/visibility/src/pkg/jdk/pkg/resources/props/MyResources.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+key=root: message
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/visibility/src/pkg/jdk/pkg/test/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.pkg.test;
+
+import java.lang.reflect.Module;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class Main {
+    public static void main(String[] args) throws Exception {
+        if (args.length != 2) {
+            System.out.println("Usage: java ... basename should-be-loaded-flag");
+            System.out.println("  ex. java ... jdk.test.resources.classes.MyResources false");
+            return;
+        }
+
+        String basename = args[0];
+        boolean shouldBeLoaded = "true".equals(args[1]);
+
+        int errors = 0;
+
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        if (cl == null) {
+            cl = ClassLoader.getSystemClassLoader();
+        }
+
+        try {
+            // Use the default Locale to avoid confusion related to fallback
+            Locale.setDefault(Locale.ENGLISH);
+            ResourceBundle rb = ResourceBundle.getBundle(basename,
+                                                         cl.getUnnamedModule());
+            if (shouldBeLoaded) {
+                System.out.println("Passed: got resource bundle:");
+            } else {
+                System.out.println("Failed: no MissingResourceException thrown");
+                errors++;
+            }
+            System.out.println("            bundle = " + rb);
+        } catch (MissingResourceException e) {
+            if (!shouldBeLoaded) {
+                System.out.println("Passed: got expected " + e);
+            } else {
+                System.out.println("Failed: got unexpected " + e);
+                errors++;
+            }
+            System.out.println("            cause = " + e.getCause());
+        } catch (Throwable t) {
+            System.out.println("Failed: unexpected throwable: " + t);
+            errors++;
+        }
+
+        if (errors > 0) {
+            throw new RuntimeException(errors + " errors");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/visibility/src/test/jdk/test/TestWithNoModuleArg.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test;
+
+import java.lang.reflect.Module;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class TestWithNoModuleArg {
+    public static void main(String[] args) throws Exception {
+        if (args.length != 2) {
+            System.out.println("Usage: java ... basename should-be-loaded-flag");
+            System.out.println("  ex. java ... jdk.test.resources.classes.MyResources false");
+            return;
+        }
+
+        String basename = args[0];
+        boolean shouldBeLoaded = "true".equals(args[1]);
+
+        int errors = 0;
+        try {
+            // Set the default Locale to Locale.ROOT to avoid any confusions related to fallback
+            Locale.setDefault(Locale.ROOT);
+            ResourceBundle rb = ResourceBundle.getBundle(basename);
+            if (shouldBeLoaded) {
+                System.out.println("Passed: got resource bundle:");
+            } else {
+                System.out.println("Failed: no MissingResourceException thrown");
+                errors++;
+            }
+            System.out.println("            bundle = " + rb);
+        } catch (MissingResourceException e) {
+            if (!shouldBeLoaded) {
+                System.out.println("Passed: got expected " + e);
+            } else {
+                System.out.println("Failed: got unexpected " + e);
+                errors++;
+            }
+            System.out.println("            cause = " + e.getCause());
+        } catch (Throwable t) {
+            System.out.println("Failed: unexpected throwable: " + t);
+            errors++;
+        }
+
+        if (errors > 0) {
+            throw new RuntimeException(errors + " errors");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/visibility/src/test/jdk/test/TestWithUnnamedModuleArg.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test;
+
+import java.lang.reflect.Module;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class TestWithUnnamedModuleArg {
+    public static void main(String[] args) throws Exception {
+        if (args.length != 2) {
+            System.out.println("Usage: java ... basename should-be-loaded-flag");
+            System.out.println("  ex. java ... jdk.test.resources.classes.MyResources false");
+            return;
+        }
+
+        String basename = args[0];
+        boolean shouldBeLoaded = "true".equals(args[1]);
+
+        int errors = 0;
+
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        if (cl == null) {
+            cl = ClassLoader.getSystemClassLoader();
+        }
+
+        try {
+            // Set the default Locale to Locale.ROOT to avoid any confusions related to fallback
+            Locale.setDefault(Locale.ROOT);
+            ResourceBundle rb = ResourceBundle.getBundle(basename,
+                                                         cl.getUnnamedModule());
+            if (shouldBeLoaded) {
+                System.out.println("Passed: got resource bundle:");
+            } else {
+                System.out.println("Failed: no MissingResourceException thrown");
+                errors++;
+            }
+            System.out.println("            bundle = " + rb);
+        } catch (MissingResourceException e) {
+            if (!shouldBeLoaded) {
+                System.out.println("Passed: got expected " + e);
+            } else {
+                System.out.println("Failed: got unexpected " + e);
+                errors++;
+            }
+            System.out.println("            cause = " + e.getCause());
+        } catch (Throwable t) {
+            System.out.println("Failed: unexpected throwable: " + t);
+            errors++;
+        }
+
+        if (errors > 0) {
+            throw new RuntimeException(errors + " errors");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/visibility/src/test/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module test {
+    // jdk.test.resources.classes.MyResourcesProvider is in named.bundles.
+    requires named.bundles;
+    uses jdk.test.resources.classes.MyResourcesProvider;
+    uses jdk.test.resources.props.MyResourcesProvider;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/visibility/visibility.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,233 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+# @test
+# @bug 8137317 8139238
+# @summary Visibility tests for ResourceBundle.getBundle with and without
+# an unnamed module argument.
+
+
+set -e
+STATUS=0
+
+runJava()
+{
+    echo "Executing java $@"
+    $JAVA $@ || STATUS=1
+    echo
+}
+
+if [ -z "$TESTJAVA" ]; then
+  if [ $# -lt 1 ]; then exit 1; fi
+  TESTJAVA="$1"; shift
+  COMPILEJAVA="${TESTJAVA}"
+  TESTSRC="`pwd`"
+  TESTCLASSES="`pwd`"
+fi
+
+JAVAC="$COMPILEJAVA/bin/javac"
+JAVA="$TESTJAVA/bin/java"
+
+rm -rf mods classes
+
+MODS=`cd $TESTSRC/src; find . -name module-info.java -exec dirname {} \; | sed 's:\./::'`
+
+for M in $MODS
+do
+    mkdir -p mods/$M
+    CLASSES="`find $TESTSRC/src/$M -name '*.java'`"
+    if [ "x$CLASSES" != x ]; then
+        $JAVAC -g -d mods -modulesourcepath $TESTSRC/src $CLASSES
+    fi
+    PROPS="`(cd $TESTSRC/src/$M; find . -name '*.properties')`"
+    if [ "x$PROPS" != x ]; then
+        for P in $PROPS
+        do
+            D=`dirname $P`
+            mkdir -p mods/$M/$D
+            cp $TESTSRC/src/$M/$P mods/$M/$D/
+        done
+    fi
+done
+
+# Package jdk.test is in named module "test".
+# Package jdk.embargo is in named module "embargo".
+
+# jdk.{test,embargo}.TestWithUnnamedModuleArg call:
+#     ResourceBundle.getBundle(basename, classloader.getUnnamedModule())
+#     where classloader is the TCCL or system class loader.
+# jdk.{test,embargo}.TestWithNoModuleArg call:
+#     ResourceBundle.getBundle(basename)
+
+# jdk.test.resources[.exported].classes.* are class-based resource bundles.
+# jdk.test.resources[.exported].props.* are properties file-based resource bundles.
+
+# Packages jdk.test.resources.{classes,props} in named module "named.bundles"
+# are exported only to named module "test".
+# Packages jdk.test.resources.exported.{classes,props} in named module
+# "exported.named.bundle" are exported to unnamed modules.
+
+########################################
+# Test cases with jdk.test.resources.* #
+########################################
+
+# Tests using jdk.test.TestWithNoModuleArg and jdk.embargo.TestWithNoModuleArg
+# neither of which specifies an unnamed module with ResourceBundle.getBundle().
+
+# jdk.test.resources.{classes,props}.* are available only to named module "test"
+# by ResourceBundleProvider.
+runJava -mp mods -m test/jdk.test.TestWithNoModuleArg \
+    jdk.test.resources.classes.MyResources true
+runJava -mp mods -m test/jdk.test.TestWithNoModuleArg \
+    jdk.test.resources.props.MyResources true
+runJava -mp mods -m embargo/jdk.embargo.TestWithNoModuleArg \
+    jdk.test.resources.classes.MyResources false
+runJava -mp mods -m embargo/jdk.embargo.TestWithNoModuleArg \
+    jdk.test.resources.props.MyResources false
+
+# Add mods/named.bundles to the class path.
+runJava -cp mods/named.bundles -mp mods -m test/jdk.test.TestWithNoModuleArg \
+    jdk.test.resources.classes.MyResources true
+runJava -cp mods/named.bundles -mp mods -m test/jdk.test.TestWithNoModuleArg \
+    jdk.test.resources.props.MyResources true
+runJava -cp mods/named.bundles -mp mods -m embargo/jdk.embargo.TestWithNoModuleArg \
+    jdk.test.resources.classes.MyResources false
+runJava -cp mods/named.bundles -mp mods -m embargo/jdk.embargo.TestWithNoModuleArg \
+    jdk.test.resources.props.MyResources false
+
+# Tests using jdk.test.TestWithUnnamedModuleArg and jdk.embargo.TestWithUnnamedModuleArg
+# both of which specify an unnamed module with ResourceBundle.getBundle.
+
+# jdk.test.resources.classes is exported to named module "test".
+# IllegalAccessException is thrown in ResourceBundle.Control.newBundle().
+runJava -mp mods -m test/jdk.test.TestWithUnnamedModuleArg \
+    jdk.test.resources.classes.MyResources false
+
+# jdk.test.resources.props is exported to named module "test".
+# loader.getResource() doesn't find jdk.test.resources.props.MyResources.
+runJava -mp mods -m test/jdk.test.TestWithUnnamedModuleArg \
+    jdk.test.resources.props.MyResources false
+
+# IllegalAccessException is thrown in ResourceBundle.Control.newBundle().
+runJava -mp mods -m embargo/jdk.embargo.TestWithUnnamedModuleArg \
+    jdk.test.resources.classes.MyResources false
+# jdk.test.resources.props is exported to named module "test".
+# loader.getResource() doesn't find jdk.test.resources.props.MyResources.
+runJava -mp mods -m embargo/jdk.embargo.TestWithUnnamedModuleArg \
+    jdk.test.resources.props.MyResources false
+
+# Add mods/named.bundles to the class path
+
+# IllegalAccessException is thrown in ResourceBundle.Control.newBundle().
+runJava -cp mods/named.bundles -mp mods -m test/jdk.test.TestWithUnnamedModuleArg \
+        jdk.test.resources.classes.MyResources false
+# loader.getResource() finds jdk.test.resources.exported.props.MyResources.
+runJava -cp mods/named.bundles -mp mods -m test/jdk.test.TestWithUnnamedModuleArg \
+        jdk.test.resources.props.MyResources true
+
+# jdk.test.resources.exported.classes.MyResources is treated
+# as if the class is in an unnamed module.
+runJava -cp mods/named.bundles -mp mods -m embargo/jdk.embargo.TestWithUnnamedModuleArg \
+        jdk.test.resources.classes.MyResources true
+# loader.getResource() finds jdk.test.resources.exported.props.MyResources.
+runJava -cp mods/named.bundles -mp mods -m embargo/jdk.embargo.TestWithUnnamedModuleArg \
+        jdk.test.resources.props.MyResources true
+
+#################################################
+# Test cases with jdk.test.resources.exported.* #
+#################################################
+# Tests using jdk.test.TestWithNoModuleArg and jdk.embargo.TestWithNoModuleArg
+# neither of which specifies an unnamed module with ResourceBundle.getBundle.
+
+# None of jdk.test.resources.exported.** is available to the named modules.
+runJava -mp mods -m test/jdk.test.TestWithNoModuleArg \
+    jdk.test.resources.exported.classes.MyResources false
+runJava -mp mods -m test/jdk.test.TestWithNoModuleArg \
+    jdk.test.resources.exported.props.MyResources false
+runJava -mp mods -m embargo/jdk.embargo.TestWithNoModuleArg \
+    jdk.test.resources.exported.classes.MyResources false
+runJava -mp mods -m embargo/jdk.embargo.TestWithNoModuleArg \
+    jdk.test.resources.exported.props.MyResources false
+
+# Add mods/exported.named.bundles to the class path.
+runJava -cp mods/exported.named.bundles -mp mods -m test/jdk.test.TestWithNoModuleArg \
+    jdk.test.resources.exported.classes.MyResources false
+runJava -cp mods/exported.named.bundles -mp mods -m test/jdk.test.TestWithNoModuleArg \
+    jdk.test.resources.exported.props.MyResources false
+runJava -cp mods/exported.named.bundles -mp mods -m embargo/jdk.embargo.TestWithNoModuleArg \
+    jdk.test.resources.exported.classes.MyResources false
+runJava -cp mods/exported.named.bundles -mp mods -m embargo/jdk.embargo.TestWithNoModuleArg \
+    jdk.test.resources.exported.props.MyResources false
+
+# Tests using jdk.test.TestWithUnnamedModuleArg and jdk.embargo.TestWithUnnamedModuleArg
+# which specify an unnamed module with ResourceBundle.getBundle.
+
+# loader.loadClass() doesn't find jdk.test.resources.exported.classes.MyResources
+# and throws a ClassNotFoundException.
+runJava -mp mods -m test/jdk.test.TestWithUnnamedModuleArg \
+        jdk.test.resources.exported.classes.MyResources false
+# The properties files in jdk.test.resources.exported.props are not found with loader.getResource().
+runJava -mp mods -m test/jdk.test.TestWithUnnamedModuleArg \
+        jdk.test.resources.exported.props.MyResources false
+
+
+# loader.loadClass() doesn't find jdk.test.resources.exported.classes.MyResources
+# and throws a ClassNotFoundException.
+runJava -mp mods -m embargo/jdk.embargo.TestWithUnnamedModuleArg \
+        jdk.test.resources.exported.classes.MyResources false
+# The properties files in jdk.test.resources.exported.props are not found
+# with loader.getResource().
+runJava -mp mods -m embargo/jdk.embargo.TestWithUnnamedModuleArg \
+        jdk.test.resources.exported.props.MyResources false
+
+# Add mods/exported.named.bundles to the class path.
+
+# jdk.test.resources.exported.classes.MyResources.getModule().isNamed() returns false.
+runJava -cp mods/exported.named.bundles -mp mods -m test/jdk.test.TestWithUnnamedModuleArg \
+        jdk.test.resources.exported.classes.MyResources true
+# loader.getResource() finds jdk.test.resources.exported.props.MyResources.
+runJava -cp mods/exported.named.bundles -mp mods -m test/jdk.test.TestWithUnnamedModuleArg \
+        jdk.test.resources.exported.props.MyResources true
+
+# jdk.test.resources.exported.classes.MyResources.getModule().isNamed() returns false.
+runJava -cp mods/exported.named.bundles -mp mods -m embargo/jdk.embargo.TestWithUnnamedModuleArg \
+        jdk.test.resources.exported.classes.MyResources true
+# loader.getResource() finds jdk.test.resources.exported.props.MyResources.
+runJava -cp mods/exported.named.bundles -mp mods -m embargo/jdk.embargo.TestWithUnnamedModuleArg \
+        jdk.test.resources.exported.props.MyResources true
+
+#######################################
+# Test cases with jdk.pkg.resources.* #
+#######################################
+# Prepare resource bundles in an unnamed module
+PKG=$TESTSRC/src/pkg
+mkdir -p classes/jdk/pkg/resources/props
+$JAVAC -g -d classes $PKG/jdk/pkg/test/Main.java $PKG/jdk/pkg/resources/classes/MyResources.java
+cp $PKG/jdk/pkg/resources/props/MyResources.properties classes/jdk/pkg/resources/props
+
+# jdk.pkg.resources.* are in an unnamed module.
+# jdk.pkg.test.Main calls ResourceBundle.getBundle with an unnamed module.
+runJava -cp classes jdk.pkg.test.Main jdk.pkg.resources.classes.MyResources true
+runJava -cp classes jdk.pkg.test.Main jdk.pkg.resources.props.MyResources true
+
+exit $STATUS
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResources.xml	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!---->
+
+<!-- DTD for properties -->
+<!DOCTYPE properties [
+<!ELEMENT properties ( comment?, entry* ) >
+<!ATTLIST properties version CDATA #FIXED "1.0">
+<!ELEMENT comment (#PCDATA) >
+<!ELEMENT entry (#PCDATA) >
+<!ATTLIST entry key CDATA #REQUIRED>
+]>
+
+<properties>
+    <comment>Test data for ResourceBundle</comment>
+    <entry key="key">root: message</entry>
+</properties>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResourcesProvider.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.resources;
+
+import java.io.BufferedInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.Properties;
+import java.util.ResourceBundle;
+import java.util.spi.ResourceBundleProvider;
+
+public class MyResourcesProvider implements ResourceBundleProvider {
+    @Override
+    public ResourceBundle getBundle(String baseName, Locale locale) {
+        String xmlName = toXMLName(baseName, locale);
+        try (InputStream is = this.getClass().getModule().getResourceAsStream(xmlName)) {
+            return new XMLResourceBundle(new BufferedInputStream(is));
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private String toXMLName(String baseName, Locale locale) {
+        StringBuilder sb = new StringBuilder(baseName.replace('.', '/'));
+        String lang = locale.getLanguage();
+        if (!lang.isEmpty()) {
+            sb.append('_').append(lang);
+            String country = locale.getCountry();
+            if (!country.isEmpty()) {
+                sb.append('_').append(country);
+            }
+        }
+        return sb.append(".xml").toString();
+    }
+
+    private static class XMLResourceBundle extends ResourceBundle {
+        private Properties props;
+
+        XMLResourceBundle(InputStream stream) throws IOException {
+            props = new Properties();
+            props.loadFromXML(stream);
+        }
+
+        @Override
+        protected Object handleGetObject(String key) {
+            if (key == null) {
+                throw new NullPointerException();
+            }
+            return props.get(key);
+        }
+
+        @Override
+        public Enumeration<String> getKeys() {
+            // Not implemented
+            return null;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResources_de.xml	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!---->
+
+<!-- DTD for properties -->
+<!DOCTYPE properties [
+<!ELEMENT properties ( comment?, entry* ) >
+<!ATTLIST properties version CDATA #FIXED "1.0">
+<!ELEMENT comment (#PCDATA) >
+<!ELEMENT entry (#PCDATA) >
+<!ATTLIST entry key CDATA #REQUIRED>
+]>
+
+<properties>
+    <comment>Test data for ResourceBundle</comment>
+    <entry key="key">de: message</entry>
+</properties>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResources_en.xml	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!---->
+
+<!-- DTD for properties -->
+<!DOCTYPE properties [
+<!ELEMENT properties ( comment?, entry* ) >
+<!ATTLIST properties version CDATA #FIXED "1.0">
+<!ELEMENT comment (#PCDATA) >
+<!ELEMENT entry (#PCDATA) >
+<!ATTLIST entry key CDATA #REQUIRED>
+]>
+
+<properties>
+    <comment>Test data for ResourceBundle</comment>
+    <entry key="key">en: message</entry>
+</properties>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResources_fr.xml	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!---->
+
+<!-- DTD for properties -->
+<!DOCTYPE properties [
+<!ELEMENT properties ( comment?, entry* ) >
+<!ATTLIST properties version CDATA #FIXED "1.0">
+<!ELEMENT comment (#PCDATA) >
+<!ELEMENT entry (#PCDATA) >
+<!ATTLIST entry key CDATA #REQUIRED>
+]>
+
+<properties>
+    <comment>Test data for ResourceBundle</comment>
+    <entry key="key">fr: message</entry>
+</properties>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResources_ja.xml	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!---->
+
+<!-- DTD for properties -->
+<!DOCTYPE properties [
+<!ELEMENT properties ( comment?, entry* ) >
+<!ATTLIST properties version CDATA #FIXED "1.0">
+<!ELEMENT comment (#PCDATA) >
+<!ELEMENT entry (#PCDATA) >
+<!ATTLIST entry key CDATA #REQUIRED>
+]>
+
+<properties>
+    <comment>Test data for ResourceBundle in named modules.</comment>
+    <entry key="key">ja: message</entry>
+</properties>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResources_zh.xml	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!---->
+
+<!-- DTD for properties -->
+<!DOCTYPE properties [
+<!ELEMENT properties ( comment?, entry* ) >
+<!ATTLIST properties version CDATA #FIXED "1.0">
+<!ELEMENT comment (#PCDATA) >
+<!ELEMENT entry (#PCDATA) >
+<!ATTLIST entry key CDATA #REQUIRED>
+]>
+
+<properties>
+    <comment>Test data for ResourceBundle in named modules.</comment>
+    <entry key="key">zh: message</entry>
+</properties>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResources_zh_TW.xml	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!---->
+
+<!-- DTD for properties -->
+<!DOCTYPE properties [
+<!ELEMENT properties ( comment?, entry* ) >
+<!ATTLIST properties version CDATA #FIXED "1.0">
+<!ELEMENT comment (#PCDATA) >
+<!ELEMENT entry (#PCDATA) >
+<!ATTLIST entry key CDATA #REQUIRED>
+]>
+
+<properties>
+    <comment>Test data for ResourceBundle in named modules.</comment>
+    <entry key="key">zh-TW: message</entry>
+</properties>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module bundles {
+    exports jdk.test.resources to test;
+    provides jdk.test.resources.MyResourcesProvider with jdk.test.resources.MyResourcesProvider;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/xmlformat/src/test/jdk/test/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test;
+
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+public class Main {
+    public static void main(String[] args) throws Exception {
+        int errors = 0;
+        for (String loctag : args) {
+            Locale locale = Locale.forLanguageTag(loctag);
+            if (locale.equals(Locale.ROOT)) {
+                continue;
+            }
+            ResourceBundle rb = ResourceBundle.getBundle("jdk.test.resources.MyResources",
+                                                         locale);
+            String tag = locale.toLanguageTag(); // normalized
+            String value = rb.getString("key");
+            System.out.println("locale = " + tag + ", value = " + value);
+            if (!value.startsWith(tag + ':')) {
+                System.out.println("ERROR: " + value + " expected: " + tag);
+                errors++;
+            }
+        }
+        if (errors > 0) {
+            throw new RuntimeException(errors + " errors");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/xmlformat/src/test/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module test {
+    requires bundles;
+
+    uses jdk.test.resources.MyResourcesProvider;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/xmlformat/xmlformat.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,68 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+# @test
+# @summary Simple test case for ResourceBundle with modules;
+#          ResourceBundle.getBundle caller is in module named "test" and
+#          all resource bundles are in single module named "bundles".
+
+
+set -e
+
+if [ -z "$TESTJAVA" ]; then
+  if [ $# -lt 1 ]; then exit 1; fi
+  TESTJAVA="$1"; shift
+  COMPILEJAVA="${TESTJAVA}"
+  TESTSRC="`pwd`"
+  TESTCLASSES="`pwd`"
+fi
+
+JAVAC="$COMPILEJAVA/bin/javac"
+JAVA="$TESTJAVA/bin/java"
+
+rm -rf mods
+
+mkdir -p mods/test
+
+B=bundles
+mkdir -p mods/$B
+CLASSES="`find $TESTSRC/src/$B -name '*.java'`"
+if [ "x$CLASSES" != x ]; then
+    $JAVAC -g -d mods -modulesourcepath $TESTSRC/src $CLASSES
+fi
+PROPS="`(cd $TESTSRC/src/$B; find . -name '*.xml')`"
+if [ "x$PROPS" != x ]; then
+    for P in $PROPS
+    do
+      D=`dirname $P`
+      mkdir -p mods/$B/$D
+      cp $TESTSRC/src/$B/$P mods/$B/$D/
+    done
+fi
+
+$JAVAC -g -d mods -modulesourcepath $TESTSRC/src \
+       -cp mods/bundles `find $TESTSRC/src/test -name "*.java"`
+
+$JAVA -mp mods -m test/jdk.test.Main de fr ja zh-tw en de
+
+exit $?
--- a/test/java/util/Scanner/ScannerStreamTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/util/Scanner/ScannerStreamTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -46,8 +46,8 @@
  * @test
  * @bug 8072722
  * @summary Tests of stream support in java.util.Scanner
- * @library ../stream/bootlib/java.base
- * @build java.util.stream.OpTestCase
+ * @library ../stream/bootlib
+ * @build java.base/java.util.stream.OpTestCase
  * @run testng/othervm ScannerStreamTest
  */
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ServiceLoader/TwoIterators.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @summary Test ServiceLoader with two iterators, interleaving their use
+ *   to test that they don't interfere with each other
+ * @run testng TwoIterators
+ */
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.ServiceLoader;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+public class TwoIterators {
+
+    // service type
+    public static interface S { }
+
+    // service provider implementations
+    public static class S1 implements S { }
+    public static class S2 implements S { }
+
+    private ClassLoader testClassLoader;
+
+    // creates the services configuration file and sets the ClassLoader
+    @BeforeClass
+    void setup() throws Exception {
+        String classes = System.getProperty("test.classes");
+        Path dir = Paths.get(classes, "META-INF", "services");
+        Files.createDirectories(dir);
+        Path config = dir.resolve(S.class.getName());
+        Files.write(config, Arrays.asList(S1.class.getName(), S2.class.getName()));
+
+        this.testClassLoader = TwoIterators.class.getClassLoader();
+    }
+
+    @Test
+    public void testSequentialUse1() {
+        ServiceLoader<S> sl = ServiceLoader.load(S.class, testClassLoader);
+
+        Iterator<S> iterator1 = sl.iterator();
+        iterator1.next();
+        iterator1.next();
+        assertFalse(iterator1.hasNext());
+
+        Iterator<S> iterator2 = sl.iterator();
+        iterator2.next();
+        iterator2.next();
+        assertFalse(iterator2.hasNext());
+    }
+
+    @Test
+    public void testSequentialUse2() {
+        ServiceLoader<S> sl = ServiceLoader.load(S.class, testClassLoader);
+
+        Iterator<S> iterator1 = sl.iterator();
+        Iterator<S> iterator2 = sl.iterator();
+
+        iterator1.next();
+        iterator1.next();
+        assertFalse(iterator1.hasNext());
+
+        iterator2.next();
+        iterator2.next();
+        assertFalse(iterator2.hasNext());
+    }
+
+    @Test
+    public void testInterleaved1() {
+        ServiceLoader<S> sl = ServiceLoader.load(S.class, testClassLoader);
+
+        Iterator<S> iterator1 = sl.iterator();
+        Iterator<S> iterator2 = sl.iterator();
+
+        iterator1.next();
+        iterator2.next();
+        iterator1.next();
+        iterator2.next();
+        assertFalse(iterator1.hasNext());
+        assertFalse(iterator2.hasNext());
+    }
+
+    @Test
+    public void testInterleaved2() {
+        ServiceLoader<S> sl = ServiceLoader.load(S.class, testClassLoader);
+
+        Iterator<S> iterator1 = sl.iterator();
+        iterator1.next();
+
+        Iterator<S> iterator2 = sl.iterator();
+
+        assertTrue(iterator1.hasNext());
+        assertTrue(iterator2.hasNext());
+
+        iterator1.next();
+        iterator2.next();
+        iterator2.next();
+
+        assertFalse(iterator1.hasNext());
+        assertFalse(iterator2.hasNext());
+    }
+
+    @Test
+    public void testInterleaved3() {
+        ServiceLoader<S> sl = ServiceLoader.load(S.class, testClassLoader);
+
+        Iterator<S> iterator1 = sl.iterator();
+        iterator1.next();
+
+        Iterator<S> iterator2 = sl.iterator();
+
+        assertTrue(iterator2.hasNext());
+        assertTrue(iterator1.hasNext());
+
+        iterator2.next();
+        iterator2.next();
+        iterator1.next();
+
+        assertFalse(iterator1.hasNext());
+        assertFalse(iterator2.hasNext());
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ServiceLoader/modules/BasicTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.lang.reflect.Layer;
+import java.security.Provider;
+import java.util.ServiceLoader;
+
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/*
+ * @test
+ * @run testng BasicTest
+ * @summary Basic test of ServiceLoader with modules
+ */
+
+public class BasicTest {
+
+    @Test
+    public void testEmptyLayer() {
+        ServiceLoader<Provider> sl
+            = ServiceLoader.load(Layer.empty(), Provider.class);
+        assertFalse(sl.iterator().hasNext());
+    }
+
+    @Test
+    public void testBootLayer() {
+        ServiceLoader<Provider> sl
+            = ServiceLoader.load(Layer.boot(), Provider.class);
+        boolean found = false;
+        for (Provider provider : sl) {
+            if (provider.getName().equals("SunJCE"))
+                found = true;
+        }
+        assertTrue(found);
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testNullLayer() {
+        ServiceLoader.load(null, Provider.class);
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testNullService() {
+        ServiceLoader.load(Layer.empty(), null);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ServiceLoader/modules/ServicesTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.File;
+import java.lang.module.Configuration;
+import java.lang.module.ModuleFinder;
+import java.lang.reflect.Layer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ServiceLoader;
+import java.util.Set;
+import javax.script.ScriptEngineFactory;
+
+import static jdk.testlibrary.ProcessTools.executeTestJava;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/**
+ * @test
+ * @library /lib/testlibrary
+ * @modules java.scripting
+            jdk.compiler
+ * @build ServicesTest CompilerUtils jdk.testlibrary.*
+ * @run testng ServicesTest
+ * @summary Tests ServiceLoader to locate service providers on the module path
+ *          and class path. Also tests ServiceLoader with a custom Layer.
+ */
+
+@Test
+public class ServicesTest {
+
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path CLASSES_DIR = Paths.get("classes");
+    private static final Path MODS_DIR = Paths.get("mods");
+
+    // modules to compile to the module path
+    private static final String MODULES[] = { "test", "bananascript" };
+
+    // directories of classes to compile to the class path
+    private static final String CLASSES[] = { "pearscript" };
+
+    // resources to copy to the class path
+    private static final String RESOURCES[] = {
+        "pearscript/META-INF/services/javax.script.ScriptEngineFactory"
+    };
+
+
+    /**
+     * Compiles all modules and classes used by the test
+     */
+    @BeforeTest
+    public void setup() throws Exception {
+
+        // modules
+        for (String mn : MODULES ) {
+            Path src = SRC_DIR.resolve(mn);
+            Path mods = MODS_DIR.resolve(mn);
+            assertTrue(CompilerUtils.compile(src, mods));
+        }
+
+        // classes
+        for (String dir : CLASSES) {
+            Path src = SRC_DIR.resolve(dir);
+            assertTrue(CompilerUtils.compile(src, CLASSES_DIR));
+        }
+
+        // copy resources
+        for (String rn : RESOURCES) {
+            Path file = Paths.get(rn.replace('/', File.separatorChar));
+            Path source = SRC_DIR.resolve(file);
+
+            // drop directory to get a target of classes/META-INF/...
+            Path target = CLASSES_DIR.resolve(file.subpath(1, file.getNameCount()));
+
+            Files.createDirectories(target.getParent());
+            Files.copy(source, target);
+        }
+
+    }
+
+
+    /**
+     * Run test with -modulepath.
+     *
+     * BananaScriptEngine should be found.
+     */
+    public void runWithModulePath() throws Exception {
+        int exitValue
+            = executeTestJava("-mp", MODS_DIR.toString(),
+                              "-m", "test/test.Main",
+                              "BananaScriptEngine")
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
+
+        assertTrue(exitValue == 0);
+    }
+
+
+    /**
+     * Run test with -modulepath and -classpath.
+     *
+     * Both BananaScriptEngine and PearScriptEngine should be found
+     */
+    public void runWithModulePathAndClassPath() throws Exception {
+        int exitValue
+            = executeTestJava("-mp", MODS_DIR.toString(),
+                              "-cp", CLASSES_DIR.toString(),
+                              "-m", "test/test.Main",
+                              "BananaScriptEngine", "PearScriptEngine")
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
+
+        assertTrue(exitValue == 0);
+    }
+
+
+    /**
+     * Exercise ServiceLoader.load(Layer, Class).
+     */
+    public void testWithCustomLayer() throws Exception {
+
+        ServiceLoader<ScriptEngineFactory> sl;
+
+        // BananaScriptEngine should not be in the boot Layer
+        sl = ServiceLoader.load(Layer.boot(), ScriptEngineFactory.class);
+        assertTrue(find("BananaScriptEngine", sl) == null);
+
+        // create a custom Layer
+        ModuleFinder finder = ModuleFinder.of(MODS_DIR);
+        Layer bootLayer = Layer.boot();
+        Configuration parent = bootLayer.configuration();
+        Configuration cf
+            = parent.resolveRequiresAndUses(finder, ModuleFinder.empty(), Set.of());
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+        Layer layer = bootLayer.defineModulesWithOneLoader(cf, scl);
+
+        assertTrue(layer.findModule("bananascript").isPresent());
+        ClassLoader loader = layer.findLoader("bananascript");
+
+        sl = ServiceLoader.load(layer, ScriptEngineFactory.class);
+        ScriptEngineFactory factory = find("BananaScriptEngine", sl);
+        assertTrue(factory != null);
+        assertEquals(factory.getClass().getModule().getName(), "bananascript");
+        assertTrue(factory.getClass().getClassLoader() == loader);
+
+    }
+
+    /**
+     * Find the given scripting engine (by name) via the ScriptEngineFactory
+     * that ServiceLoader has found.
+     */
+    static ScriptEngineFactory find(String name,
+                                    ServiceLoader<ScriptEngineFactory> sl) {
+        for (ScriptEngineFactory factory : sl) {
+            if (factory.getEngineName().equals(name))
+                return factory;
+        }
+        return null;
+    }
+
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ServiceLoader/modules/src/bananascript/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module bananascript {
+    requires java.scripting;
+
+    provides javax.script.ScriptEngineFactory
+      with org.banana.BananaScriptEngineFactory;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ServiceLoader/modules/src/bananascript/org/banana/BananaScript.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.banana;
+
+import java.io.Reader;
+import javax.script.Bindings;
+import javax.script.ScriptContext;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineFactory;
+
+public class BananaScript implements ScriptEngine {
+
+    @Override
+    public Object eval(String script, ScriptContext context) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Object eval(Reader reader , ScriptContext context) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Object eval(String script) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Object eval(Reader reader) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Object eval(String script, Bindings n) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Object eval(Reader reader , Bindings n) {
+        throw new RuntimeException();
+    }
+    @Override
+    public void put(String key, Object value) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Object get(String key) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Bindings getBindings(int scope) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public void setBindings(Bindings bindings, int scope) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Bindings createBindings() {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public ScriptContext getContext() {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public void setContext(ScriptContext context) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public ScriptEngineFactory getFactory() {
+        throw new RuntimeException();
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ServiceLoader/modules/src/bananascript/org/banana/BananaScriptEngineFactory.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.banana;
+
+import java.util.Arrays;
+import java.util.List;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineFactory;
+
+public class BananaScriptEngineFactory implements ScriptEngineFactory {
+
+    @Override
+    public String getEngineName() {
+        return "BananaScriptEngine";
+    }
+
+    @Override
+    public String getEngineVersion() {
+        return "1.0";
+    }
+
+    @Override
+    public List<String> getExtensions() {
+        return Arrays.asList("banana");
+    }
+
+    @Override
+    public List<String> getMimeTypes() {
+        return Arrays.asList("application/x-bananascript");
+    }
+
+    @Override
+    public List<String> getNames() {
+        return Arrays.asList("BananaScript");
+    }
+
+    @Override
+    public String getLanguageName() {
+        return "BananaScript";
+    }
+
+    @Override
+    public String getLanguageVersion() {
+        return "1.0";
+    }
+
+    @Override
+    public Object getParameter(String key) {
+        return null;
+    }
+
+    @Override
+    public String getMethodCallSyntax(String obj, String m, String... args) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public String getOutputStatement(String toDisplay) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public String getProgram(String... statements) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public ScriptEngine getScriptEngine() {
+        return new BananaScript();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ServiceLoader/modules/src/pearscript/META-INF/services/javax.script.ScriptEngineFactory	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,1 @@
+org.pear.PearScriptEngineFactory
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ServiceLoader/modules/src/pearscript/org/pear/PearScript.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.pear;
+
+import java.io.Reader;
+import javax.script.Bindings;
+import javax.script.ScriptContext;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineFactory;
+
+public class PearScript implements ScriptEngine {
+
+    @Override
+    public Object eval(String script, ScriptContext context) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Object eval(Reader reader , ScriptContext context) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Object eval(String script) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Object eval(Reader reader) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Object eval(String script, Bindings n) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Object eval(Reader reader , Bindings n) {
+        throw new RuntimeException();
+    }
+    @Override
+    public void put(String key, Object value) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Object get(String key) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Bindings getBindings(int scope) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public void setBindings(Bindings bindings, int scope) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Bindings createBindings() {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public ScriptContext getContext() {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public void setContext(ScriptContext context) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public ScriptEngineFactory getFactory() {
+        throw new RuntimeException();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ServiceLoader/modules/src/pearscript/org/pear/PearScriptEngineFactory.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.pear;
+
+import java.util.Arrays;
+import java.util.List;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineFactory;
+
+public class PearScriptEngineFactory implements ScriptEngineFactory {
+
+    @Override
+    public String getEngineName() {
+        return "PearScriptEngine";
+    }
+
+    @Override
+    public String getEngineVersion() {
+        return "1.0";
+    }
+
+    @Override
+    public List<String> getExtensions() {
+        return Arrays.asList("pear");
+    }
+
+    @Override
+    public List<String> getMimeTypes() {
+        return Arrays.asList("application/x-pearscript");
+    }
+
+    @Override
+    public List<String> getNames() {
+        return Arrays.asList("PearScript");
+    }
+
+    @Override
+    public String getLanguageName() {
+        return "PearScript";
+    }
+
+    @Override
+    public String getLanguageVersion() {
+        return "1.0";
+    }
+
+    @Override
+    public Object getParameter(String key) {
+        return null;
+    }
+
+    @Override
+    public String getMethodCallSyntax(String obj, String m, String... args) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public String getOutputStatement(String toDisplay) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public String getProgram(String... statements) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public ScriptEngine getScriptEngine() {
+        return new PearScript();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ServiceLoader/modules/src/test/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module test {
+    requires java.scripting;
+
+    uses javax.script.ScriptEngineFactory;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ServiceLoader/modules/src/test/test/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package test;
+
+import java.util.HashSet;
+import java.util.ServiceLoader;
+import java.util.Set;
+import javax.script.ScriptEngineFactory;
+
+public class Main {
+    public static void main(String[] args) {
+        Set<String> engines = new HashSet<>();
+        for (ScriptEngineFactory factory: ServiceLoader.load(ScriptEngineFactory.class)) {
+            System.out.format("loaded: %s%n" , factory.getEngineName());
+            engines.add(factory.getEngineName());
+        }
+
+        for (String engine: args) {
+            if (!engines.contains(engine))
+                throw new RuntimeException(engine + " not found");
+        }
+    }
+}
--- a/test/java/util/logging/LocalizedLevelName.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/util/logging/LocalizedLevelName.java	Thu Mar 17 19:04:16 2016 +0000
@@ -21,6 +21,7 @@
  * questions.
  */
 
+import java.lang.reflect.Module;
 import java.util.*;
 import java.util.logging.*;
 
@@ -97,7 +98,10 @@
 
     private static final String RBNAME = "sun.util.logging.resources.logging";
     private static String getLocalizedMessage(Locale locale, String key) {
-        ResourceBundle rb = ResourceBundle.getBundle(RBNAME, locale);
+        // this test verifies if the logging.properties in the java.logging module
+        // is localized.
+        Module module = java.util.logging.Level.class.getModule();
+        ResourceBundle rb = ResourceBundle.getBundle(RBNAME, locale, module);
         return rb.getString(key);
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/logging/modules/GetResourceBundleTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
+import static jdk.testlibrary.ProcessTools.*;
+import static org.testng.Assert.*;
+
+/**
+ * @test
+ * @bug 8129126 8136802 8137316 8137317 8136804 8139350
+ * @library /lib/testlibrary
+ * @modules jdk.compiler
+ * @build GetResourceBundleTest CompilerUtils jdk.testlibrary.ProcessTools
+ * @run testng GetResourceBundleTest
+ * @summary Tests Logger.getLogger + logger.getResourceBundle in an named/unnamed module,
+ *          resources are in named and unnamed modules respectively.
+ *          Positive tests to ensure that a Logger can retrieve ResourceBundle in its current module.
+ *          Negative tests to ensure that a Logger cannot retrieve ResourceBundle in another module.
+ *          This test also verifies 8136802 8137316 8137317 8136804 8139350.
+ */
+
+public class GetResourceBundleTest {
+
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    private static final Path MOD_SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path MOD_DEST_DIR = Paths.get("mods");
+    private static final Path PKG_SRC_DIR = Paths.get(TEST_SRC, "pkgs");
+    private static final Path PKG_DEST_DIR = Paths.get("pkgs");
+
+    private static final String[] modules = new String[] {"m1", "m2"};
+
+    /**
+     * Compiles all modules used by the test, copy resource files.
+     */
+    @BeforeClass
+    public void setup() throws Exception {
+        // compile all modules
+        for (String mn : modules) {
+            Path msrc = MOD_SRC_DIR.resolve(mn);
+            assertTrue(CompilerUtils.compile(msrc, MOD_DEST_DIR,
+                    "-modulesourcepath", MOD_SRC_DIR.toString()));
+        }
+        assertTrue(CompilerUtils.compile(PKG_SRC_DIR, PKG_DEST_DIR,
+                "-modulepath", MOD_DEST_DIR.toString(), "-addmods", String.join(",", modules)));
+
+        // copy resource files
+        String[] files = { "m1/p1/resource/p.properties", "m2/p2/resource/p.properties" };
+        for(String f : files) {
+            Files.copy(MOD_SRC_DIR.resolve(f), MOD_DEST_DIR.resolve(f), REPLACE_EXISTING);
+        }
+        String p3 = "p3/resource/p.properties";
+        Files.copy(PKG_SRC_DIR.resolve(p3), PKG_DEST_DIR.resolve(p3), REPLACE_EXISTING);
+    }
+
+    @Test
+    public void runWithoutSecurityManager() throws Exception {
+        int exitValue = executeTestJava(
+                "-cp", PKG_DEST_DIR.toString(),
+                "-mp", MOD_DEST_DIR.toString(),
+                "-addmods", String.join(",", modules),
+                "p3.test.ResourceBundleTest")
+                .outputTo(System.out)
+                .errorTo(System.err)
+                .getExitValue();
+        assertTrue(exitValue == 0);
+    }
+
+    @Test
+    public void runWithSecurityManager() throws Exception {
+        int exitValue = executeTestJava(
+                "-Djava.security.manager",
+                "-cp", PKG_DEST_DIR.toString(),
+                "-mp", MOD_DEST_DIR.toString(),
+                "-addmods", String.join(",", modules),
+                "p3.test.ResourceBundleTest")
+                .outputTo(System.out)
+                .errorTo(System.err)
+                .getExitValue();
+        assertTrue(exitValue == 0);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/logging/modules/pkgs/p3/resource/ClassResource.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p3.resource;
+
+import java.util.ListResourceBundle;
+
+public class ClassResource extends ListResourceBundle {
+
+    protected Object[][] getContents() {
+        return new Object[][] {
+                { "OkKey", "OK" },
+                { "CancelKey", "Cancel" }, };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/logging/modules/pkgs/p3/resource/p.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,1 @@
+OkKey=OK
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/logging/modules/pkgs/p3/test/ResourceBundleTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p3.test;
+
+import java.lang.reflect.Module;
+import java.util.logging.Logger;
+import java.util.MissingResourceException;
+import java.util.PropertyResourceBundle;
+import java.util.ResourceBundle;
+
+import p2.test.ModuleLoggerAccess;
+
+/*
+ * Test Logger.getLogger + logger.getResourceBundle in unnamed/named module,
+ * resources are in named and unnamed modules respectively.
+ */
+public class ResourceBundleTest {
+    private static final String RESOURCE_KEY = "OkKey";
+    private static final String RESOURCE_VALUE = "OK";
+
+    private static final String HELP_MSG =
+            "Test that a class in a %s module %s obtain a logger " +
+            "which uses a resource bundle %s bundled in " +
+            "%s module. ( The package in which the resource is " +
+            "contained is not exported by the module )";
+    private static final String NAMED_POSITIVE_CLASSBUNDLE_MSG =
+            String.format(HELP_MSG, "named", "can", "class", "the same");
+    private static final String UNNAMED_POSITIVE_CLASSBUNDLE_MSG =
+            String.format(HELP_MSG, "unnamed", "can", "class", "the same");
+    private static final String NAMED_POSITIVE_PROPERTYBUNDLE_MSG =
+            String.format(HELP_MSG, "named", "can", "property", "the same");
+    private static final String UNNAMED_POSITIVE_PROPERTYBUNDLE_MSG =
+            String.format(HELP_MSG, "unnamed", "can", "property", "the same");
+    private static final String NAMED_NEGATIVE_CLASSBUNDLE_MSG =
+            String.format(HELP_MSG, "named", "cannot", "class", "another");
+    private static final String UNNAMED_NEGATIVE_CLASSBUNDLE_MSG =
+            String.format(HELP_MSG, "unnamed", "cannot", "class", "another");
+    private static final String NAMED_NEGATIVE_PROPERTYBUNDLE_MSG =
+            String.format(HELP_MSG, "named", "cannot", "property", "another");
+    private static final String UNNAMED_NEGATIVE_PROPERTYBUNDLE_MSG =
+            String.format(HELP_MSG, "unnamed", "cannot", "property", "another");
+
+    public static void main(String[] args) {
+        verifySetup();
+        testLoggerRBs();
+        failToLoadRBs();
+    }
+
+    static void verifySetup() {
+        Module m = ResourceBundleTest.class.getModule();
+        System.out.println("Module Name for ResourceBundleTest : " + m.getName());
+        assertTrue(!m.isNamed());
+        m = ModuleLoggerAccess.class.getModule();
+        System.out.println("Module Name for ModuleLoggerAccess : " + m.getName());
+        assertTrue(m.isNamed());
+    }
+
+    /*
+     * Positive tests :
+     *  Should be able to access class/property resource bundle in current module,
+     *  no matter named or unnamed module.
+     */
+    static void testLoggerRBs() {
+        testLoggerClassRBs();
+        testLoggerPropertyRBs();
+    }
+
+    static void testLoggerClassRBs() {
+        testLoggerResoureBundle(
+                Logger.getLogger("mylogger.a", "p3.resource.ClassResource"),
+                p3.resource.ClassResource.class,
+                UNNAMED_POSITIVE_CLASSBUNDLE_MSG);
+        testLoggerResoureBundle(
+                ModuleLoggerAccess.getLogger("mylogger.b", "p2.resource.ClassResource"),
+                ModuleLoggerAccess.getResourceClass(),
+                NAMED_POSITIVE_CLASSBUNDLE_MSG);
+    }
+
+    static void testLoggerPropertyRBs() {
+        testLoggerResoureBundle(
+                Logger.getLogger("mylogger.c", "p3.resource.p"),
+                PropertyResourceBundle.class,
+                UNNAMED_POSITIVE_PROPERTYBUNDLE_MSG);
+        testLoggerResoureBundle(
+                ModuleLoggerAccess.getLogger("mylogger.d", "p2.resource.p"),
+                PropertyResourceBundle.class,
+                NAMED_POSITIVE_PROPERTYBUNDLE_MSG);
+    }
+
+    static void testLoggerResoureBundle(Logger logger, Class<?> rbType, String helpMsg) {
+        System.out.println(helpMsg);
+        ResourceBundle rb = logger.getResourceBundle();
+        assertTrue(rbType.isInstance(rb));
+        assertTrue(RESOURCE_VALUE.equals(rb.getString(RESOURCE_KEY)));
+    }
+
+    /*
+     * Negative tests :
+     *  MissingResourceException should be thrown when access class/property resource bundle
+     *  from another module, no matter named or unnamed module.
+     */
+    static void failToLoadRBs() {
+        failToLoadClassRBs();
+        failToLoadPropertyRBs();
+    }
+
+    static void failToLoadClassRBs() {
+        // in an unnamed module, try to create a logger with
+        // class resource bundle in named module m1 or m2.
+        failToLoadResourceBundle("mylogger.e", "p1.resource.ClassResource",
+                false, UNNAMED_NEGATIVE_CLASSBUNDLE_MSG);
+        failToLoadResourceBundle("mylogger.f", "p2.resource.ClassResource",
+                false, UNNAMED_NEGATIVE_CLASSBUNDLE_MSG);
+        // in named module m2, try to create a logger with
+        // class resource bundle in another named module m1.
+        failToLoadResourceBundle("mylogger.g", "p1.resource.ClassResource",
+                true, NAMED_NEGATIVE_CLASSBUNDLE_MSG);
+        // in named module m2, try to create a logger with
+        // class resource bundle in an unnamed module.
+        failToLoadResourceBundle("mylogger.h", "p3.resource.ClassResource",
+                true, NAMED_NEGATIVE_CLASSBUNDLE_MSG);
+    }
+
+    static void failToLoadPropertyRBs() {
+        // in an unnamed module, try to create a logger with
+        // property resource bundle in named module m1 or m2.
+        failToLoadResourceBundle("mylogger.i", "p1.resource.p",
+                false, UNNAMED_NEGATIVE_PROPERTYBUNDLE_MSG);
+        failToLoadResourceBundle("mylogger.j", "p2.resource.p",
+                false, UNNAMED_NEGATIVE_PROPERTYBUNDLE_MSG);
+        // in named module m2, try to create a logger with
+        // property resource bundle in another named module m1.
+        failToLoadResourceBundle("mylogger.k", "p1.resource.p",
+                true, NAMED_NEGATIVE_PROPERTYBUNDLE_MSG);
+        // in named module m2, try to create a logger with
+        // property resource bundle in an unnamed module.
+        failToLoadResourceBundle("mylogger.l", "p3.resource.p",
+                true, NAMED_NEGATIVE_PROPERTYBUNDLE_MSG);
+    }
+
+    static void failToLoadResourceBundle(String loggerName, String rbName,
+            boolean getLoggerInNamedModule, String helpMsg) {
+        String msg = String.format(
+                "Logger : %s. Expected exception is not thrown for ResourceBundle : %s.",
+                loggerName, rbName);
+        System.out.println(helpMsg);
+        try {
+            if(getLoggerInNamedModule) {
+                ModuleLoggerAccess.getLogger(loggerName, rbName);
+            } else {
+                Logger.getLogger(loggerName, rbName);
+            }
+            throw new RuntimeException(msg);
+        } catch (MissingResourceException expected) {
+            System.out.println("Get expected exception : " + expected);
+            return;
+        }
+    }
+
+    public static void assertTrue(boolean b) {
+        if (!b) {
+            throw new RuntimeException("Expect true, get false!");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/logging/modules/src/m1/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m1 {
+    requires java.logging;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/logging/modules/src/m1/p1/resource/ClassResource.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p1.resource;
+
+import java.util.ListResourceBundle;
+
+public class ClassResource extends ListResourceBundle {
+
+    protected Object[][] getContents() {
+        return new Object[][] {
+                { "OkKey", "OK" },
+                { "CancelKey", "Cancel" }, };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/logging/modules/src/m1/p1/resource/p.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,1 @@
+OkKey=OK
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/logging/modules/src/m2/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m2 {
+    requires m1;
+    requires java.logging;
+    exports p2.test;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/logging/modules/src/m2/p2/resource/ClassResource.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p2.resource;
+
+import java.util.ListResourceBundle;
+
+public class ClassResource extends ListResourceBundle {
+    protected Object[][] getContents() {
+        return new Object[][] {
+                { "OkKey", "OK" },
+                { "CancelKey", "Cancel" }, };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/logging/modules/src/m2/p2/resource/p.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,1 @@
+OkKey=OK
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/logging/modules/src/m2/p2/test/ModuleLoggerAccess.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p2.test;
+
+import java.util.logging.Logger;
+
+/*
+ * Logger in this named module m2 loading a resource bundle
+ * in m2, m1 or unnamed module.
+ */
+public class ModuleLoggerAccess {
+
+    public static Logger getLogger(String loggerName, String rbName) {
+        return Logger.getLogger(loggerName, rbName);
+    }
+
+    public static Class<?> getResourceClass() {
+        return p2.resource.ClassResource.class;
+    }
+}
--- a/test/java/util/regex/PatternStreamTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/util/regex/PatternStreamTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -25,8 +25,8 @@
  * @test
  * @bug 8016846 8024341 8071479 8145006
  * @summary Unit tests stream and lambda-based methods on Pattern and Matcher
- * @library ../stream/bootlib/java.base
- * @build java.util.stream.OpTestCase
+ * @library ../stream/bootlib
+ * @build java.base/java.util.stream.OpTestCase
  * @run testng/othervm PatternStreamTest
  */
 
--- a/test/java/util/stream/bootlib/TEST.properties	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-# This file identifies root(s) of the test-ng hierarchy.
-
-bootclasspath.dirs = java.base
--- a/test/java/util/stream/boottest/TEST.properties	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/util/stream/boottest/TEST.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,4 @@
 # This file identifies root(s) of the test-ng hierarchy.
 
-TestNG.dirs = java.base
-bootclasspath.dirs = java.base
-lib.dirs = /java/util/stream/bootlib/java.base
+TestNG.dirs = .
+lib.dirs = /java/util/stream/bootlib
--- a/test/java/util/stream/test/TEST.properties	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/java/util/stream/test/TEST.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -2,7 +2,7 @@
 
 TestNG.dirs = .
 
-lib.dirs = /java/util/stream/bootlib/java.base
+lib.dirs = /java/util/stream/bootlib
 
 # Tests that must run in othervm mode
 othervm.dirs= /java/util/stream
--- a/test/javax/crypto/NullCipher/TestWithoutInit.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/javax/crypto/NullCipher/TestWithoutInit.java	Thu Mar 17 19:04:16 2016 +0000
@@ -34,7 +34,6 @@
 
 import javax.crypto.*;
 import javax.crypto.spec.*;
-import com.sun.crypto.provider.*;
 
 public class TestWithoutInit {
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/imageio/plugins/external_plugin_tests/TestClassPathPlugin.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,107 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+# @test
+# @bug 8081729
+# @summary Test external plugin as classpath jar and as a modular jar.
+#          Test both cases with and without a security manager.
+
+set -e
+
+exception=0
+
+if [ -z "$TESTJAVA" ]; then
+  if [ $# -lt 1 ]; then  echo "No Java path specified. Exiting."; fi
+  if [ $# -lt 1 ]; then exit 1; fi
+  TESTJAVA="$1"; shift
+  COMPILEJAVA="${TESTJAVA}"
+  TESTSRC="`pwd`"
+  TESTCLASSES="`pwd`"
+fi
+
+JAVAC="$COMPILEJAVA/bin/javac"
+JAR="$COMPILEJAVA/bin/jar"
+JAVA="$TESTJAVA/bin/java ${TESTVMOPTS}"
+
+TESTDIR="$TESTCLASSES/classes"
+PLUGINDIR="$TESTCLASSES/classes"
+mkdir -p $TESTDIR
+$JAVAC -d $TESTDIR `find $TESTSRC/src/simptest -name "*.java"`
+
+# compile the plugin java sources and services file into a temp location.
+
+mkdir -p $TESTCLASSES/tmpdir/simp
+cp -r $TESTSRC/src/simp/META-INF $TESTCLASSES/tmpdir
+$JAVAC -d $TESTCLASSES/tmpdir `find $TESTSRC/src/simp -name "*.java"`
+
+# create modular jar file (inc. module-info.java) from the class files.
+mkdir -p $PLUGINDIR
+$JAR cf $PLUGINDIR/simp.jar -C $TESTCLASSES/tmpdir META-INF/services \
+    -C $TESTCLASSES/tmpdir module-info.class -C $TESTCLASSES/tmpdir simp
+
+OS=`uname -s`
+case "$OS" in
+  Windows_* | CYGWIN* )
+CPSEP=";"
+  ;;
+  * )
+CPSEP=":"
+  ;;
+esac
+
+# expect to find SimpReader via jar on classpath.
+# Will be treated as a regular jar.
+echo "Test classpath jar .. "
+$JAVA  -cp ${TESTDIR}${CPSEP}${PLUGINDIR}/simp.jar simptest.TestSIMPPlugin
+if [ $? -ne 0 ]; then
+    exception=1
+      echo "Classpath test failed: exception thrown!"
+fi
+echo "Test classpath jar with security manager .."
+$JAVA -Djava.security.manager -cp .${CPSEP}${TESTDIR}${CPSEP}${PLUGINDIR}/simp.jar simptest.TestSIMPPlugin
+if [ $? -ne 0 ]; then
+    exception=1
+    echo "Classpath + SecurityManager test failed: exception thrown!"
+fi
+
+# expect to find SimpReader on module path
+echo "Test modular jar .. "
+$JAVA -mp $PLUGINDIR -cp $TESTDIR simptest.TestSIMPPlugin
+
+if [ $? -ne 0 ]; then
+    exception=1
+    echo "modular jar test failed: exception thrown!"
+fi
+
+echo "Test modular jar with security manager .."
+$JAVA -Djava.security.manager -mp $PLUGINDIR -cp $TESTDIR simptest.TestSIMPPlugin
+if [ $? -ne 0 ]; then
+    exception=1
+    echo "modular jar with security manager test failed: exception thrown!"
+fi
+
+if [ $exception -ne 0 ]; then
+    echo "TEST FAILED"
+    exit 1
+fi
+exit 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/imageio/plugins/external_plugin_tests/src/simp/META-INF/services/javax.imageio.spi.ImageReaderSpi	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,1 @@
+simp.SIMPImageReaderSpi
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/imageio/plugins/external_plugin_tests/src/simp/SIMPImageReader.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,145 @@
+/**
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package simp;
+
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import javax.imageio.IIOException;
+import javax.imageio.ImageReadParam;
+import javax.imageio.ImageReader;
+import javax.imageio.ImageTypeSpecifier;
+import javax.imageio.metadata.IIOMetadata;
+import javax.imageio.spi.ImageReaderSpi;
+import javax.imageio.stream.ImageInputStream;
+
+/**
+  * A simple image format which has no compression and is a
+  * header with bytes 'SIMP', two signed bytes for width and height,
+  * and then unpadded 3 byte per pixel data representing RGB assumed
+  * to be in sRGB. The signed byte implies a maximum size of 127x127 pixels.
+  * Trailing data is ignored but there must be at least
+  * 3*width*height bytes of data following the simple 6 byte header.
+  */
+public class SIMPImageReader extends ImageReader {
+
+    private ImageInputStream stream = null;
+    private byte width = -1, height = -1;
+    SIMPMetadata metadata = null;
+    byte[] imageData = null;
+
+    public SIMPImageReader(ImageReaderSpi originatingProvider) {
+       super(originatingProvider);
+    }
+
+    public void setInput(Object input,
+                         boolean seekForwardOnly,
+                         boolean ignoreMetadata) {
+        super.setInput(input, seekForwardOnly, ignoreMetadata);
+        stream = (ImageInputStream) input;
+    }
+
+    private void checkState(int imageIndex) throws IOException {
+        if (stream == null) {
+            throw new IllegalStateException("input not set.");
+        }
+        if (imageIndex != 0) {
+            throw new IndexOutOfBoundsException("index != 0");
+        }
+        if (width==-1) {
+            byte[] sig = new byte[4];
+            stream.reset();
+            stream.read(sig);
+            boolean ok = sig[0]=='S' && sig[1]=='I' &&
+                         sig[2]=='M' && sig[3]=='P';
+            if (!ok) {
+                throw new IIOException("Not a SIMP image");
+            }
+            width = stream.readByte();
+            height = stream.readByte();
+        }
+        if (width <= 0 || height <= 0) {
+            throw new IOException("bad image size");
+        }
+        metadata = new SIMPMetadata(width, height);
+    }
+
+    public int getWidth(int imageIndex) throws IOException {
+        checkState(imageIndex);
+        return width;
+    }
+
+    public int getHeight(int imageIndex) throws IOException {
+        checkState(imageIndex);
+        return height;
+    }
+
+     public int getNumImages(boolean allowSearch) throws IOException {
+        checkState(0);
+        return 1;
+    }
+
+     public IIOMetadata getStreamMetadata() throws IOException {
+        return null;
+     }
+
+     public IIOMetadata getImageMetadata(int imageIndex) throws IOException {
+        checkState(imageIndex);
+        return metadata;
+    }
+
+    public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex)
+        throws IOException {
+
+        checkState(imageIndex);
+        BufferedImage bi =
+            new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
+        ArrayList<ImageTypeSpecifier> list = new ArrayList<>(1);
+        list.add(new ImageTypeSpecifier(bi));
+        return list.iterator();
+    }
+
+    public BufferedImage read(int imageIndex, ImageReadParam param)
+                            throws IOException {
+        checkState(imageIndex);
+        int len = 3*width*height;
+        byte[] imageData = new byte[len];
+        // The following is not efficient and is skipping all the
+        // progress updates, and ignoring the ImageReadParam, which
+        // it should not, but it is all we need for this test.
+        stream.readFully(imageData, 0, len);
+        BufferedImage bi =
+            new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+        int off = 0;
+        for (int h=0;h<height;h++) {
+            int rgb = imageData[off]++ << 16 |
+                      imageData[off++] <<  8 | imageData[off++];
+            for (int w=0;w<width;w++) {
+                bi.setRGB(w, h, rgb);
+            }
+        }
+        return bi;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/imageio/plugins/external_plugin_tests/src/simp/SIMPImageReaderSpi.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,86 @@
+/**
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package simp;
+
+import java.io.IOException;
+import java.util.Locale;
+import javax.imageio.IIOException;
+import javax.imageio.ImageReader;
+import javax.imageio.spi.ImageReaderSpi;
+import javax.imageio.stream.ImageInputStream;
+
+public class SIMPImageReaderSpi extends ImageReaderSpi {
+
+    private static final String[] FORMATNAMES = {"simp, SIMP"};
+    private static final String[] SUFFIXES = {"simp"};
+    private static final String[] MIMETYPES = {"image/simp"};
+
+    public SIMPImageReaderSpi() {
+        super("J Duke",                   // vendor
+              "1.0",                      // version
+               FORMATNAMES,               // format names
+               SUFFIXES,                  // file suffixes
+               MIMETYPES,                 // mimetypes
+               "simp.SIMPImageReader",    // reader class name
+               new Class<?>[] { ImageInputStream.class }, // input types
+               null,              // writer class names. TBD.
+               true,              // supports native metadata,
+               null,              // [no] native stream metadata format
+               null,              // [no] native stream metadata class
+               null,              // [no] native extra stream metadata format
+               null,              // [no] native extra stream metadata class
+               true,              // supports standard metadata,
+               "simp_metadata_1.0",       // metadata format name,
+               "simp.SIMPMetadataFormat", // metadata format class name
+               null,              // [no] extra image metadata format
+               null               // [no] extra image metadata format class
+         );
+         System.out.println("INIT SIMPImageReaderSpi");
+    }
+
+    public String getDescription(Locale locale) {
+        return "SIMPle Image Format Reader";
+    }
+
+    public boolean canDecodeInput(Object source) throws IOException {
+        if (!(source instanceof ImageInputStream)) {
+            return false;
+        }
+        ImageInputStream stream = (ImageInputStream)source;
+
+        stream.mark();
+        try {
+             byte[] sig = new byte[4];
+             stream.read(sig);
+             return sig[0]=='S' && sig[1]=='I' && sig[2]=='M' && sig[3]=='P';
+        } finally {
+            stream.reset();
+        }
+    }
+
+    public ImageReader createReaderInstance(Object extension)
+        throws IIOException {
+        return new SIMPImageReader(this);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/imageio/plugins/external_plugin_tests/src/simp/SIMPMetadata.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,94 @@
+/**
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package simp;
+
+import javax.imageio.metadata.IIOMetadata;
+import javax.imageio.metadata.IIOMetadataNode;
+import javax.imageio.metadata.IIOMetadataFormatImpl;
+import org.w3c.dom.Node;
+
+public class SIMPMetadata extends IIOMetadata {
+
+   static final String nativeMetadataFormatName = "simp_metadata_1.0";
+
+   private int width, height;
+
+   public SIMPMetadata() {
+       super(true,
+             nativeMetadataFormatName, "simp.SIMPMetadataFormat", null, null);
+   }
+
+   public SIMPMetadata(int width, int height) {
+       this();
+       this.width = width;
+       this.height = height;
+   }
+
+   public boolean isReadOnly() {
+        return true;
+   }
+
+   public void setFromTree(String formatName, Node root) {
+    }
+
+    public void mergeTree(String formatName, Node root) {
+        throw new IllegalStateException("read only metadata");
+    }
+
+    public void reset() {
+        throw new IllegalStateException("read only metadata");
+    }
+
+    private IIOMetadataNode addChildNode(IIOMetadataNode root,
+                                         String name,
+                                         Object object) {
+        IIOMetadataNode child = new IIOMetadataNode(name);
+        if (object != null) {
+            child.setUserObject(object);
+            child.setNodeValue(object.toString());
+        }
+        root.appendChild(child);
+        return child;
+    }
+
+    private Node getNativeTree() {
+        IIOMetadataNode root =
+            new IIOMetadataNode(nativeMetadataFormatName);
+        addChildNode(root, "width", width);
+        addChildNode(root, "weight", height);
+        return root;
+    }
+
+    public Node getAsTree(String formatName) {
+        if (formatName.equals(nativeMetadataFormatName)) {
+            return getNativeTree();
+        } else if (formatName.equals
+                   (IIOMetadataFormatImpl.standardMetadataFormatName)) {
+            return getStandardTree();
+        } else {
+            throw new IllegalArgumentException("unsupported format");
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/imageio/plugins/external_plugin_tests/src/simp/SIMPMetadataFormat.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,62 @@
+/**
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package simp;
+
+import java.util.Arrays;
+import javax.imageio.ImageTypeSpecifier;
+import javax.imageio.metadata.IIOMetadataFormat;
+import javax.imageio.metadata.IIOMetadataFormatImpl;
+
+public class SIMPMetadataFormat extends IIOMetadataFormatImpl {
+
+    private static IIOMetadataFormat instance = null;
+
+    public static synchronized IIOMetadataFormat getInstance() {
+        if (instance == null) {
+            instance = new SIMPMetadataFormat();
+        }
+        return instance;
+    }
+
+    public boolean canNodeAppear(String elementName,
+                                 ImageTypeSpecifier imageType) {
+        return true;
+    }
+
+    private SIMPMetadataFormat() {
+        super(SIMPMetadata.nativeMetadataFormatName,
+              CHILD_POLICY_SOME);
+
+        addElement("ImageDescriptor",
+                   SIMPMetadata.nativeMetadataFormatName,
+                   CHILD_POLICY_EMPTY);
+
+        addAttribute("ImageDescriptor", "width",
+                     DATATYPE_INTEGER, true, null,
+                     "1", "127", true, true);
+        addAttribute("ImageDescriptor", "height",
+                     DATATYPE_INTEGER, true, null,
+                     "1", "127", true, true);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/imageio/plugins/external_plugin_tests/src/simp/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module simp {
+    requires java.desktop;
+    exports simp to java.desktop;
+    provides javax.imageio.spi.ImageReaderSpi with simp.SIMPImageReaderSpi;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/imageio/plugins/external_plugin_tests/src/simptest/TestSIMPPlugin.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,73 @@
+/**
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package simptest;
+
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.Iterator;
+import javax.imageio.ImageIO;
+import javax.imageio.ImageReader;
+import javax.imageio.metadata.IIOMetadata;
+import javax.imageio.metadata.IIOMetadataFormat;
+import javax.imageio.spi.ImageReaderSpi;
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.stream.MemoryCacheImageInputStream;
+
+public class TestSIMPPlugin {
+
+    static byte[] simpData = { (byte)'S', (byte)'I', (byte)'M', (byte)'P',
+                               1, 1, 0, 0, 0};
+
+    public static void main(String args[]) throws Exception {
+        Iterator<ImageReader> readers = ImageIO.getImageReadersBySuffix("simp");
+        ImageReader simpReader = null;
+        if (readers.hasNext()) {
+            simpReader = readers.next();
+            System.out.println("reader="+simpReader);
+        }
+        if (simpReader == null) {
+            throw new RuntimeException("Reader not found.");
+        }
+
+        ImageReaderSpi spi = simpReader.getOriginatingProvider();
+        IIOMetadataFormat spiFmt =
+            spi.getImageMetadataFormat("simp_metadata_1.0");
+        System.out.println("fmt from SPI=" + spiFmt);
+
+        ByteArrayInputStream bais = new ByteArrayInputStream(simpData);
+        ImageInputStream iis = new MemoryCacheImageInputStream(bais);
+        simpReader.setInput(iis);
+        BufferedImage bi = simpReader.read(0);
+        System.out.println(bi);
+        IIOMetadata metadata = simpReader.getImageMetadata(0);
+        System.out.println("Image metadata="+metadata);
+        IIOMetadataFormat format =
+            metadata.getMetadataFormat("simp_metadata_1.0");
+        System.out.println("Image metadata format="+format);
+        if (format == null) {
+            throw new RuntimeException("MetadataFormat not found.");
+        }
+    }
+}
--- a/test/javax/imageio/stream/StreamCloserLeak/run_test.sh	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/javax/imageio/stream/StreamCloserLeak/run_test.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -198,15 +198,15 @@
     fail "Unable to create temp directory."
 fi
 
-# Verify that all classoladers are destroyed
-${TESTJAVA}/bin/java ${TESTVMOPTS} -cp Test.jar test.Main
+# Verify that all classloaders are destroyed
+${TESTJAVA}/bin/java -XaddExports:java.desktop/sun.awt=ALL-UNNAMED ${TESTVMOPTS} -cp Test.jar test.Main
 if [ $? -ne 0 ] ; then
     fail "Test FAILED: some classloaders weren't destroyed."
 fi
 
 
 # Verify that ImageIO shutdown hook works correcly
-${TESTJAVA}/bin/java ${TESTVMOPTS} \
+${TESTJAVA}/bin/java -XaddExports:java.desktop/sun.awt=ALL-UNNAMED ${TESTVMOPTS} \
     -cp Test.jar -DforgetSomeStreams=true test.Main
 if [ $? -ne 0 ] ; then
     fail "Test FAILED: some classloaders weren't destroyed of shutdown hook failed."
--- a/test/javax/management/MBeanInfo/NotificationInfoTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/javax/management/MBeanInfo/NotificationInfoTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -37,8 +37,13 @@
 import java.lang.management.*;
 import java.lang.reflect.*;
 import java.net.*;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.*;
-import java.util.jar.*;
+import java.util.stream.Collectors;
 import javax.management.*;
 import javax.management.relation.*;
 import javax.management.remote.*;
@@ -83,9 +88,13 @@
         System.out.println("Checking platform MBeans...");
         checkPlatformMBeans();
 
-        URL codeBase = ClassLoader.getSystemResource("javax/management/MBeanServer.class");
-        if (codeBase == null) {
-            throw new Exception("Could not determine codeBase for " + MBeanServer.class);
+        URL codeBase;
+        String home = System.getProperty("java.home");
+        Path classFile = Paths.get(home, "modules", "java.management");
+        if (Files.isDirectory(classFile)) {
+            codeBase = classFile.toUri().toURL();
+        } else {
+            codeBase = URI.create("jrt:/java.management").toURL();
         }
 
         System.out.println();
@@ -214,14 +223,13 @@
         System.out.println();
     }
 
-    private static String[] findStandardMBeans(URL codeBase)
-            throws Exception {
+    private static String[] findStandardMBeans(URL codeBase) throws Exception {
         Set<String> names;
-        if (codeBase.getProtocol().equalsIgnoreCase("file")
-            && codeBase.toString().endsWith("/"))
+        if (codeBase.getProtocol().equalsIgnoreCase("jrt")) {
+            names = findStandardMBeansFromRuntime();
+        } else {
             names = findStandardMBeansFromDir(codeBase);
-        else
-            names = findStandardMBeansFromJar(codeBase);
+        }
 
         Set<String> standardMBeanNames = new TreeSet<String>();
         for (String name : names) {
@@ -234,21 +242,17 @@
         return standardMBeanNames.toArray(new String[0]);
     }
 
-    private static Set<String> findStandardMBeansFromJar(URL codeBase)
-            throws Exception {
-        InputStream is = codeBase.openStream();
-        JarInputStream jis = new JarInputStream(is);
-        Set<String> names = new TreeSet<String>();
-        JarEntry entry;
-        while ((entry = jis.getNextJarEntry()) != null) {
-            String name = entry.getName();
-            if (!name.endsWith(".class"))
-                continue;
-            name = name.substring(0, name.length() - 6);
-            name = name.replace('/', '.');
-            names.add(name);
-        }
-        return names;
+    private static Set<String> findStandardMBeansFromRuntime() throws Exception {
+        FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
+        Path modules = fs.getPath("/modules");
+        return Files.walk(modules)
+                .filter(path -> path.toString().endsWith(".class"))
+                .map(path -> path.subpath(2, path.getNameCount()))
+                .map(Path::toString)
+                .map(s -> s.substring(0, s.length() - 6))  // drop .class
+                .filter(s -> !s.equals("module-info"))
+                .map(s -> s.replace('/', '.'))
+                .collect(Collectors.toSet());
     }
 
     private static Set<String> findStandardMBeansFromDir(URL codeBase)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/naming/module/basic.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,104 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+# @test
+# @summary Test of JNDI factories using classes exported by third-party modules.
+
+# Demonstrates Java object storage/retrieval, LDAP control and URL context
+# usage using an LDAP directory. The objects and their associated object
+# factories, state factories, control factories and URL context factories
+# are exported from third-party modules.
+#
+# Seven types of object are used:
+#   - an AWT object (Serializable) from the 'java.desktop' JDK module
+#   - a Person object (DirContext) from the 'person' third-party module
+#   - a Fruit object (Referenceable) from the 'fruit' third-party module
+#   - an RMI object (Remote) from the 'hello' third-party module
+#   - an LDAP request control (Control) from the 'foo' third-party module
+#   - an LDAP response control (Control) from the 'authz' third-party module
+#   - an ldapv4 URL (DirContext) from the 'ldapv4' third-party module
+#
+
+set -e
+
+if [ -z "$TESTJAVA" ]; then
+  if [ $# -lt 1 ]; then exit 1; fi
+  TESTJAVA="$1"; shift
+  COMPILEJAVA="${TESTJAVA}"
+  TESTSRC="`pwd`"
+  TESTCLASSES="`pwd`"
+fi
+
+JAVAC="$COMPILEJAVA/bin/javac"
+JAVA="$TESTJAVA/bin/java"
+
+echo "\nPreparing the 'person' module..."
+mkdir -p mods/person
+$JAVAC -d mods/person `find $TESTSRC/src/person -name "*.java"`
+
+echo "\nPreparing the 'fruit' module..."
+mkdir -p mods/fruit
+$JAVAC -d mods/fruit `find $TESTSRC/src/fruit -name "*.java"`
+
+echo "\nPreparing the 'hello' module..."
+mkdir -p mods/hello
+$JAVAC -d mods/hello `find $TESTSRC/src/hello -name "*.java"`
+
+echo "\nPreparing the 'foo' module..."
+mkdir -p mods/foo
+$JAVAC -d mods/foo `find $TESTSRC/src/foo -name "*.java"`
+
+echo "\nPreparing the 'authz' module..."
+mkdir -p mods/authz
+$JAVAC -d mods/authz `find $TESTSRC/src/authz -name "*.java"`
+
+echo "\nPreparing the 'ldapv4' module..."
+mkdir -p mods/ldapv4
+$JAVAC -d mods/ldapv4 `find $TESTSRC/src/ldapv4 -name "*.java"`
+
+echo "\nPreparing the 'test' module..."
+mkdir -p mods/test
+$JAVAC -d mods -modulesourcepath $TESTSRC/src `find $TESTSRC/src/test -name "*.java"`
+
+
+echo "\nRunning with the 'java.desktop' module..."
+$JAVA -Dtest.src=${TESTSRC} -mp mods -m test/test.StoreObject ldap://localhost/dc=ie,dc=oracle,dc=com
+
+echo "\nRunning with the 'person' module..."
+$JAVA -Dtest.src=${TESTSRC} -mp mods -m test/test.StorePerson ldap://localhost/dc=ie,dc=oracle,dc=com
+
+echo "\nRunning with the 'fruit' module..."
+$JAVA -Dtest.src=${TESTSRC} -mp mods -m test/test.StoreFruit ldap://localhost/dc=ie,dc=oracle,dc=com
+
+echo "\nRunning with the 'hello' module..."
+$JAVA -Dtest.src=${TESTSRC} -mp mods -m test/test.StoreRemote ldap://localhost/dc=ie,dc=oracle,dc=com
+
+echo "\nRunning with the 'foo' module..."
+$JAVA -Dtest.src=${TESTSRC} -mp mods -m test/test.ConnectWithFoo ldap://localhost/dc=ie,dc=oracle,dc=com
+
+echo "\nRunning with the 'authz' module..."
+$JAVA -Dtest.src=${TESTSRC} -mp mods -m test/test.ConnectWithAuthzId ldap://localhost/dc=ie,dc=oracle,dc=com
+
+echo "\nRunning with the 'ldapv4' module..."
+$JAVA -Dtest.src=${TESTSRC} -mp mods -m test/test.ReadByUrl ldap://localhost/dc=ie,dc=oracle,dc=com
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/naming/module/src/authz/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module authz {
+    requires java.naming;
+    exports org.example.authz;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/naming/module/src/authz/org/example/authz/AuthzIdRequestControl.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * This class implements the LDAPv3 Authorization Identity request control
+ * as defined in
+ * <a href="http://tools.ietf.org/html/rfc3829">RFC 3829</a>.
+ */
+
+package org.example.authz;
+
+import javax.naming.ldap.*;
+
+public class AuthzIdRequestControl extends BasicControl {
+
+    public static final String OID = "2.16.840.1.113730.3.4.16";
+
+    public AuthzIdRequestControl() {
+        super(OID, true, null);
+    }
+
+    public AuthzIdRequestControl(boolean criticality) {
+        super(OID, criticality, null);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/naming/module/src/authz/org/example/authz/AuthzIdResponseControl.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * This class implements the LDAPv3 Authorization Identity response control
+ * as defined in
+ * <a href="http://tools.ietf.org/html/rfc3829">RFC 3829</a>.
+ */
+
+package org.example.authz;
+
+import java.io.*;
+import javax.naming.ldap.*;
+
+public class AuthzIdResponseControl extends BasicControl {
+
+    public static final String OID = "2.16.840.1.113730.3.4.15";
+
+    private String identity = null;
+
+    public AuthzIdResponseControl(String id, boolean criticality, byte[] value)
+        throws IOException {
+
+        super(id, criticality, value);
+
+        // decode value
+        if (value != null && value.length > 0) {
+            identity = new String(value, "UTF8");
+        }
+    }
+
+    public String getIdentity() {
+        return identity;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/naming/module/src/authz/org/example/authz/AuthzIdResponseControlFactory.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * This class constructs LDAPv3 Authorization Identity response controls.
+ */
+
+package org.example.authz;
+
+import java.io.*;
+import javax.naming.*;
+import javax.naming.ldap.*;
+
+public class AuthzIdResponseControlFactory extends ControlFactory {
+
+    public AuthzIdResponseControlFactory() {
+    }
+
+    public Control getControlInstance(Control control) throws NamingException {
+        String id = control.getID();
+
+        try {
+            if (id.equals(AuthzIdResponseControl.OID)) {
+                return new AuthzIdResponseControl(id, control.isCritical(),
+                    control.getEncodedValue());
+            }
+        } catch (IOException e) {
+            NamingException ne = new NamingException();
+            ne.setRootCause(e);
+            throw ne;
+        }
+
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/naming/module/src/foo/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module foo {
+    requires java.naming;
+    exports org.example.foo;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/naming/module/src/foo/org/example/foo/FooControl.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * This is a dummy LDAP control.
+ */
+
+package org.example.foo;
+
+import javax.naming.ldap.*;
+
+public class FooControl extends BasicControl {
+
+    public FooControl() {
+        super("1.2.3.4.5.6.7.8.9", true, null);
+    }
+
+    public FooControl(boolean criticality) {
+        super("1.2.3.4.5.6.7.8.9", criticality, null);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/naming/module/src/fruit/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module fruit {
+    requires java.naming;
+    exports org.example.fruit;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/naming/module/src/fruit/org/example/fruit/Fruit.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.example.fruit;
+
+import javax.naming.*;
+
+/**
+  * This class is used by the StoreFruit test.
+  * It is a referenceable class that can be stored by service
+  * providers like the LDAP and file system providers.
+  */
+public class Fruit implements Referenceable {
+    static String location = null;
+    String fruit;
+
+    public Fruit(String f) {
+        fruit = f;
+    }
+
+    public Reference getReference() throws NamingException {
+        return new Reference(
+            Fruit.class.getName(),
+            new StringRefAddr("fruit", fruit),
+            FruitFactory.class.getName(),
+            location);          // factory location
+    }
+
+    public String toString() {
+        return fruit;
+    }
+
+    public static void setLocation(String loc) {
+        location = loc;
+System.out.println("setting location to : " + location);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/naming/module/src/fruit/org/example/fruit/FruitFactory.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.example.fruit;
+
+import java.util.Hashtable;
+import javax.naming.*;
+import javax.naming.spi.ObjectFactory;
+
+/**
+ * This is an object factory that when given a reference for a Fruit
+ * object, will create an instance of the corresponding Fruit.
+ */
+public class FruitFactory implements ObjectFactory {
+    public FruitFactory() {
+    }
+
+    public Object getObjectInstance(Object obj, Name name, Context ctx,
+        Hashtable env) throws Exception {
+        if (obj instanceof Reference) {
+            Reference ref = (Reference)obj;
+            if (ref.getClassName().equals(Fruit.class.getName())) {
+                RefAddr addr = ref.get("fruit");
+                if (addr != null) {
+                    return new Fruit((String)addr.getContent());
+                }
+            }
+        }
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/naming/module/src/hello/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module hello {
+    requires java.rmi;
+    exports org.example.hello;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/naming/module/src/hello/org/example/hello/Hello.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.example.hello;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+/**
+  * This interface is used by the StoreRemote test.
+  * It is a Remote interface. See HelloImpl.java for an implementation.
+  */
+
+public interface Hello extends Remote {
+    public String sayHello() throws RemoteException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/naming/module/src/hello/org/example/hello/HelloImpl.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.example.hello;
+
+import java.rmi.*;
+import java.rmi.server.UnicastRemoteObject;
+
+/**
+  * This class is used by the StoreRemote test.
+  * It is an implementation of the Hello interface.
+  */
+
+public class HelloImpl extends UnicastRemoteObject implements Hello {
+    public HelloImpl() throws RemoteException {
+    }
+
+    public String sayHello() throws RemoteException {
+        return ("Hello, the time is " + new java.util.Date());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/naming/module/src/ldapv4/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module ldapv4 {
+    requires java.naming;
+    exports org.example.ldapv4;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/naming/module/src/ldapv4/org/example/ldapv4/ldapv4URLContext.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * This is a dummy URL context for 'ldapv4://'.
+ */
+
+package org.example.ldapv4;
+
+import java.net.*;
+import java.util.*;
+import javax.naming.*;
+import javax.naming.directory.*;
+import javax.naming.spi.*;
+
+public class ldapv4URLContext implements DirContext {
+
+    private DirContext ctx;
+
+    public ldapv4URLContext(Hashtable env) throws NamingException {
+        ctx = new InitialDirContext(env);
+    }
+
+    public Object lookup(String name) throws NamingException {
+        try {
+            return ctx.lookup("");
+        } catch (Exception e) {
+            NamingException ne = new NamingException();
+            ne.setRootCause(e);
+            throw ne;
+        } finally {
+            ctx.close();
+        }
+    }
+
+    public Object lookup(Name name) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public void bind(String name, Object obj) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public void bind(Name name, Object obj) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public void rebind(String name, Object obj) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public void rebind(Name name, Object obj) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public void unbind(String name) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public void unbind(Name name) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public void rename(String oldName, String newName) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public void rename(Name name, Name newName) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public NamingEnumeration<NameClassPair> list(String name)
+        throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public NamingEnumeration<NameClassPair> list(Name name)
+        throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public NamingEnumeration<Binding> listBindings(String name)
+        throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public NamingEnumeration<Binding> listBindings(Name name)
+        throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public void destroySubcontext(String name) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public void destroySubcontext(Name name) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public Context createSubcontext(String name) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public Context createSubcontext(Name name) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public Object lookupLink(String name) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public Object lookupLink(Name name) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public NameParser getNameParser(String name) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public NameParser getNameParser(Name name) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public String composeName(String name, String prefix)
+        throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public Name composeName(Name name, Name prefix) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public String getNameInNamespace() throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public Object removeFromEnvironment(String propName)
+        throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public Object addToEnvironment(String propName, Object propVal)
+        throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public Hashtable getEnvironment() throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public void close() throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public Attributes getAttributes(Name name) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public Attributes getAttributes(String name) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public Attributes getAttributes(Name name, String[] attrIds)
+            throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public Attributes getAttributes(String name, String[] attrIds)
+            throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public void modifyAttributes(Name name, int mod_op, Attributes attrs)
+            throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public void modifyAttributes(String name, int mod_op, Attributes attrs)
+            throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public void modifyAttributes(Name name, ModificationItem[] mods)
+            throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public void modifyAttributes(String name, ModificationItem[] mods)
+            throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public void bind(Name name, Object obj, Attributes attrs)
+            throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public void bind(String name, Object obj, Attributes attrs)
+            throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public void rebind(Name name, Object obj, Attributes attrs)
+            throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public void rebind(String name, Object obj, Attributes attrs)
+            throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public DirContext createSubcontext(Name name, Attributes attrs)
+            throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public DirContext createSubcontext(String name, Attributes attrs)
+            throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public DirContext getSchema(Name name) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public DirContext getSchema(String name) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public DirContext getSchemaClassDefinition(Name name)
+            throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public DirContext getSchemaClassDefinition(String name)
+            throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public NamingEnumeration<SearchResult>
+        search(Name name,
+               Attributes matchingAttributes,
+               String[] attributesToReturn)
+        throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public NamingEnumeration<SearchResult>
+        search(String name,
+               Attributes matchingAttributes,
+               String[] attributesToReturn)
+        throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public NamingEnumeration<SearchResult>
+        search(Name name, Attributes matchingAttributes)
+        throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public NamingEnumeration<SearchResult>
+        search(String name, Attributes matchingAttributes)
+        throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public NamingEnumeration<SearchResult>
+        search(Name name,
+               String filter,
+               SearchControls cons)
+        throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public NamingEnumeration<SearchResult>
+        search(String name,
+               String filter,
+               SearchControls cons)
+        throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public NamingEnumeration<SearchResult>
+        search(Name name,
+               String filterExpr,
+               Object[] filterArgs,
+               SearchControls cons)
+        throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    public NamingEnumeration<SearchResult>
+        search(String name,
+               String filterExpr,
+               Object[] filterArgs,
+               SearchControls cons)
+        throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/naming/module/src/ldapv4/org/example/ldapv4/ldapv4URLContextFactory.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * This is a dumy URL context factory for 'ldapv4://'.
+ */
+
+package org.example.ldapv4;
+
+import java.util.*;
+import javax.naming.*;
+import javax.naming.directory.*;
+import javax.naming.spi.*;
+
+public class ldapv4URLContextFactory implements ObjectFactory {
+
+    public ldapv4URLContextFactory() {
+    }
+
+    public Object getObjectInstance(Object urlInfo, Name name, Context nameCtx,
+            Hashtable<?,?> env) throws Exception {
+
+        Hashtable<String,String> env2 = new Hashtable<>();
+        env2.put(Context.INITIAL_CONTEXT_FACTORY,
+            "com.sun.jndi.ldap.LdapCtxFactory");
+        String ldapUrl = (String)env.get(Context.PROVIDER_URL);
+        env2.put(Context.PROVIDER_URL, ldapUrl.replaceFirst("ldapv4", "ldap"));
+        //env2.put("com.sun.jndi.ldap.trace.ber", System.out);
+        return new ldapv4URLContext(env2);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/naming/module/src/person/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module person {
+    requires java.naming;
+    exports org.example.person;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/naming/module/src/person/org/example/person/Person.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * This class has DirContext attributes and is used by the StorePerson test.
+ * Implementation of the inetOrgPerson LDAP object class as defined in
+ * <a href="http://www.ietf.org/internet-drafts/draft-smith-ldap-inetorgperson-03.txt">draft-smith-ldap-inetorgperson-03.txt</a>.
+ */
+
+package org.example.person;
+
+import javax.naming.*;
+import javax.naming.directory.*;
+
+public class Person {
+
+    private BasicAttributes attrs;
+
+    public Person(String commonName, String surname) {
+
+        attrs = new BasicAttributes(true);
+        Attribute objectClass = new BasicAttribute("objectClass");
+        objectClass.add("top");
+        objectClass.add("person");
+        objectClass.add("inetOrgPerson");
+
+        attrs.put(objectClass);
+        attrs.put(new BasicAttribute("cn", commonName));
+        attrs.put(new BasicAttribute("sn", surname));
+    }
+
+    public Attributes getAttributes() {
+        return attrs;
+    }
+
+    public void setAudio(byte[] value) {
+        attrs.put(new BasicAttribute("audio", value));
+    }
+
+    public void setBusinessCategory(String value) {
+        attrs.put(new BasicAttribute("businessCategory", value));
+    }
+
+    public void setCarLicense(String value) {
+        attrs.put(new BasicAttribute("carLicense", value));
+    }
+
+    public void setDepartmentNumber(String value) {
+        attrs.put(new BasicAttribute("departmentNumber", value));
+    }
+
+    public void setDisplayName(String value) {
+        attrs.put(new BasicAttribute("displayName", value));
+    }
+
+    public void setEmployeeNumber(String value) {
+        attrs.put(new BasicAttribute("employeeNumber", value));
+    }
+
+    public void setEmployeeType(String value) {
+        attrs.put(new BasicAttribute("employeeType", value));
+    }
+
+    public void setGivenName(String value) {
+        attrs.put(new BasicAttribute("givenName", value));
+    }
+
+    public void setHomePhoneNumber(String value) {
+        attrs.put(new BasicAttribute("homePhone", value));
+    }
+
+    public void setHomePostalAddress(String value) {
+        attrs.put(new BasicAttribute("homePostalAddress", value));
+    }
+
+    public void setInitials(String value) {
+        attrs.put(new BasicAttribute("initials", value));
+    }
+
+    public void setJPEGPhoto(String value) {
+        attrs.put(new BasicAttribute("jpegPhoto", value));
+    }
+
+    public void setMailAddress(String value) {
+        attrs.put(new BasicAttribute("mail", value));
+    }
+
+    public void setManagerName(String value) {
+        attrs.put(new BasicAttribute("manager", value));
+    }
+
+    public void setMobileNumber(String value) {
+        attrs.put(new BasicAttribute("mobile", value));
+    }
+
+    public void setOrganizationName(String value) {
+        attrs.put(new BasicAttribute("o", value));
+    }
+
+    public void setPagerNumber(String value) {
+        attrs.put(new BasicAttribute("pager", value));
+    }
+
+    public void setPhoto(String value) {
+        attrs.put(new BasicAttribute("photo", value));
+    }
+
+    public void setRoomNumber(String value) {
+        attrs.put(new BasicAttribute("roomNumber", value));
+    }
+
+    public void setSecretaryName(String value) {
+        attrs.put(new BasicAttribute("secretary", value));
+    }
+
+    public void setUserID(String value) {
+        attrs.put(new BasicAttribute("uid", value));
+    }
+
+    public void setUserCertificate(String value) {
+        attrs.put(new BasicAttribute("userCertificate", value));
+    }
+
+    public void setX500UniqueID(String value) {
+        attrs.put(new BasicAttribute("x500UniqueIdentifier", value));
+    }
+
+    public void setPreferredLanguage(String value) {
+        attrs.put(new BasicAttribute("preferredLanguage", value));
+    }
+
+    public void setUserSMIMECertificate(String value) {
+        attrs.put(new BasicAttribute("userSMIMECertificate", value));
+    }
+
+    public void setUserPKCS12(String value) {
+        attrs.put(new BasicAttribute("userPKCS12", value));
+    }
+
+    /* ----- Attributes inherited from the Person LDAP object class ----- */
+
+    public void setDescription(String value) {
+        attrs.put(new BasicAttribute("description", value));
+    }
+
+    public void setDestinationIndicator(String value) {
+        attrs.put(new BasicAttribute("destinationIndicator", value));
+    }
+
+    public void setFaxNumber(String value) {
+        attrs.put(new BasicAttribute("facsimileTelephoneNumber", value));
+    }
+
+    public void setISDNNumber(String value) {
+        attrs.put(new BasicAttribute("internationalISDNNumber", value));
+    }
+
+    public void setLocalityName(String value) {
+        attrs.put(new BasicAttribute("localityName", value));
+    }
+
+    public void setOrganizationalUnitName(String value) {
+        attrs.put(new BasicAttribute("ou", value));
+    }
+
+    public void setPhysicalDeliveryOfficeName(String value) {
+        attrs.put(new BasicAttribute("physicalDeliveryOfficeName", value));
+    }
+
+    public void setPostalAddress(String value) {
+        attrs.put(new BasicAttribute("postalAddress", value));
+    }
+
+    public void setPostalCode(String value) {
+        attrs.put(new BasicAttribute("postalCode", value));
+    }
+
+    public void setPostOfficeBox(String value) {
+        attrs.put(new BasicAttribute("postOfficeBox", value));
+    }
+
+    public void setPreferredDeliveryMethod(String value) {
+        attrs.put(new BasicAttribute("preferredDeliveryMethod", value));
+    }
+
+    public void setRegisteredAddress(String value) {
+        attrs.put(new BasicAttribute("registeredAddress", value));
+    }
+
+    public void setSeeAlso(String value) {
+        attrs.put(new BasicAttribute("seeAlso", value));
+    }
+
+    public void setStateOrProvinceName(String value) {
+        attrs.put(new BasicAttribute("st", value));
+    }
+
+    public void setStreetAddress(String value) {
+        attrs.put(new BasicAttribute("street", value));
+    }
+
+    public void setTelephoneNumber(String value) {
+        attrs.put(new BasicAttribute("telephoneNumber", value));
+    }
+
+    public void setTeletexTerminalID(String value) {
+        attrs.put(new BasicAttribute("teletexTerminalIdentifier", value));
+    }
+
+    public void setTelexNumber(String value) {
+        attrs.put(new BasicAttribute("telexNumber", value));
+    }
+
+    public void setTitle(String value) {
+        attrs.put(new BasicAttribute("title", value));
+    }
+
+    public void setUserPassword(String value) {
+        attrs.put(new BasicAttribute("userPassword", value));
+    }
+
+    public void setX121Address(String value) {
+        attrs.put(new BasicAttribute("x121Address", value));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/naming/module/src/person/org/example/person/PersonFactory.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * State factory and object factory for the Person class.
+ */
+
+package org.example.person;
+
+import java.util.Hashtable;
+import javax.naming.*;
+import javax.naming.directory.*;
+import javax.naming.spi.*;
+
+public class PersonFactory implements DirStateFactory, DirObjectFactory {
+
+    public PersonFactory() {
+    }
+
+    @Override
+    public Object getStateToBind(Object obj, Name name,
+        Context nameCtx, Hashtable environment) throws NamingException {
+
+        return null;
+    }
+
+    @Override
+    public DirStateFactory.Result getStateToBind(Object obj, Name name,
+        Context nameCtx, Hashtable environment, Attributes inAttrs)
+            throws NamingException {
+
+        if (obj instanceof Person) {
+            return new DirStateFactory.Result(null,
+                                              personToAttributes((Person)obj));
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public Object getObjectInstance(Object obj, Name name, Context ctx,
+        Hashtable environment) throws Exception {
+
+        return null;
+    }
+
+    @Override
+    public Object getObjectInstance(Object obj, Name name, Context ctx,
+        Hashtable environment, Attributes attributes) throws Exception {
+
+        if (obj instanceof DirContext) {
+            ((DirContext)obj).close(); // cleanup
+            return attributesToPerson(attributes);
+
+        } else {
+            return null;
+        }
+    }
+
+    private Attributes personToAttributes(Person person) {
+
+        // TBD: build attrs using methods in Person class instead of calling ...
+
+        return person.getAttributes();
+    }
+
+    private Person attributesToPerson(Attributes attrset)
+        throws NamingException {
+
+        Attributes attrs = (Attributes)attrset;
+        Person person = new Person((String)attrs.get("cn").get(),
+                                   (String)attrs.get("sn").get());
+
+        person.setMailAddress((String)attrs.get("mail").get());
+
+        // TBD: extract any other attributes
+
+        return person;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/naming/module/src/test/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module test {
+    requires java.naming;
+    requires java.desktop;
+    requires java.xml.bind; // for javax.xml.bind.DatatypeConverter
+    requires java.rmi; // for java.rmi.server.UnicastRemoteObject
+    requires person;
+    requires fruit;
+    requires hello;
+    requires foo;
+    requires authz;
+    requires ldapv4;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/naming/module/src/test/test/ConnectWithAuthzId.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Demonstrate JNDI using an LDAP request/response control.
+ * The Authorization Identity controls and their associated control factory
+ * is supplied by a third-party module.
+ */
+
+package test;
+
+import java.net.*;
+import java.util.*;
+import javax.naming.*;
+import javax.naming.directory.*;
+import javax.naming.ldap.*;
+
+import org.example.authz.AuthzIdRequestControl;
+import org.example.authz.AuthzIdResponseControl;
+
+public class ConnectWithAuthzId {
+
+    // LDAP capture file
+    private static final String LDAP_CAPTURE_FILE =
+        System.getProperty("test.src") +
+        "/src/test/test/ConnectWithAuthzId.ldap";
+    // LDAPServer socket
+    private static ServerSocket serverSocket;
+
+    public static void main(String[] args) throws Exception {
+
+        /*
+         * Process arguments
+         */
+
+        int argc = args.length;
+        if ((argc < 1) ||
+            ((argc == 1) && (args[0].equalsIgnoreCase("-help")))) {
+
+            System.err.println("\nUsage:   ConnectWithAuthzId <ldapurl>\n");
+            System.err.println("        <ldapurl> is the LDAP URL of the parent entry\n");
+            System.err.println("example:");
+            System.err.println("        java ConnectWithAuthzId ldap://oasis/o=airius.com");
+            return;
+        }
+
+        /*
+         * Launch the LDAP server with the ConnectWithAuthzId.ldap capture file
+         */
+
+        serverSocket = new ServerSocket(0);
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    new LDAPServer(serverSocket, LDAP_CAPTURE_FILE);
+               } catch (Exception e) {
+                   System.out.println("ERROR: unable to launch LDAP server");
+                   e.printStackTrace();
+               }
+            }
+        }).start();
+
+        /*
+         * Connect to the LDAP directory
+         */
+
+        Hashtable<String,Object> env = new Hashtable<>();
+        env.put(Context.INITIAL_CONTEXT_FACTORY,
+            "com.sun.jndi.ldap.LdapCtxFactory");
+        URI ldapUri = new URI(args[0]);
+        if (ldapUri.getPort() == -1) {
+            ldapUri = new URI(ldapUri.getScheme(), null, ldapUri.getHost(),
+                serverSocket.getLocalPort(), ldapUri.getPath(), null, null);
+        }
+        env.put(Context.PROVIDER_URL, ldapUri.toString());
+        env.put(Context.SECURITY_AUTHENTICATION, "simple");
+        env.put(Context.SECURITY_PRINCIPAL, "cn=admin,dc=ie,dc=oracle,dc=com");
+        env.put(Context.SECURITY_CREDENTIALS, "changeit");
+        env.put(LdapContext.CONTROL_FACTORIES,
+            "org.example.authz.AuthzIdResponseControlFactory");
+        if (args[args.length - 1].equalsIgnoreCase("-trace")) {
+            env.put("com.sun.jndi.ldap.trace.ber", System.out);
+        }
+
+        System.out.println("ConnectWithAuthzId: connecting to " + ldapUri);
+        LdapContext ctx = null;
+        Control[] connectionControls = { new AuthzIdRequestControl(false) };
+
+        try {
+            ctx = new InitialLdapContext(env, connectionControls);
+            System.out.println("ConnectWithAuthzId: connected");
+            // Retrieve the response controls
+            Control[] responseControls = ctx.getResponseControls();
+            if (responseControls != null) {
+                for (Control responseControl : responseControls) {
+                    System.out.println("ConnectWithAuthzId: received response" +
+                        " control: " + responseControl.getID());
+                    if (responseControl instanceof AuthzIdResponseControl) {
+                        AuthzIdResponseControl authzId =
+                            (AuthzIdResponseControl)responseControl;
+                        System.out.println("ConnectWithAuthzId: identity is  " +
+                            authzId.getIdentity());
+                    }
+                }
+            }
+        } catch (NamingException e) {
+            System.err.println("ConnectWithAuthzId: error connecting " + e);
+        } finally {
+            if (ctx != null) {
+                ctx.close();
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/naming/module/src/test/test/ConnectWithAuthzId.ldap	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,96 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+################################################################################
+# Capture file for ConnectWithAuthzId.java
+#
+# NOTE: This hexadecimal dump of LDAP protocol messages was generated by
+#       running the ConnectWithAuthzId application program against a real LDAP
+#       server and setting the JNDI/LDAP environment property:
+#       com.sun.jndi.ldap.trace.ber to activate LDAP message tracing.
+#       (Some manual BER encoding was needed to simulate the response control.)
+#
+#      (The ASN.1 annotations were generated separately by the dumpasn1
+#       utility and added only for clarity.)
+#
+################################################################################
+
+# LDAP BindRequest:
+#
+#   0   81: SEQUENCE {
+#   2    1:   INTEGER 1
+#   5   46:   [APPLICATION 0] {
+#   7    1:     INTEGER 3
+#  10   31:     OCTET STRING 'cn=admin,dc=ie,dc=oracle,dc=com'
+#  43    8:     [0] 'changeit'
+#         :     }
+#  53   28:   [0] {
+#  55   26:     SEQUENCE {
+#  57   24:       OCTET STRING '2.16.840.1.113730.3.4.16'
+#         :       }
+#         :     }
+#         :   }
+0000: 30 51 02 01 01 60 2E 02   01 03 04 1F 63 6E 3D 61  0Q...`......cn=a
+0010: 64 6D 69 6E 2C 64 63 3D   69 65 2C 64 63 3D 6F 72  dmin,dc=ie,dc=or
+0020: 61 63 6C 65 2C 64 63 3D   63 6F 6D 80 08 63 68 61  acle,dc=com..cha
+0030: 6E 67 65 69 74 A0 1C 30   1A 04 18 32 2E 31 36 2E  ngeit..0...2.16.
+0040: 38 34 30 2E 31 2E 31 31   33 37 33 30 2E 33 2E 34  840.1.113730.3.4
+0050: 2E 31 36                                           .16
+
+# LDAP BindResponse:
+#
+#   0   51: SEQUENCE {
+#   2    1:   INTEGER 1
+#   5    7:   [APPLICATION 1] {
+#   7    1:     ENUMERATED 0
+#  10    0:     OCTET STRING
+#  12    0:     OCTET STRING
+#         :     }
+#  14   37:   [0] {
+#  16   35:     SEQUENCE {
+#  18   24:       OCTET STRING '2.16.840.1.113730.3.4.15'
+#  44    7:       OCTET STRING 'u:admin'
+#         :       }
+#         :     }
+#         :   }
+#
+0000: 30 33 02 01 01 61 07 0A   01 00 04 00 04 00 A0 25  0....a..........
+0010: 30 23 04 18 32 2E 31 36   2E 38 34 30 2E 31 2E 31  0...2.16.840.1.1
+0020: 31 33 37 33 30 2E 33 2E   34 2E 31 35 04 07 75 3A  13730.3.4.15..u:
+0030: 61 64 6D 69 6E                                     admin
+
+# LDAP UnbindRequest:
+#
+#   0   34: SEQUENCE {
+#   2    1:   INTEGER 2
+#   5    0:   [APPLICATION 2]
+#   7   27:   [0] {
+#   9   25:     SEQUENCE {
+#  11   23:       OCTET STRING '2.16.840.1.113730.3.4.2'
+#         :       }
+#         :     }
+#         :   }
+#
+0000: 30 22 02 01 02 42 00 A0   1B 30 19 04 17 32 2E 31  0"...B...0...2.1
+0010: 36 2E 38 34 30 2E 31 2E   31 31 33 37 33 30 2E 33  6.840.1.113730.3
+0020: 2E 34 2E 32                                        .4.2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/naming/module/src/test/test/ConnectWithFoo.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Demonstrate JNDI using an LDAP connection control supplied by a third-party
+ * module.
+ */
+
+package test;
+
+import java.net.*;
+import java.util.*;
+import javax.naming.*;
+import javax.naming.directory.*;
+import javax.naming.ldap.*;
+
+import org.example.foo.FooControl;
+
+public class ConnectWithFoo {
+
+    // LDAP capture file
+    private static final String LDAP_CAPTURE_FILE =
+        System.getProperty("test.src") + "/src/test/test/ConnectWithFoo.ldap";
+    // LDAPServer socket
+    private static ServerSocket serverSocket;
+
+    public static void main(String[] args) throws Exception {
+
+        /*
+         * Process arguments
+         */
+
+        int argc = args.length;
+        if ((argc < 1) ||
+            ((argc == 1) && (args[0].equalsIgnoreCase("-help")))) {
+
+            System.err.println("\nUsage:   ConnectWithFoo <ldapurl>\n");
+            System.err.println("        <ldapurl> is the LDAP URL of the parent entry\n");
+            System.err.println("example:");
+            System.err.println("        java ConnectWithFoo ldap://oasis/o=airius.com");
+            return;
+        }
+
+        /*
+         * Launch the LDAP server with the ConnectWithFoo.ldap capture file
+         */
+
+        serverSocket = new ServerSocket(0);
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    new LDAPServer(serverSocket, LDAP_CAPTURE_FILE);
+               } catch (Exception e) {
+                   System.out.println("ERROR: unable to launch LDAP server");
+                   e.printStackTrace();
+               }
+            }
+        }).start();
+
+        /*
+         * Connect to the LDAP directory
+         */
+
+        Hashtable<String,Object> env = new Hashtable<>();
+        env.put(Context.INITIAL_CONTEXT_FACTORY,
+            "com.sun.jndi.ldap.LdapCtxFactory");
+        URI ldapUri = new URI(args[0]);
+        if (ldapUri.getPort() == -1) {
+            ldapUri = new URI(ldapUri.getScheme(), null, ldapUri.getHost(),
+                serverSocket.getLocalPort(), ldapUri.getPath(), null, null);
+        }
+        env.put(Context.PROVIDER_URL, ldapUri.toString());
+        if (args[args.length - 1].equalsIgnoreCase("-trace")) {
+            env.put("com.sun.jndi.ldap.trace.ber", System.out);
+        }
+
+        System.out.println("ConnectWithFoo: connecting to " + ldapUri);
+        LdapContext ctx = null;
+        Control[] connectionControls = { new FooControl(false) };
+
+        try {
+            ctx = new InitialLdapContext(env, connectionControls);
+            System.out.println("ConnectWithFoo: connected");
+        } catch (NamingException e) {
+            System.err.println("ConnectWithFoo: error connecting " + e);
+        } finally {
+            if (ctx != null) {
+                ctx.close();
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/naming/module/src/test/test/ConnectWithFoo.ldap	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,84 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+################################################################################
+# Capture file for ConnectWithFoo.java
+#
+# NOTE: This hexadecimal dump of LDAP protocol messages was generated by
+#       running the ConnectWithFoo application program against a real LDAP
+#       server and setting the JNDI/LDAP environment property:
+#       com.sun.jndi.ldap.trace.ber to activate LDAP message tracing.
+#
+#      (The ASN.1 annotations were generated separately by the dumpasn1
+#       utility and added only for clarity.)
+#
+################################################################################
+
+# LDAP BindRequest:
+#
+#   0   35: SEQUENCE {
+#   2    1:   INTEGER 1
+#   5    7:   [APPLICATION 0] {
+#   7    1:     INTEGER 3
+#  10    0:     OCTET STRING
+#  12    0:     [0]
+#         :     }
+#  14   21:   [0] {
+#  16   19:     SEQUENCE {
+#  18   17:       OCTET STRING '1.2.3.4.5.6.7.8.9'
+#         :       }
+#         :     }
+#         :   }
+#
+0000: 30 23 02 01 01 60 07 02   01 03 04 00 80 00 A0 15  0#...`..........
+0010: 30 13 04 11 31 2E 32 2E   33 2E 34 2E 35 2E 36 2E  0...1.2.3.4.5.6.
+0020: 37 2E 38 2E 39                                     7.8.9
+
+# LDAP BindResponse:
+#
+#   0   12: SEQUENCE {
+#   2    1:   INTEGER 1
+#   5    7:   [APPLICATION 1] {
+#   7    1:     ENUMERATED 0
+#  10    0:     OCTET STRING
+#  12    0:     OCTET STRING
+#         :     }
+#         :   }
+#
+0000: 30 0C 02 01 01 61 07 0A   01 00 04 00 04 00        0....a........
+
+# LDAP UnbindRequest:
+#
+#   0   34: SEQUENCE {
+#   2    1:   INTEGER 2
+#   5    0:   [APPLICATION 2]
+#   7   27:   [0] {
+#   9   25:     SEQUENCE {
+#  11   23:       OCTET STRING '2.16.840.1.113730.3.4.2'
+#         :       }
+#         :     }
+#         :   }
+#
+0000: 30 22 02 01 02 42 00 A0   1B 30 19 04 17 32 2E 31  0"...B...0...2.1
+0010: 36 2E 38 34 30 2E 31 2E   31 31 33 37 33 30 2E 33  6.840.1.113730.3
+0020: 2E 34 2E 32                                        .4.2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/naming/module/src/test/test/LDAPServer.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package test;
+
+import java.io.*;
+import java.nio.file.*;
+import java.math.BigInteger;
+import java.net.*;
+import java.util.*;
+import java.util.regex.*;
+import javax.xml.bind.DatatypeConverter;
+
+/*
+ * A dummy LDAP server.
+ *
+ * Loads a sequence of LDAP messages from a capture file into its cache.
+ * It listens for LDAP requests, finds a match in its cache and sends the
+ * corresponding LDAP responses.
+ *
+ * The capture file contains an LDAP protocol exchange in the hexadecimal
+ * dump format emitted by sun.misc.HexDumpEncoder:
+ *
+ * xxxx: 00 11 22 33 44 55 66 77   88 99 aa bb cc dd ee ff  ................
+ *
+ * Typically, LDAP protocol exchange is generated by running the LDAP client
+ * application program against a real LDAP server and setting the JNDI/LDAP
+ * environment property: com.sun.jndi.ldap.trace.ber to activate LDAP message
+ * tracing.
+ */
+public class LDAPServer {
+
+    /*
+     * A cache of LDAP requests and responses.
+     * Messages with the same ID are stored in a list.
+     * The first element in the list is the LDAP request,
+     * the remaining elements are the LDAP responses.
+     */
+    private final Map<Integer,List<byte[]>> cache = new HashMap<>();
+
+    public LDAPServer(ServerSocket serverSocket, String filename)
+        throws Exception {
+
+        System.out.println("LDAPServer: Loading LDAP cache from: " + filename);
+        loadCaptureFile(filename);
+
+        System.out.println("LDAPServer: listening on port " +
+            serverSocket.getLocalPort());
+
+        try (Socket clientSocket = serverSocket.accept();
+            OutputStream out = clientSocket.getOutputStream();
+            InputStream in = clientSocket.getInputStream();) {
+
+            byte[] inBuffer = new byte[8192];
+            int count;
+
+            while ((count = in.read(inBuffer)) > 0) {
+                byte[] request = Arrays.copyOf(inBuffer, count);
+                int[] ids = getIDs(request);
+                int messageID = ids[0];
+                String operation = getOperation(ids[1]);
+                System.out.println("\nLDAPServer: received LDAP " + operation +
+                    "  [message ID " + messageID + "]");
+
+                List<byte[]> encodings = cache.get(messageID);
+                if (encodings == null ||
+                    (!Arrays.equals(request, encodings.get(0)))) {
+                    throw new Exception(
+                        "LDAPServer: ERROR: received an LDAP " + operation +
+                        " (ID=" + messageID + ") not present in cache");
+                }
+
+                for (int i = 1; i < encodings.size(); i++) {
+                    // skip the request (at index 0)
+                    byte[] response = encodings.get(i);
+                    out.write(response, 0, response.length);
+                    ids = getIDs(response);
+                    System.out.println("\nLDAPServer: Sent LDAP " +
+                        getOperation(ids[1]) + "  [message ID " + ids[0] + "]");
+                }
+            }
+        } catch (IOException e) {
+            System.out.println("LDAPServer: ERROR: " + e);
+            throw e;
+        }
+
+        System.out.println("\n[LDAP server exited normally]");
+    }
+
+    /*
+     * Load a capture file containing an LDAP protocol exchange in the
+     * hexadecimal dump format emitted by sun.misc.HexDumpEncoder:
+     *
+     * xxxx: 00 11 22 33 44 55 66 77   88 99 aa bb cc dd ee ff  ................
+     */
+    private void loadCaptureFile(String filename) throws IOException {
+        StringBuilder hexString = new StringBuilder();
+        String pattern = "(....): (..) (..) (..) (..) (..) (..) (..) (..)   (..) (..) (..) (..) (..) (..) (..) (..).*";
+
+        try (Scanner fileScanner =  new Scanner(Paths.get(filename))) {
+            while (fileScanner.hasNextLine()){
+
+                try (Scanner lineScanner =
+                    new Scanner(fileScanner.nextLine())) {
+                    if (lineScanner.findInLine(pattern) == null) {
+                        continue;
+                    }
+                    MatchResult result = lineScanner.match();
+                    for (int i = 1; i <= result.groupCount(); i++) {
+                        String digits = result.group(i);
+                        if (digits.length() == 4) {
+                            if (digits.equals("0000")) { // start-of-message
+                                if (hexString.length() > 0) {
+                                    addToCache(hexString.toString());
+                                    hexString = new StringBuilder();
+                                }
+                            }
+                            continue;
+                        } else if (digits.equals("  ")) { // short message
+                            continue;
+                        }
+                        hexString.append(digits);
+                    }
+                }
+            }
+        }
+        addToCache(hexString.toString());
+    }
+
+    /*
+     * Add an LDAP encoding to the cache (by messageID key).
+     */
+    private void addToCache(String hexString) throws IOException {
+        byte[] encoding = DatatypeConverter.parseHexBinary(hexString);
+        int[] ids = getIDs(encoding);
+        int messageID = ids[0];
+        List<byte[]> encodings = cache.get(messageID);
+        if (encodings == null) {
+            encodings = new ArrayList<>();
+        }
+        System.out.println("    adding LDAP " + getOperation(ids[1]) +
+            " with message ID " + messageID + " to the cache");
+        encodings.add(encoding);
+        cache.put(messageID, encodings);
+    }
+
+    /*
+     * Extracts the message ID and operation ID from an LDAP protocol encoding
+     * and returns them in a 2-element array of integers.
+     */
+    private static int[] getIDs(byte[] encoding) throws IOException {
+        if (encoding[0] != 0x30) {
+            throw new IOException("Error: bad LDAP encoding in capture file: " +
+                "expected ASN.1 SEQUENCE tag (0x30), encountered " +
+                encoding[0]);
+        }
+
+        int index = 2;
+        if ((encoding[1] & 0x80) == 0x80) {
+            index += (encoding[1] & 0x0F);
+        }
+
+        if (encoding[index] != 0x02) {
+            throw new IOException("Error: bad LDAP encoding in capture file: " +
+                "expected ASN.1 INTEGER tag (0x02), encountered " +
+                encoding[index]);
+        }
+        int length = encoding[index + 1];
+        index += 2;
+        int messageID =
+            new BigInteger(1,
+                Arrays.copyOfRange(encoding, index, index + length)).intValue();
+        index += length;
+        int operationID = encoding[index];
+
+        return new int[]{messageID, operationID};
+    }
+
+    /*
+     * Maps an LDAP operation ID to a string description
+     */
+    private static String getOperation(int operationID) {
+        switch (operationID) {
+        case 0x60:
+            return "BindRequest";       // [APPLICATION 0]
+        case 0x61:
+            return "BindResponse";      // [APPLICATION 1]
+        case 0x42:
+            return "UnbindRequest";     // [APPLICATION 2]
+        case 0x63:
+            return "SearchRequest";     // [APPLICATION 3]
+        case 0x64:
+            return "SearchResultEntry"; // [APPLICATION 4]
+        case 0x65:
+            return "SearchResultDone";  // [APPLICATION 5]
+        case 0x66:
+            return "ModifyRequest";     // [APPLICATION 6]
+        case 0x67:
+            return "ModifyResponse";    // [APPLICATION 7]
+        case 0x68:
+            return "AddRequest";        // [APPLICATION 8]
+        case 0x69:
+            return "AddResponse";       // [APPLICATION 9]
+        case 0x4A:
+            return "DeleteRequest";     // [APPLICATION 10]
+        case 0x6B:
+            return "DeleteResponse";    // [APPLICATION 11]
+        case 0x6C:
+            return "ModifyDNRequest";   // [APPLICATION 12]
+        case 0x6D:
+            return "ModifyDNResponse";  // [APPLICATION 13]
+        case 0x6E:
+            return "CompareRequest";    // [APPLICATION 14]
+        case 0x6F:
+            return "CompareResponse";   // [APPLICATION 15]
+        case 0x50:
+            return "AbandonRequest";    // [APPLICATION 16]
+        case 0x73:
+            return "SearchResultReference";  // [APPLICATION 19]
+        case 0x77:
+            return "ExtendedRequest";   // [APPLICATION 23]
+        case 0x78:
+            return "ExtendedResponse";  // [APPLICATION 24]
+        case 0x79:
+            return "IntermediateResponse";  // [APPLICATION 25]
+        default:
+            return "Unknown";
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/naming/module/src/test/test/ReadByUrl.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Demonstrate JNDI using the 'ldapv4' URL scheme supplied by a third-party
+ * module.
+ */
+
+package test;
+
+import java.net.*;
+import java.util.*;
+import javax.naming.*;
+import javax.naming.directory.*;
+import javax.naming.ldap.*;
+
+public class ReadByUrl {
+
+    // LDAP capture file
+    private static final String LDAP_CAPTURE_FILE =
+        System.getProperty("test.src") + "/src/test/test/ReadByUrl.ldap";
+    // LDAPServer socket
+    private static ServerSocket serverSocket;
+
+    public static void main(String[] args) throws Exception {
+
+        /*
+         * Process arguments
+         */
+
+        int argc = args.length;
+        if ((argc < 1) ||
+            ((argc == 1) && (args[0].equalsIgnoreCase("-help")))) {
+
+            System.err.println("\nUsage:   ReadByUrl <ldapurl>\n");
+            System.err.println("        <ldapurl> is the LDAP URL of the parent entry\n");
+            System.err.println("example:");
+            System.err.println("        java ReadByUrl ldap://oasis/o=airius.com");
+            return;
+        }
+
+        /*
+         * Launch the LDAP server with the ReadByUrl.ldap capture file
+         */
+
+        serverSocket = new ServerSocket(0);
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    new LDAPServer(serverSocket, LDAP_CAPTURE_FILE);
+               } catch (Exception e) {
+                   System.out.println("ERROR: unable to launch LDAP server");
+                   e.printStackTrace();
+               }
+            }
+        }).start();
+
+        /*
+         * Connect to the LDAP directory
+         */
+
+        Hashtable<String,Object> env = new Hashtable<>();
+        URI ldapUri = new URI(args[0]);
+        if (ldapUri.getPort() == -1) {
+            ldapUri = new URI("ldapv4", null, ldapUri.getHost(),
+                serverSocket.getLocalPort(), ldapUri.getPath(), null, null);
+        }
+        env.put(Context.PROVIDER_URL, ldapUri.toString());
+        if (args[args.length - 1].equalsIgnoreCase("-trace")) {
+            env.put("com.sun.jndi.ldap.trace.ber", System.out);
+        }
+
+        // URL context factory location for 'ldapv4://'
+        env.put(Context.URL_PKG_PREFIXES, "org.example");
+
+        System.out.println("ReadByUrl: connecting to " + ldapUri);
+        DirContext ctx = null;
+
+        try {
+            ctx = new InitialDirContext(env);
+            System.out.println("ReadByUrl: connected");
+            DirContext entry = (DirContext) ctx.lookup(ldapUri.toString());
+            entry.close();
+        } catch (NamingException e) {
+            System.err.println("ReadByUrl: error connecting " + e);
+        } finally {
+            if (ctx != null) {
+                ctx.close();
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/naming/module/src/test/test/ReadByUrl.ldap	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,158 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+################################################################################
+# Capture file for ReadByUrl.java
+#
+# NOTE: This hexadecimal dump of LDAP protocol messages was generated by
+#       running the ReadByUrl application program against a real LDAP
+#       server and setting the JNDI/LDAP environment property:
+#       com.sun.jndi.ldap.trace.ber to activate LDAP message tracing.
+#
+#      (The ASN.1 annotations were generated separately by the dumpasn1
+#       utility and added only for clarity.)
+#
+################################################################################
+
+# LDAP BindRequest:
+#
+#   0   12: SEQUENCE {
+#   2    1:   INTEGER 1
+#   5    7:   [APPLICATION 0] {
+#   7    1:     INTEGER 3
+#  10    0:     OCTET STRING
+#  12    0:     [0]
+#         :     }
+#         :   }
+#
+0000: 30 0C 02 01 01 60 07 02   01 03 04 00 80 00        0....`........
+
+# LDAP BindResponse:
+#
+#   0   12: SEQUENCE {
+#   2    1:   INTEGER 1
+#   5    7:   [APPLICATION 1] {
+#   7    1:     ENUMERATED 0
+#  10    0:     OCTET STRING
+#  12    0:     OCTET STRING
+#         :     }
+#         :   }
+#
+0000: 30 0C 02 01 01 61 07 0A   01 00 04 00 04 00        0....a........
+
+# LDAP SearchRequest:
+#
+#   0   88: SEQUENCE {
+#   2    1:   INTEGER 2
+#   5   54:   [APPLICATION 3] {
+#   7   22:     OCTET STRING 'dc=ie,dc=oracle,dc=com'
+#  31    1:     ENUMERATED 0
+#  34    1:     ENUMERATED 3
+#  37    1:     INTEGER 0
+#  40    1:     INTEGER 0
+#  43    1:     BOOLEAN FALSE
+#  46   11:     [7] 'objectClass'
+#  59    0:     SEQUENCE {}
+#         :     }
+#  61   27:   [0] {
+#  63   25:     SEQUENCE {
+#  65   23:       OCTET STRING '2.16.840.1.113730.3.4.2'
+#         :       }
+#         :     }
+#         :   }
+0000: 30 58 02 01 02 63 36 04   16 64 63 3D 69 65 2C 64  0X...c6..dc=ie,d
+0010: 63 3D 6F 72 61 63 6C 65   2C 64 63 3D 63 6F 6D 0A  c=oracle,dc=com.
+0020: 01 00 0A 01 03 02 01 00   02 01 00 01 01 00 87 0B  ................
+0030: 6F 62 6A 65 63 74 43 6C   61 73 73 30 00 A0 1B 30  objectClass0...0
+0040: 19 04 17 32 2E 31 36 2E   38 34 30 2E 31 2E 31 31  ...2.16.840.1.11
+0050: 33 37 33 30 2E 33 2E 34   2E 32                    3730.3.4.2
+
+# LDAP SearchResultEntry:
+#
+#   0  111: SEQUENCE {
+#   2    1:   INTEGER 2
+#   5  106:   [APPLICATION 4] {
+#   7   22:     OCTET STRING 'dc=ie,dc=oracle,dc=com'
+#  31   80:     SEQUENCE {
+#  33   44:       SEQUENCE {
+#  35   11:         OCTET STRING 'objectClass'
+#  48   29:         SET {
+#  50    3:           OCTET STRING 'top'
+#  55    8:           OCTET STRING 'dcObject'
+#  65   12:           OCTET STRING 'organization'
+#         :           }
+#         :         }
+#  79   20:       SEQUENCE {
+#  81    1:         OCTET STRING 6F
+#  84   15:         SET {
+#  86   13:           OCTET STRING 'ie.oracle.com'
+#         :           }
+#         :         }
+# 101   10:       SEQUENCE {
+# 103    2:         OCTET STRING 64 63
+# 107    4:         SET {
+# 109    2:           OCTET STRING 69 65
+#         :           }
+#         :         }
+#         :       }
+#         :     }
+#         :   }
+#
+0000: 30 6F 02 01 02 64 6A 04   16 64 63 3D 69 65 2C 64  0o...dj..dc=ie,d
+0010: 63 3D 6F 72 61 63 6C 65   2C 64 63 3D 63 6F 6D 30  c=oracle,dc=com0
+0020: 50 30 2C 04 0B 6F 62 6A   65 63 74 43 6C 61 73 73  P0,..objectClass
+0030: 31 1D 04 03 74 6F 70 04   08 64 63 4F 62 6A 65 63  1...top..dcObjec
+0040: 74 04 0C 6F 72 67 61 6E   69 7A 61 74 69 6F 6E 30  t..organization0
+0050: 14 04 01 6F 31 0F 04 0D   69 65 2E 6F 72 61 63 6C  ...o1...ie.oracl
+0060: 65 2E 63 6F 6D 30 0A 04   02 64 63 31 04 04 02 69  e.com0...dc1...i
+0070: 65                                                 e
+
+# LDAP SearchResultDone:
+#
+#   0   12: SEQUENCE {
+#   2    1:   INTEGER 2
+#   5    7:   [APPLICATION 5] {
+#   7    1:     ENUMERATED 0
+#  10    0:     OCTET STRING
+#  12    0:     OCTET STRING
+#         :     }
+#         :   }
+#
+0000: 30 0C 02 01 02 65 07 0A   01 00 04 00 04 00        0....e........
+
+# LDAP UnbindRequest:
+#
+#   0   34: SEQUENCE {
+#   2    1:   INTEGER 3
+#   5    0:   [APPLICATION 2]
+#   7   27:   [0] {
+#   9   25:     SEQUENCE {
+#  11   23:       OCTET STRING '2.16.840.1.113730.3.4.2'
+#         :       }
+#         :     }
+#         :   }
+#
+0000: 30 22 02 01 03 42 00 A0   1B 30 19 04 17 32 2E 31  0"...B...0...2.1
+0010: 36 2E 38 34 30 2E 31 2E   31 31 33 37 33 30 2E 33  6.840.1.113730.3
+0020: 2E 34 2E 32                                        .4.2
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/naming/module/src/test/test/StoreFruit.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Demonstrate Java object storage and retrieval using an LDAP directory.
+ * The Fruit object and its associated object factory is supplied by a
+ * third-party module. The Fruit object implements javax.naming.Referenceable.
+ */
+
+package test;
+
+import java.net.*;
+import java.util.*;
+import javax.naming.*;
+import javax.naming.directory.*;
+
+import org.example.fruit.Fruit;
+
+public class StoreFruit {
+
+    // LDAP capture file
+    private static final String LDAP_CAPTURE_FILE =
+        System.getProperty("test.src") + "/src/test/test/StoreFruit.ldap";
+    // LDAPServer socket
+    private static ServerSocket serverSocket;
+
+    public static void main(String[] args) throws Exception {
+
+        /*
+         * Process arguments
+         */
+
+        int argc = args.length;
+        if ((argc < 1) ||
+            ((argc == 1) && (args[0].equalsIgnoreCase("-help")))) {
+
+            System.err.println("\nUsage:   StoreFruit <ldapurl>\n");
+            System.err.println("        <ldapurl> is the LDAP URL of the parent entry\n");
+            System.err.println("example:");
+            System.err.println("        java StoreFruit ldap://oasis/o=airius.com");
+    return;
+        }
+
+        /*
+         * Launch the LDAP server with the StoreFruit.ldap capture file
+         */
+
+        serverSocket = new ServerSocket(0);
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    new LDAPServer(serverSocket, LDAP_CAPTURE_FILE);
+               } catch (Exception e) {
+                   System.out.println("ERROR: unable to launch LDAP server");
+                   e.printStackTrace();
+               }
+            }
+        }).start();
+
+        /*
+         * Store fruit objects in the LDAP directory
+         */
+
+        Hashtable<String,Object> env = new Hashtable<>();
+        env.put(Context.INITIAL_CONTEXT_FACTORY,
+    "com.sun.jndi.ldap.LdapCtxFactory");
+        URI ldapUri = new URI(args[0]);
+        if (ldapUri.getPort() == -1) {
+            ldapUri = new URI(ldapUri.getScheme(), null, ldapUri.getHost(),
+                serverSocket.getLocalPort(), ldapUri.getPath(), null, null);
+        }
+        env.put(Context.PROVIDER_URL, ldapUri.toString());
+        if (args[args.length - 1].equalsIgnoreCase("-trace")) {
+            env.put("com.sun.jndi.ldap.trace.ber", System.out);
+        }
+
+        System.out.println("StoreFruit: connecting to " + ldapUri);
+        DirContext ctx = new InitialDirContext(env);
+        Fruit fruit = null;
+        String dn = "cn=myfruit";
+        String dn2 = "cn=myapple";
+
+        try {
+            fruit = new Fruit("orange");
+            ctx.bind(dn, fruit);
+            System.out.println("StoreFruit: created entry '" + dn + "'");
+        } catch (NameAlreadyBoundException e) {
+            System.err.println("StoreFruit: entry '" + dn +
+                "' already exists");
+            cleanup(ctx, (String)null);
+            return;
+        }
+
+        try {
+            ctx.bind(dn2, new Fruit("apple"));
+            System.out.println("StoreFruit: created entry '" + dn2 + "'");
+        } catch (NameAlreadyBoundException e) {
+            System.err.println("StoreFruit: entry '" + dn2 +
+                "' already exists");
+            cleanup(ctx, dn);
+            return;
+        }
+
+        /*
+         * Retrieve fruit objects from the LDAP directory
+         */
+
+        try {
+            Fruit fruit2 = (Fruit) ctx.lookup(dn);
+            System.out.println("StoreFruit: retrieved object: " + fruit2);
+        } catch (NamingException e) {
+            System.err.println("StoreFruit: error retrieving entry '" +
+                dn + "' " + e);
+            e.printStackTrace();
+            cleanup(ctx, dn, dn2);
+            return;
+        }
+
+        try {
+            Fruit fruit3 = (Fruit) ctx.lookup(dn2);
+            System.out.println("StoreFruit: retrieved object: " + fruit3);
+        } catch (NamingException e) {
+            System.err.println("StoreFruit: error retrieving entry '" +
+                dn2 + "' " + e);
+            e.printStackTrace();
+            cleanup(ctx, dn, dn2);
+            return;
+        }
+
+        cleanup(ctx, dn, dn2);
+    }
+
+    /*
+     * Remove objects from the LDAP directory
+     */
+    private static void cleanup(DirContext ctx, String... dns)
+        throws NamingException {
+
+        for (String dn : dns) {
+            try {
+                ctx.destroySubcontext(dn);
+                System.out.println("StoreFruit: removed entry '" + dn + "'");
+            } catch (NamingException e) {
+                System.err.println("StoreFruit: error removing entry '" + dn +
+                    "' " + e);
+            }
+        }
+        ctx.close();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/naming/module/src/test/test/StoreFruit.ldap	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,512 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+################################################################################
+# Capture file for StoreFruit.java
+#
+# NOTE: This hexadecimal dump of LDAP protocol messages was generated by
+#       running the StoreFruit application program against a real LDAP
+#       server and setting the JNDI/LDAP environment property:
+#       com.sun.jndi.ldap.trace.ber to activate LDAP message tracing.
+#
+#      (The ASN.1 annotations were generated separately by the dumpasn1
+#       utility and added only for clarity.)
+#
+################################################################################
+
+# LDAP BindRequest:
+#
+#   0   12: SEQUENCE {
+#   2    1:   INTEGER 1
+#   5    7:   [APPLICATION 0] {
+#   7    1:     INTEGER 3
+#  10    0:     OCTET STRING
+#  12    0:     [0]
+#         :     }
+#         :   }
+#
+0000: 30 0C 02 01 01 60 07 02   01 03 04 00 80 00        0....`........
+
+# LDAP BindResponse:
+#
+#   0   12: SEQUENCE {
+#   2    1:   INTEGER 1
+#   5    7:   [APPLICATION 1] {
+#   7    1:     ENUMERATED 0
+#  10    0:     OCTET STRING
+#  12    0:     OCTET STRING
+#         :     }
+#         :   }
+#
+0000: 30 0C 02 01 01 61 07 0A   01 00 04 00 04 00        0....a........
+
+# LDAP AddRequest:
+#
+#   0  297: SEQUENCE {
+#   4    1:   INTEGER 2
+#   7  261:   [APPLICATION 8] {
+#  11   33:     OCTET STRING 'cn=myfruit,dc=ie,dc=oracle,dc=com'
+#  46  223:     SEQUENCE {
+#  49   68:       SEQUENCE {
+#  51   11:         OCTET STRING 'objectClass'
+#  64   53:         SET {
+#  66    3:           OCTET STRING 'top'
+#  71   13:           OCTET STRING 'javaContainer'
+#  86   10:           OCTET STRING 'javaObject'
+#  98   19:           OCTET STRING 'javaNamingReference'
+#         :           }
+#         :         }
+# 119   41:       SEQUENCE {
+# 121   20:         OCTET STRING 'javaReferenceAddress'
+# 143   17:         SET {
+# 145   15:           OCTET STRING '#0#fruit#orange'
+#         :           }
+#         :         }
+# 162   47:       SEQUENCE {
+# 164   11:         OCTET STRING 'javaFactory'
+# 177   32:         SET {
+# 179   30:           OCTET STRING 'org.example.fruit.FruitFactory'
+#         :           }
+#         :         }
+# 211   42:       SEQUENCE {
+# 213   13:         OCTET STRING 'javaClassName'
+# 228   25:         SET {
+# 230   23:           OCTET STRING 'org.example.fruit.Fruit'
+#         :           }
+#         :         }
+# 255   15:       SEQUENCE {
+# 257    2:         OCTET STRING 63 6E
+# 261    9:         SET {
+# 263    7:           OCTET STRING 'myfruit'
+#         :           }
+#         :         }
+#         :       }
+#         :     }
+# 272   27:   [0] {
+# 274   25:     SEQUENCE {
+# 276   23:       OCTET STRING '2.16.840.1.113730.3.4.2'
+#         :       }
+#         :     }
+#         :   }
+#
+0000: 30 82 01 29 02 01 02 68   82 01 05 04 21 63 6E 3D  0..)...h....!cn=
+0010: 6D 79 66 72 75 69 74 2C   64 63 3D 69 65 2C 64 63  myfruit,dc=ie,dc
+0020: 3D 6F 72 61 63 6C 65 2C   64 63 3D 63 6F 6D 30 81  =oracle,dc=com0.
+0030: DF 30 44 04 0B 6F 62 6A   65 63 74 43 6C 61 73 73  .0D..objectClass
+0040: 31 35 04 03 74 6F 70 04   0D 6A 61 76 61 43 6F 6E  15..top..javaCon
+0050: 74 61 69 6E 65 72 04 0A   6A 61 76 61 4F 62 6A 65  tainer..javaObje
+0060: 63 74 04 13 6A 61 76 61   4E 61 6D 69 6E 67 52 65  ct..javaNamingRe
+0070: 66 65 72 65 6E 63 65 30   29 04 14 6A 61 76 61 52  ference0)..javaR
+0080: 65 66 65 72 65 6E 63 65   41 64 64 72 65 73 73 31  eferenceAddress1
+0090: 11 04 0F 23 30 23 66 72   75 69 74 23 6F 72 61 6E  ...#0#fruit#oran
+00A0: 67 65 30 2F 04 0B 6A 61   76 61 46 61 63 74 6F 72  ge0/..javaFactor
+00B0: 79 31 20 04 1E 6F 72 67   2E 65 78 61 6D 70 6C 65  y1 ..org.example
+00C0: 2E 66 72 75 69 74 2E 46   72 75 69 74 46 61 63 74  .fruit.FruitFact
+00D0: 6F 72 79 30 2A 04 0D 6A   61 76 61 43 6C 61 73 73  ory0*..javaClass
+00E0: 4E 61 6D 65 31 19 04 17   6F 72 67 2E 65 78 61 6D  Name1...org.exam
+00F0: 70 6C 65 2E 66 72 75 69   74 2E 46 72 75 69 74 30  ple.fruit.Fruit0
+0100: 0F 04 02 63 6E 31 09 04   07 6D 79 66 72 75 69 74  ...cn1...myfruit
+0110: A0 1B 30 19 04 17 32 2E   31 36 2E 38 34 30 2E 31  ..0...2.16.840.1
+0120: 2E 31 31 33 37 33 30 2E   33 2E 34 2E 32           .113730.3.4.2
+
+# LDAP AddResponse:
+#
+#   0   12: SEQUENCE {
+#   2    1:   INTEGER 2
+#   5    7:   [APPLICATION 9] {
+#   7    1:     ENUMERATED 0
+#  10    0:     OCTET STRING
+#  12    0:     OCTET STRING
+#         :     }
+#         :   }
+#
+0000: 30 0C 02 01 02 69 07 0A   01 00 04 00 04 00        0....i........
+
+# LDAP AddRequest:
+#
+#   0  296: SEQUENCE {
+#   4    1:   INTEGER 3
+#   7  260:   [APPLICATION 8] {
+#  11   33:     OCTET STRING 'cn=myapple,dc=ie,dc=oracle,dc=com'
+#  46  222:     SEQUENCE {
+#  49   68:       SEQUENCE {
+#  51   11:         OCTET STRING 'objectClass'
+#  64   53:         SET {
+#  66    3:           OCTET STRING 'top'
+#  71   13:           OCTET STRING 'javaContainer'
+#  86   10:           OCTET STRING 'javaObject'
+#  98   19:           OCTET STRING 'javaNamingReference'
+#         :           }
+#         :         }
+# 119   40:       SEQUENCE {
+# 121   20:         OCTET STRING 'javaReferenceAddress'
+# 143   16:         SET {
+# 145   14:           OCTET STRING '#0#fruit#apple'
+#         :           }
+#         :         }
+# 161   47:       SEQUENCE {
+# 163   11:         OCTET STRING 'javaFactory'
+# 176   32:         SET {
+# 178   30:           OCTET STRING 'org.example.fruit.FruitFactory'
+#         :           }
+#         :         }
+# 210   42:       SEQUENCE {
+# 212   13:         OCTET STRING 'javaClassName'
+# 227   25:         SET {
+# 229   23:           OCTET STRING 'org.example.fruit.Fruit'
+#         :           }
+#         :         }
+# 254   15:       SEQUENCE {
+# 256    2:         OCTET STRING 63 6E
+# 260    9:         SET {
+# 262    7:           OCTET STRING 'myapple'
+#         :           }
+#         :         }
+#         :       }
+#         :     }
+# 271   27:   [0] {
+# 273   25:     SEQUENCE {
+# 275   23:       OCTET STRING '2.16.840.1.113730.3.4.2'
+#         :       }
+#         :     }
+#         :   }
+#
+0000: 30 82 01 28 02 01 03 68   82 01 04 04 21 63 6E 3D  0..(...h....!cn=
+0010: 6D 79 61 70 70 6C 65 2C   64 63 3D 69 65 2C 64 63  myapple,dc=ie,dc
+0020: 3D 6F 72 61 63 6C 65 2C   64 63 3D 63 6F 6D 30 81  =oracle,dc=com0.
+0030: DE 30 44 04 0B 6F 62 6A   65 63 74 43 6C 61 73 73  .0D..objectClass
+0040: 31 35 04 03 74 6F 70 04   0D 6A 61 76 61 43 6F 6E  15..top..javaCon
+0050: 74 61 69 6E 65 72 04 0A   6A 61 76 61 4F 62 6A 65  tainer..javaObje
+0060: 63 74 04 13 6A 61 76 61   4E 61 6D 69 6E 67 52 65  ct..javaNamingRe
+0070: 66 65 72 65 6E 63 65 30   28 04 14 6A 61 76 61 52  ference0(..javaR
+0080: 65 66 65 72 65 6E 63 65   41 64 64 72 65 73 73 31  eferenceAddress1
+0090: 10 04 0E 23 30 23 66 72   75 69 74 23 61 70 70 6C  ...#0#fruit#appl
+00A0: 65 30 2F 04 0B 6A 61 76   61 46 61 63 74 6F 72 79  e0/..javaFactory
+00B0: 31 20 04 1E 6F 72 67 2E   65 78 61 6D 70 6C 65 2E  1 ..org.example.
+00C0: 66 72 75 69 74 2E 46 72   75 69 74 46 61 63 74 6F  fruit.FruitFacto
+00D0: 72 79 30 2A 04 0D 6A 61   76 61 43 6C 61 73 73 4E  ry0*..javaClassN
+00E0: 61 6D 65 31 19 04 17 6F   72 67 2E 65 78 61 6D 70  ame1...org.examp
+00F0: 6C 65 2E 66 72 75 69 74   2E 46 72 75 69 74 30 0F  le.fruit.Fruit0.
+0100: 04 02 63 6E 31 09 04 07   6D 79 61 70 70 6C 65 A0  ..cn1...myapple.
+0110: 1B 30 19 04 17 32 2E 31   36 2E 38 34 30 2E 31 2E  .0...2.16.840.1.
+0120: 31 31 33 37 33 30 2E 33   2E 34 2E 32              113730.3.4.2
+
+# LDAP AddResponse:
+#
+#   0   12: SEQUENCE {
+#   2    1:   INTEGER 3
+#   5    7:   [APPLICATION 9] {
+#   7    1:     ENUMERATED 0
+#  10    0:     OCTET STRING
+#  12    0:     OCTET STRING
+#         :     }
+#         :   }
+#
+0000: 30 0C 02 01 03 69 07 0A   01 00 04 00 04 00        0....i........
+
+# LDAP SearchRequest:
+#
+#   0   99: SEQUENCE {
+#   2    1:   INTEGER 4
+#   5   65:   [APPLICATION 3] {
+#   7   33:     OCTET STRING 'cn=myfruit,dc=ie,dc=oracle,dc=com'
+#  42    1:     ENUMERATED 0
+#  45    1:     ENUMERATED 3
+#  48    1:     INTEGER 0
+#  51    1:     INTEGER 0
+#  54    1:     BOOLEAN FALSE
+#  57   11:     [7] 'objectClass'
+#  70    0:     SEQUENCE {}
+#         :     }
+#  72   27:   [0] {
+#  74   25:     SEQUENCE {
+#  76   23:       OCTET STRING '2.16.840.1.113730.3.4.2'
+#         :       }
+#         :     }
+#         :   }
+#
+0000: 30 63 02 01 04 63 41 04   21 63 6E 3D 6D 79 66 72  0c...cA.!cn=myfr
+0010: 75 69 74 2C 64 63 3D 69   65 2C 64 63 3D 6F 72 61  uit,dc=ie,dc=ora
+0020: 63 6C 65 2C 64 63 3D 63   6F 6D 0A 01 00 0A 01 03  cle,dc=com......
+0030: 02 01 00 02 01 00 01 01   00 87 0B 6F 62 6A 65 63  ...........objec
+0040: 74 43 6C 61 73 73 30 00   A0 1B 30 19 04 17 32 2E  tClass0...0...2.
+0050: 31 36 2E 38 34 30 2E 31   2E 31 31 33 37 33 30 2E  16.840.1.113730.
+0060: 33 2E 34 2E 32                                     3.4.2
+
+# LDAP SearchResultEntry:
+#
+#   0  268: SEQUENCE {
+#   4    1:   INTEGER 4
+#   7  261:   [APPLICATION 4] {
+#  11   33:     OCTET STRING 'cn=myfruit,dc=ie,dc=oracle,dc=com'
+#  46  223:     SEQUENCE {
+#  49   68:       SEQUENCE {
+#  51   11:         OCTET STRING 'objectClass'
+#  64   53:         SET {
+#  66    3:           OCTET STRING 'top'
+#  71   13:           OCTET STRING 'javaContainer'
+#  86   10:           OCTET STRING 'javaObject'
+#  98   19:           OCTET STRING 'javaNamingReference'
+#         :           }
+#         :         }
+# 119   41:       SEQUENCE {
+# 121   20:         OCTET STRING 'javaReferenceAddress'
+# 143   17:         SET {
+# 145   15:           OCTET STRING '#0#fruit#orange'
+#         :           }
+#         :         }
+# 162   47:       SEQUENCE {
+# 164   11:         OCTET STRING 'javaFactory'
+# 177   32:         SET {
+# 179   30:           OCTET STRING 'org.example.fruit.FruitFactory'
+#         :           }
+#         :         }
+# 211   42:       SEQUENCE {
+# 213   13:         OCTET STRING 'javaClassName'
+# 228   25:         SET {
+# 230   23:           OCTET STRING 'org.example.fruit.Fruit'
+#         :           }
+#         :         }
+# 255   15:       SEQUENCE {
+# 257    2:         OCTET STRING 63 6E
+# 261    9:         SET {
+# 263    7:           OCTET STRING 'myfruit'
+#         :           }
+#         :         }
+#         :       }
+#         :     }
+#         :   }
+#
+0000: 30 82 01 0C 02 01 04 64   82 01 05 04 21 63 6E 3D  0......d....!cn=
+0010: 6D 79 66 72 75 69 74 2C   64 63 3D 69 65 2C 64 63  myfruit,dc=ie,dc
+0020: 3D 6F 72 61 63 6C 65 2C   64 63 3D 63 6F 6D 30 81  =oracle,dc=com0.
+0030: DF 30 44 04 0B 6F 62 6A   65 63 74 43 6C 61 73 73  .0D..objectClass
+0040: 31 35 04 03 74 6F 70 04   0D 6A 61 76 61 43 6F 6E  15..top..javaCon
+0050: 74 61 69 6E 65 72 04 0A   6A 61 76 61 4F 62 6A 65  tainer..javaObje
+0060: 63 74 04 13 6A 61 76 61   4E 61 6D 69 6E 67 52 65  ct..javaNamingRe
+0070: 66 65 72 65 6E 63 65 30   29 04 14 6A 61 76 61 52  ference0)..javaR
+0080: 65 66 65 72 65 6E 63 65   41 64 64 72 65 73 73 31  eferenceAddress1
+0090: 11 04 0F 23 30 23 66 72   75 69 74 23 6F 72 61 6E  ...#0#fruit#oran
+00A0: 67 65 30 2F 04 0B 6A 61   76 61 46 61 63 74 6F 72  ge0/..javaFactor
+00B0: 79 31 20 04 1E 6F 72 67   2E 65 78 61 6D 70 6C 65  y1 ..org.example
+00C0: 2E 66 72 75 69 74 2E 46   72 75 69 74 46 61 63 74  .fruit.FruitFact
+00D0: 6F 72 79 30 2A 04 0D 6A   61 76 61 43 6C 61 73 73  ory0*..javaClass
+00E0: 4E 61 6D 65 31 19 04 17   6F 72 67 2E 65 78 61 6D  Name1...org.exam
+00F0: 70 6C 65 2E 66 72 75 69   74 2E 46 72 75 69 74 30  ple.fruit.Fruit0
+0100: 0F 04 02 63 6E 31 09 04   07 6D 79 66 72 75 69 74  ...cn1...myfruit
+
+# LDAP SearchResultDone:
+#
+#   0   12: SEQUENCE {
+#   2    1:   INTEGER 4
+#   5    7:   [APPLICATION 5] {
+#   7    1:     ENUMERATED 0
+#  10    0:     OCTET STRING
+#  12    0:     OCTET STRING
+#         :     }
+#         :   }
+#
+0000: 30 0C 02 01 04 65 07 0A   01 00 04 00 04 00        0....e........
+
+# LDAP SearchRequest:
+#
+#   0   99: SEQUENCE {
+#   2    1:   INTEGER 5
+#   5   65:   [APPLICATION 3] {
+#   7   33:     OCTET STRING 'cn=myapple,dc=ie,dc=oracle,dc=com'
+#  42    1:     ENUMERATED 0
+#  45    1:     ENUMERATED 3
+#  48    1:     INTEGER 0
+#  51    1:     INTEGER 0
+#  54    1:     BOOLEAN FALSE
+#  57   11:     [7] 'objectClass'
+#  70    0:     SEQUENCE {}
+#         :     }
+#  72   27:   [0] {
+#  74   25:     SEQUENCE {
+#  76   23:       OCTET STRING '2.16.840.1.113730.3.4.2'
+#         :       }
+#         :     }
+#         :   }
+#
+0000: 30 63 02 01 05 63 41 04   21 63 6E 3D 6D 79 61 70  0c...cA.!cn=myap
+0010: 70 6C 65 2C 64 63 3D 69   65 2C 64 63 3D 6F 72 61  ple,dc=ie,dc=ora
+0020: 63 6C 65 2C 64 63 3D 63   6F 6D 0A 01 00 0A 01 03  cle,dc=com......
+0030: 02 01 00 02 01 00 01 01   00 87 0B 6F 62 6A 65 63  ...........objec
+0040: 74 43 6C 61 73 73 30 00   A0 1B 30 19 04 17 32 2E  tClass0...0...2.
+0050: 31 36 2E 38 34 30 2E 31   2E 31 31 33 37 33 30 2E  16.840.1.113730.
+0060: 33 2E 34 2E 32                                     3.4.2
+
+# LDAP SearchResultEntry:
+#
+#   0  267: SEQUENCE {
+#   4    1:   INTEGER 5
+#   7  260:   [APPLICATION 4] {
+#  11   33:     OCTET STRING 'cn=myapple,dc=ie,dc=oracle,dc=com'
+#  46  222:     SEQUENCE {
+#  49   68:       SEQUENCE {
+#  51   11:         OCTET STRING 'objectClass'
+#  64   53:         SET {
+#  66    3:           OCTET STRING 'top'
+#  71   13:           OCTET STRING 'javaContainer'
+#  86   10:           OCTET STRING 'javaObject'
+#  98   19:           OCTET STRING 'javaNamingReference'
+#         :           }
+#         :         }
+# 119   40:       SEQUENCE {
+# 121   20:         OCTET STRING 'javaReferenceAddress'
+# 143   16:         SET {
+# 145   14:           OCTET STRING '#0#fruit#apple'
+#         :           }
+#         :         }
+# 161   47:       SEQUENCE {
+# 163   11:         OCTET STRING 'javaFactory'
+# 176   32:         SET {
+# 178   30:           OCTET STRING 'org.example.fruit.FruitFactory'
+#         :           }
+#         :         }
+# 210   42:       SEQUENCE {
+# 212   13:         OCTET STRING 'javaClassName'
+# 227   25:         SET {
+# 229   23:           OCTET STRING 'org.example.fruit.Fruit'
+#         :           }
+#         :         }
+# 254   15:       SEQUENCE {
+# 256    2:         OCTET STRING 63 6E
+# 260    9:         SET {
+# 262    7:           OCTET STRING 'myapple'
+#         :           }
+#         :         }
+#         :       }
+#         :     }
+#         :   }
+#
+0000: 30 82 01 0B 02 01 05 64   82 01 04 04 21 63 6E 3D  0......d....!cn=
+0010: 6D 79 61 70 70 6C 65 2C   64 63 3D 69 65 2C 64 63  myapple,dc=ie,dc
+0020: 3D 6F 72 61 63 6C 65 2C   64 63 3D 63 6F 6D 30 81  =oracle,dc=com0.
+0030: DE 30 44 04 0B 6F 62 6A   65 63 74 43 6C 61 73 73  .0D..objectClass
+0040: 31 35 04 03 74 6F 70 04   0D 6A 61 76 61 43 6F 6E  15..top..javaCon
+0050: 74 61 69 6E 65 72 04 0A   6A 61 76 61 4F 62 6A 65  tainer..javaObje
+0060: 63 74 04 13 6A 61 76 61   4E 61 6D 69 6E 67 52 65  ct..javaNamingRe
+0070: 66 65 72 65 6E 63 65 30   28 04 14 6A 61 76 61 52  ference0(..javaR
+0080: 65 66 65 72 65 6E 63 65   41 64 64 72 65 73 73 31  eferenceAddress1
+0090: 10 04 0E 23 30 23 66 72   75 69 74 23 61 70 70 6C  ...#0#fruit#appl
+00A0: 65 30 2F 04 0B 6A 61 76   61 46 61 63 74 6F 72 79  e0/..javaFactory
+00B0: 31 20 04 1E 6F 72 67 2E   65 78 61 6D 70 6C 65 2E  1 ..org.example.
+00C0: 66 72 75 69 74 2E 46 72   75 69 74 46 61 63 74 6F  fruit.FruitFacto
+00D0: 72 79 30 2A 04 0D 6A 61   76 61 43 6C 61 73 73 4E  ry0*..javaClassN
+00E0: 61 6D 65 31 19 04 17 6F   72 67 2E 65 78 61 6D 70  ame1...org.examp
+00F0: 6C 65 2E 66 72 75 69 74   2E 46 72 75 69 74 30 0F  le.fruit.Fruit0.
+0100: 04 02 63 6E 31 09 04 07   6D 79 61 70 70 6C 65     ..cn1...myapple
+
+# LDAP SearchResultDone:
+#
+#   0   12: SEQUENCE {
+#   2    1:   INTEGER 5
+#   5    7:   [APPLICATION 5] {
+#   7    1:     ENUMERATED 0
+#  10    0:     OCTET STRING
+#  12    0:     OCTET STRING
+#         :     }
+#         :   }
+#
+0000: 30 0C 02 01 05 65 07 0A   01 00 04 00 04 00        0....e........
+
+# LDAP DeleteRequest:
+#
+#   0   67: SEQUENCE {
+#   2    1:   INTEGER 6
+#   5   33:   [APPLICATION 10] 'cn=myfruit,dc=ie,dc=oracle,dc=com'
+#  40   27:   [0] {
+#  42   25:     SEQUENCE {
+#  44   23:       OCTET STRING '2.16.840.1.113730.3.4.2'
+#         :       }
+#         :     }
+#         :   }
+#
+0000: 30 43 02 01 06 4A 21 63   6E 3D 6D 79 66 72 75 69  0C...J!cn=myfrui
+0010: 74 2C 64 63 3D 69 65 2C   64 63 3D 6F 72 61 63 6C  t,dc=ie,dc=oracl
+0020: 65 2C 64 63 3D 63 6F 6D   A0 1B 30 19 04 17 32 2E  e,dc=com..0...2.
+0030: 31 36 2E 38 34 30 2E 31   2E 31 31 33 37 33 30 2E  16.840.1.113730.
+0040: 33 2E 34 2E 32                                     3.4.2
+
+# LDAP DeleteResponse:
+#
+#   0   12: SEQUENCE {
+#   2    1:   INTEGER 6
+#   5    7:   [APPLICATION 11] {
+#   7    1:     ENUMERATED 0
+#  10    0:     OCTET STRING
+#  12    0:     OCTET STRING
+#         :     }
+#         :   }
+#
+0000: 30 0C 02 01 06 6B 07 0A   01 00 04 00 04 00        0....k........
+
+# LDAP DeleteRequest:
+#
+#   0   67: SEQUENCE {
+#   2    1:   INTEGER 7
+#   5   33:   [APPLICATION 10] 'cn=myapple,dc=ie,dc=oracle,dc=com'
+#  40   27:   [0] {
+#  42   25:     SEQUENCE {
+#  44   23:       OCTET STRING '2.16.840.1.113730.3.4.2'
+#         :       }
+#         :     }
+#         :   }
+#
+0000: 30 43 02 01 07 4A 21 63   6E 3D 6D 79 61 70 70 6C  0C...J!cn=myappl
+0010: 65 2C 64 63 3D 69 65 2C   64 63 3D 6F 72 61 63 6C  e,dc=ie,dc=oracl
+0020: 65 2C 64 63 3D 63 6F 6D   A0 1B 30 19 04 17 32 2E  e,dc=com..0...2.
+0030: 31 36 2E 38 34 30 2E 31   2E 31 31 33 37 33 30 2E  16.840.1.113730.
+0040: 33 2E 34 2E 32                                     3.4.2
+
+# LDAP DeleteResponse:
+#
+#   0   12: SEQUENCE {
+#   2    1:   INTEGER 7
+#   5    7:   [APPLICATION 11] {
+#   7    1:     ENUMERATED 0
+#  10    0:     OCTET STRING
+#  12    0:     OCTET STRING
+#         :     }
+#         :   }
+#
+0000: 30 0C 02 01 07 6B 07 0A   01 00 04 00 04 00        0....k........
+
+# LDAP UnbindRequest:
+#
+#   0   34: SEQUENCE {
+#   2    1:   INTEGER 8
+#   5    0:   [APPLICATION 2]
+#   7   27:   [0] {
+#   9   25:     SEQUENCE {
+#  11   23:       OCTET STRING '2.16.840.1.113730.3.4.2'
+#         :       }
+#         :     }
+#         :   }
+#
+0000: 30 22 02 01 08 42 00 A0   1B 30 19 04 17 32 2E 31  0"...B...0...2.1
+0010: 36 2E 38 34 30 2E 31 2E   31 31 33 37 33 30 2E 33  6.840.1.113730.3
+0020: 2E 34 2E 32                                        .4.2
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/naming/module/src/test/test/StoreObject.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Demonstrate Java object storage and retrieval using an LDAP directory.
+ * The ActionEvent object is serializable and is supplied by the java.desktop
+ * module.
+ */
+
+package test;
+
+import java.awt.event.ActionEvent;
+import java.net.*;
+import java.util.*;
+import javax.naming.*;
+import javax.naming.directory.*;
+
+public class StoreObject {
+
+    // LDAP capture file
+    private static final String LDAP_CAPTURE_FILE =
+        System.getProperty("test.src") + "/src/test/test/StoreObject.ldap";
+    // LDAPServer socket
+    private static ServerSocket serverSocket;
+
+    public static void main(String[] args) throws Exception {
+
+        /*
+         * Process arguments
+         */
+
+        int argc = args.length;
+        if ((argc < 1) ||
+            ((argc == 1) && (args[0].equalsIgnoreCase("-help")))) {
+
+            System.err.println("\nUsage:   StoreObject <ldapurl>\n");
+            System.err.println("        <ldapurl> is the LDAP URL of the parent entry\n");
+            System.err.println("example:");
+            System.err.println("        java StoreObject ldap://oasis/o=airius.com");
+            return;
+        }
+
+        /*
+         * Launch the LDAP server with the StoreObject.ldap capture file
+         */
+
+        serverSocket = new ServerSocket(0);
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    new LDAPServer(serverSocket, LDAP_CAPTURE_FILE);
+               } catch (Exception e) {
+                   System.out.println("ERROR: unable to launch LDAP server");
+                   e.printStackTrace();
+               }
+            }
+        }).start();
+
+        /*
+         * Store objects in the LDAP directory
+         */
+
+        Hashtable<String,Object> env = new Hashtable<>();
+        env.put(Context.INITIAL_CONTEXT_FACTORY,
+            "com.sun.jndi.ldap.LdapCtxFactory");
+        URI ldapUri = new URI(args[0]);
+        if (ldapUri.getPort() == -1) {
+            ldapUri = new URI(ldapUri.getScheme(), null, ldapUri.getHost(),
+                serverSocket.getLocalPort(), ldapUri.getPath(), null, null);
+        }
+        env.put(Context.PROVIDER_URL, ldapUri.toString());
+        if (args[args.length - 1].equalsIgnoreCase("-trace")) {
+            env.put("com.sun.jndi.ldap.trace.ber", System.out);
+        }
+
+        System.out.println("StoreObject: connecting to " + ldapUri);
+        DirContext ctx = new InitialDirContext(env);
+        String dn = "cn=myevent";
+        String dn2 = "cn=myevent2";
+
+        try {
+            ctx.bind(dn, new ActionEvent("", 1, "Hello1"));
+            System.out.println("StoreObject: created entry '" + dn + "'");
+        } catch (NameAlreadyBoundException e) {
+            System.err.println("StoreObject: entry '" + dn +
+                "' already exists");
+            cleanup(ctx, (String)null);
+            return;
+        }
+
+        try {
+            ctx.bind(dn2, new ActionEvent("", 2, "Hello2"));
+            System.out.println("StoreObject: created entry '" + dn2 + "'");
+        } catch (NameAlreadyBoundException e) {
+            System.err.println("StoreObject: entry '" + dn2 +
+                "' already exists");
+            cleanup(ctx, dn);
+            return;
+        }
+
+        /*
+         * Retrieve objects from the LDAP directory
+         */
+
+        try {
+            ActionEvent b = (ActionEvent) ctx.lookup(dn);
+            System.out.println("StoreObject: retrieved object: " + b);
+        } catch (NamingException e) {
+            System.err.println("StoreObject: error retrieving entry '" +
+                dn + "' " + e);
+            e.printStackTrace();
+            cleanup(ctx, dn, dn2);
+            return;
+        }
+
+        try {
+            ActionEvent t = (ActionEvent) ctx.lookup(dn2);
+            System.out.println("StoreObject: retrieved object: " + t);
+        } catch (NamingException e) {
+            System.err.println("StoreObject: error retrieving entry '" +
+                dn2 + "' " + e);
+            e.printStackTrace();
+            cleanup(ctx, dn, dn2);
+            return;
+        }
+
+        cleanup(ctx, dn, dn2);
+        ctx.close();
+    }
+
+    /*
+     * Remove objects from the LDAP directory
+     */
+    private static void cleanup(DirContext ctx, String... dns)
+        throws NamingException {
+
+        for (String dn : dns) {
+            try {
+                ctx.destroySubcontext(dn);
+                System.out.println("StoreObject: removed entry '" + dn + "'");
+            } catch (NamingException e) {
+                System.err.println("StoreObject: error removing entry '" + dn +
+                    "' " + e);
+            }
+        }
+        ctx.close();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/naming/module/src/test/test/StoreObject.ldap	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,664 @@
+#
+# Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+################################################################################
+# Capture file for StoreObject.java
+#
+# NOTE: This hexadecimal dump of LDAP protocol messages was generated by
+#       running the StoreObject application program against a real LDAP
+#       server and setting the JNDI/LDAP environment property:
+#       com.sun.jndi.ldap.trace.ber to activate LDAP message tracing.
+#
+#      (The ASN.1 annotations were generated separately by the dumpasn1
+#       utility and added only for clarity.)
+#
+################################################################################
+
+# LDAP BindRequest:
+#
+#   0  12: SEQUENCE {
+#   2   1:   INTEGER 1
+#   5   7:   [APPLICATION 0] {
+#   7   1:     INTEGER 3
+#  10   0:     OCTET STRING
+#  12   0:     [0]
+#        :     }
+#        :   }
+#
+0000: 30 0C 02 01 01 60 07 02   01 03 04 00 80 00        0....`........
+
+# LDAP BindResponse:
+#
+#   0  12: SEQUENCE {
+#   2   1:   INTEGER 1
+#   5   7:   [APPLICATION 1] {
+#   7   1:     ENUMERATED 0
+#  10   0:     OCTET STRING
+#  12   0:     OCTET STRING
+#        :     }
+#        :   }
+#
+0000: 30 0C 02 01 01 61 07 0A   01 00 04 00 04 00        0....a........
+
+# LDAP AddRequest:
+#
+#   0 597: SEQUENCE {
+#   4   1:   INTEGER 2
+#   7 561:   [APPLICATION 8] {
+#  11  33:     OCTET STRING 'cn=myevent,dc=ie,dc=oracle,dc=com'
+#  46 522:     SEQUENCE {
+#  50 253:       SEQUENCE {
+#  53  18:         OCTET STRING 'javaSerializedData'
+#  73 230:         SET {
+#  76 227:           OCTET STRING
+#        :             AC ED 00 05 73 72 00 1A 6A 61 76 61 2E 61 77 74
+#        :             2E 65 76 65 6E 74 2E 41 63 74 69 6F 6E 45 76 65
+#        :             6E 74 95 8A DA 7A 58 11 2F 2B 02 00 03 49 00 09
+#        :             6D 6F 64 69 66 69 65 72 73 4A 00 04 77 68 65 6E
+#        :             4C 00 0D 61 63 74 69 6F 6E 43 6F 6D 6D 61 6E 64
+#        :             74 00 12 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74
+#        :             72 69 6E 67 3B 78 72 00 11 6A 61 76 61 2E 61 77
+#        :             74 2E 41 57 54 45 76 65 6E 74 E6 AB 2D E1 18 DF
+#        :             8A C3 02 00 03 5A 20 08 63 6F 6E 73 75 6D 65 64
+#        :             49 00 02 69 64 5B 00 05 62 64 61 74 61 74 00 02
+#        :             5B 42 78 72 00 15 6A 61 76 61 2E 75 74 69 6C 2E
+#        :             45 76 65 6E 74 4F 62 6A 65 63 74 4C 8D 09 4E 18
+#        :             6D 7D A8 02 00 00 78 70 00 00 00 00 01 70 00 00
+#        :             00 00 00 00 00 00 00 00 00 00 74 00 06 48 65 6C
+#        :             6C 6F 31
+#        :           }
+#        :         }
+# 306  69:       SEQUENCE {
+# 308  11:         OCTET STRING 'objectClass'
+# 321  54:         SET {
+# 323   3:           OCTET STRING 'top'
+# 328  13:           OCTET STRING 'javaContainer'
+# 343  10:           OCTET STRING 'javaObject'
+# 355  20:           OCTET STRING 'javaSerializedObject'
+#        :           }
+#        :         }
+# 377 128:       SEQUENCE {
+# 380  14:         OCTET STRING 'javaClassNames'
+# 396 110:         SET {
+# 398  26:           OCTET STRING 'java.awt.event.ActionEvent'
+# 426  17:           OCTET STRING 'java.awt.AWTEvent'
+# 445  21:           OCTET STRING 'java.util.EventObject'
+# 468  16:           OCTET STRING 'java.lang.Object'
+# 486  20:           OCTET STRING 'java.io.Serializable'
+#        :           }
+#        :         }
+# 508  45:       SEQUENCE {
+# 510  13:         OCTET STRING 'javaClassName'
+# 525  28:         SET {
+# 527  26:           OCTET STRING 'java.awt.event.ActionEvent'
+#        :           }
+#        :         }
+# 555  15:       SEQUENCE {
+# 557   2:         OCTET STRING 'cn'
+# 561   9:         SET {
+# 563   7:           OCTET STRING 'myevent'
+#        :           }
+#        :         }
+#        :       }
+#        :     }
+# 572  27:   [0] {
+# 574  25:     SEQUENCE {
+# 576  23:       OCTET STRING '2.16.840.1.113730.3.4.2'
+#        :       }
+#        :     }
+#        :   }
+#
+0000: 30 82 02 55 02 01 02 68   82 02 31 04 21 63 6E 3D  0..U...h..1.!cn=
+0010: 6D 79 65 76 65 6E 74 2C   64 63 3D 69 65 2C 64 63  myevent,dc=ie,dc
+0020: 3D 6F 72 61 63 6C 65 2C   64 63 3D 63 6F 6D 30 82  =oracle,dc=com0.
+0030: 02 0A 30 81 FD 04 12 6A   61 76 61 53 65 72 69 61  ..0....javaSeria
+0040: 6C 69 7A 65 64 44 61 74   61 31 81 E6 04 81 E3 AC  lizedData1......
+0050: ED 00 05 73 72 00 1A 6A   61 76 61 2E 61 77 74 2E  ...sr..java.awt.
+0060: 65 76 65 6E 74 2E 41 63   74 69 6F 6E 45 76 65 6E  event.ActionEven
+0070: 74 95 8A DA 7A 58 11 2F   2B 02 00 03 49 00 09 6D  t...zX./+...I..m
+0080: 6F 64 69 66 69 65 72 73   4A 00 04 77 68 65 6E 4C  odifiersJ..whenL
+0090: 00 0D 61 63 74 69 6F 6E   43 6F 6D 6D 61 6E 64 74  ..actionCommandt
+00A0: 00 12 4C 6A 61 76 61 2F   6C 61 6E 67 2F 53 74 72  ..Ljava/lang/Str
+00B0: 69 6E 67 3B 78 72 00 11   6A 61 76 61 2E 61 77 74  ing;xr..java.awt
+00C0: 2E 41 57 54 45 76 65 6E   74 E6 AB 2D E1 18 DF 8A  .AWTEvent..-....
+00D0: C3 02 00 03 5A 00 08 63   6F 6E 73 75 6D 65 64 49  ....Z..consumedI
+00E0: 00 02 69 64 5B 00 05 62   64 61 74 61 74 00 02 5B  ..id[..bdatat..[
+00F0: 42 78 72 00 15 6A 61 76   61 2E 75 74 69 6C 2E 45  Bxr..java.util.E
+0100: 76 65 6E 74 4F 62 6A 65   63 74 4C 8D 09 4E 18 6D  ventObjectL..N.m
+0110: 7D A8 02 00 00 78 70 00   00 00 00 01 70 00 00 00  .....xp.....p...
+0120: 00 00 00 00 00 00 00 00   00 74 00 06 48 65 6C 6C  .........t..Hell
+0130: 6F 31 30 45 04 0B 6F 62   6A 65 63 74 43 6C 61 73  o10E..objectClas
+0140: 73 31 36 04 03 74 6F 70   04 0D 6A 61 76 61 43 6F  s16..top..javaCo
+0150: 6E 74 61 69 6E 65 72 04   0A 6A 61 76 61 4F 62 6A  ntainer..javaObj
+0160: 65 63 74 04 14 6A 61 76   61 53 65 72 69 61 6C 69  ect..javaSeriali
+0170: 7A 65 64 4F 62 6A 65 63   74 30 81 80 04 0E 6A 61  zedObject0....ja
+0180: 76 61 43 6C 61 73 73 4E   61 6D 65 73 31 6E 04 1A  vaClassNames1n..
+0190: 6A 61 76 61 2E 61 77 74   2E 65 76 65 6E 74 2E 41  java.awt.event.A
+01A0: 63 74 69 6F 6E 45 76 65   6E 74 04 11 6A 61 76 61  ctionEvent..java
+01B0: 2E 61 77 74 2E 41 57 54   45 76 65 6E 74 04 15 6A  .awt.AWTEvent..j
+01C0: 61 76 61 2E 75 74 69 6C   2E 45 76 65 6E 74 4F 62  ava.util.EventOb
+01D0: 6A 65 63 74 04 10 6A 61   76 61 2E 6C 61 6E 67 2E  ject..java.lang.
+01E0: 4F 62 6A 65 63 74 04 14   6A 61 76 61 2E 69 6F 2E  Object..java.io.
+01F0: 53 65 72 69 61 6C 69 7A   61 62 6C 65 30 2D 04 0D  Serializable0-..
+0200: 6A 61 76 61 43 6C 61 73   73 4E 61 6D 65 31 1C 04  javaClassName1..
+0210: 1A 6A 61 76 61 2E 61 77   74 2E 65 76 65 6E 74 2E  .java.awt.event.
+0220: 41 63 74 69 6F 6E 45 76   65 6E 74 30 0F 04 02 63  ActionEvent0...c
+0230: 6E 31 09 04 07 6D 79 65   76 65 6E 74 A0 1B 30 19  n1...myevent..0.
+0240: 04 17 32 2E 31 36 2E 38   34 30 2E 31 2E 31 31 33  ..2.16.840.1.113
+0250: 37 33 30 2E 33 2E 34 2E   32                       730.3.4.2
+
+# LDAP AddResponse:
+#
+#   0  12: SEQUENCE {
+#   2   1:   INTEGER 2
+#   5   7:   [APPLICATION 9] {
+#   7   1:     ENUMERATED 0
+#  10   0:     OCTET STRING
+#  12   0:     OCTET STRING
+#        :     }
+#        :   }
+#
+0000: 30 0C 02 01 02 69 07 0A   01 00 04 00 04 00        0....i........
+
+# LDAP AddRequest:
+#
+#   0 599: SEQUENCE {
+#   4   1:   INTEGER 3
+#   7 563:   [APPLICATION 8] {
+#  11  34:     OCTET STRING 'cn=myevent2,dc=ie,dc=oracle,dc=com'
+#  47 523:     SEQUENCE {
+#  51 253:       SEQUENCE {
+#  54  18:         OCTET STRING 'javaSerializedData'
+#  74 230:         SET {
+#  77 227:           OCTET STRING
+#        :             AC ED 00 05 73 72 00 1A 6A 61 76 61 2E 61 77 74
+#        :             2E 65 76 65 6E 74 2E 41 63 74 69 6F 6E 45 76 65
+#        :             6E 74 95 8A DA 7A 58 11 2F 2B 02 00 03 49 00 09
+#        :             6D 6F 64 69 66 69 65 72 73 4A 00 04 77 68 65 6E
+#        :             4C 00 0D 61 63 74 69 6F 6E 43 6F 6D 6D 61 6E 64
+#        :             74 00 12 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74
+#        :             72 69 6E 67 3B 78 72 00 11 6A 61 76 61 2E 61 77
+#        :             74 2E 41 57 54 45 76 65 6E 74 E6 AB 2D E1 18 DF
+#        :             8A C3 02 00 03 5A 20 08 63 6F 6E 73 75 6D 65 64
+#        :             49 00 02 69 64 5B 00 05 62 64 61 74 61 74 00 02
+#        :             5B 42 78 72 00 15 6A 61 76 61 2E 75 74 69 6C 2E
+#        :             45 76 65 6E 74 4F 62 6A 65 63 74 4C 8D 09 4E 18
+#        :             6D 7D A8 02 00 00 78 70 00 00 00 00 02 70 00 00
+#        :             00 00 00 00 00 00 00 00 00 00 74 00 06 48 65 6C
+#        :             6C 6F 32
+#        :           }
+#        :         }
+# 307  69:       SEQUENCE {
+# 309  11:         OCTET STRING 'objectClass'
+# 322  54:         SET {
+# 324   3:           OCTET STRING 'top'
+# 325  13:           OCTET STRING 'javaContainer'
+# 344  10:           OCTET STRING 'javaObject'
+# 356  20:           OCTET STRING 'javaSerializedObject'
+#        :           }
+#        :         }
+# 378 128:       SEQUENCE {
+# 381  14:         OCTET STRING 'javaClassNames'
+# 397 110:         SET {
+# 399  26:           OCTET STRING 'java.awt.event.ActionEvent'
+# 427  17:           OCTET STRING 'java.awt.AWTEvent'
+# 446  21:           OCTET STRING 'java.util.EventObject'
+# 469  16:           OCTET STRING 'java.lang.Object'
+# 487  20:           OCTET STRING 'java.io.Serializable'
+#        :           }
+#        :         }
+# 509  45:       SEQUENCE {
+# 511  13:         OCTET STRING 'javaClassName'
+# 526  28:         SET {
+# 528  26:           OCTET STRING 'java.awt.event.ActionEvent'
+#        :           }
+#        :         }
+# 556  15:       SEQUENCE {
+# 558   2:         OCTET STRING 'cn'
+# 562  10:         SET {
+# 564   8:           OCTET STRING 'myevent2'
+#        :           }
+#        :         }
+#        :       }
+#        :     }
+# 574  27:   [0] {
+# 576  25:     SEQUENCE {
+# 578  23:       OCTET STRING '2.16.840.1.113730.3.4.2'
+#        :       }
+#        :     }
+#        :   }
+#
+0000: 30 82 02 57 02 01 03 68   82 02 33 04 22 63 6E 3D  0..W...h..3."cn=
+0010: 6D 79 65 76 65 6E 74 32   2C 64 63 3D 69 65 2C 64  myevent2,dc=ie,d
+0020: 63 3D 6F 72 61 63 6C 65   2C 64 63 3D 63 6F 6D 30  c=oracle,dc=com0
+0030: 82 02 0B 30 81 FD 04 12   6A 61 76 61 53 65 72 69  ...0....javaSeri
+0040: 61 6C 69 7A 65 64 44 61   74 61 31 81 E6 04 81 E3  alizedData1.....
+0050: AC ED 00 05 73 72 00 1A   6A 61 76 61 2E 61 77 74  ....sr..java.awt
+0060: 2E 65 76 65 6E 74 2E 41   63 74 69 6F 6E 45 76 65  .event.ActionEve
+0070: 6E 74 95 8A DA 7A 58 11   2F 2B 02 00 03 49 00 09  nt...zX./+...I..
+0080: 6D 6F 64 69 66 69 65 72   73 4A 00 04 77 68 65 6E  modifiersJ..when
+0090: 4C 00 0D 61 63 74 69 6F   6E 43 6F 6D 6D 61 6E 64  L..actionCommand
+00A0: 74 00 12 4C 6A 61 76 61   2F 6C 61 6E 67 2F 53 74  t..Ljava/lang/St
+00B0: 72 69 6E 67 3B 78 72 00   11 6A 61 76 61 2E 61 77  ring;xr..java.aw
+00C0: 74 2E 41 57 54 45 76 65   6E 74 E6 AB 2D E1 18 DF  t.AWTEvent..-...
+00D0: 8A C3 02 00 03 5A 00 08   63 6F 6E 73 75 6D 65 64  .....Z..consumed
+00E0: 49 00 02 69 64 5B 00 05   62 64 61 74 61 74 00 02  I..id[..bdatat..
+00F0: 5B 42 78 72 00 15 6A 61   76 61 2E 75 74 69 6C 2E  [Bxr..java.util.
+0100: 45 76 65 6E 74 4F 62 6A   65 63 74 4C 8D 09 4E 18  EventObjectL..N.
+0110: 6D 7D A8 02 00 00 78 70   00 00 00 00 02 70 00 00  m.....xp.....p..
+0120: 00 00 00 00 00 00 00 00   00 00 74 00 06 48 65 6C  ..........t..Hel
+0130: 6C 6F 32 30 45 04 0B 6F   62 6A 65 63 74 43 6C 61  lo20E..objectCla
+0140: 73 73 31 36 04 03 74 6F   70 04 0D 6A 61 76 61 43  ss16..top..javaC
+0150: 6F 6E 74 61 69 6E 65 72   04 0A 6A 61 76 61 4F 62  ontainer..javaOb
+0160: 6A 65 63 74 04 14 6A 61   76 61 53 65 72 69 61 6C  ject..javaSerial
+0170: 69 7A 65 64 4F 62 6A 65   63 74 30 81 80 04 0E 6A  izedObject0....j
+0180: 61 76 61 43 6C 61 73 73   4E 61 6D 65 73 31 6E 04  avaClassNames1n.
+0190: 1A 6A 61 76 61 2E 61 77   74 2E 65 76 65 6E 74 2E  .java.awt.event.
+01A0: 41 63 74 69 6F 6E 45 76   65 6E 74 04 11 6A 61 76  ActionEvent..jav
+01B0: 61 2E 61 77 74 2E 41 57   54 45 76 65 6E 74 04 15  a.awt.AWTEvent..
+01C0: 6A 61 76 61 2E 75 74 69   6C 2E 45 76 65 6E 74 4F  java.util.EventO
+01D0: 62 6A 65 63 74 04 10 6A   61 76 61 2E 6C 61 6E 67  bject..java.lang
+01E0: 2E 4F 62 6A 65 63 74 04   14 6A 61 76 61 2E 69 6F  .Object..java.io
+01F0: 2E 53 65 72 69 61 6C 69   7A 61 62 6C 65 30 2D 04  .Serializable0-.
+0200: 0D 6A 61 76 61 43 6C 61   73 73 4E 61 6D 65 31 1C  .javaClassName1.
+0210: 04 1A 6A 61 76 61 2E 61   77 74 2E 65 76 65 6E 74  ..java.awt.event
+0220: 2E 41 63 74 69 6F 6E 45   76 65 6E 74 30 10 04 02  .ActionEvent0...
+0230: 63 6E 31 0A 04 08 6D 79   65 76 65 6E 74 32 A0 1B  cn1...myevent2..
+0240: 30 19 04 17 32 2E 31 36   2E 38 34 30 2E 31 2E 31  0...2.16.840.1.1
+0250: 31 33 37 33 30 2E 33 2E   34 2E 32                 13730.3.4.2
+
+# LDAP AddResponse:
+#
+#   0  12: SEQUENCE {
+#   2   1:   INTEGER 3
+#   5   7:   [APPLICATION 9] {
+#   7   1:     ENUMERATED 0
+#  10   0:     OCTET STRING
+#  12   0:     OCTET STRING
+#        :     }
+#        :   }
+#
+0000: 30 0C 02 01 03 69 07 0A   01 00 04 00 04 00        0....i........
+
+# LDAP SearchRequest:
+#
+#   0  99: SEQUENCE {
+#   2   1:   INTEGER 4
+#   5  65:   [APPLICATION 3] {
+#   7  33:     OCTET STRING 'cn=myevent,dc=ie,dc=oracle,dc=com'
+#  42   1:     ENUMERATED 0
+#  45   1:     ENUMERATED 0
+#  48   1:     INTEGER 0
+#  51   1:     INTEGER 0
+#  54   1:     BOOLEAN FALSE
+#  57  11:     [7] 'objectClass'
+#  70   0:     SEQUENCE {}
+#        :     }
+#  72  27:   [0] {
+#  74  25:     SEQUENCE {
+#  76  23:       OCTET STRING '2.16.840.1.113730.3.4.2'
+#        :       }
+#        :     }
+#        :   }
+#
+0000: 30 63 02 01 04 63 41 04   21 63 6E 3D 6D 79 65 76  0c...cA.!cn=myev
+0010: 65 6E 74 2C 64 63 3D 69   65 2C 64 63 3D 6F 72 61  ent,dc=ie,dc=ora
+0020: 63 6C 65 2C 64 63 3D 63   6F 6D 0A 01 00 0A 01 03  cle,dc=com......
+0030: 02 01 00 02 01 00 01 01   00 87 0B 6F 62 6A 65 63  ...........objec
+0040: 74 43 6C 61 73 73 30 00   A0 1B 30 19 04 17 32 2E  tClass0...0...2.
+0050: 31 36 2E 38 34 30 2E 31   2E 31 31 33 37 33 30 2E  16.840.1.113730.
+0060: 33 2E 34 2E 32                                     3.4.2
+
+# LDAP SearchResultEntry:
+#
+#   0 568: SEQUENCE {
+#   4   1:   INTEGER 4
+#   7 561:   [APPLICATION 4] {
+#  11  33:     OCTET STRING 'cn=myevent,dc=ie,dc=oracle,dc=com'
+#  46 522:     SEQUENCE {
+#  50  15:       SEQUENCE {
+#  52   2:         OCTET STRING 'cn'
+#  56   9:         SET {
+#  58   7:           OCTET STRING 'myevent'
+#        :           }
+#        :         }
+#  67 128:       SEQUENCE {
+#  70  14:         OCTET STRING 'javaClassNames'
+#  86 110:         SET {
+#  88  26:           OCTET STRING 'java.awt.event.ActionEvent'
+# 116  17:           OCTET STRING 'java.awt.AWTEvent'
+# 135  21:           OCTET STRING 'java.util.EventObject'
+# 158  16:           OCTET STRING 'java.lang.Object'
+# 176  20:           OCTET STRING 'java.io.Serializable'
+#        :           }
+#        :         }
+# 198  45:       SEQUENCE {
+# 200  13:         OCTET STRING 'javaClassName'
+# 215  28:         SET {
+# 217  26:           OCTET STRING 'java.awt.event.ActionEvent'
+#        :           }
+#        :         }
+# 245  69:       SEQUENCE {
+# 247  11:         OCTET STRING 'objectClass'
+# 260  54:         SET {
+# 262  10:           OCTET STRING 'javaObject'
+# 274   3:           OCTET STRING 'top'
+# 279  20:           OCTET STRING 'javaSerializedObject'
+# 301  13:           OCTET STRING 'javaContainer'
+#        :           }
+#        :         }
+# 316 253:       SEQUENCE {
+# 319  18:         OCTET STRING 'javaSerializedData'
+# 339 230:         SET {
+# 342 227:           OCTET STRING
+#        :             AC ED 00 05 73 72 00 1A 6A 61 76 61 2E 61 77 74
+#        :             2E 65 76 65 6E 74 2E 41 63 74 69 6F 6E 45 76 65
+#        :             6E 74 95 8A DA 7A 58 11 2F 2B 02 00 03 49 00 09
+#        :             6D 6F 64 69 66 69 65 72 73 4A 00 04 77 68 65 6E
+#        :             4C 00 0D 61 63 74 69 6F 6E 43 6F 6D 6D 61 6E 64
+#        :             74 00 12 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74
+#        :             72 69 6E 67 3B 78 72 00 11 6A 61 76 61 2E 61 77
+#        :             74 2E 41 57 54 45 76 65 6E 74 E6 AB 2D E1 18 DF
+#        :             8A C3 02 00 03 5A 20 08 63 6F 6E 73 75 6D 65 64
+#        :             49 00 02 69 64 5B 00 05 62 64 61 74 61 74 00 02
+#        :             5B 42 78 72 00 15 6A 61 76 61 2E 75 74 69 6C 2E
+#        :             45 76 65 6E 74 4F 62 6A 65 63 74 4C 8D 09 4E 18
+#        :             6D 7D A8 02 00 00 78 70 00 00 00 00 01 70 00 00
+#        :             00 00 00 00 00 00 00 00 00 00 74 00 06 48 65 6C
+#        :             6C 6F 31
+#        :           }
+#        :         }
+#        :       }
+#        :     }
+#        :   }
+#
+0000: 30 82 02 38 02 01 04 64   82 02 31 04 21 63 6E 3D  0..8...d..1.!cn=
+0010: 6D 79 65 76 65 6E 74 2C   64 63 3D 69 65 2C 64 63  myevent,dc=ie,dc
+0020: 3D 6F 72 61 63 6C 65 2C   64 63 3D 63 6F 6D 30 82  =oracle,dc=com0.
+0030: 02 0A 30 0F 04 02 63 6E   31 09 04 07 6D 79 65 76  ..0...cn1...myev
+0040: 65 6E 74 30 81 80 04 0E   6A 61 76 61 43 6C 61 73  ent0....javaClas
+0050: 73 4E 61 6D 65 73 31 6E   04 1A 6A 61 76 61 2E 61  sNames1n..java.a
+0060: 77 74 2E 65 76 65 6E 74   2E 41 63 74 69 6F 6E 45  wt.event.ActionE
+0070: 76 65 6E 74 04 11 6A 61   76 61 2E 61 77 74 2E 41  vent..java.awt.A
+0080: 57 54 45 76 65 6E 74 04   15 6A 61 76 61 2E 75 74  WTEvent..java.ut
+0090: 69 6C 2E 45 76 65 6E 74   4F 62 6A 65 63 74 04 10  il.EventObject..
+00A0: 6A 61 76 61 2E 6C 61 6E   67 2E 4F 62 6A 65 63 74  java.lang.Object
+00B0: 04 14 6A 61 76 61 2E 69   6F 2E 53 65 72 69 61 6C  ..java.io.Serial
+00C0: 69 7A 61 62 6C 65 30 2D   04 0D 6A 61 76 61 43 6C  izable0-..javaCl
+00D0: 61 73 73 4E 61 6D 65 31   1C 04 1A 6A 61 76 61 2E  assName1...java.
+00E0: 61 77 74 2E 65 76 65 6E   74 2E 41 63 74 69 6F 6E  awt.event.Action
+00F0: 45 76 65 6E 74 30 45 04   0B 6F 62 6A 65 63 74 43  Event0E..objectC
+0100: 6C 61 73 73 31 36 04 0A   6A 61 76 61 4F 62 6A 65  lass16..javaObje
+0110: 63 74 04 03 74 6F 70 04   14 6A 61 76 61 53 65 72  ct..top..javaSer
+0120: 69 61 6C 69 7A 65 64 4F   62 6A 65 63 74 04 0D 6A  ializedObject..j
+0130: 61 76 61 43 6F 6E 74 61   69 6E 65 72 30 81 FD 04  avaContainer0...
+0140: 12 6A 61 76 61 53 65 72   69 61 6C 69 7A 65 64 44  .javaSerializedD
+0150: 61 74 61 31 81 E6 04 81   E3 AC ED 00 05 73 72 00  ata1.........sr.
+0160: 1A 6A 61 76 61 2E 61 77   74 2E 65 76 65 6E 74 2E  .java.awt.event.
+0170: 41 63 74 69 6F 6E 45 76   65 6E 74 95 8A DA 7A 58  ActionEvent...zX
+0180: 11 2F 2B 02 00 03 49 00   09 6D 6F 64 69 66 69 65  ./+...I..modifie
+0190: 72 73 4A 00 04 77 68 65   6E 4C 00 0D 61 63 74 69  rsJ..whenL..acti
+01A0: 6F 6E 43 6F 6D 6D 61 6E   64 74 00 12 4C 6A 61 76  onCommandt..Ljav
+01B0: 61 2F 6C 61 6E 67 2F 53   74 72 69 6E 67 3B 78 72  a/lang/String;xr
+01C0: 00 11 6A 61 76 61 2E 61   77 74 2E 41 57 54 45 76  ..java.awt.AWTEv
+01D0: 65 6E 74 E6 AB 2D E1 18   DF 8A C3 02 00 03 5A 00  ent..-........Z.
+01E0: 08 63 6F 6E 73 75 6D 65   64 49 00 02 69 64 5B 00  .consumedI..id[.
+01F0: 05 62 64 61 74 61 74 00   02 5B 42 78 72 00 15 6A  .bdatat..[Bxr..j
+0200: 61 76 61 2E 75 74 69 6C   2E 45 76 65 6E 74 4F 62  ava.util.EventOb
+0210: 6A 65 63 74 4C 8D 09 4E   18 6D 7D A8 02 00 00 78  jectL..N.m.....x
+0220: 70 00 00 00 00 01 70 00   00 00 00 00 00 00 00 00  p.....p.........
+0230: 00 00 00 74 00 06 48 65   6C 6C 6F 31              ...t..Hello1
+
+# LDAP SearchResultDone:
+#
+#   0  12: SEQUENCE {
+#   2   1:   INTEGER 4
+#   5   7:   [APPLICATION 5] {
+#   7   1:     ENUMERATED 0
+#  10   0:     OCTET STRING
+#  12   0:     OCTET STRING
+#        :     }
+#        :   }
+#
+0000: 30 0C 02 01 04 65 07 0A   01 00 04 00 04 00        0....e........
+
+# LDAP SearchRequest:
+#
+#   0 100: SEQUENCE {
+#   2   1:   INTEGER 5
+#   5  66:   [APPLICATION 3] {
+#   7  34:     OCTET STRING 'cn=myevent2,dc=ie,dc=oracle,dc=com'
+#  43   1:     ENUMERATED 0
+#  46   1:     ENUMERATED 0
+#  49   1:     INTEGER 0
+#  52   1:     INTEGER 0
+#  55   1:     BOOLEAN FALSE
+#  58  11:     [7] 'objectClass'
+#  71   0:     SEQUENCE {}
+#        :     }
+#  73  27:   [0] {
+#  75  25:     SEQUENCE {
+#  77  23:       OCTET STRING '2.16.840.1.113730.3.4.2'
+#        :       }
+#        :     }
+#        :   }
+#
+0000: 30 64 02 01 05 63 42 04   22 63 6E 3D 6D 79 65 76  0d...cB."cn=myev
+0010: 65 6E 74 32 2C 64 63 3D   69 65 2C 64 63 3D 6F 72  ent2,dc=ie,dc=or
+0020: 61 63 6C 65 2C 64 63 3D   63 6F 6D 0A 01 00 0A 01  acle,dc=com.....
+0030: 03 02 01 00 02 01 00 01   01 00 87 0B 6F 62 6A 65  ............obje
+0040: 63 74 43 6C 61 73 73 30   00 A0 1B 30 19 04 17 32  ctClass0...0...2
+0050: 2E 31 36 2E 38 34 30 2E   31 2E 31 31 33 37 33 30  .16.840.1.113730
+0060: 2E 33 2E 34 2E 32                                  .3.4.2
+
+# LDAP SearchResultEntry:
+#
+#   0 570: SEQUENCE {
+#   4   1:   INTEGER 5
+#   7 563:   [APPLICATION 4] {
+#  11  34:     OCTET STRING 'cn=myevent2,dc=ie,dc=oracle,dc=com'
+#  47 523:     SEQUENCE {
+#  51  16:       SEQUENCE {
+#  53   2:         OCTET STRING 'cn'
+#  57  10:         SET {
+#  59   8:           OCTET STRING 'myevent2'
+#        :           }
+#        :         }
+#  69 128:       SEQUENCE {
+#  72  14:         OCTET STRING 'javaClassNames'
+#  88 110:         SET {
+#  90  26:           OCTET STRING 'java.awt.event.ActionEvent'
+# 118  17:           OCTET STRING 'java.awt.AWTEvent'
+# 137  21:           OCTET STRING 'java.util.EventObject'
+# 160  16:           OCTET STRING 'java.lang.Object'
+# 178  20:           OCTET STRING 'java.io.Serializable'
+#        :           }
+#        :         }
+# 200  45:       SEQUENCE {
+# 202  13:         OCTET STRING 'javaClassName'
+# 217  28:         SET {
+# 219  26:           OCTET STRING 'java.awt.event.ActionEvent'
+#        :           }
+#        :         }
+# 247  69:       SEQUENCE {
+# 249  11:         OCTET STRING 'objectClass'
+# 262  54:         SET {
+# 264  10:           OCTET STRING 'javaObject'
+# 276   3:           OCTET STRING 'top'
+# 281  20:           OCTET STRING 'javaSerializedObject'
+# 303  13:           OCTET STRING 'javaContainer'
+#        :           }
+#        :         }
+# 318 253:       SEQUENCE {
+# 321  18:         OCTET STRING 'javaSerializedData'
+# 341 230:         SET {
+# 344 227:           OCTET STRING
+#        :             AC ED 00 05 73 72 00 1A 6A 61 76 61 2E 61 77 74
+#        :             2E 65 76 65 6E 74 2E 41 63 74 69 6F 6E 45 76 65
+#        :             6E 74 95 8A DA 7A 58 11 2F 2B 02 00 03 49 00 09
+#        :             6D 6F 64 69 66 69 65 72 73 4A 00 04 77 68 65 6E
+#        :             4C 00 0D 61 63 74 69 6F 6E 43 6F 6D 6D 61 6E 64
+#        :             74 00 12 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74
+#        :             72 69 6E 67 3B 78 72 00 11 6A 61 76 61 2E 61 77
+#        :             74 2E 41 57 54 45 76 65 6E 74 E6 AB 2D E1 18 DF
+#        :             8A C3 02 00 03 5A 20 08 63 6F 6E 73 75 6D 65 64
+#        :             49 00 02 69 64 5B 00 05 62 64 61 74 61 74 00 02
+#        :             5B 42 78 72 00 15 6A 61 76 61 2E 75 74 69 6C 2E
+#        :             45 76 65 6E 74 4F 62 6A 65 63 74 4C 8D 09 4E 18
+#        :             6D 7D A8 02 00 00 78 70 00 00 00 00 02 70 00 00
+#        :             00 00 00 00 00 00 00 00 00 00 74 00 06 48 65 6C
+#        :             6C 6F 32
+#        :           }
+#        :         }
+#        :       }
+#        :     }
+#        :   }
+#
+0000: 30 82 02 3A 02 01 05 64   82 02 33 04 22 63 6E 3D  0..:...d..3."cn=
+0010: 6D 79 65 76 65 6E 74 32   2C 64 63 3D 69 65 2C 64  myevent2,dc=ie,d
+0020: 63 3D 6F 72 61 63 6C 65   2C 64 63 3D 63 6F 6D 30  c=oracle,dc=com0
+0030: 82 02 0B 30 10 04 02 63   6E 31 0A 04 08 6D 79 65  ...0...cn1...mye
+0040: 76 65 6E 74 32 30 81 80   04 0E 6A 61 76 61 43 6C  vent20....javaCl
+0050: 61 73 73 4E 61 6D 65 73   31 6E 04 1A 6A 61 76 61  assNames1n..java
+0060: 2E 61 77 74 2E 65 76 65   6E 74 2E 41 63 74 69 6F  .awt.event.Actio
+0070: 6E 45 76 65 6E 74 04 11   6A 61 76 61 2E 61 77 74  nEvent..java.awt
+0080: 2E 41 57 54 45 76 65 6E   74 04 15 6A 61 76 61 2E  .AWTEvent..java.
+0090: 75 74 69 6C 2E 45 76 65   6E 74 4F 62 6A 65 63 74  util.EventObject
+00A0: 04 10 6A 61 76 61 2E 6C   61 6E 67 2E 4F 62 6A 65  ..java.lang.Obje
+00B0: 63 74 04 14 6A 61 76 61   2E 69 6F 2E 53 65 72 69  ct..java.io.Seri
+00C0: 61 6C 69 7A 61 62 6C 65   30 2D 04 0D 6A 61 76 61  alizable0-..java
+00D0: 43 6C 61 73 73 4E 61 6D   65 31 1C 04 1A 6A 61 76  ClassName1...jav
+00E0: 61 2E 61 77 74 2E 65 76   65 6E 74 2E 41 63 74 69  a.awt.event.Acti
+00F0: 6F 6E 45 76 65 6E 74 30   45 04 0B 6F 62 6A 65 63  onEvent0E..objec
+0100: 74 43 6C 61 73 73 31 36   04 0A 6A 61 76 61 4F 62  tClass16..javaOb
+0110: 6A 65 63 74 04 03 74 6F   70 04 14 6A 61 76 61 53  ject..top..javaS
+0120: 65 72 69 61 6C 69 7A 65   64 4F 62 6A 65 63 74 04  erializedObject.
+0130: 0D 6A 61 76 61 43 6F 6E   74 61 69 6E 65 72 30 81  .javaContainer0.
+0140: FD 04 12 6A 61 76 61 53   65 72 69 61 6C 69 7A 65  ...javaSerialize
+0150: 64 44 61 74 61 31 81 E6   04 81 E3 AC ED 00 05 73  dData1.........s
+0160: 72 00 1A 6A 61 76 61 2E   61 77 74 2E 65 76 65 6E  r..java.awt.even
+0170: 74 2E 41 63 74 69 6F 6E   45 76 65 6E 74 95 8A DA  t.ActionEvent...
+0180: 7A 58 11 2F 2B 02 00 03   49 00 09 6D 6F 64 69 66  zX./+...I..modif
+0190: 69 65 72 73 4A 00 04 77   68 65 6E 4C 00 0D 61 63  iersJ..whenL..ac
+01A0: 74 69 6F 6E 43 6F 6D 6D   61 6E 64 74 00 12 4C 6A  tionCommandt..Lj
+01B0: 61 76 61 2F 6C 61 6E 67   2F 53 74 72 69 6E 67 3B  ava/lang/String;
+01C0: 78 72 00 11 6A 61 76 61   2E 61 77 74 2E 41 57 54  xr..java.awt.AWT
+01D0: 45 76 65 6E 74 E6 AB 2D   E1 18 DF 8A C3 02 00 03  Event..-........
+01E0: 5A 00 08 63 6F 6E 73 75   6D 65 64 49 00 02 69 64  Z..consumedI..id
+01F0: 5B 00 05 62 64 61 74 61   74 00 02 5B 42 78 72 00  [..bdatat..[Bxr.
+0200: 15 6A 61 76 61 2E 75 74   69 6C 2E 45 76 65 6E 74  .java.util.Event
+0210: 4F 62 6A 65 63 74 4C 8D   09 4E 18 6D 7D A8 02 00  ObjectL..N.m....
+0220: 00 78 70 00 00 00 00 02   70 00 00 00 00 00 00 00  .xp.....p.......
+0230: 00 00 00 00 00 74 00 06   48 65 6C 6C 6F 32        .....t..Hello2
+
+# LDAP SearchResultDone:
+#
+#   0  12: SEQUENCE {
+#   2   1:   INTEGER 5
+#   5   7:   [APPLICATION 5] {
+#   7   1:     ENUMERATED 0
+#  10   0:     OCTET STRING
+#  12   0:     OCTET STRING
+#        :     }
+#        :   }
+#
+0000: 30 0C 02 01 05 65 07 0A   01 00 04 00 04 00        0....e........
+
+# LDAP DeleteRequest:
+#
+#   0  67: SEQUENCE {
+#   2   1:   INTEGER 6
+#   5  33:   [APPLICATION 10] 'cn=myevent,dc=ie,dc=oracle,dc=com'
+#  40  27:   [0] {
+#  42  25:     SEQUENCE {
+#  44  23:       OCTET STRING '2.16.840.1.113730.3.4.2'
+#        :       }
+#        :     }
+#        :   }
+#
+0000: 30 43 02 01 06 4A 21 63   6E 3D 6D 79 65 76 65 6E  0C...J!cn=myeven
+0010: 74 2C 64 63 3D 69 65 2C   64 63 3D 6F 72 61 63 6C  t,dc=ie,dc=oracl
+0020: 65 2C 64 63 3D 63 6F 6D   A0 1B 30 19 04 17 32 2E  e,dc=com..0...2.
+0030: 31 36 2E 38 34 30 2E 31   2E 31 31 33 37 33 30 2E  16.840.1.113730.
+0040: 33 2E 34 2E 32                                     3.4.2
+
+# LDAP DeleteResponse:
+#
+#   0  12: SEQUENCE {
+#   2   1:   INTEGER 6
+#   5   7:   [APPLICATION 11] {
+#   7   1:     ENUMERATED 0
+#  10   0:     OCTET STRING
+#  12   0:     OCTET STRING
+#        :     }
+#        :   }
+#
+0000: 30 0C 02 01 06 6B 07 0A   01 00 04 00 04 00        0....k........
+
+# LDAP DeleteRequest:
+#
+#   0  68: SEQUENCE {
+#   2   1:   INTEGER 7
+#   5  34:   [APPLICATION 10] 'cn=myevent2,dc=ie,dc=oracle,dc=com'
+#  41  27:   [0] {
+#  43  25:     SEQUENCE {
+#  45  23:       OCTET STRING '2.16.840.1.113730.3.4.2'
+#        :       }
+#        :     }
+#        :   }
+#
+0000: 30 44 02 01 07 4A 22 63   6E 3D 6D 79 65 76 65 6E  0D...J"cn=myeven
+0010: 74 32 2C 64 63 3D 69 65   2C 64 63 3D 6F 72 61 63  t2,dc=ie,dc=orac
+0020: 6C 65 2C 64 63 3D 63 6F   6D A0 1B 30 19 04 17 32  le,dc=com..0...2
+0030: 2E 31 36 2E 38 34 30 2E   31 2E 31 31 33 37 33 30  .16.840.1.113730
+0040: 2E 33 2E 34 2E 32                                  .3.4.2
+
+# LDAP DeleteResponse:
+#
+#   0  12: SEQUENCE {
+#   2   1:   INTEGER 7
+#   5   7:   [APPLICATION 11] {
+#   7   1:     ENUMERATED 0
+#  10   0:     OCTET STRING
+#  12   0:     OCTET STRING
+#        :     }
+#        :   }
+#
+0000: 30 0C 02 01 07 6B 07 0A   01 00 04 00 04 00        0....k........
+
+# LDAP UnbindRequest:
+#
+#   0  34: SEQUENCE {
+#   2   1:   INTEGER 8
+#   5   0:   [APPLICATION 2]
+#   7  27:   [0] {
+#   9  25:     SEQUENCE {
+#  11  23:       OCTET STRING '2.16.840.1.113730.3.4.2'
+#        :       }
+#        :     }
+#        :   }
+#
+0000: 30 22 02 01 08 42 00 A0   1B 30 19 04 17 32 2E 31  0"...B...0...2.1
+0010: 36 2E 38 34 30 2E 31 2E   31 31 33 37 33 30 2E 33  6.840.1.113730.3
+0020: 2E 34 2E 32                                        .4.2
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/naming/module/src/test/test/StorePerson.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Demonstrate Java object storage and retrieval using an LDAP directory.
+ * The Person object and its associated object and state factory is supplied by
+ * a third-party module. As the Person object does not implement
+ * javax.naming.Referenceable, the classname of its state and object factory
+ * must be specified to the JNDI initial context.
+ */
+
+package test;
+
+import java.net.*;
+import java.util.*;
+import javax.naming.*;
+import javax.naming.directory.*;
+
+import org.example.person.Person;
+
+public class StorePerson {
+
+    // LDAP capture file
+    private static final String LDAP_CAPTURE_FILE =
+        System.getProperty("test.src") + "/src/test/test/StorePerson.ldap";
+    // LDAPServer socket
+    private static ServerSocket serverSocket;
+
+    public static void main(String[] args) throws Exception {
+
+        /*
+         * Process arguments
+         */
+
+        int argc = args.length;
+        if ((argc < 1) ||
+            ((argc == 1) && (args[0].equalsIgnoreCase("-help")))) {
+
+            System.err.println("\nUsage:   StorePerson <ldapurl>\n");
+            System.err.println("        <ldapurl> is the LDAP URL of the parent entry\n");
+            System.err.println("example:");
+            System.err.println("        java StorePerson ldap://oasis/o=airius.com");
+            return;
+        }
+
+        /*
+         * Launch the LDAP server with the StorePerson.ldap capture file
+         */
+
+        serverSocket = new ServerSocket(0);
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    new LDAPServer(serverSocket, LDAP_CAPTURE_FILE);
+               } catch (Exception e) {
+                   System.out.println("ERROR: unable to launch LDAP server");
+                   e.printStackTrace();
+               }
+            }
+        }).start();
+
+        /*
+         * Store Person objects in the LDAP directory
+         */
+
+        Hashtable<String,Object> env = new Hashtable<>();
+        env.put(Context.INITIAL_CONTEXT_FACTORY,
+    "com.sun.jndi.ldap.LdapCtxFactory");
+        URI ldapUri = new URI(args[0]);
+        if (ldapUri.getPort() == -1) {
+            ldapUri = new URI(ldapUri.getScheme(), null, ldapUri.getHost(),
+                serverSocket.getLocalPort(), ldapUri.getPath(), null, null);
+        }
+        env.put(Context.PROVIDER_URL, ldapUri.toString());
+        if (args[args.length - 1].equalsIgnoreCase("-trace")) {
+            env.put("com.sun.jndi.ldap.trace.ber", System.out);
+        }
+
+        // Specify the factory classname explicitly
+        env.put(Context.STATE_FACTORIES, "org.example.person.PersonFactory");
+        env.put(Context.OBJECT_FACTORIES, "org.example.person.PersonFactory");
+
+        System.out.println("StorePerson: connecting to " + ldapUri);
+        DirContext ctx = new InitialDirContext(env);
+        Person person = null;
+        String name = "John Smith";
+        String dn = "cn=" + name;
+
+        try {
+            person = new Person(name, "Smith");
+            person.setMailAddress("jsmith@smith.com");
+            ctx.bind(dn, person);
+            System.out.println("StorePerson: created entry '" + dn + "'");
+        } catch (NameAlreadyBoundException e) {
+            System.err.println("StorePerson: entry '" + dn +
+                "' already exists");
+            cleanup(ctx, (String)null);
+            return;
+        }
+
+        name = "Jill Smyth";
+        String dn2 = "cn=" + name;
+        Person person2 = new Person(name, "Smyth");
+        person2.setMailAddress("jsmyth@smith.com");
+
+        try {
+            ctx.bind(dn2, person2);
+            System.out.println("StorePerson: created entry '" + dn2 + "'");
+        } catch (NameAlreadyBoundException e) {
+            System.err.println("StorePerson: entry '" + dn2 +
+                "' already exists");
+            cleanup(ctx, dn);
+            return;
+        }
+
+        /*
+         * Retrieve Person objects from the LDAP directory
+         */
+
+        try {
+            Person person3 = (Person) ctx.lookup(dn);
+            System.out.println("StorePerson: retrieved object: " + person3);
+            if (person.getAttributes().equals(person3.getAttributes())) {
+                System.out.println(
+                    "StorePerson: retrieved person matches original");
+            } else {
+                System.out.println(
+                    "StorePerson: retrieved person does NOT match original");
+            }
+        } catch (NamingException e) {
+            System.err.println("StorePerson: error retrieving entry '" +
+                dn + "' " + e);
+            e.printStackTrace();
+            cleanup(ctx, dn, dn2);
+            return;
+        }
+
+        try {
+            Person person4 = (Person) ctx.lookup(dn2);
+            System.out.println("StorePerson: retrieved object: " + person4);
+            if (person2.getAttributes().equals(person4.getAttributes())) {
+                System.out.println(
+                    "StorePerson: retrieved person matches original");
+            } else {
+                System.out.println(
+                    "StorePerson: retrieved person does NOT match original");
+            }
+        } catch (NamingException e) {
+            System.err.println("StorePerson: error retrieving entry '" +
+                dn2 + "' " + e);
+            e.printStackTrace();
+            cleanup(ctx, dn, dn2);
+            return;
+        }
+
+        cleanup(ctx, dn, dn2);
+        return;
+    }
+
+    /*
+     * Remove objects from the LDAP directory
+     */
+    private static void cleanup(DirContext ctx, String... dns)
+        throws NamingException {
+
+        for (String dn : dns) {
+            try {
+                ctx.destroySubcontext(dn);
+                System.out.println("StorePerson: removed entry '" + dn + "'");
+            } catch (NamingException e) {
+                System.err.println("StorePerson: error removing entry '" + dn +
+                    "' " + e);
+            }
+        }
+        ctx.close();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/naming/module/src/test/test/StorePerson.ldap	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,456 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+################################################################################
+# Capture file for StorePerson.java
+#
+# NOTE: This hexadecimal dump of LDAP protocol messages was generated by
+#       running the StorePerson application program against a real LDAP
+#       server and setting the JNDI/LDAP environment property:
+#       com.sun.jndi.ldap.trace.ber to activate LDAP message tracing.
+#
+#      (The ASN.1 annotations were generated separately by the dumpasn1
+#       utility and added only for clarity.)
+#
+################################################################################
+
+# LDAP BindRequest:
+#
+#   0   12: SEQUENCE {
+#   2    1:   INTEGER 1
+#   5    7:   [APPLICATION 0] {
+#   7    1:     INTEGER 3
+#  10    0:     OCTET STRING
+#  12    0:     [0]
+#         :     }
+#         :   }
+#
+0000: 30 0C 02 01 01 60 07 02   01 03 04 00 80 00        0....`........
+
+# LDAP BindResponse:
+#
+#   0   12: SEQUENCE {
+#   2    1:   INTEGER 1
+#   5    7:   [APPLICATION 1] {
+#   7    1:     ENUMERATED 0
+#  10    0:     OCTET STRING
+#  12    0:     OCTET STRING
+#         :     }
+#         :   }
+#
+0000: 30 0C 02 01 01 61 07 0A   01 00 04 00 04 00        0....a........
+
+# LDAP AddRequest:
+#
+#   0  183: SEQUENCE {
+#   3    1:   INTEGER 2
+#   6  148:   [APPLICATION 8] {
+#   9   36:     OCTET STRING 'cn=John Smith,dc=ie,dc=oracle,dc=com'
+#  47  108:     SEQUENCE {
+#  49   26:       SEQUENCE {
+#  51    4:         OCTET STRING 'mail'
+#  57   18:         SET {
+#  59   16:           OCTET STRING 'jsmith@smith.com'
+#         :           }
+#         :         }
+#  77   43:       SEQUENCE {
+#  79   11:         OCTET STRING 'objectClass'
+#  92   28:         SET {
+#  94    3:           OCTET STRING 'top'
+#  99    6:           OCTET STRING 'person'
+# 107   13:           OCTET STRING 'inetOrgPerson'
+#         :           }
+#         :         }
+# 122   13:       SEQUENCE {
+# 124    2:         OCTET STRING 73 6E
+# 128    7:         SET {
+# 130    5:           OCTET STRING 'Smith'
+#         :           }
+#         :         }
+# 137   18:       SEQUENCE {
+# 139    2:         OCTET STRING 63 6E
+# 143   12:         SET {
+# 145   10:           OCTET STRING 'John Smith'
+#         :           }
+#         :         }
+#         :       }
+#         :     }
+# 157   27:   [0] {
+# 159   25:     SEQUENCE {
+# 161   23:       OCTET STRING '2.16.840.1.113730.3.4.2'
+#         :       }
+#         :     }
+#         :   }
+#
+0000: 30 81 B7 02 01 02 68 81   94 04 24 63 6E 3D 4A 6F  0.....h...$cn=Jo
+0010: 68 6E 20 53 6D 69 74 68   2C 64 63 3D 69 65 2C 64  hn Smith,dc=ie,d
+0020: 63 3D 6F 72 61 63 6C 65   2C 64 63 3D 63 6F 6D 30  c=oracle,dc=com0
+0030: 6C 30 1A 04 04 6D 61 69   6C 31 12 04 10 6A 73 6D  l0...mail1...jsm
+0040: 69 74 68 40 73 6D 69 74   68 2E 63 6F 6D 30 2B 04  ith@smith.com0+.
+0050: 0B 6F 62 6A 65 63 74 43   6C 61 73 73 31 1C 04 03  .objectClass1...
+0060: 74 6F 70 04 06 70 65 72   73 6F 6E 04 0D 69 6E 65  top..person..ine
+0070: 74 4F 72 67 50 65 72 73   6F 6E 30 0D 04 02 73 6E  tOrgPerson0...sn
+0080: 31 07 04 05 53 6D 69 74   68 30 12 04 02 63 6E 31  1...Smith0...cn1
+0090: 0C 04 0A 4A 6F 68 6E 20   53 6D 69 74 68 A0 1B 30  ...John Smith..0
+00A0: 19 04 17 32 2E 31 36 2E   38 34 30 2E 31 2E 31 31  ...2.16.840.1.11
+00B0: 33 37 33 30 2E 33 2E 34   2E 32                    3730.3.4.2
+
+# LDAP AddResponse:
+#
+#   0   12: SEQUENCE {
+#   2    1:   INTEGER 2
+#   5    7:   [APPLICATION 9] {
+#   7    1:     ENUMERATED 0
+#  10    0:     OCTET STRING
+#  12    0:     OCTET STRING
+#         :     }
+#         :   }
+#
+0000: 30 0C 02 01 02 69 07 0A   01 00 04 00 04 00        0....i........
+
+# LDAP AddRequest:
+#
+#   0  183: SEQUENCE {
+#   3    1:   INTEGER 3
+#   6  148:   [APPLICATION 8] {
+#   9   36:     OCTET STRING 'cn=Jill Smyth,dc=ie,dc=oracle,dc=com'
+#  47  108:     SEQUENCE {
+#  49   26:       SEQUENCE {
+#  51    4:         OCTET STRING 'mail'
+#  57   18:         SET {
+#  59   16:           OCTET STRING 'jsmyth@smith.com'
+#         :           }
+#         :         }
+#  77   43:       SEQUENCE {
+#  79   11:         OCTET STRING 'objectClass'
+#  92   28:         SET {
+#  94    3:           OCTET STRING 'top'
+#  99    6:           OCTET STRING 'person'
+# 107   13:           OCTET STRING 'inetOrgPerson'
+#         :           }
+#         :         }
+# 122   13:       SEQUENCE {
+# 124    2:         OCTET STRING 73 6E
+# 128    7:         SET {
+# 130    5:           OCTET STRING 'Smyth'
+#         :           }
+#         :         }
+# 137   18:       SEQUENCE {
+# 139    2:         OCTET STRING 63 6E
+# 143   12:         SET {
+# 145   10:           OCTET STRING 'Jill Smyth'
+#         :           }
+#         :         }
+#         :       }
+#         :     }
+# 157   27:   [0] {
+# 159   25:     SEQUENCE {
+# 161   23:       OCTET STRING '2.16.840.1.113730.3.4.2'
+#         :       }
+#         :     }
+#         :   }
+#
+0000: 30 81 B7 02 01 03 68 81   94 04 24 63 6E 3D 4A 69  0.....h...$cn=Ji
+0010: 6C 6C 20 53 6D 79 74 68   2C 64 63 3D 69 65 2C 64  ll Smyth,dc=ie,d
+0020: 63 3D 6F 72 61 63 6C 65   2C 64 63 3D 63 6F 6D 30  c=oracle,dc=com0
+0030: 6C 30 1A 04 04 6D 61 69   6C 31 12 04 10 6A 73 6D  l0...mail1...jsm
+0040: 79 74 68 40 73 6D 69 74   68 2E 63 6F 6D 30 2B 04  yth@smith.com0+.
+0050: 0B 6F 62 6A 65 63 74 43   6C 61 73 73 31 1C 04 03  .objectClass1...
+0060: 74 6F 70 04 06 70 65 72   73 6F 6E 04 0D 69 6E 65  top..person..ine
+0070: 74 4F 72 67 50 65 72 73   6F 6E 30 0D 04 02 73 6E  tOrgPerson0...sn
+0080: 31 07 04 05 53 6D 79 74   68 30 12 04 02 63 6E 31  1...Smyth0...cn1
+0090: 0C 04 0A 4A 69 6C 6C 20   53 6D 79 74 68 A0 1B 30  ...Jill Smyth..0
+00A0: 19 04 17 32 2E 31 36 2E   38 34 30 2E 31 2E 31 31  ...2.16.840.1.11
+00B0: 33 37 33 30 2E 33 2E 34   2E 32                    3730.3.4.2
+
+# LDAP AddResponse:
+#
+#   0   12: SEQUENCE {
+#   2    1:   INTEGER 3
+#   5    7:   [APPLICATION 9] {
+#   7    1:     ENUMERATED 0
+#  10    0:     OCTET STRING
+#  12    0:     OCTET STRING
+#         :     }
+#         :   }
+#
+0000: 30 0C 02 01 03 69 07 0A   01 00 04 00 04 00        0....i........
+
+# LDAP SearchRequest:
+#
+#   0  102: SEQUENCE {
+#   2    1:   INTEGER 4
+#   5   68:   [APPLICATION 3] {
+#   7   36:     OCTET STRING 'cn=John Smith,dc=ie,dc=oracle,dc=com'
+#  45    1:     ENUMERATED 0
+#  48    1:     ENUMERATED 3
+#  51    1:     INTEGER 0
+#  54    1:     INTEGER 0
+#  57    1:     BOOLEAN FALSE
+#  60   11:     [7] 'objectClass'
+#  73    0:     SEQUENCE {}
+#         :     }
+#  75   27:   [0] {
+#  77   25:     SEQUENCE {
+#  79   23:       OCTET STRING '2.16.840.1.113730.3.4.2'
+#         :       }
+#         :     }
+#         :   }
+#
+0000: 30 66 02 01 04 63 44 04   24 63 6E 3D 4A 6F 68 6E  0f...cD.$cn=John
+0010: 20 53 6D 69 74 68 2C 64   63 3D 69 65 2C 64 63 3D   Smith,dc=ie,dc=
+0020: 6F 72 61 63 6C 65 2C 64   63 3D 63 6F 6D 0A 01 00  oracle,dc=com...
+0030: 0A 01 03 02 01 00 02 01   00 01 01 00 87 0B 6F 62  ..............ob
+0040: 6A 65 63 74 43 6C 61 73   73 30 00 A0 1B 30 19 04  jectClass0...0..
+0050: 17 32 2E 31 36 2E 38 34   30 2E 31 2E 31 31 33 37  .2.16.840.1.1137
+0060: 33 30 2E 33 2E 34 2E 32                            30.3.4.2
+
+# LDAP SearchResultEntry:
+#
+#   0  154: SEQUENCE {
+#   3    1:   INTEGER 4
+#   6  148:   [APPLICATION 4] {
+#   9   36:     OCTET STRING 'cn=John Smith,dc=ie,dc=oracle,dc=com'
+#  47  108:     SEQUENCE {
+#  49   26:       SEQUENCE {
+#  51    4:         OCTET STRING 'mail'
+#  57   18:         SET {
+#  59   16:           OCTET STRING 'jsmith@smith.com'
+#         :           }
+#         :         }
+#  77   43:       SEQUENCE {
+#  79   11:         OCTET STRING 'objectClass'
+#  92   28:         SET {
+#  94    3:           OCTET STRING 'top'
+#  99    6:           OCTET STRING 'person'
+# 107   13:           OCTET STRING 'inetOrgPerson'
+#         :           }
+#         :         }
+# 122   13:       SEQUENCE {
+# 124    2:         OCTET STRING 73 6E
+# 128    7:         SET {
+# 130    5:           OCTET STRING 'Smith'
+#         :           }
+#         :         }
+# 137   18:       SEQUENCE {
+# 139    2:         OCTET STRING 63 6E
+# 143   12:         SET {
+# 145   10:           OCTET STRING 'John Smith'
+#         :           }
+#         :         }
+#         :       }
+#         :     }
+#         :   }
+#
+0000: 30 81 9A 02 01 04 64 81   94 04 24 63 6E 3D 4A 6F  0.....d...$cn=Jo
+0010: 68 6E 20 53 6D 69 74 68   2C 64 63 3D 69 65 2C 64  hn Smith,dc=ie,d
+0020: 63 3D 6F 72 61 63 6C 65   2C 64 63 3D 63 6F 6D 30  c=oracle,dc=com0
+0030: 6C 30 1A 04 04 6D 61 69   6C 31 12 04 10 6A 73 6D  l0...mail1...jsm
+0040: 69 74 68 40 73 6D 69 74   68 2E 63 6F 6D 30 2B 04  ith@smith.com0+.
+0050: 0B 6F 62 6A 65 63 74 43   6C 61 73 73 31 1C 04 03  .objectClass1...
+0060: 74 6F 70 04 06 70 65 72   73 6F 6E 04 0D 69 6E 65  top..person..ine
+0070: 74 4F 72 67 50 65 72 73   6F 6E 30 0D 04 02 73 6E  tOrgPerson0...sn
+0080: 31 07 04 05 53 6D 69 74   68 30 12 04 02 63 6E 31  1...Smith0...cn1
+0090: 0C 04 0A 4A 6F 68 6E 20   53 6D 69 74 68           ...John Smith
+
+# LDAP SearchResultDone:
+#
+#   0   12: SEQUENCE {
+#   2    1:   INTEGER 4
+#   5    7:   [APPLICATION 5] {
+#   7    1:     ENUMERATED 0
+#  10    0:     OCTET STRING
+#  12    0:     OCTET STRING
+#         :     }
+#         :   }
+#
+0000: 30 0C 02 01 04 65 07 0A   01 00 04 00 04 00        0....e........
+
+# LDAP SearchRequest:
+#
+#   0  102: SEQUENCE {
+#   2    1:   INTEGER 5
+#   5   68:   [APPLICATION 3] {
+#   7   36:     OCTET STRING 'cn=Jill Smyth,dc=ie,dc=oracle,dc=com'
+#  45    1:     ENUMERATED 0
+#  48    1:     ENUMERATED 3
+#  51    1:     INTEGER 0
+#  54    1:     INTEGER 0
+#  57    1:     BOOLEAN FALSE
+#  60   11:     [7] 'objectClass'
+#  73    0:     SEQUENCE {}
+#         :     }
+#  75   27:   [0] {
+#  77   25:     SEQUENCE {
+#  79   23:       OCTET STRING '2.16.840.1.113730.3.4.2'
+#         :       }
+#         :     }
+#         :   }
+#
+0000: 30 66 02 01 05 63 44 04   24 63 6E 3D 4A 69 6C 6C  0f...cD.$cn=Jill
+0010: 20 53 6D 79 74 68 2C 64   63 3D 69 65 2C 64 63 3D   Smyth,dc=ie,dc=
+0020: 6F 72 61 63 6C 65 2C 64   63 3D 63 6F 6D 0A 01 00  oracle,dc=com...
+0030: 0A 01 03 02 01 00 02 01   00 01 01 00 87 0B 6F 62  ..............ob
+0040: 6A 65 63 74 43 6C 61 73   73 30 00 A0 1B 30 19 04  jectClass0...0..
+0050: 17 32 2E 31 36 2E 38 34   30 2E 31 2E 31 31 33 37  .2.16.840.1.1137
+0060: 33 30 2E 33 2E 34 2E 32                            30.3.4.2
+
+# LDAP SearchResultEntry:
+#
+#   0  154: SEQUENCE {
+#   3    1:   INTEGER 5
+#   6  148:   [APPLICATION 4] {
+#   9   36:     OCTET STRING 'cn=Jill Smyth,dc=ie,dc=oracle,dc=com'
+#  47  108:     SEQUENCE {
+#  49   26:       SEQUENCE {
+#  51    4:         OCTET STRING 'mail'
+#  57   18:         SET {
+#  59   16:           OCTET STRING 'jsmyth@smith.com'
+#         :           }
+#         :         }
+#  77   43:       SEQUENCE {
+#  79   11:         OCTET STRING 'objectClass'
+#  92   28:         SET {
+#  94    3:           OCTET STRING 'top'
+#  99    6:           OCTET STRING 'person'
+# 107   13:           OCTET STRING 'inetOrgPerson'
+#         :           }
+#         :         }
+# 122   13:       SEQUENCE {
+# 124    2:         OCTET STRING 73 6E
+# 128    7:         SET {
+# 130    5:           OCTET STRING 'Smyth'
+#         :           }
+#         :         }
+# 137   18:       SEQUENCE {
+# 139    2:         OCTET STRING 63 6E
+# 143   12:         SET {
+# 145   10:           OCTET STRING 'Jill Smyth'
+#         :           }
+#         :         }
+#         :       }
+#         :     }
+#         :   }
+#
+0000: 30 81 9A 02 01 05 64 81   94 04 24 63 6E 3D 4A 69  0.....d...$cn=Ji
+0010: 6C 6C 20 53 6D 79 74 68   2C 64 63 3D 69 65 2C 64  ll Smyth,dc=ie,d
+0020: 63 3D 6F 72 61 63 6C 65   2C 64 63 3D 63 6F 6D 30  c=oracle,dc=com0
+0030: 6C 30 1A 04 04 6D 61 69   6C 31 12 04 10 6A 73 6D  l0...mail1...jsm
+0040: 79 74 68 40 73 6D 69 74   68 2E 63 6F 6D 30 2B 04  yth@smith.com0+.
+0050: 0B 6F 62 6A 65 63 74 43   6C 61 73 73 31 1C 04 03  .objectClass1...
+0060: 74 6F 70 04 06 70 65 72   73 6F 6E 04 0D 69 6E 65  top..person..ine
+0070: 74 4F 72 67 50 65 72 73   6F 6E 30 0D 04 02 73 6E  tOrgPerson0...sn
+0080: 31 07 04 05 53 6D 79 74   68 30 12 04 02 63 6E 31  1...Smyth0...cn1
+0090: 0C 04 0A 4A 69 6C 6C 20   53 6D 79 74 68           ...Jill Smyth
+
+# LDAP SearchResultDone:
+#
+#   0   12: SEQUENCE {
+#   2    1:   INTEGER 5
+#   5    7:   [APPLICATION 5] {
+#   7    1:     ENUMERATED 0
+#  10    0:     OCTET STRING
+#  12    0:     OCTET STRING
+#         :     }
+#         :   }
+#
+0000: 30 0C 02 01 05 65 07 0A   01 00 04 00 04 00        0....e........
+
+# LDAP DeleteRequest:
+#
+#   0   70: SEQUENCE {
+#   2    1:   INTEGER 6
+#   5   36:   [APPLICATION 10] 'cn=John Smith,dc=ie,dc=oracle,dc=com'
+#  43   27:   [0] {
+#  45   25:     SEQUENCE {
+#  47   23:       OCTET STRING '2.16.840.1.113730.3.4.2'
+#         :       }
+#         :     }
+#         :   }
+#
+0000: 30 46 02 01 06 4A 24 63   6E 3D 4A 6F 68 6E 20 53  0F...J$cn=John S
+0010: 6D 69 74 68 2C 64 63 3D   69 65 2C 64 63 3D 6F 72  mith,dc=ie,dc=or
+0020: 61 63 6C 65 2C 64 63 3D   63 6F 6D A0 1B 30 19 04  acle,dc=com..0..
+0030: 17 32 2E 31 36 2E 38 34   30 2E 31 2E 31 31 33 37  .2.16.840.1.1137
+0040: 33 30 2E 33 2E 34 2E 32                            30.3.4.2
+
+# LDAP DeleteResponse:
+#
+#   0   12: SEQUENCE {
+#   2    1:   INTEGER 6
+#   5    7:   [APPLICATION 11] {
+#   7    1:     ENUMERATED 0
+#  10    0:     OCTET STRING
+#  12    0:     OCTET STRING
+#         :     }
+#         :   }
+#
+0000: 30 0C 02 01 06 6B 07 0A   01 00 04 00 04 00        0....k........
+
+# LDAP DeleteRequest:
+#
+#   0   70: SEQUENCE {
+#   2    1:   INTEGER 7
+#   5   36:   [APPLICATION 10] 'cn=Jill Smyth,dc=ie,dc=oracle,dc=com'
+#  43   27:   [0] {
+#  45   25:     SEQUENCE {
+#  47   23:       OCTET STRING '2.16.840.1.113730.3.4.2'
+#         :       }
+#         :     }
+#         :   }
+#
+0000: 30 46 02 01 07 4A 24 63   6E 3D 4A 69 6C 6C 20 53  0F...J$cn=Jill S
+0010: 6D 79 74 68 2C 64 63 3D   69 65 2C 64 63 3D 6F 72  myth,dc=ie,dc=or
+0020: 61 63 6C 65 2C 64 63 3D   63 6F 6D A0 1B 30 19 04  acle,dc=com..0..
+0030: 17 32 2E 31 36 2E 38 34   30 2E 31 2E 31 31 33 37  .2.16.840.1.1137
+0040: 33 30 2E 33 2E 34 2E 32                            30.3.4.2
+
+# LDAP DeleteResponse:
+#
+#   0   12: SEQUENCE {
+#   2    1:   INTEGER 7
+#   5    7:   [APPLICATION 11] {
+#   7    1:     ENUMERATED 0
+#  10    0:     OCTET STRING
+#  12    0:     OCTET STRING
+#         :     }
+#         :   }
+#
+0000: 30 0C 02 01 07 6B 07 0A   01 00 04 00 04 00        0....k........
+
+# LDAP UnbindRequest:
+#
+#   0   34: SEQUENCE {
+#   2    1:   INTEGER 8
+#   5    0:   [APPLICATION 2]
+#   7   27:   [0] {
+#   9   25:     SEQUENCE {
+#  11   23:       OCTET STRING '2.16.840.1.113730.3.4.2'
+#         :       }
+#         :     }
+#         :   }
+#
+0000: 30 22 02 01 08 42 00 A0   1B 30 19 04 17 32 2E 31  0"...B...0...2.1
+0010: 36 2E 38 34 30 2E 31 2E   31 31 33 37 33 30 2E 33  6.840.1.113730.3
+0020: 2E 34 2E 32                                        .4.2
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/naming/module/src/test/test/StoreRemote.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Demonstrate Java Remote object storage and retrieval using an LDAP directory.
+ * The RMI object is supplied by a third-party module.
+ */
+
+package test;
+
+import java.io.*;
+import java.net.*;
+import java.rmi.Remote;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.*;
+import javax.naming.*;
+import javax.naming.directory.*;
+
+import org.example.hello.*;
+
+public class StoreRemote {
+
+    // LDAP capture file
+    private static final String LDAP_CAPTURE_FILE =
+        System.getProperty("test.src") + "/src/test/test/StoreRemote.ldap";
+    // LDAPServer socket
+    private static ServerSocket serverSocket;
+
+    public static void main(String[] args) throws Exception {
+
+        /*
+         * Process arguments
+         */
+
+        int argc = args.length;
+        if ((argc < 1) ||
+            ((argc == 1) && (args[0].equalsIgnoreCase("-help")))) {
+
+            System.err.println("\nUsage:   StoreRemote <ldapurl>\n");
+            System.err.println("        <ldapurl> is the LDAP URL of the parent entry\n");
+            System.err.println("example:");
+            System.err.println("        java StoreRemote ldap://oasis/o=airius.com");
+            return;
+        }
+
+        /*
+         * Launch the LDAP server with the StoreRemote.ldap capture file
+         */
+
+        serverSocket = new ServerSocket(0);
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    new LDAPServer(serverSocket, LDAP_CAPTURE_FILE);
+               } catch (Exception e) {
+                   System.out.println("ERROR: unable to launch LDAP server");
+                   e.printStackTrace();
+               }
+            }
+        }).start();
+
+        /*
+         * Store a Remote object in the LDAP directory
+         */
+
+        Hashtable<String,Object> env = new Hashtable<>();
+        env.put(Context.INITIAL_CONTEXT_FACTORY,
+            "com.sun.jndi.ldap.LdapCtxFactory");
+        URI ldapUri = new URI(args[0]);
+        if (ldapUri.getPort() == -1) {
+            ldapUri = new URI(ldapUri.getScheme(), null, ldapUri.getHost(),
+                serverSocket.getLocalPort(), ldapUri.getPath(), null, null);
+        }
+        env.put(Context.PROVIDER_URL, ldapUri.toString());
+        if (args[args.length - 1].equalsIgnoreCase("-trace")) {
+            env.put("com.sun.jndi.ldap.trace.ber", System.out);
+        }
+
+        System.out.println("StoreRemote: connecting to " + ldapUri);
+        DirContext ctx = new InitialDirContext(env);
+        String dn = "cn=myremote";
+
+        try {
+            Hello hello = new HelloImpl();
+            ctx.bind(dn, hello);
+            System.out.println("StoreRemote: created entry '" + dn + "'");
+
+            // Explicitly release the RMI object
+            UnicastRemoteObject.unexportObject(hello, true);
+
+        } catch (NameAlreadyBoundException e) {
+            System.err.println("StoreRemote: entry '" + dn +
+                "' already exists");
+            cleanup(ctx, (String)null);
+            return;
+        }
+
+        /*
+         * Retrieve the Remote object from the LDAP directory
+         */
+
+        try {
+            Hello obj = (Hello) ctx.lookup(dn);
+            System.out.println("StoreRemote: retrieved object: " + obj);
+            System.out.println("StoreRemote: calling Hello.sayHello()...\n" +
+                obj.sayHello());
+
+            // Explicitly release the RMI object
+            UnicastRemoteObject.unexportObject(obj, true);
+
+        } catch (NamingException e) {
+            System.err.println("StoreRemote: error retrieving entry '" +
+                dn + "' " + e);
+            e.printStackTrace();
+            cleanup(ctx, dn);
+            return;
+        }
+
+        cleanup(ctx, dn);
+    }
+
+    /*
+     * Remove objects from the LDAP directory
+     */
+    private static void cleanup(DirContext ctx, String... dns)
+        throws NamingException {
+
+        for (String dn : dns) {
+            try {
+                ctx.destroySubcontext(dn);
+                System.out.println("StoreRemote: removed entry '" + dn + "'");
+            } catch (NamingException e) {
+                System.err.println("StoreRemote: error removing entry '" + dn +
+                    "' " + e);
+            }
+        }
+        ctx.close();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/naming/module/src/test/test/StoreRemote.ldap	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,411 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+################################################################################
+# Capture file for StoreRemote.java
+#
+# NOTE: This hexadecimal dump of LDAP protocol messages was generated by
+#       running the StoreRemote application program against a real LDAP
+#       server and setting the JNDI/LDAP environment property:
+#       com.sun.jndi.ldap.trace.ber to activate LDAP message tracing.
+#
+#      (The ASN.1 annotations were generated separately by the dumpasn1
+#       utility and added only for clarity.)
+#
+################################################################################
+
+# LDAP BindRequest:
+#
+#   0   12: SEQUENCE {
+#   2    1:   INTEGER 1
+#   5    7:   [APPLICATION 0] {
+#   7    1:     INTEGER 3
+#  10    0:     OCTET STRING
+#  12    0:     [0]
+#         :     }
+#         :   }
+#
+0000: 30 0C 02 01 01 60 07 02   01 03 04 00 80 00        0....`........
+
+# LDAP BindResponse:
+#
+#   0   12: SEQUENCE {
+#   2    1:   INTEGER 1
+#   5    7:   [APPLICATION 1] {
+#   7    1:     ENUMERATED 0
+#  10    0:     OCTET STRING
+#  12    0:     OCTET STRING
+#         :     }
+#         :   }
+#
+0000: 30 0C 02 01 01 61 07 0A   01 00 04 00 04 00        0....a........
+
+# LDAP AddRequest:
+#
+#   0  791: SEQUENCE {
+#   4    1:   INTEGER 2
+#   7  755:   [APPLICATION 8] {
+#  11   34:     OCTET STRING 'cn=myremote,dc=ie,dc=oracle,dc=com'
+#  47  715:     SEQUENCE {
+#  51  344:       SEQUENCE {
+#  55   18:         OCTET STRING 'javaSerializedData'
+#  75  320:         SET {
+#  79  316:           OCTET STRING
+#         :             AC ED 00 05 73 72 00 1B 6F 72 67 2E 65 78 61 6D
+#         :             70 6C 65 2E 68 65 6C 6C 6F 2E 48 65 6C 6C 6F 49
+#         :             6D 70 6C A9 56 08 D1 0C 92 18 98 02 00 00 78 72
+#         :             00 23 6A 61 76 61 2E 72 6D 69 2E 73 65 72 76 65
+#         :             72 2E 55 6E 69 63 61 73 74 52 65 6D 6F 74 65 4F
+#         :             62 6A 65 63 74 45 09 12 15 F5 E2 7E 31 02 00 03
+#         :             49 00 04 70 6F 72 74 4C 00 03 63 73 66 74 00 28
+#         :             4C 6A 61 76 61 2F 72 6D 69 2F 73 65 72 76 65 72
+#         :             2F 52 4D 49 43 6C 69 65 6E 74 53 6F 63 6B 65 74
+#         :             46 61 63 74 6F 72 79 3B 4C 00 03 73 73 66 74 00
+#         :             28 4C 6A 61 76 61 2F 72 6D 69 2F 73 65 72 76 65
+#         :             72 2F 52 4D 49 53 65 72 76 65 72 53 6F 63 6B 65
+#         :             74 46 61 63 74 6F 72 79 3B 78 72 00 1C 6A 61 76
+#         :             61 2E 72 6D 69 2E 73 65 72 76 65 72 2E 52 65 6D
+#         :             6F 74 65 53 65 72 76 65 72 C7 19 07 12 68 F3 39
+#         :             FB 02 00 00 78 72 00 1C 6A 61 76 61 2E 72 6D 69
+#         :             2E 73 65 72 76 65 72 2E 52 65 6D 6F 74 65 4F 62
+#         :             6A 65 63 74 D3 61 B4 91 0C 61 33 1E 03 00 00 78
+#         :             70 77 12 00 10 55 6E 69 63 61 73 74 53 65 72 76
+#         :             65 72 52 65 66 78 00 00 00 00 70 70
+#         :           }
+#         :         }
+# 399   69:       SEQUENCE {
+# 401   11:         OCTET STRING 'objectClass'
+# 414   54:         SET {
+# 416    3:           OCTET STRING 'top'
+# 421   13:           OCTET STRING 'javaContainer'
+# 436   10:           OCTET STRING 'javaObject'
+# 448   20:           OCTET STRING 'javaSerializedObject'
+#         :           }
+#         :         }
+# 470  227:       SEQUENCE {
+# 473   14:         OCTET STRING 'javaClassNames'
+# 489  208:         SET {
+# 492   27:           OCTET STRING 'org.example.hello.HelloImpl'
+# 521   35:           OCTET STRING 'java.rmi.server.UnicastRemoteObject'
+# 558   28:           OCTET STRING 'java.rmi.server.RemoteServer'
+# 588   28:           OCTET STRING 'java.rmi.server.RemoteObject'
+# 618   16:           OCTET STRING 'java.lang.Object'
+# 636   15:           OCTET STRING 'java.rmi.Remote'
+# 653   20:           OCTET STRING 'java.io.Serializable'
+# 675   23:           OCTET STRING 'org.example.hello.Hello'
+#         :           }
+#         :         }
+# 700   46:       SEQUENCE {
+# 702   13:         OCTET STRING 'javaClassName'
+# 717   29:         SET {
+# 719   27:           OCTET STRING 'org.example.hello.HelloImpl'
+#         :           }
+#         :         }
+# 748   16:       SEQUENCE {
+# 750    2:         OCTET STRING 63 6E
+# 754   10:         SET {
+# 756    8:           OCTET STRING 'myremote'
+#         :           }
+#         :         }
+#         :       }
+#         :     }
+# 766   27:   [0] {
+# 768   25:     SEQUENCE {
+# 770   23:       OCTET STRING '2.16.840.1.113730.3.4.2'
+#         :       }
+#         :     }
+#         :   }
+#
+0000: 30 82 03 17 02 01 02 68   82 02 F3 04 22 63 6E 3D  0......h...."cn=
+0010: 6D 79 72 65 6D 6F 74 65   2C 64 63 3D 69 65 2C 64  myremote,dc=ie,d
+0020: 63 3D 6F 72 61 63 6C 65   2C 64 63 3D 63 6F 6D 30  c=oracle,dc=com0
+0030: 82 02 CB 30 82 01 58 04   12 6A 61 76 61 53 65 72  ...0..X..javaSer
+0040: 69 61 6C 69 7A 65 64 44   61 74 61 31 82 01 40 04  ializedData1..@.
+0050: 82 01 3C AC ED 00 05 73   72 00 1B 6F 72 67 2E 65  ..<....sr..org.e
+0060: 78 61 6D 70 6C 65 2E 68   65 6C 6C 6F 2E 48 65 6C  xample.hello.Hel
+0070: 6C 6F 49 6D 70 6C A9 56   08 D1 0C 92 18 98 02 00  loImpl.V........
+0080: 00 78 72 00 23 6A 61 76   61 2E 72 6D 69 2E 73 65  .xr.#java.rmi.se
+0090: 72 76 65 72 2E 55 6E 69   63 61 73 74 52 65 6D 6F  rver.UnicastRemo
+00A0: 74 65 4F 62 6A 65 63 74   45 09 12 15 F5 E2 7E 31  teObjectE......1
+00B0: 02 00 03 49 00 04 70 6F   72 74 4C 00 03 63 73 66  ...I..portL..csf
+00C0: 74 00 28 4C 6A 61 76 61   2F 72 6D 69 2F 73 65 72  t.(Ljava/rmi/ser
+00D0: 76 65 72 2F 52 4D 49 43   6C 69 65 6E 74 53 6F 63  ver/RMIClientSoc
+00E0: 6B 65 74 46 61 63 74 6F   72 79 3B 4C 00 03 73 73  ketFactory;L..ss
+00F0: 66 74 00 28 4C 6A 61 76   61 2F 72 6D 69 2F 73 65  ft.(Ljava/rmi/se
+0100: 72 76 65 72 2F 52 4D 49   53 65 72 76 65 72 53 6F  rver/RMIServerSo
+0110: 63 6B 65 74 46 61 63 74   6F 72 79 3B 78 72 00 1C  cketFactory;xr..
+0120: 6A 61 76 61 2E 72 6D 69   2E 73 65 72 76 65 72 2E  java.rmi.server.
+0130: 52 65 6D 6F 74 65 53 65   72 76 65 72 C7 19 07 12  RemoteServer....
+0140: 68 F3 39 FB 02 00 00 78   72 00 1C 6A 61 76 61 2E  h.9....xr..java.
+0150: 72 6D 69 2E 73 65 72 76   65 72 2E 52 65 6D 6F 74  rmi.server.Remot
+0160: 65 4F 62 6A 65 63 74 D3   61 B4 91 0C 61 33 1E 03  eObject.a...a3..
+0170: 00 00 78 70 77 12 00 10   55 6E 69 63 61 73 74 53  ..xpw...UnicastS
+0180: 65 72 76 65 72 52 65 66   78 00 00 00 00 70 70 30  erverRefx....pp0
+0190: 45 04 0B 6F 62 6A 65 63   74 43 6C 61 73 73 31 36  E..objectClass16
+01A0: 04 03 74 6F 70 04 0D 6A   61 76 61 43 6F 6E 74 61  ..top..javaConta
+01B0: 69 6E 65 72 04 0A 6A 61   76 61 4F 62 6A 65 63 74  iner..javaObject
+01C0: 04 14 6A 61 76 61 53 65   72 69 61 6C 69 7A 65 64  ..javaSerialized
+01D0: 4F 62 6A 65 63 74 30 81   E3 04 0E 6A 61 76 61 43  Object0....javaC
+01E0: 6C 61 73 73 4E 61 6D 65   73 31 81 D0 04 1B 6F 72  lassNames1....or
+01F0: 67 2E 65 78 61 6D 70 6C   65 2E 68 65 6C 6C 6F 2E  g.example.hello.
+0200: 48 65 6C 6C 6F 49 6D 70   6C 04 23 6A 61 76 61 2E  HelloImpl.#java.
+0210: 72 6D 69 2E 73 65 72 76   65 72 2E 55 6E 69 63 61  rmi.server.Unica
+0220: 73 74 52 65 6D 6F 74 65   4F 62 6A 65 63 74 04 1C  stRemoteObject..
+0230: 6A 61 76 61 2E 72 6D 69   2E 73 65 72 76 65 72 2E  java.rmi.server.
+0240: 52 65 6D 6F 74 65 53 65   72 76 65 72 04 1C 6A 61  RemoteServer..ja
+0250: 76 61 2E 72 6D 69 2E 73   65 72 76 65 72 2E 52 65  va.rmi.server.Re
+0260: 6D 6F 74 65 4F 62 6A 65   63 74 04 10 6A 61 76 61  moteObject..java
+0270: 2E 6C 61 6E 67 2E 4F 62   6A 65 63 74 04 0F 6A 61  .lang.Object..ja
+0280: 76 61 2E 72 6D 69 2E 52   65 6D 6F 74 65 04 14 6A  va.rmi.Remote..j
+0290: 61 76 61 2E 69 6F 2E 53   65 72 69 61 6C 69 7A 61  ava.io.Serializa
+02A0: 62 6C 65 04 17 6F 72 67   2E 65 78 61 6D 70 6C 65  ble..org.example
+02B0: 2E 68 65 6C 6C 6F 2E 48   65 6C 6C 6F 30 2E 04 0D  .hello.Hello0...
+02C0: 6A 61 76 61 43 6C 61 73   73 4E 61 6D 65 31 1D 04  javaClassName1..
+02D0: 1B 6F 72 67 2E 65 78 61   6D 70 6C 65 2E 68 65 6C  .org.example.hel
+02E0: 6C 6F 2E 48 65 6C 6C 6F   49 6D 70 6C 30 10 04 02  lo.HelloImpl0...
+02F0: 63 6E 31 0A 04 08 6D 79   72 65 6D 6F 74 65 A0 1B  cn1...myremote..
+0300: 30 19 04 17 32 2E 31 36   2E 38 34 30 2E 31 2E 31  0...2.16.840.1.1
+0310: 31 33 37 33 30 2E 33 2E   34 2E 32                 13730.3.4.2
+
+# LDAP AddResponse:
+#
+#   0   12: SEQUENCE {
+#   2    1:   INTEGER 2
+#   5    7:   [APPLICATION 9] {
+#   7    1:     ENUMERATED 0
+#  10    0:     OCTET STRING
+#  12    0:     OCTET STRING
+#         :     }
+#         :   }
+#
+0000: 30 0C 02 01 02 69 07 0A   01 00 04 00 04 00        0....i........
+
+# LDAP SearchRequest:
+#
+#   0  100: SEQUENCE {
+#   2    1:   INTEGER 3
+#   5   66:   [APPLICATION 3] {
+#   7   34:     OCTET STRING 'cn=myremote,dc=ie,dc=oracle,dc=com'
+#  43    1:     ENUMERATED 0
+#  46    1:     ENUMERATED 3
+#  49    1:     INTEGER 0
+#  52    1:     INTEGER 0
+#  55    1:     BOOLEAN FALSE
+#  58   11:     [7] 'objectClass'
+#  71    0:     SEQUENCE {}
+#         :     }
+#  73   27:   [0] {
+#  75   25:     SEQUENCE {
+#  77   23:       OCTET STRING '2.16.840.1.113730.3.4.2'
+#         :       }
+#         :     }
+#         :   }
+#
+0000: 30 64 02 01 03 63 42 04   22 63 6E 3D 6D 79 72 65  0d...cB."cn=myre
+0010: 6D 6F 74 65 2C 64 63 3D   69 65 2C 64 63 3D 6F 72  mote,dc=ie,dc=or
+0020: 61 63 6C 65 2C 64 63 3D   63 6F 6D 0A 01 00 0A 01  acle,dc=com.....
+0030: 03 02 01 00 02 01 00 01   01 00 87 0B 6F 62 6A 65  ............obje
+0040: 63 74 43 6C 61 73 73 30   00 A0 1B 30 19 04 17 32  ctClass0...0...2
+0050: 2E 31 36 2E 38 34 30 2E   31 2E 31 31 33 37 33 30  .16.840.1.113730
+0060: 2E 33 2E 34 2E 32                                  .3.4.2
+
+# LDAP SearchResultEntry:
+#
+#
+#   0  762: SEQUENCE {
+#   4    1:   INTEGER 3
+#   7  755:   [APPLICATION 4] {
+#  11   34:     OCTET STRING 'cn=myremote,dc=ie,dc=oracle,dc=com'
+#  47  715:     SEQUENCE {
+#  51  344:       SEQUENCE {
+#  55   18:         OCTET STRING 'javaSerializedData'
+#  75  320:         SET {
+#  79  316:           OCTET STRING
+#         :             AC ED 00 05 73 72 00 1B 6F 72 67 2E 65 78 61 6D
+#         :             70 6C 65 2E 68 65 6C 6C 6F 2E 48 65 6C 6C 6F 49
+#         :             6D 70 6C A9 56 08 D1 0C 92 18 98 02 00 00 78 72
+#         :             00 23 6A 61 76 61 2E 72 6D 69 2E 73 65 72 76 65
+#         :             72 2E 55 6E 69 63 61 73 74 52 65 6D 6F 74 65 4F
+#         :             62 6A 65 63 74 45 09 12 15 F5 E2 7E 31 02 00 03
+#         :             49 00 04 70 6F 72 74 4C 00 03 63 73 66 74 00 28
+#         :             4C 6A 61 76 61 2F 72 6D 69 2F 73 65 72 76 65 72
+#         :             2F 52 4D 49 43 6C 69 65 6E 74 53 6F 63 6B 65 74
+#         :             46 61 63 74 6F 72 79 3B 4C 00 03 73 73 66 74 00
+#         :             28 4C 6A 61 76 61 2F 72 6D 69 2F 73 65 72 76 65
+#         :             72 2F 52 4D 49 53 65 72 76 65 72 53 6F 63 6B 65
+#         :             74 46 61 63 74 6F 72 79 3B 78 72 00 1C 6A 61 76
+#         :             61 2E 72 6D 69 2E 73 65 72 76 65 72 2E 52 65 6D
+#         :             6F 74 65 53 65 72 76 65 72 C7 19 07 12 68 F3 39
+#         :             FB 02 00 00 78 72 00 1C 6A 61 76 61 2E 72 6D 69
+#         :             2E 73 65 72 76 65 72 2E 52 65 6D 6F 74 65 4F 62
+#         :             6A 65 63 74 D3 61 B4 91 0C 61 33 1E 03 00 00 78
+#         :             70 77 12 00 10 55 6E 69 63 61 73 74 53 65 72 76
+#         :             65 72 52 65 66 78 00 00 00 00 70 70
+#         :           }
+#         :         }
+# 399   69:       SEQUENCE {
+# 401   11:         OCTET STRING 'objectClass'
+# 414   54:         SET {
+# 416    3:           OCTET STRING 'top'
+# 421   13:           OCTET STRING 'javaContainer'
+# 436   10:           OCTET STRING 'javaObject'
+# 448   20:           OCTET STRING 'javaSerializedObject'
+#         :           }
+#         :         }
+# 470  227:       SEQUENCE {
+# 473   14:         OCTET STRING 'javaClassNames'
+# 489  208:         SET {
+# 492   27:           OCTET STRING 'org.example.hello.HelloImpl'
+# 521   35:           OCTET STRING 'java.rmi.server.UnicastRemoteObject'
+# 558   28:           OCTET STRING 'java.rmi.server.RemoteServer'
+# 588   28:           OCTET STRING 'java.rmi.server.RemoteObject'
+# 618   16:           OCTET STRING 'java.lang.Object'
+# 636   15:           OCTET STRING 'java.rmi.Remote'
+# 653   20:           OCTET STRING 'java.io.Serializable'
+# 675   23:           OCTET STRING 'org.example.hello.Hello'
+#         :           }
+#         :         }
+# 700   46:       SEQUENCE {
+# 702   13:         OCTET STRING 'javaClassName'
+# 717   29:         SET {
+# 719   27:           OCTET STRING 'org.example.hello.HelloImpl'
+#         :           }
+#         :         }
+# 748   16:       SEQUENCE {
+# 750    2:         OCTET STRING 63 6E
+# 754   10:         SET {
+# 756    8:           OCTET STRING 'myremote'
+#         :           }
+#         :         }
+#         :       }
+#         :     }
+#         :   }
+#
+0000: 30 82 02 FA 02 01 03 64   82 02 F3 04 22 63 6E 3D  0......d...."cn=
+0010: 6D 79 72 65 6D 6F 74 65   2C 64 63 3D 69 65 2C 64  myremote,dc=ie,d
+0020: 63 3D 6F 72 61 63 6C 65   2C 64 63 3D 63 6F 6D 30  c=oracle,dc=com0
+0030: 82 02 CB 30 82 01 58 04   12 6A 61 76 61 53 65 72  ...0..X..javaSer
+0040: 69 61 6C 69 7A 65 64 44   61 74 61 31 82 01 40 04  ializedData1..@.
+0050: 82 01 3C AC ED 00 05 73   72 00 1B 6F 72 67 2E 65  ..<....sr..org.e
+0060: 78 61 6D 70 6C 65 2E 68   65 6C 6C 6F 2E 48 65 6C  xample.hello.Hel
+0070: 6C 6F 49 6D 70 6C A9 56   08 D1 0C 92 18 98 02 00  loImpl.V........
+0080: 00 78 72 00 23 6A 61 76   61 2E 72 6D 69 2E 73 65  .xr.#java.rmi.se
+0090: 72 76 65 72 2E 55 6E 69   63 61 73 74 52 65 6D 6F  rver.UnicastRemo
+00A0: 74 65 4F 62 6A 65 63 74   45 09 12 15 F5 E2 7E 31  teObjectE......1
+00B0: 02 00 03 49 00 04 70 6F   72 74 4C 00 03 63 73 66  ...I..portL..csf
+00C0: 74 00 28 4C 6A 61 76 61   2F 72 6D 69 2F 73 65 72  t.(Ljava/rmi/ser
+00D0: 76 65 72 2F 52 4D 49 43   6C 69 65 6E 74 53 6F 63  ver/RMIClientSoc
+00E0: 6B 65 74 46 61 63 74 6F   72 79 3B 4C 00 03 73 73  ketFactory;L..ss
+00F0: 66 74 00 28 4C 6A 61 76   61 2F 72 6D 69 2F 73 65  ft.(Ljava/rmi/se
+0100: 72 76 65 72 2F 52 4D 49   53 65 72 76 65 72 53 6F  rver/RMIServerSo
+0110: 63 6B 65 74 46 61 63 74   6F 72 79 3B 78 72 00 1C  cketFactory;xr..
+0120: 6A 61 76 61 2E 72 6D 69   2E 73 65 72 76 65 72 2E  java.rmi.server.
+0130: 52 65 6D 6F 74 65 53 65   72 76 65 72 C7 19 07 12  RemoteServer....
+0140: 68 F3 39 FB 02 00 00 78   72 00 1C 6A 61 76 61 2E  h.9....xr..java.
+0150: 72 6D 69 2E 73 65 72 76   65 72 2E 52 65 6D 6F 74  rmi.server.Remot
+0160: 65 4F 62 6A 65 63 74 D3   61 B4 91 0C 61 33 1E 03  eObject.a...a3..
+0170: 00 00 78 70 77 12 00 10   55 6E 69 63 61 73 74 53  ..xpw...UnicastS
+0180: 65 72 76 65 72 52 65 66   78 00 00 00 00 70 70 30  erverRefx....pp0
+0190: 45 04 0B 6F 62 6A 65 63   74 43 6C 61 73 73 31 36  E..objectClass16
+01A0: 04 03 74 6F 70 04 0D 6A   61 76 61 43 6F 6E 74 61  ..top..javaConta
+01B0: 69 6E 65 72 04 0A 6A 61   76 61 4F 62 6A 65 63 74  iner..javaObject
+01C0: 04 14 6A 61 76 61 53 65   72 69 61 6C 69 7A 65 64  ..javaSerialized
+01D0: 4F 62 6A 65 63 74 30 81   E3 04 0E 6A 61 76 61 43  Object0....javaC
+01E0: 6C 61 73 73 4E 61 6D 65   73 31 81 D0 04 1B 6F 72  lassNames1....or
+01F0: 67 2E 65 78 61 6D 70 6C   65 2E 68 65 6C 6C 6F 2E  g.example.hello.
+0200: 48 65 6C 6C 6F 49 6D 70   6C 04 23 6A 61 76 61 2E  HelloImpl.#java.
+0210: 72 6D 69 2E 73 65 72 76   65 72 2E 55 6E 69 63 61  rmi.server.Unica
+0220: 73 74 52 65 6D 6F 74 65   4F 62 6A 65 63 74 04 1C  stRemoteObject..
+0230: 6A 61 76 61 2E 72 6D 69   2E 73 65 72 76 65 72 2E  java.rmi.server.
+0240: 52 65 6D 6F 74 65 53 65   72 76 65 72 04 1C 6A 61  RemoteServer..ja
+0250: 76 61 2E 72 6D 69 2E 73   65 72 76 65 72 2E 52 65  va.rmi.server.Re
+0260: 6D 6F 74 65 4F 62 6A 65   63 74 04 10 6A 61 76 61  moteObject..java
+0270: 2E 6C 61 6E 67 2E 4F 62   6A 65 63 74 04 0F 6A 61  .lang.Object..ja
+0280: 76 61 2E 72 6D 69 2E 52   65 6D 6F 74 65 04 14 6A  va.rmi.Remote..j
+0290: 61 76 61 2E 69 6F 2E 53   65 72 69 61 6C 69 7A 61  ava.io.Serializa
+02A0: 62 6C 65 04 17 6F 72 67   2E 65 78 61 6D 70 6C 65  ble..org.example
+02B0: 2E 68 65 6C 6C 6F 2E 48   65 6C 6C 6F 30 2E 04 0D  .hello.Hello0...
+02C0: 6A 61 76 61 43 6C 61 73   73 4E 61 6D 65 31 1D 04  javaClassName1..
+02D0: 1B 6F 72 67 2E 65 78 61   6D 70 6C 65 2E 68 65 6C  .org.example.hel
+02E0: 6C 6F 2E 48 65 6C 6C 6F   49 6D 70 6C 30 10 04 02  lo.HelloImpl0...
+02F0: 63 6E 31 0A 04 08 6D 79   72 65 6D 6F 74 65        cn1...myremote
+
+# LDAP SearchResultDone:
+#
+#   0   12: SEQUENCE {
+#   2    1:   INTEGER 3
+#   5    7:   [APPLICATION 5] {
+#   7    1:     ENUMERATED 0
+#  10    0:     OCTET STRING
+#  12    0:     OCTET STRING
+#         :     }
+#         :   }
+#
+0000: 30 0C 02 01 03 65 07 0A   01 00 04 00 04 00        0....e........
+
+# LDAP DeleteRequest:
+#
+#   0   68: SEQUENCE {
+#   2    1:   INTEGER 4
+#   5   34:   [APPLICATION 10] 'cn=myremote,dc=ie,dc=oracle,dc=com'
+#  41   27:   [0] {
+#  43   25:     SEQUENCE {
+#  45   23:       OCTET STRING '2.16.840.1.113730.3.4.2'
+#         :       }
+#         :     }
+#         :   }
+#
+0000: 30 44 02 01 04 4A 22 63   6E 3D 6D 79 72 65 6D 6F  0D...J"cn=myremo
+0010: 74 65 2C 64 63 3D 69 65   2C 64 63 3D 6F 72 61 63  te,dc=ie,dc=orac
+0020: 6C 65 2C 64 63 3D 63 6F   6D A0 1B 30 19 04 17 32  le,dc=com..0...2
+0030: 2E 31 36 2E 38 34 30 2E   31 2E 31 31 33 37 33 30  .16.840.1.113730
+0040: 2E 33 2E 34 2E 32                                  .3.4.2
+
+# LDAP DeleteResponse:
+#
+#   0   12: SEQUENCE {
+#   2    1:   INTEGER 4
+#   5    7:   [APPLICATION 11] {
+#   7    1:     ENUMERATED 0
+#  10    0:     OCTET STRING
+#  12    0:     OCTET STRING
+#         :     }
+#         :   }
+#
+0000: 30 0C 02 01 04 6B 07 0A   01 00 04 00 04 00        0....k........
+
+# LDAP UnbindRequest:
+#
+#   0   34: SEQUENCE {
+#   2    1:   INTEGER 5
+#   5    0:   [APPLICATION 2]
+#   7   27:   [0] {
+#   9   25:     SEQUENCE {
+#  11   23:       OCTET STRING '2.16.840.1.113730.3.4.2'
+#         :       }
+#         :     }
+#         :   }
+#
+0000: 30 22 02 01 05 42 00 A0   1B 30 19 04 17 32 2E 31  0"...B...0...2.1
+0010: 36 2E 38 34 30 2E 31 2E   31 31 33 37 33 30 2E 33  6.840.1.113730.3
+0020: 2E 34 2E 32                                        .4.2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/Stapling/TEST.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,5 @@
+modules = \
+    java.base/sun.security.provider.certpath \
+    java.base/sun.security.util \
+    java.base/sun.security.validator \
+    java.base/sun.security.x509 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/security/auth/login/modules/JaasClient.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package client;
+
+import java.io.IOException;
+import java.security.Principal;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.login.LoginException;
+import javax.security.auth.login.LoginContext;
+import com.sun.security.auth.UnixPrincipal;
+
+/**
+ * JAAS client which will try to authenticate a user through a custom JAAS LOGIN
+ * Module.
+ */
+public class JaasClient {
+
+    private static final String USER_NAME = "testUser";
+    private static final String PASSWORD = "testPassword";
+    private static final String LOGIN_CONTEXT = "ModularLoginConf";
+
+    public static void main(String[] args) {
+        try {
+            LoginContext lc = new LoginContext(LOGIN_CONTEXT,
+                    new MyCallbackHandler());
+            lc.login();
+            checkPrincipal(lc, true);
+            lc.logout();
+            checkPrincipal(lc, false);
+        } catch (LoginException le) {
+            throw new RuntimeException(le);
+        }
+        System.out.println("Test passed.");
+
+    }
+
+    /*
+     * Check context for principal of the test user.
+     */
+    private static void checkPrincipal(LoginContext loginContext,
+            boolean principalShouldExist) {
+        if (!principalShouldExist) {
+            if (loginContext.getSubject().getPrincipals().size() != 0) {
+                throw new RuntimeException("Test failed. Principal was not "
+                        + "cleared.");
+            }
+            return;
+        }
+        for (Principal p : loginContext.getSubject().getPrincipals()) {
+            if (p instanceof UnixPrincipal
+                    && USER_NAME.equals(p.getName())) {
+                //Proper principal was found, return.
+                return;
+            }
+        }
+        throw new RuntimeException("Test failed. UnixPrincipal "
+                + USER_NAME + " expected.");
+
+    }
+
+    private static class MyCallbackHandler implements CallbackHandler {
+
+        @Override
+        public void handle(Callback[] callbacks) throws IOException,
+                UnsupportedCallbackException {
+            for (Callback callback : callbacks) {
+                if (callback instanceof NameCallback) {
+                    ((NameCallback) callback).setName(USER_NAME);
+                } else if (callback instanceof PasswordCallback) {
+                    ((PasswordCallback) callback).setPassword(
+                            PASSWORD.toCharArray());
+                } else {
+                    throw new UnsupportedCallbackException(callback);
+                }
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/security/auth/login/modules/JaasModularClientTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Arrays;
+import java.io.IOException;
+import java.lang.module.ModuleDescriptor;
+import java.util.ArrayList;
+import jdk.testlibrary.ProcessTools;
+import jdk.testlibrary.OutputAnalyzer;
+import org.testng.annotations.BeforeTest;
+
+/**
+ * @test
+ * @bug 8078813
+ * @library /lib/testlibrary
+ * @library /java/security/modules
+ * @build CompilerUtils JarUtils
+ * @summary Test custom JAAS module with all possible modular option. The test
+ *          includes different combination of JAAS client/login modules
+ *          interaction with or without service description.
+ * @run testng JaasModularClientTest
+ */
+public class JaasModularClientTest extends ModularTest {
+
+    private static final Path S_SRC = SRC.resolve("TestLoginModule.java");
+    private static final String S_PKG = "login";
+    private static final String S_JAR_NAME = S_PKG + JAR_EXTN;
+    private static final String S_DESCR_JAR_NAME = S_PKG + DESCRIPTOR
+            + JAR_EXTN;
+    private static final String MS_JAR_NAME = MODULAR + S_PKG + JAR_EXTN;
+    private static final String MS_DESCR_JAR_NAME = MODULAR + S_PKG + DESCRIPTOR
+            + JAR_EXTN;
+
+    private static final Path C_SRC = SRC.resolve("JaasClient.java");
+    private static final String C_PKG = "client";
+    private static final String C_JAR_NAME = C_PKG + JAR_EXTN;
+    private static final String MC_DEPENDS_ON_AUTO_SERVICE_JAR_NAME = MODULAR
+            + C_PKG + AUTO + JAR_EXTN;
+    private static final String MC_JAR_NAME = MODULAR + C_PKG + JAR_EXTN;
+
+    private static final Path BUILD_DIR = Paths.get(".").resolve("build");
+    private static final Path COMPILE_DIR = BUILD_DIR.resolve("bin");
+    private static final Path S_BUILD_DIR = COMPILE_DIR.resolve(S_PKG);
+    private static final Path S_WITH_META_DESCR_BUILD_DIR = COMPILE_DIR.resolve(
+            S_PKG + DESCRIPTOR);
+    private static final Path C_BUILD_DIR = COMPILE_DIR.resolve(C_PKG);
+    private static final Path M_BASE_PATH = BUILD_DIR.resolve("mbase");
+    private static final Path ARTIFACTS_DIR = BUILD_DIR.resolve("artifacts");
+
+    private static final Path S_ARTIFACTS_DIR = ARTIFACTS_DIR.resolve(S_PKG);
+    private static final Path S_JAR = S_ARTIFACTS_DIR.resolve(S_JAR_NAME);
+    private static final Path S_WITH_DESCRIPTOR_JAR = S_ARTIFACTS_DIR.resolve(
+            S_DESCR_JAR_NAME);
+    private static final Path MS_JAR = S_ARTIFACTS_DIR.resolve(MS_JAR_NAME);
+    private static final Path MS_WITH_DESCR_JAR = S_ARTIFACTS_DIR.resolve(
+            MS_DESCR_JAR_NAME);
+
+    private static final Path C_ARTIFACTS_DIR = ARTIFACTS_DIR.resolve(C_PKG);
+    private static final Path C_JAR = C_ARTIFACTS_DIR.resolve(C_JAR_NAME);
+    private static final Path MC_JAR = C_ARTIFACTS_DIR.resolve(MC_JAR_NAME);
+    private static final Path MC_DEPENDS_ON_AUTO_SERVICE_JAR = C_ARTIFACTS_DIR
+            .resolve(MC_DEPENDS_ON_AUTO_SERVICE_JAR_NAME);
+
+    private static final String MAIN = C_PKG + ".JaasClient";
+    private static final String S_INTERFACE
+            = "javax.security.auth.spi.LoginModule";
+    private static final String S_IMPL = S_PKG + ".TestLoginModule";
+    private static final List<String> M_REQUIRED = Arrays.asList("java.base",
+            "jdk.security.auth");
+    private static final Path META_DESCR_PATH = Paths.get("META-INF")
+            .resolve("services").resolve(S_INTERFACE);
+    private static final Path S_META_DESCR_FPATH = S_WITH_META_DESCR_BUILD_DIR
+            .resolve(META_DESCR_PATH);
+
+    private static final boolean WITH_S_DESCR = true;
+    private static final boolean WITHOUT_S_DESCR = false;
+    private static final String LOGIN_MODULE_NOT_FOUND_MSG
+            = "No LoginModule found";
+    private static final String NO_FAILURE = null;
+    private static final Map<String, String> VM_ARGS = new LinkedHashMap<>();
+
+    /**
+     * Generates Test specific input parameters.
+     */
+    @Override
+    public Object[][] getTestInput() {
+
+        List<List<Object>> params = new ArrayList<>();
+        String[] args = new String[]{};
+        //PARAMETER ORDERS -
+        //client Module Type, Service Module Type,
+        //Service META Descriptor Required,
+        //Expected Failure message, mechanism used to find the provider
+        params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.EXPLICIT,
+                WITH_S_DESCR, NO_FAILURE, args));
+        params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.EXPLICIT,
+                WITHOUT_S_DESCR, NO_FAILURE, args));
+        params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.AUTO,
+                WITH_S_DESCR, NO_FAILURE, args));
+        params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.AUTO,
+                WITHOUT_S_DESCR, LOGIN_MODULE_NOT_FOUND_MSG, args));
+        params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.UNNAMED,
+                WITH_S_DESCR, NO_FAILURE, args));
+        params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.UNNAMED,
+                WITHOUT_S_DESCR, NO_FAILURE, args));
+
+        params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.EXPLICIT,
+                WITH_S_DESCR, NO_FAILURE, args));
+        params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.EXPLICIT,
+                WITHOUT_S_DESCR, NO_FAILURE, args));
+        params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.AUTO,
+                WITH_S_DESCR, NO_FAILURE, args));
+        params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.AUTO,
+                WITHOUT_S_DESCR, LOGIN_MODULE_NOT_FOUND_MSG, args));
+        params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.UNNAMED,
+                WITH_S_DESCR, NO_FAILURE, args));
+        params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.UNNAMED,
+                WITHOUT_S_DESCR, NO_FAILURE, args));
+
+        params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.EXPLICIT,
+                WITH_S_DESCR, NO_FAILURE, args));
+        params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.EXPLICIT,
+                WITHOUT_S_DESCR, NO_FAILURE, args));
+        params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.AUTO,
+                WITH_S_DESCR, NO_FAILURE, args));
+        params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.AUTO,
+                WITHOUT_S_DESCR, LOGIN_MODULE_NOT_FOUND_MSG, args));
+        params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.UNNAMED,
+                WITH_S_DESCR, NO_FAILURE, args));
+        params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.UNNAMED,
+                WITHOUT_S_DESCR, NO_FAILURE, args));
+        return params.stream().map(p -> p.toArray()).toArray(Object[][]::new);
+    }
+
+    /**
+     * Pre-compile and generate the artifacts required to run this test before
+     * running each test cases.
+     */
+    @BeforeTest
+    public void buildArtifacts() {
+
+        boolean done = true;
+        try {
+            VM_ARGS.put("-Duser.language=", "en");
+            VM_ARGS.put("-Duser.region", "US");
+            VM_ARGS.put("-Djava.security.auth.login.config=", SRC.resolve(
+                    "jaas.conf").toFile().getCanonicalPath());
+
+            done = CompilerUtils.compile(S_SRC, S_BUILD_DIR);
+            done &= CompilerUtils.compile(S_SRC, S_WITH_META_DESCR_BUILD_DIR);
+            done &= createMetaInfServiceDescriptor(S_META_DESCR_FPATH, S_IMPL);
+            //Generate regular/modular jars with(out) META-INF
+            //service descriptor
+            generateJar(true, MODULE_TYPE.EXPLICIT, MS_JAR, S_BUILD_DIR, false);
+            generateJar(true, MODULE_TYPE.EXPLICIT, MS_WITH_DESCR_JAR,
+                    S_WITH_META_DESCR_BUILD_DIR, false);
+            generateJar(true, MODULE_TYPE.UNNAMED, S_JAR, S_BUILD_DIR, false);
+            generateJar(true, MODULE_TYPE.UNNAMED, S_WITH_DESCRIPTOR_JAR,
+                    S_WITH_META_DESCR_BUILD_DIR, false);
+            //Generate regular/modular(depends on explicit/auto service)
+            //jars for client
+            done &= CompilerUtils.compile(C_SRC, C_BUILD_DIR);
+            generateJar(false, MODULE_TYPE.EXPLICIT, MC_JAR, C_BUILD_DIR, true);
+            generateJar(false, MODULE_TYPE.EXPLICIT,
+                    MC_DEPENDS_ON_AUTO_SERVICE_JAR, C_BUILD_DIR, false);
+            generateJar(false, MODULE_TYPE.UNNAMED, C_JAR, C_BUILD_DIR, false);
+            System.out.format("%nArtifacts generated successfully? %s", done);
+            if (!done) {
+                throw new RuntimeException("Artifact generation failed");
+            }
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Generate modular/regular jar based on module type for this test.
+     */
+    private void generateJar(boolean isService, MODULE_TYPE moduleType,
+            Path jar, Path compilePath, boolean depends) throws IOException {
+
+        ModuleDescriptor mDescriptor = null;
+        if (isService) {
+            mDescriptor = generateModuleDescriptor(isService, moduleType, S_PKG,
+                    S_PKG, S_INTERFACE, S_IMPL, null, M_REQUIRED, depends);
+        } else {
+            mDescriptor = generateModuleDescriptor(isService, moduleType, C_PKG,
+                    C_PKG, S_INTERFACE, null, S_PKG, M_REQUIRED, depends);
+        }
+        generateJar(mDescriptor, jar, compilePath);
+    }
+
+    /**
+     * Holds Logic for the test client. This method will get called with each
+     * test parameter.
+     */
+    @Override
+    public OutputAnalyzer executeTestClient(MODULE_TYPE cModuleType,
+            Path cJarPath, MODULE_TYPE sModuletype, Path sJarPath,
+            String... args) throws Exception {
+
+        OutputAnalyzer output = null;
+        try {
+            //For automated/explicit module type copy the corresponding
+            //jars to module base folder, which will be considered as
+            //module base path during execution.
+            if (!(cModuleType == MODULE_TYPE.UNNAMED
+                    && sModuletype == MODULE_TYPE.UNNAMED)) {
+                copyJarsToModuleBase(cModuleType, cJarPath, M_BASE_PATH);
+                copyJarsToModuleBase(sModuletype, sJarPath, M_BASE_PATH);
+            }
+
+            System.out.format("%nExecuting java client with required"
+                    + " custom service in class/module path.");
+            String mName = getModuleName(cModuleType, cJarPath,
+                    C_PKG);
+            Path cmBasePath = (cModuleType != MODULE_TYPE.UNNAMED
+                    || sModuletype != MODULE_TYPE.UNNAMED) ? M_BASE_PATH : null;
+            String cPath = buildClassPath(cModuleType, cJarPath, sModuletype,
+                    sJarPath);
+            output = ProcessTools.executeTestJava(
+                    getJavaCommand(cmBasePath, cPath, mName, MAIN, VM_ARGS,
+                            args)).outputTo(System.out).errorTo(System.out);
+        } finally {
+            //clean module path so that the modulepath can hold only
+            //the required jars for next run.
+            cleanModuleBasePath(M_BASE_PATH);
+            System.out.println("--------------------------------------------");
+        }
+        return output;
+    }
+
+    /**
+     * Decide the pre-generated client/service jar path for each test case
+     * based on client/service module type.
+     */
+    @Override
+    public Path findJarPath(boolean service, MODULE_TYPE moduleType,
+            boolean addMetaDesc, boolean dependsOnServiceModule) {
+        if (service) {
+            if (moduleType == MODULE_TYPE.EXPLICIT) {
+                if (addMetaDesc) {
+                    return MS_WITH_DESCR_JAR;
+                } else {
+                    return MS_JAR;
+                }
+            } else {
+                if (addMetaDesc) {
+                    return S_WITH_DESCRIPTOR_JAR;
+                } else {
+                    return S_JAR;
+                }
+            }
+        } else {
+            if (moduleType == MODULE_TYPE.EXPLICIT) {
+                if (dependsOnServiceModule) {
+                    return MC_JAR;
+                } else {
+                    return MC_DEPENDS_ON_AUTO_SERVICE_JAR;
+                }
+            } else {
+                return C_JAR;
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/security/auth/login/modules/TEST.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,1 @@
+modules java.base/jdk.internal.module
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/security/auth/login/modules/TestLoginModule.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package login;
+
+import java.io.IOException;
+import java.util.Map;
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.login.LoginException;
+import javax.security.auth.spi.LoginModule;
+import com.sun.security.auth.UnixPrincipal;
+
+/**
+ * Custom JAAS login module which will be loaded through Java LoginContext when
+ * it is bundled by Strict/Auto/Unnamed modules.
+ */
+public class TestLoginModule implements LoginModule {
+
+    private static final String USER_NAME = "testUser";
+    private static final String PASSWORD = "testPassword";
+    private Subject subject;
+    private CallbackHandler callbackHandler;
+    private UnixPrincipal userPrincipal;
+    private String username;
+    private String password;
+    private boolean succeeded = false;
+    private boolean commitSucceeded = false;
+
+    @Override
+    public void initialize(Subject subject, CallbackHandler callbackHandler,
+            Map<String, ?> sharedState, Map<String, ?> options) {
+
+        this.subject = subject;
+        this.callbackHandler = callbackHandler;
+        System.out.println(String.format(
+                "'%s' login module initialized", this.getClass()));
+    }
+
+    /*
+     * Authenticate the user by prompting for a username and password.
+     */
+    @Override
+    public boolean login() throws LoginException {
+        if (callbackHandler == null) {
+            throw new LoginException("No CallbackHandler available");
+        }
+
+        Callback[] callbacks = new Callback[2];
+        callbacks[0] = new NameCallback("Username: ");
+        callbacks[1] = new PasswordCallback("Password: ", false);
+
+        try {
+            callbackHandler.handle(callbacks);
+            username = ((NameCallback) callbacks[0]).getName();
+            password = new String(((PasswordCallback) callbacks[1])
+                    .getPassword());
+            System.out.println(String.format("'%s' login module found username"
+                    + " as '%s' and password as '%s'", this.getClass(),
+                    username, password));
+            if (username.equals(USER_NAME)
+                    && password.equals(PASSWORD)) {
+                System.out.println(String.format("'%s' login module "
+                        + "authentication done successfully", this.getClass()));
+                succeeded = true;
+                return true;
+            }
+            throw new IllegalArgumentException("Incorrect username/password!");
+        } catch (IOException | UnsupportedCallbackException e) {
+            throw new LoginException("Login failed: " + e.getMessage());
+        }
+    }
+
+    @Override
+    public boolean commit() throws LoginException {
+        if (succeeded == false) {
+            return false;
+        }
+        userPrincipal = new UnixPrincipal(username);
+        if (!subject.getPrincipals().contains(userPrincipal)) {
+            subject.getPrincipals().add(userPrincipal);
+        }
+        System.out.println(String.format("'%s' login module authentication "
+                + "committed", this.getClass()));
+        password = null;
+        commitSucceeded = true;
+        return true;
+    }
+
+    @Override
+    public boolean abort() throws LoginException {
+        if (succeeded == false) {
+            return false;
+        }
+        System.out.println(String.format(
+                "'%s' login module aborted", this.getClass()));
+        clearState();
+        return true;
+    }
+
+    @Override
+    public boolean logout() throws LoginException {
+        clearState();
+        System.out.println(String.format(
+                "'%s' login module logout completed", this.getClass()));
+        return true;
+    }
+
+    private void clearState() {
+        if (commitSucceeded) {
+            subject.getPrincipals().remove(userPrincipal);
+        }
+        username = null;
+        password = null;
+        userPrincipal = null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/security/auth/login/modules/jaas.conf	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,3 @@
+ModularLoginConf {
+    login.TestLoginModule required;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/swing/JComboBox/8080972/TestBasicComboBoxEditor.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import javax.swing.JTextField;
+import javax.swing.SwingUtilities;
+import javax.swing.plaf.basic.BasicComboBoxEditor;
+/*
+ * @test
+ * @bug 8080972
+ * @summary Audit Core Reflection in module java.desktop for places that will
+ *          require changes to work with modules
+ * @author Alexander Scherbatiy
+ */
+
+public class TestBasicComboBoxEditor {
+
+    public static void main(String[] args) throws Exception {
+        SwingUtilities.invokeAndWait(TestBasicComboBoxEditor::testBasicComboBoxEditor);
+        System.setSecurityManager(new SecurityManager());
+        SwingUtilities.invokeAndWait(TestBasicComboBoxEditor::testBasicComboBoxEditor);
+    }
+
+    private static void testBasicComboBoxEditor() {
+
+        BasicComboBoxEditor comboBoxEditor = new BasicComboBoxEditor();
+        comboBoxEditor.setItem(new UserComboBoxEditorType("100"));
+
+        JTextField editor = (JTextField) comboBoxEditor.getEditorComponent();
+        editor.setText("200");
+        UserComboBoxEditorType item = (UserComboBoxEditorType) comboBoxEditor.getItem();
+
+        if (!item.str.equals("200")) {
+            throw new RuntimeException("Wrong itme value!");
+        }
+    }
+
+    public static class UserComboBoxEditorType {
+
+        String str;
+
+        public UserComboBoxEditorType(String str) {
+            this.str = str;
+        }
+
+        public static UserComboBoxEditorType valueOf(String str) {
+            return new UserComboBoxEditorType(str);
+        }
+
+        @Override
+        public String toString() {
+            return "UserComboBoxEditorType: " + str;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/swing/JEditorPane/8080972/TestJEditor.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+import javax.swing.Action;
+import javax.swing.JEditorPane;
+import javax.swing.SwingUtilities;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Caret;
+import javax.swing.text.Document;
+import javax.swing.text.EditorKit;
+import javax.swing.text.ViewFactory;
+
+/*
+ * @test
+ * @bug 8080972
+ * @summary Audit Core Reflection in module java.desktop for places that will
+ *          require changes to work with modules
+ * @author Alexander Scherbatiy
+ */
+public class TestJEditor {
+
+    public static void main(String[] args) throws Exception {
+
+        SwingUtilities.invokeAndWait(TestJEditor::testJEditorPane);
+        System.setSecurityManager(new SecurityManager());
+        SwingUtilities.invokeAndWait(TestJEditor::testJEditorPane);
+    }
+
+    private static void testJEditorPane() {
+
+        try {
+
+            JEditorPane.registerEditorKitForContentType("text/html", UserEditorKit.class.getName());
+            EditorKit editorKit = JEditorPane.createEditorKitForContentType("text/html");
+
+            if (!(editorKit instanceof UserEditorKit)) {
+                throw new RuntimeException("Editor kit is not UserEditorKit!");
+            }
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static class UserEditorKit extends EditorKit {
+
+        @Override
+        public String getContentType() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public ViewFactory getViewFactory() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public Action[] getActions() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public Caret createCaret() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public Document createDefaultDocument() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public void read(InputStream in, Document doc, int pos) throws IOException, BadLocationException {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public void write(OutputStream out, Document doc, int pos, int len) throws IOException, BadLocationException {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public void read(Reader in, Document doc, int pos) throws IOException, BadLocationException {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public void write(Writer out, Document doc, int pos, int len) throws IOException, BadLocationException {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/swing/JFormattedTextField/8080972/TestDefaultFormatter.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.text.ParseException;
+import javax.swing.SwingUtilities;
+import javax.swing.text.DefaultFormatter;
+/*
+ * @test
+ * @bug 8080972
+ * @summary Audit Core Reflection in module java.desktop for places that will
+ *          require changes to work with modules
+ * @author Alexander Scherbatiy
+ */
+
+public class TestDefaultFormatter {
+
+    public static void main(String[] args) throws Exception {
+        SwingUtilities.invokeAndWait(TestDefaultFormatter::testDefaultFormatter);
+        System.setSecurityManager(new SecurityManager());
+        SwingUtilities.invokeAndWait(TestDefaultFormatter::testDefaultFormatter);
+    }
+    private static void testDefaultFormatter() {
+        testDefaultFormatter(new DefaultFormatter() {
+        });
+        testDefaultFormatter(new DefaultFormatter());
+    }
+
+    private static void testDefaultFormatter(DefaultFormatter formatter ) {
+        try {
+            System.out.println("formatter: " + formatter.getClass());
+            formatter.setValueClass(UserValueClass.class);
+            UserValueClass userValue = (UserValueClass) formatter.stringToValue("test");
+
+            if (!userValue.str.equals("test")) {
+                throw new RuntimeException("String value is wrong!");
+            }
+        } catch (ParseException ex) {
+            throw new RuntimeException(ex);
+        }
+
+    }
+
+    public static class UserValueClass {
+
+        String str;
+
+        public UserValueClass(String str) {
+            this.str = str;
+        }
+
+        @Override
+        public String toString() {
+            return "UserValueClass: " + str;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/swing/JTable/8080972/TestJTableCellEditor.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import javax.swing.JTable;
+import javax.swing.SwingUtilities;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.TableCellEditor;
+/*
+ * @test
+ * @bug 8080972
+ * @summary Audit Core Reflection in module java.desktop for places that will
+ *          require changes to work with modules
+ * @author Alexander Scherbatiy
+ */
+
+public class TestJTableCellEditor {
+
+    public static void main(String[] args) throws Exception {
+        SwingUtilities.invokeAndWait(TestJTableCellEditor::testJTableCellEditor);
+        System.setSecurityManager(new SecurityManager());
+        SwingUtilities.invokeAndWait(TestJTableCellEditor::testJTableCellEditor);
+    }
+
+    private static void testJTableCellEditor() {
+
+        final Class cls = UserEditor.class;
+
+        JTable table = new JTable(new AbstractTableModel() {
+            public int getRowCount() {
+                return 0;
+            }
+
+            public int getColumnCount() {
+                return 1;
+            }
+
+            public Object getValueAt(int r, int c) {
+                return "Some Value";
+            }
+
+            public Class getColumnClass(int c) {
+                return cls;
+            }
+        });
+
+        TableCellEditor editor = table.getDefaultEditor(Object.class);
+        editor.getTableCellEditorComponent(table,
+                UserEditor.TEST_VALUE, false, 0, 0);
+        editor.stopCellEditing();
+        Object obj = editor.getCellEditorValue();
+
+        if (obj == null) {
+            throw new RuntimeException("Editor object is null!");
+        }
+
+        if (!UserEditor.TEST_VALUE.equals(((UserEditor) obj).value)) {
+            throw new RuntimeException("Value is incorrect!");
+        }
+    }
+
+    public static class UserEditor {
+
+        private static final String TEST_VALUE = "Test Value";
+
+        private final String value;
+
+        public UserEditor(String value) {
+            this.value = value;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/swing/UIDefaults/8080972/TestProxyLazyValue.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import javax.swing.SwingUtilities;
+import javax.swing.UIDefaults;
+/*
+ * @test
+ * @bug 8080972
+ * @summary Audit Core Reflection in module java.desktop for places that will
+ *          require changes to work with modules
+ * @author Alexander Scherbatiy
+ */
+
+public class TestProxyLazyValue {
+
+    public static void main(String[] args) throws Exception {
+        SwingUtilities.invokeAndWait(TestProxyLazyValue::testUserProxyLazyValue);
+        SwingUtilities.invokeAndWait(TestProxyLazyValue::testProxyLazyValue);
+        System.setSecurityManager(new SecurityManager());
+        SwingUtilities.invokeAndWait(TestProxyLazyValue::testUserProxyLazyValue);
+        SwingUtilities.invokeAndWait(TestProxyLazyValue::testProxyLazyValue);
+    }
+
+    private static void testUserProxyLazyValue() {
+
+        Object obj = new UserProxyLazyValue(
+                UserLazyClass.class.getName()).createValue(null);
+
+        if (!(obj instanceof UserLazyClass)) {
+            throw new RuntimeException("Object is not UserLazyClass!");
+        }
+
+        obj = new UserProxyLazyValue(UserLazyClass.class.getName(),
+                new Object[]{UserLazyClass.CONSTRUCTOR_ARG}).createValue(null);
+
+        if (!(obj instanceof UserLazyClass)) {
+            throw new RuntimeException("Object is not UserLazyClass!");
+        }
+
+        if (((UserLazyClass) obj).arg != UserLazyClass.CONSTRUCTOR_ARG) {
+            throw new RuntimeException("Constructt argument is wrong!");
+        }
+
+        obj = new UserProxyLazyValue(UserLazyClass.class.getName(),
+                "method1").createValue(null);
+
+        if (!UserLazyClass.RESULT_1.equals(obj)) {
+            throw new RuntimeException("Result is wrong!");
+        }
+
+        obj = new UserProxyLazyValue(UserLazyClass.class.getName(),
+                "method2", new Object[]{UserLazyClass.RESULT_2}).createValue(null);
+
+        if (!UserLazyClass.RESULT_2.equals(obj)) {
+            throw new RuntimeException("Result is wrong!");
+        }
+    }
+
+    private static void testProxyLazyValue() {
+
+        Object obj = new UIDefaults.ProxyLazyValue(
+                UserLazyClass.class.getName()).createValue(null);
+
+        if (!(obj instanceof UserLazyClass)) {
+            throw new RuntimeException("Object is not UserLazyClass!");
+        }
+
+        obj = new UIDefaults.ProxyLazyValue(UserLazyClass.class.getName(),
+                new Object[]{UserLazyClass.CONSTRUCTOR_ARG}).createValue(null);
+
+        if (!(obj instanceof UserLazyClass)) {
+            throw new RuntimeException("Object is not UserLazyClass!");
+        }
+
+        if (((UserLazyClass) obj).arg != UserLazyClass.CONSTRUCTOR_ARG) {
+            throw new RuntimeException("Constructt argument is wrong!");
+        }
+
+        obj = new UIDefaults.ProxyLazyValue(UserLazyClass.class.getName(),
+                "method1").createValue(null);
+
+        if (!UserLazyClass.RESULT_1.equals(obj)) {
+            throw new RuntimeException("Result is wrong!");
+        }
+
+        obj = new UIDefaults.ProxyLazyValue(UserLazyClass.class.getName(),
+                "method2", new Object[]{UserLazyClass.RESULT_2}).createValue(null);
+
+        if (!UserLazyClass.RESULT_2.equals(obj)) {
+            throw new RuntimeException("Result is wrong!");
+        }
+    }
+
+    public static class UserLazyClass {
+
+        static final int CONSTRUCTOR_ARG = 100;
+        static final String RESULT_1 = "1";
+        static final String RESULT_2 = "2";
+
+        int arg;
+
+        public UserLazyClass() {
+        }
+
+        public UserLazyClass(int arg) {
+            this.arg = arg;
+        }
+
+        public static String method1() {
+            return RESULT_1;
+        }
+
+        public static String method2(String arg) {
+            return arg;
+        }
+    }
+
+    public static class UserProxyLazyValue extends UIDefaults.ProxyLazyValue {
+
+        public UserProxyLazyValue(String className) {
+            super(className);
+        }
+
+        public UserProxyLazyValue(String className, Object[] constructorArgs) {
+            super(className, constructorArgs);
+        }
+
+        public UserProxyLazyValue(String className, String methodName) {
+            super(className, methodName);
+        }
+
+        public UserProxyLazyValue(String className, String methodName,
+                Object[] methodArgs) {
+            super(className, methodName, methodArgs);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/swing/dnd/8080972/TestTransferHandler.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.awt.Color;
+import javax.swing.JComponent;
+import javax.swing.SwingUtilities;
+import javax.swing.TransferHandler;
+import java.awt.datatransfer.*;
+/*
+ * @test
+ * @bug 8080972
+ * @summary Audit Core Reflection in module java.desktop for places that will
+ *          require changes to work with modules
+ * @author Alexander Scherbatiy
+ */
+
+public class TestTransferHandler {
+
+    public static void main(String[] args) throws Exception {
+        SwingUtilities.invokeAndWait(TestTransferHandler::testTransferHandler);
+        System.setSecurityManager(new SecurityManager());
+        SwingUtilities.invokeAndWait(TestTransferHandler::testTransferHandler);
+    }
+
+    private static void testTransferHandler() {
+        try {
+            TransferHandler transferHandler = new TransferHandler("userColor");
+            UserJComponent comp = new UserJComponent();
+
+            final String colorType = DataFlavor.javaJVMLocalObjectMimeType
+                    + ";class=java.awt.Color";
+            final DataFlavor colorFlavor = new DataFlavor(colorType);
+
+            Transferable transferable = new Transferable() {
+
+                public DataFlavor[] getTransferDataFlavors() {
+                    return new DataFlavor[]{colorFlavor};
+
+                }
+
+                public boolean isDataFlavorSupported(DataFlavor flavor) {
+                    return true;
+                }
+
+                public Object getTransferData(DataFlavor flavor) {
+                    return UserJComponent.TEST_COLOR;
+                }
+
+            };
+
+            transferHandler.importData(comp, transferable);
+
+            if (!UserJComponent.TEST_COLOR.equals(comp.color)) {
+                throw new RuntimeException("Wrong color!");
+            }
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static class UserJComponent extends JComponent {
+
+        public static final Color USER_COLOR = new Color(10, 20, 30);
+        public static final Color TEST_COLOR = new Color(15, 25, 35);
+
+        Color color = USER_COLOR;
+
+        public UserJComponent() {
+
+        }
+
+        public Color getUserColor() {
+            return color;
+        }
+
+        public void setUserColor(Color color) {
+            this.color = color;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/swing/plaf/nimbus/8080972/TestAbstractRegionPainter.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.awt.Color;
+import java.awt.Graphics2D;
+import javax.swing.JComponent;
+import javax.swing.SwingUtilities;
+import javax.swing.plaf.nimbus.AbstractRegionPainter;
+/*
+ * @test
+ * @bug 8080972
+ * @summary Audit Core Reflection in module java.desktop for places that will
+ *          require changes to work with modules
+ * @author Alexander Scherbatiy
+ */
+
+public class TestAbstractRegionPainter {
+
+    public static void main(String[] args) throws Exception {
+        SwingUtilities.invokeAndWait(TestAbstractRegionPainter::testAbstractRegionPainter);
+        System.setSecurityManager(new SecurityManager());
+        SwingUtilities.invokeAndWait(TestAbstractRegionPainter::testAbstractRegionPainter);
+    }
+
+    private static void testAbstractRegionPainter() {
+        UserAbstractRegionPainter painter = new UserAbstractRegionPainter();
+
+        JComponent userComponent = new UserJComponent();
+
+        Color color = painter.getUserComponentColor(userComponent, "UserColor",
+                Color.yellow, 0, 0, 0);
+
+        if (!UserJComponent.USER_COLOR.equals(color)) {
+            throw new RuntimeException("Wrong color: " + color);
+        }
+    }
+
+    public static class UserJComponent extends JComponent {
+
+        public static final Color USER_COLOR = new Color(10, 20, 30);
+        public static final Color TEST_COLOR = new Color(15, 25, 35);
+
+        Color color = USER_COLOR;
+
+        public UserJComponent() {
+
+        }
+
+        public Color getUserColor() {
+            return color;
+        }
+
+        public void setUserColor(Color color) {
+            this.color = color;
+        }
+    }
+
+    public static class UserAbstractRegionPainter extends AbstractRegionPainter {
+
+        public Color getUserComponentColor(JComponent c, String property,
+                Color defaultColor,
+                float saturationOffset,
+                float brightnessOffset,
+                int alphaOffset) {
+            return getComponentColor(c, property, defaultColor, saturationOffset, brightnessOffset, alphaOffset);
+        }
+
+        @Override
+        protected AbstractRegionPainter.PaintContext getPaintContext() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        protected void doPaint(Graphics2D g, JComponent c, int width, int height, Object[] extendedCacheKeys) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/swing/text/View/8080972/TestObjectView.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.awt.Color;
+import java.awt.Component;
+import java.util.Enumeration;
+import javax.swing.JComponent;
+import javax.swing.SwingUtilities;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.Document;
+import javax.swing.text.Element;
+import javax.swing.text.html.HTML;
+import javax.swing.text.html.ObjectView;
+/*
+ * @test
+ * @bug 8080972
+ * @summary Audit Core Reflection in module java.desktop for places that will
+ *          require changes to work with modules
+ * @author Alexander Scherbatiy
+ */
+
+public class TestObjectView {
+
+    public static void main(String[] args) throws Exception {
+        SwingUtilities.invokeAndWait(TestObjectView::testObjectView);
+        System.setSecurityManager(new SecurityManager());
+        SwingUtilities.invokeAndWait(TestObjectView::testObjectView);
+    }
+
+    private static void testObjectView() {
+
+        UserObjectView objectView = new UserObjectView(new UserElement());
+
+        Component comp = objectView.createComponent();
+
+        if (!(comp instanceof UserJComponent)) {
+            throw new RuntimeException("Component is not UserJComponent!");
+        }
+    }
+    public static class UserJComponent extends JComponent {
+
+        public static final Color USER_COLOR = new Color(10, 20, 30);
+        public static final Color TEST_COLOR = new Color(15, 25, 35);
+
+        Color color = USER_COLOR;
+
+        public UserJComponent() {
+
+        }
+
+        public Color getUserColor() {
+            System.out.println("[user component] get user color");
+            return color;
+        }
+
+        public void setUserColor(Color color) {
+            System.out.println("[user component] set user color");
+            this.color = color;
+        }
+
+    }
+
+    public static class UserObjectView extends ObjectView {
+
+        public UserObjectView(Element elem) {
+            super(elem);
+        }
+
+        @Override
+        public Component createComponent() {
+            return super.createComponent();
+        }
+    }
+
+    public static class UserElement implements Element {
+
+        @Override
+        public Document getDocument() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public Element getParentElement() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public String getName() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public AttributeSet getAttributes() {
+            return new AttributeSet() {
+
+                @Override
+                public int getAttributeCount() {
+                    throw new UnsupportedOperationException("Not supported yet.");
+                }
+
+                @Override
+                public boolean isDefined(Object attrName) {
+                    throw new UnsupportedOperationException("Not supported yet.");
+                }
+
+                @Override
+                public boolean isEqual(AttributeSet attr) {
+                    throw new UnsupportedOperationException("Not supported yet.");
+                }
+
+                @Override
+                public AttributeSet copyAttributes() {
+                    throw new UnsupportedOperationException("Not supported yet.");
+                }
+
+                @Override
+                public Object getAttribute(Object key) {
+                    if (key.equals(HTML.Attribute.CLASSID)) {
+                        return UserJComponent.class.getName();
+                    }
+
+                    return null;
+                }
+
+                @Override
+                public Enumeration<?> getAttributeNames() {
+                    throw new UnsupportedOperationException("Not supported yet.");
+                }
+
+                @Override
+                public boolean containsAttribute(Object name, Object value) {
+                    throw new UnsupportedOperationException("Not supported yet.");
+                }
+
+                @Override
+                public boolean containsAttributes(AttributeSet attributes) {
+                    throw new UnsupportedOperationException("Not supported yet.");
+                }
+
+                @Override
+                public AttributeSet getResolveParent() {
+                    throw new UnsupportedOperationException("Not supported yet.");
+                }
+            };
+        }
+
+        @Override
+        public int getStartOffset() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public int getEndOffset() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public int getElementIndex(int offset) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public int getElementCount() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public Element getElement(int index) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public boolean isLeaf() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+    }
+}
--- a/test/javax/xml/jaxp/Encodings/CheckEncodingPropertiesFile.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/javax/xml/jaxp/Encodings/CheckEncodingPropertiesFile.java	Thu Mar 17 19:04:16 2016 +0000
@@ -39,6 +39,7 @@
 import com.sun.org.apache.xml.internal.serializer.EncodingInfo;
 import com.sun.org.apache.xml.internal.serializer.Encodings;
 import java.io.InputStreamReader;
+import java.lang.reflect.Module;
 import java.lang.reflect.Method;
 import java.nio.charset.Charset;
 import java.util.ArrayList;
@@ -61,7 +62,8 @@
 
     public static void main(String[] args) throws Exception {
         Properties props = new Properties();
-        try (InputStreamReader is = new InputStreamReader(ClassLoader.getSystemResourceAsStream(ENCODINGS_FILE))) {
+        Module xmlModule = EncodingInfo.class.getModule();
+        try (InputStreamReader is = new InputStreamReader(xmlModule.getResourceAsStream(ENCODINGS_FILE))) {
             props.load(is);
         }
 
@@ -71,7 +73,7 @@
            // Check that the content of the Encodings.properties included in
            // the tested build image matches the content of the file in the source
            // jaxp tree of the jdk forest.
-           throw new RuntimeException("UTF8 key missing in " + ClassLoader.getSystemResource(ENCODINGS_FILE));
+           throw new RuntimeException("UTF8 key missing in " + ENCODINGS_FILE);
        }
 
         //printAllCharsets();
--- a/test/javax/xml/jaxp/common/8035437/run.sh	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/javax/xml/jaxp/common/8035437/run.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -28,17 +28,18 @@
 # @summary Tests that java.lang.AbstractMethodError is not thrown when
 #    serializing improper version of DocumentImpl class.
 
-mkdir -p exec compile
+mkdir -p exec/java.xml compile/java.xml
 
 $COMPILEJAVA/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \
-   -d compile $TESTSRC/Document.java $TESTSRC/Node.java || exit 1
+   -d compile/java.xml -Xmodule:java.xml $TESTSRC/Document.java $TESTSRC/Node.java || exit 1
 
 $COMPILEJAVA/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \
-   -Xbootclasspath/p:compile -d exec $TESTSRC/DocumentImpl.java || exit 1
+   -d exec/java.xml -Xpatch:compile -Xmodule:java.xml $TESTSRC/DocumentImpl.java || exit 2
 
 $COMPILEJAVA/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \
-   $TESTSRC/AbstractMethodErrorTest.java -d exec || exit 1
+   $TESTSRC/AbstractMethodErrorTest.java -d exec || exit 3
 
-$TESTJAVA/bin/java ${TESTVMOPTS} -Xbootclasspath/p:exec -cp exec AbstractMethodErrorTest || exit 1
+$TESTJAVA/bin/java ${TESTVMOPTS} -Xpatch:exec -cp exec AbstractMethodErrorTest || exit 4
 
 exit 0
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/xml/soap/XmlTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import javax.xml.soap.AttachmentPart;
+import javax.xml.soap.MessageFactory;
+import javax.xml.soap.Name;
+import javax.xml.soap.SOAPEnvelope;
+import javax.xml.soap.SOAPException;
+import javax.xml.soap.SOAPMessage;
+import javax.xml.transform.stream.StreamSource;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Iterator;
+
+/*
+ * @test
+ * @summary tests JAF DataHandler can be instantiated; test serialize and
+ *   deserialize SOAP message containing xml attachment
+ */
+public class XmlTest {
+
+    public void test() throws Exception {
+
+        File file = new File("message.xml");
+        file.deleteOnExit();
+
+        MessageFactory mf = MessageFactory.newInstance();
+        SOAPMessage msg = createMessage(mf);
+
+        // Save the soap message to file
+        try (FileOutputStream sentFile = new FileOutputStream(file)) {
+            msg.writeTo(sentFile);
+        }
+
+        // See if we get the image object back
+        try (FileInputStream fin = new FileInputStream(file)) {
+            SOAPMessage newMsg = mf.createMessage(msg.getMimeHeaders(), fin);
+
+            newMsg.writeTo(new ByteArrayOutputStream());
+
+            Iterator<?> i = newMsg.getAttachments();
+            while (i.hasNext()) {
+                AttachmentPart att = (AttachmentPart) i.next();
+                Object obj = att.getContent();
+                if (!(obj instanceof StreamSource)) {
+                    fail("Got incorrect attachment type [" + obj.getClass() + "], " +
+                         "expected [javax.xml.transform.stream.StreamSource]");
+                }
+            }
+        }
+
+    }
+
+    private SOAPMessage createMessage(MessageFactory mf) throws SOAPException, IOException {
+        SOAPMessage msg = mf.createMessage();
+        SOAPEnvelope envelope = msg.getSOAPPart().getEnvelope();
+        Name name = envelope.createName("hello", "ex", "http://example.com");
+        envelope.getBody().addChildElement(name).addTextNode("THERE!");
+
+        String s = "<root><hello>THERE!</hello></root>";
+
+        AttachmentPart ap = msg.createAttachmentPart(
+                new StreamSource(new ByteArrayInputStream(s.getBytes())),
+                "text/xml"
+        );
+        msg.addAttachmentPart(ap);
+        msg.saveChanges();
+
+        return msg;
+    }
+
+    private void fail(String s) {
+        throw new RuntimeException(s);
+    }
+
+    public static void main(String[] args) throws Exception {
+        new XmlTest().test();
+    }
+
+}
--- a/test/jdk/asm/AsmSanity.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/jdk/asm/AsmSanity.java	Thu Mar 17 19:04:16 2016 +0000
@@ -32,7 +32,7 @@
  * - Verify that if user code is compiled without ct.sym, it can't access asm classes
  *   at runtime when a security manager is in use.
  *
- * @compile/fail AsmSanity.java
+ * @modules java.base/jdk.internal.org.objectweb.asm
  *
  * @compile -XDignore.symbol.file=true AsmSanity.java
  * @run main/othervm AsmSanity
@@ -44,11 +44,6 @@
 
 // Verify that the expected asm pkgs are present
 import jdk.internal.org.objectweb.asm.*;
-import jdk.internal.org.objectweb.asm.commons.*;
-import jdk.internal.org.objectweb.asm.signature.*;
-import jdk.internal.org.objectweb.asm.tree.*;
-import jdk.internal.org.objectweb.asm.tree.analysis.*;
-import jdk.internal.org.objectweb.asm.util.*;
 
 // Verify that we can actually run some of the asm code.
 public class AsmSanity {
--- a/test/jdk/internal/jimage/ExecutableTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2015 SAP SE. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-import java.nio.file.DirectoryStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.attribute.PosixFilePermission;
-import static java.nio.file.attribute.PosixFilePermission.*;
-import java.util.Arrays;
-import java.util.EnumSet;
-import java.util.HashSet;
-import java.util.Set;
-
-/*
- * @test
- * @bug 8132475
- * @summary Check that the executables in the current JDK image
- *          are executable by all users.
- * @run main ExecutableTest
- * @author Volker Simonis
- */
-
-public class ExecutableTest {
-
-    // The bin/ directory may contain non-executable files (see 8132704)
-    private static final String[] exclude = { "jmc.ini" };
-    private static final Set<String> excludeSet =
-        new HashSet<String>(Arrays.asList(exclude));
-
-    public static void main(String args[]) throws Throwable {
-        String JAVA_HOME = System.getProperty("java.home");
-        Path binPath = Paths.get(JAVA_HOME, "bin");
-        DirectoryStream<Path> stream = Files.newDirectoryStream(binPath);
-        EnumSet<PosixFilePermission> execPerms =
-            EnumSet.of(GROUP_EXECUTE, OTHERS_EXECUTE, OWNER_EXECUTE);
-        for (Path entry : stream) {
-            if (excludeSet.contains(entry.getFileName().toString())) continue;
-            if (Files.isRegularFile(entry)) {
-                if (!Files.isExecutable(entry)) {
-                    throw new Error(entry + " is not executable!");
-                }
-                try {
-                    Set<PosixFilePermission> perm = Files.getPosixFilePermissions(entry);
-                    if (!perm.containsAll(execPerms)) {
-                        throw new Error(entry + " has not all executable permissions!\n" +
-                                        "Should have: " + execPerms + "\nbut has: " + perm);
-                    }
-                } catch (UnsupportedOperationException e) {}
-            }
-        }
-    }
-}
--- a/test/jdk/internal/jimage/JImageReadTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/jdk/internal/jimage/JImageReadTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -23,20 +23,23 @@
 
 /*
  * @test
+ * @summary Unit test for libjimage JIMAGE_Open/Read/Close
  * @modules java.base/jdk.internal.jimage
- * @run testng JImageReadTest
- * @summary Unit test for libjimage JIMAGE_Open/Read/Close
  */
 
 import java.io.File;
-import java.io.FileOutputStream;
 import java.io.FileWriter;
 import java.io.IOException;
 import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.Arrays;
 
 import jdk.internal.jimage.BasicImageReader;
-import jdk.internal.jimage.ImageNativeSubstrate;
+import jdk.internal.jimage.ImageReader;
+import jdk.internal.jimage.ImageLocation;
 
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Optional;
@@ -49,9 +52,7 @@
 public class JImageReadTest {
 
     static String javaHome = System.getProperty("java.home");
-    static String imageFile = javaHome + File.separator + "lib"
-            + File.separator + "modules" + File.separator
-            + "bootmodules.jimage";
+    static Path imageFile = Paths.get(javaHome, "lib", "modules");
 
     @DataProvider(name="classes")
     static Object[][] loadClasses() {
@@ -66,16 +67,6 @@
         };
     }
 
-
-    @DataProvider(name="packages")
-    static Object[][] loadPackages() {
-        return new Object[][] {
-                {"java.base", "java/lang"},
-                {"java.base", "java/io"},
-                {"java.logging", "java/util/logging"},
-        };
-    }
-
     /**
      * Test a class is correctly accessible from the image in a module.
      *
@@ -86,60 +77,46 @@
     @Test(dataProvider="classes")
     public static void test1_ReadClasses(String moduleName, String className) throws Exception {
         final int classMagic = 0xCAFEBABE;
-        final long NOT_FOUND = 0L;
 
-        if (!(new File(imageFile)).exists()) {
+        if (!Files.exists(imageFile)) {
             System.out.printf("Test skipped; no jimage file");
             return;
         }
 
-        long jimageHandle = ImageNativeSubstrate.JIMAGE_Open(imageFile);
-        Assert.assertTrue(jimageHandle != 0, "JIMAGE_Open failed: id: " + jimageHandle);
+        BasicImageReader reader = BasicImageReader.open(imageFile);
+        Assert.assertTrue(reader != null, "JIMAGE_Open failed: " + imageFile);
+
+        ImageLocation location = reader.findLocation(moduleName, className);
 
-        long[] sizeArray = new long[1];
-        long locationHandle =
-                ImageNativeSubstrate.JIMAGE_FindResource(jimageHandle,
-                moduleName, "9.0", className, sizeArray);
-        long size = sizeArray[0];
-        System.out.printf("reading: module: %s, path: %s, handle: %16x, " +
-                        "location: %d, size: %d%n",
-                moduleName, className, jimageHandle, locationHandle, size);
+        if (location != null && !location.verify("/" + moduleName + "/" + className)) {
+            location = null;
+        }
+
+        long size = location != null ? location.getUncompressedSize() : 0;
+
+        System.out.printf("reading: module: %s, path: %s, size: %d%n",
+                moduleName, className, size);
         if (moduleName.contains("NOSUCH") || className.contains("NOSUCH")) {
-            Assert.assertEquals(locationHandle, NOT_FOUND,
+            Assert.assertTrue(location == null,
                     "location found for non-existing module: "
                     + moduleName
                     + ", or class: " + className);
             return;         // no more to test for non-existing class
         } else {
-            Assert.assertTrue(locationHandle != NOT_FOUND, "location not found: " + className);
+            Assert.assertTrue(location != null, "location not found: " + className);
             Assert.assertTrue(size > 0, "size of should be > 0: " + className);
         }
 
         // positive: read whole class
-        ByteBuffer buffer = ByteBuffer.allocate((int)size);
-        long actual = ImageNativeSubstrate.JIMAGE_GetResource(jimageHandle,
-                locationHandle, buffer.array(), size);
-        Assert.assertEquals(actual, size, "bytes read not equal bytes requested");
+        ByteBuffer buffer = reader.getResourceBuffer(location);
+        Assert.assertTrue(buffer != null, "bytes read not equal bytes requested");
 
         if (className.endsWith(".class")) {
             int m = buffer.getInt();
             Assert.assertEquals(m, classMagic, "Classfile has bad magic number");
         }
 
-        // Read less than the size of the artifact
-        buffer.rewind();
-        Arrays.fill(buffer.array(), (byte)0xc0);
-        long sizeExpected = size - 10;
-        actual = ImageNativeSubstrate.JIMAGE_GetResource(jimageHandle,
-                locationHandle, buffer.array(), sizeExpected);
-        Assert.assertEquals(actual, sizeExpected, "bytes read not equal bytes requested");
-
-        if (className.endsWith(".class")) {
-            int m1 = buffer.getInt();
-            Assert.assertEquals(m1, classMagic, "Read operation succeeded but has bad magic number");
-        }
-
-        ImageNativeSubstrate.JIMAGE_Close(jimageHandle);
+        reader.close();
     }
 
     /**
@@ -149,63 +126,37 @@
      */
     @Test
     static void test2_ImageResources() throws IOException {
-        if (!(new File(imageFile)).exists()) {
+        if (!Files.exists(imageFile)) {
             System.out.printf("Test skipped; no jimage file");
             return;
         }
 
-        long jimageHandle = ImageNativeSubstrate.JIMAGE_Open(imageFile);
-        Assert.assertTrue(jimageHandle != 0, "JIMAGE_Open failed: id: " + jimageHandle);
+        BasicImageReader reader = BasicImageReader.open(imageFile);
+        Assert.assertTrue(reader != null, "JIMAGE_Open failed: " + imageFile);
 
-        String[] names = new String[4096];
-        int max = ImageNativeSubstrate.JIMAGE_Resources(jimageHandle,
-                names);
+        String[] names = reader.getEntryNames();
 
         // Repeat with count available
-        names = new String[max + 1];
-        int count = ImageNativeSubstrate.JIMAGE_Resources(jimageHandle,
-                names);
+        int count = names.length;
+
         System.out.printf(" count: %d, a class: %s\n", count, names[0]);
+
         int minEntryCount = 16000;
-        Assert.assertTrue(max > minEntryCount,
-                "missing entries, should be more than " + minEntryCount +
-                ", reported: " + count);
-        Assert.assertTrue(count == max,
+        Assert.assertTrue(minEntryCount < count,
                 "unexpected count of entries, count: " + count
-                        + ", max: " + max);
+                        + ", min: " + minEntryCount);
         for (int i = 0; i < count; i++) {
             checkFullName(names[i]);
         }
 
-        ImageNativeSubstrate.JIMAGE_Close(jimageHandle);
+        reader.close();
     }
 
-    /**
-     * Tests that a package exists and correctly mapped to the module.
-     *
-     * @param moduleName the module name
-     * @param packageName the package name
-     * @throws IOException thrown if an error occurs
-     */
-    @Test(dataProvider="packages")
-    static void test3_PackageToModule(String moduleName, String packageName) throws IOException {
-        if (!(new File(imageFile)).exists()) {
-            System.out.printf("Test skipped; no jimage file");
+    static void checkFullName(String path) {
+        if (path.startsWith("/packages") || path.startsWith("/modules")) {
             return;
         }
 
-        long jimageHandle = ImageNativeSubstrate.JIMAGE_Open(imageFile);
-        Assert.assertTrue(jimageHandle != 0, "JIMAGE_Open failed: id: " + jimageHandle);
-
-        String result = ImageNativeSubstrate.JIMAGE_PackageToModule(jimageHandle, packageName);
-        System.out.printf(" package: %s, module: %s%n", packageName, result);
-        Assert.assertEquals(result, moduleName, "wrong module for package: " + packageName);
-
-        ImageNativeSubstrate.JIMAGE_Close(jimageHandle);
-    }
-
-
-    static void checkFullName(String path) {
         int next = 0;
         String m = null;
         String p = null;
@@ -241,8 +192,8 @@
      * from the BasicImageReader they are ignored.
      */
     @Test
-    static void test4_verifyNames() {
-        if (!(new File(imageFile)).exists()) {
+    static void test3_verifyNames() {
+        if (!Files.exists(imageFile)) {
             System.out.printf("Test skipped; no jimage file");
             return;
         }
@@ -271,9 +222,6 @@
             System.out.printf("native name count: %d, modCount: %d, pkgCount: %d, otherCount: %d%n",
                     names.length, modCount, pkgCount, otherCount);
 
-            Assert.assertEquals(modCount, 0, "JIMAGE_ResourceIterator should not return any '/modules' paths");
-            Assert.assertEquals(pkgCount, 0, "JIMAGE_ResourceIterator should not return any '/packages' paths");
-
             // Sort and merge the two arrays.  Every name should appear exactly twice.
             Arrays.sort(names);
             Arrays.sort(nativeNames);
@@ -336,21 +284,13 @@
      */
     static String[] JIMAGE_Names() throws IOException {
 
-        long jimageHandle = ImageNativeSubstrate.JIMAGE_Open(imageFile);
-        Assert.assertTrue(jimageHandle != 0, "JIMAGE_Open failed: id: " + jimageHandle);
-
-        String[] names = new String[50000];
-        int max = ImageNativeSubstrate.JIMAGE_Resources(jimageHandle, names);
+        BasicImageReader reader = BasicImageReader.open(imageFile);
+        Assert.assertNotNull(reader, "JIMAGE_Open failed: " + imageFile);
 
-        if (max > names.length) {
-            // Not all names fit, repeat with correct size
-            names = new String[max];
-            max = ImageNativeSubstrate.JIMAGE_Resources(jimageHandle, names);
-        } else {
-            names = Arrays.copyOf(names, max);
-        }
+        String[] names = reader.getEntryNames();
 
-        ImageNativeSubstrate.JIMAGE_Close(jimageHandle);
+        reader.close();
+
         return names;
     }
 
@@ -366,24 +306,55 @@
         System.out.printf(" %s: %d names%n", fname, names.length);
     }
 
-    @Test
-    static void test5_nameTooLong() throws IOException {
+    //@Test
+    static void test4_nameTooLong() throws IOException {
         long[] size = new long[1];
         String moduleName = "FictiousModuleName";
         String className = String.format("A%09999d", 1);
 
-        long jimageHandle = ImageNativeSubstrate.JIMAGE_Open(imageFile);
-        Assert.assertTrue(jimageHandle != 0, "JIMAGE_Open failed: id: " + jimageHandle);
+        BasicImageReader reader = BasicImageReader.open(imageFile);
+        Assert.assertNotNull(reader, "JIMAGE_Open failed: " + imageFile);
+
+        String name = "/" + moduleName + "/" + className;
+        ImageLocation location = reader.findLocation(name);
 
-        long locationHandle =
-                ImageNativeSubstrate.JIMAGE_FindResource(jimageHandle,
-                        moduleName, "9.0", className, size);
+        if (location != null && !location.verify(name)) {
+            location = null;
+        }
+        Assert.assertTrue(location == null, "Too long name should have failed");
 
-        Assert.assertEquals(0, locationHandle, "Too long name should have failed");
-
-        ImageNativeSubstrate.JIMAGE_Close(jimageHandle);
+        reader.close();
     }
 
+    /**
+     * Verify that the ImageReader returned by ImageReader.open has the
+     * the requested endianness or fails with an IOException if not.
+     */
+    @Test
+    static void test5_imageReaderEndianness() throws IOException {
+        ImageReader nativeReader = ImageReader.open(imageFile);
+        Assert.assertEquals(nativeReader.getByteOrder(), ByteOrder.nativeOrder());
+
+        try {
+            ImageReader leReader = ImageReader.open(imageFile, ByteOrder.LITTLE_ENDIAN);
+            Assert.assertEquals(leReader.getByteOrder(), ByteOrder.LITTLE_ENDIAN);
+            leReader.close();
+        } catch (IOException io) {
+            // IOException expected if LITTLE_ENDIAN not the nativeOrder()
+            Assert.assertNotEquals(ByteOrder.nativeOrder(), ByteOrder.LITTLE_ENDIAN);
+        }
+
+        try {
+            ImageReader beReader = ImageReader.open(imageFile, ByteOrder.BIG_ENDIAN);
+            Assert.assertEquals(beReader.getByteOrder(), ByteOrder.BIG_ENDIAN);
+            beReader.close();
+        } catch (IOException io) {
+            // IOException expected if LITTLE_ENDIAN not the nativeOrder()
+            Assert.assertNotEquals(ByteOrder.nativeOrder(), ByteOrder.BIG_ENDIAN);
+        }
+
+        nativeReader.close();
+    }
     // main method to run standalone from jtreg
 
     @Test(enabled=false)
--- a/test/jdk/internal/jimage/JImageTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,80 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-/*
- * @test
- * @library /lib/testlibrary
- * @build jdk.testlibrary.*
- * @summary Test to see if jimage tool extracts and recreates correctly.
- * @run main/timeout=360 JImageTest
- */
-
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.Arrays;
-
-import jdk.testlibrary.ProcessTools;
-
-
-/**
- * Basic test for jimage tool.
- */
-public class JImageTest {
-    private static void jimage(String... jimageArgs) throws Exception {
-        ArrayList<String> args = new ArrayList<>();
-        args.add("-ms8m");
-        args.add("jdk.tools.jimage.Main");
-        args.addAll(Arrays.asList(jimageArgs));
-
-        ProcessBuilder builder = ProcessTools.createJavaProcessBuilder(args.toArray(new String[args.size()]));
-        int res = builder.inheritIO().start().waitFor();
-
-        if (res != 0) {
-            throw new RuntimeException("JImageTest tool FAILED");
-        }
-    }
-
-    public static void main(String[] args) throws Exception {
-        final String JAVA_HOME = System.getProperty("java.home");
-        Path jimagePath = Paths.get(JAVA_HOME, "bin", "jimage");
-        Path bootimagePath = Paths.get(JAVA_HOME, "lib", "modules", "bootmodules.jimage");
-
-        if (Files.exists(jimagePath) && Files.exists(bootimagePath)) {
-            String jimage = jimagePath.toAbsolutePath().toString();
-            String bootimage = bootimagePath.toAbsolutePath().toString();
-            String extractDir = Paths.get(".", "extract").toAbsolutePath().toString();
-            String recreateImage = Paths.get(".", "recreate.jimage").toAbsolutePath().toString();
-            String relativeRecreateImage = Paths.get(".", "recreate2.jimage").toString();
-            jimage("extract", "--dir", extractDir, bootimage);
-            jimage("recreate", "--dir", extractDir, recreateImage);
-            jimage("recreate", "--dir", extractDir, relativeRecreateImage);
-
-            System.out.println("Test successful");
-         } else {
-            System.out.println("Test skipped, no module image");
-         }
-
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/internal/jimage/TEST.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,7 @@
+# This file identifies root(s) of the test-ng hierarchy.
+
+TestNG.dirs = .
+
+modules=java.base/jdk.internal.jimage
+
+javatest.maxOutputSize = 2500000
--- a/test/jdk/internal/jimage/VerifyJimage.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,240 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-import java.io.File;
-import java.io.IOException;
-import java.io.UncheckedIOException;
-import java.nio.file.DirectoryStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.attribute.BasicFileAttributes;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Deque;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.ConcurrentLinkedDeque;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import jdk.internal.jimage.BasicImageReader;
-import jdk.internal.jimage.ImageLocation;
-
-/*
- * @test
- * @summary Verify jimage
- * @modules java.base/jdk.internal.jimage
- * @run main/othervm VerifyJimage
- */
-
-/**
- * This test runs in two modes:
- * (1) No argument: it verifies the jimage by loading all classes in the runtime
- * (2) path of exploded modules: it compares bytes of each file in the exploded
- *     module with the entry in jimage
- *
- * FIXME: exception thrown when findLocation from jimage by multiple threads
- * -Djdk.test.threads=<n> to specify the number of threads.
- */
-public class VerifyJimage {
-    private static final Deque<String> failed = new ConcurrentLinkedDeque<>();
-
-    public static void main(String... args) throws Exception {
-        long start = System.nanoTime();
-        int numThreads = Integer.getInteger("jdk.test.threads", 1);
-        List<JImageReader> readers = newJImageReaders();
-        VerifyJimage verify = new VerifyJimage(readers, numThreads);
-        if (args.length == 0) {
-            // load classes from jimage
-            verify.loadClasses();
-        } else {
-            Path dir = Paths.get(args[0]);
-            if (Files.notExists(dir) || !Files.isDirectory(dir)) {
-                throw new RuntimeException("Invalid argument: " + dir);
-            }
-            verify.compareExplodedModules(dir);
-        }
-        verify.waitForCompletion();
-        long end = System.nanoTime();
-        int entries = readers.stream()
-                             .mapToInt(JImageReader::entries)
-                             .sum();
-        System.out.format("%d entries %d files verified: %d ms %d errors%n",
-                          entries, verify.count.get(),
-                          TimeUnit.NANOSECONDS.toMillis(end - start), failed.size());
-        for (String f : failed) {
-            System.err.println(f);
-        }
-    }
-
-    private final AtomicInteger count = new AtomicInteger(0);
-    private final List<JImageReader> readers;
-    private final ExecutorService pool;
-
-    VerifyJimage(List<JImageReader> readers, int numThreads) {
-        this.readers = readers;
-        this.pool = Executors.newFixedThreadPool(numThreads);
-    }
-
-    private void waitForCompletion() throws InterruptedException {
-        pool.shutdown();
-        pool.awaitTermination(20, TimeUnit.SECONDS);
-    }
-
-    private void compareExplodedModules(Path dir) throws IOException {
-        System.out.println("comparing jimage with " + dir);
-
-        try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
-            for (Path mdir : stream) {
-                if (Files.isDirectory(mdir)) {
-                    pool.execute(new Runnable() {
-                        @Override
-                        public void run() {
-                            try {
-                                Files.find(mdir, Integer.MAX_VALUE, (Path p, BasicFileAttributes attr)
-                                           -> !Files.isDirectory(p) &&
-                                              !mdir.relativize(p).toString().startsWith("_") &&
-                                              !p.getFileName().toString().equals("MANIFEST.MF"))
-                                     .forEach(p -> compare(mdir, p, readers));
-                            } catch (IOException e) {
-                                throw new UncheckedIOException(e);
-                            }
-                        }
-                    });
-                }
-            }
-        }
-    }
-
-    private final List<String> BOOT_RESOURCES = Arrays.asList(
-        "java.base/META-INF/services/java.nio.file.spi.FileSystemProvider"
-    );
-    private final List<String> EXT_RESOURCES = Arrays.asList(
-        "jdk.zipfs/META-INF/services/java.nio.file.spi.FileSystemProvider"
-    );
-    private final List<String> APP_RESOURCES = Arrays.asList(
-        "jdk.hotspot.agent/META-INF/services/com.sun.jdi.connect.Connector",
-        "jdk.jdi/META-INF/services/com.sun.jdi.connect.Connector"
-    );
-
-    private void compare(Path mdir, Path p, List<JImageReader> readers) {
-        String entry = mdir.relativize(p).toString().replace(File.separatorChar, '/');
-
-        count.incrementAndGet();
-        String file = mdir.getFileName().toString() + "/" + entry;
-        if (APP_RESOURCES.contains(file)) {
-            // skip until the service config file is merged
-            System.out.println("Skipped " + file);
-            return;
-        }
-
-        String jimage;
-        if (BOOT_RESOURCES.contains(file)) {
-            jimage = "bootmodules.jimage";
-        } else if (EXT_RESOURCES.contains(file)) {
-            jimage = "extmodules.jimage";
-        } else {
-            jimage = "";
-        }
-        JImageReader reader = readers.stream()
-                .filter(r -> r.findLocation(entry) != null)
-                .filter(r -> jimage.isEmpty() || r.imageName().equals(jimage))
-                .findFirst().orElse(null);
-        if (reader == null) {
-            failed.add(entry + " not found: " + p.getFileName().toString());
-        } else {
-            reader.compare(entry, p);
-        }
-    }
-
-    private void loadClasses() {
-        ClassLoader loader = ClassLoader.getSystemClassLoader();
-        for (JImageReader reader : readers) {
-            Arrays.stream(reader.getEntryNames())
-                    .filter(n -> n.endsWith(".class"))
-                    .forEach(n -> {
-                        String cn = n.substring(0, n.length()-6).replace('/', '.');
-                        count.incrementAndGet();
-                        try {
-                            Class.forName(cn, false, loader);
-                        } catch (ClassNotFoundException e) {
-                            failed.add(reader.imageName() + ": " + cn + " not found");
-                        }
-                    });
-        }
-    }
-
-
-   private static List<JImageReader> newJImageReaders() throws IOException {
-        String home = System.getProperty("java.home");
-        Path mlib = Paths.get(home, "lib", "modules");
-        try (Stream<Path> paths = Files.list(mlib)) {
-            Set<Path> jimages = paths.filter(p -> p.toString().endsWith(".jimage"))
-                                     .collect(Collectors.toSet());
-            List<JImageReader> result = new ArrayList<>();
-            for (Path jimage: jimages) {
-                result.add(new JImageReader(jimage));
-                System.out.println("opened " + jimage);
-            }
-            return result;
-        }
-    }
-
-    static class JImageReader extends BasicImageReader {
-        final Path jimage;
-        JImageReader(Path p) throws IOException {
-            super(p.toString());
-            this.jimage = p;
-        }
-
-        String imageName() {
-            return jimage.getFileName().toString();
-        }
-
-        int entries() {
-            try {
-                return getHeader().getTableLength();
-            } catch (IOException ex) {
-                failed.add(imageName() + ": can't access header");
-                return 0;
-            }
-        }
-
-        void compare(String entry, Path p) {
-            try {
-                byte[] bytes = Files.readAllBytes(p);
-                byte[] imagebytes = getResource(entry);
-                if (!Arrays.equals(bytes, imagebytes)) {
-                    failed.add(imageName() + ": bytes differs than " + p.toString());
-                }
-            } catch (IOException e) {
-                throw new UncheckedIOException(e);
-            }
-        }
-    }
-}
--- a/test/jdk/internal/jrtfs/Basic.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/jdk/internal/jrtfs/Basic.java	Thu Mar 17 19:04:16 2016 +0000
@@ -28,8 +28,10 @@
  */
 
 import java.io.InputStream;
+import java.io.IOException;
 import java.io.DataInputStream;
 import java.nio.file.DirectoryStream;
+import java.nio.file.InvalidPathException;
 import java.nio.file.Files;
 import java.nio.file.FileSystem;
 import java.nio.file.FileSystems;
@@ -38,16 +40,20 @@
 import java.nio.file.Paths;
 import java.net.URI;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.stream.Stream;
 
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotEquals;
+import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertTrue;
 import static org.testng.Assert.assertFalse;
 
@@ -57,6 +63,34 @@
 
 public class Basic {
 
+    private FileSystem theFileSystem;
+    private FileSystem fs;
+
+    @BeforeClass
+    public void setup() {
+        try {
+            theFileSystem = FileSystems.getFileSystem(URI.create("jrt:/"));
+            Map<String, String> env = new HashMap<>();
+            // set java.home property to be underlying java.home
+            // so that jrt-fs.jar loading is exercised.
+            env.put("java.home", System.getProperty("java.home"));
+            fs = FileSystems.newFileSystem(URI.create("jrt:/"), env);
+        } catch (IOException ioExp) {
+            throw new RuntimeException(ioExp);
+        }
+    }
+
+    @AfterClass
+    public void tearDown() {
+        try {
+            fs.close();
+        } catch (Exception ignored) {}
+    }
+
+    private FileSystem selectFileSystem(boolean theDefault) {
+        return theDefault? theFileSystem : fs;
+    }
+
     // Checks that the given FileSystem is a jrt file system.
     private void checkFileSystem(FileSystem fs) {
         assertTrue(fs.provider().getScheme().equalsIgnoreCase("jrt"));
@@ -95,17 +129,32 @@
         }
     }
 
+    @Test
+    public void testNewFileSystemWithJavaHome() throws Exception {
+        Map<String, String> env = new HashMap<>();
+        // set java.home property to be underlying java.home
+        // so that jrt-fs.jar loading is exercised.
+        env.put("java.home", System.getProperty("java.home"));
+        try (FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"), env)) {
+            checkFileSystem(fs);
+            // jrt-fs.jar classes are loaded by another (non-boot) loader in this case
+            assertNotNull(fs.provider().getClass().getClassLoader());
+        }
+    }
+
     @DataProvider(name = "knownClassFiles")
     private Object[][] knownClassFiles() {
         return new Object[][] {
-            { "/modules/java.base/java/lang/Object.class" },
-            { "modules/java.base/java/lang/Object.class" },
+            { "/modules/java.base/java/lang/Object.class", true },
+            { "modules/java.base/java/lang/Object.class", true },
+            { "/modules/java.base/java/lang/Object.class", false },
+            { "modules/java.base/java/lang/Object.class", false },
         };
     }
 
     @Test(dataProvider = "knownClassFiles")
-    public void testKnownClassFiles(String path) throws Exception {
-        FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
+    public void testKnownClassFiles(String path, boolean theDefault) throws Exception {
+        FileSystem fs = selectFileSystem(theDefault);
         Path classFile = fs.getPath(path);
 
         assertTrue(Files.isRegularFile(classFile));
@@ -121,25 +170,38 @@
     @DataProvider(name = "knownDirectories")
     private Object[][] knownDirectories() {
         return new Object[][] {
-            { "/"                     },
-            { "."                     },
-            { "./"                    },
-            { "/."                    },
-            { "/./"                   },
-            { "/modules/java.base/.."         },
-            { "/modules/java.base/../"        },
-            { "/modules/java.base/../."       },
-            { "/modules/java.base"            },
-            { "/modules/java.base/java/lang"  },
-            { "modules/java.base/java/lang"   },
-            { "/modules/java.base/java/lang/" },
-            { "modules/java.base/java/lang/"  }
+            { "/", true                     },
+            { "." , true                    },
+            { "./", true                    },
+            { "/.", true                    },
+            { "/./", true                   },
+            { "/modules/java.base/..", true         },
+            { "/modules/java.base/../", true        },
+            { "/modules/java.base/../.", true       },
+            { "/modules/java.base", true            },
+            { "/modules/java.base/java/lang", true  },
+            { "modules/java.base/java/lang", true   },
+            { "/modules/java.base/java/lang/", true },
+            { "modules/java.base/java/lang/", true  },
+            { "/", false                     },
+            { "." , false                    },
+            { "./", false                    },
+            { "/.", false                    },
+            { "/./", false                   },
+            { "/modules/java.base/..", false         },
+            { "/modules/java.base/../", false        },
+            { "/modules/java.base/../.", false       },
+            { "/modules/java.base", false            },
+            { "/modules/java.base/java/lang", false  },
+            { "modules/java.base/java/lang", false   },
+            { "/modules/java.base/java/lang/", false },
+            { "modules/java.base/java/lang/", false  },
         };
     }
 
     @Test(dataProvider = "knownDirectories")
-    public void testKnownDirectories(String path) throws Exception {
-        FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
+    public void testKnownDirectories(String path, boolean theDefault) throws Exception {
+        FileSystem fs = selectFileSystem(theDefault);
         Path dir = fs.getPath(path);
 
         assertTrue(Files.isDirectory(dir));
@@ -383,6 +445,8 @@
             { "/modules/java.base/packages.offsets" },
             { "/modules/java.instrument/packages.offsets" },
             { "/modules/jdk.zipfs/packages.offsets" },
+            { "/modules/java.base/_the.java.base.vardeps" },
+            { "/modules/java.base/_the.java.base_batch" },
             { "/java/lang" },
             { "/java/util" },
         };
@@ -568,48 +632,55 @@
     }
 
     @Test
-    public void testPackagesSubDirList() throws Exception {
+    public void invalidPathTest() {
         FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
-        String pathName = "/packages/javax.annotation";
-        Path path = fs.getPath(pathName);
-        boolean seenJavaCompiler = false, seenAnnotationsCommon = false;
-        try (DirectoryStream<Path> stream = Files.newDirectoryStream(path)) {
-            for (Path p : stream) {
-               String str = p.toString();
-               if (str.equals(pathName + "/java.compiler")) {
-                   seenJavaCompiler = true;
-               } else if (str.equals(pathName + "/java.annotations.common")) {
-                   seenAnnotationsCommon = true;
-               }
-            }
+        InvalidPathException ipe = null;
+        try {
+            boolean res = Files.exists(fs.getPath("/packages/\ud834\udd7b"));
+            assertFalse(res);
+            return;
+        } catch (InvalidPathException e) {
+            ipe = e;
         }
-        assertTrue(seenJavaCompiler);
-        assertTrue(seenAnnotationsCommon);
+        assertTrue(ipe != null);
     }
 
-    @Test
-    public void testRootDirList() throws Exception {
+    @DataProvider(name="packagesLinkedDirs")
+    private Object[][] packagesLinkedDirs() {
+        return new Object[][] {
+            { "/packages/java.lang/java.base/java/lang/ref"             },
+            { "/./packages/java.lang/java.base/java/lang/ref"           },
+            { "packages/java.lang/java.base/java/lang/ref"              },
+            { "/packages/../packages/java.lang/java.base/java/lang/ref" },
+            { "/packages/java.lang/java.base/java/util/zip"             },
+            { "/./packages/java.lang/java.base/java/util/zip"           },
+            { "packages/java.lang/java.base/java/util/zip"              },
+            { "/packages/../packages/java.lang/java.base/java/util/zip" },
+            { "/packages/com.oracle/java.xml.ws/com"                    },
+            { "/./packages/com.oracle/java.xml.ws/com"                  },
+            { "packages/com.oracle/java.xml.ws/com"                     },
+            { "/packages/../packages/com.oracle/java.xml.ws/com"        }
+        };
+    }
+
+    // @bug 8141521: jrt file system's DirectoryStream reports child paths
+    // with wrong paths for directories under /packages
+    @Test(dataProvider = "packagesLinkedDirs")
+    public void dirStreamPackagesDirTest(String dirName) throws IOException {
         FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
-        Path path = fs.getPath("/");
-        // check /packages and /modules are not repeated
-        // and seen once.
-        boolean packages = false, modules = false;
-        try (DirectoryStream<Path> stream = Files.newDirectoryStream(path)) {
-            for (Path p : stream) {
-                String str = p.toString();
-                switch (str) {
-                    case "/packages":
-                        assertFalse(packages, "/packages repeated");
-                        packages = true;
-                        break;
-                    case "/modules":
-                        assertFalse(modules, "/modules repeated");
-                        modules = true;
-                        break;
+        Path path = fs.getPath(dirName);
+
+        int childCount = 0, dirPrefixOkayCount = 0;
+        try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(path)) {
+            for (Path child : dirStream) {
+                childCount++;
+                if (child.toString().startsWith(dirName)) {
+                    dirPrefixOkayCount++;
                 }
             }
         }
-        assertTrue(packages, "/packages missing in / list!");
-        assertTrue(modules, "/modules missing in / list!");
+
+        assertTrue(childCount != 0);
+        assertEquals(dirPrefixOkayCount, childCount);
     }
 }
--- a/test/jdk/internal/ref/Cleaner/ExitOnThrow.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/jdk/internal/ref/Cleaner/ExitOnThrow.java	Thu Mar 17 19:04:16 2016 +0000
@@ -25,6 +25,7 @@
  * @test
  * @bug 4954921 8009259
  * @library /test/lib/share/classes
+ * @modules java.base/jdk.internal.ref
  * @build jdk.test.lib.*
  * @build jdk.test.lib.process.*
  * @run main ExitOnThrow
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/modules/etc/VerifyModuleDelegation.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @summary Verify the defining class loader of each module never delegates
+ *          to its child class loader. Also sanity check java.compact2
+ *          requires.
+ * @run testng VerifyModuleDelegation
+ */
+
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReference;
+import java.lang.reflect.Layer;
+import java.util.Set;
+
+import static java.lang.module.ModuleDescriptor.Requires.Modifier.*;
+
+import org.testng.annotations.*;
+
+import static org.testng.Assert.*;
+
+public class VerifyModuleDelegation {
+    private static final String JAVA_BASE = "java.base";
+    private static final String JAVA_COMPACT1 = "java.compact1";
+    private static final String JAVA_COMPACT2 = "java.compact2";
+
+    private static final ModuleDescriptor BASE
+        = new ModuleDescriptor.Builder(JAVA_BASE).build();
+
+    private static final ModuleDescriptor COMPACT2
+        = new ModuleDescriptor.Builder(JAVA_COMPACT2)
+            .requires(MANDATED, JAVA_BASE)
+            .requires(PUBLIC, JAVA_COMPACT1)
+            .requires(PUBLIC, "java.rmi")
+            .requires(PUBLIC, "java.sql")
+            .requires(PUBLIC, "java.xml")
+            .build();
+
+    private static final Set<ModuleReference> MREFS
+            = ModuleFinder.ofSystem().findAll();
+
+    private void check(ModuleDescriptor md, ModuleDescriptor ref) {
+        assertTrue(md.requires().size() == ref.requires().size());
+        assertTrue(md.requires().containsAll(ref.requires()));
+    }
+
+    @Test
+    public void checkJavaBase() {
+        ModuleDescriptor md =
+                MREFS.stream().map(ModuleReference::descriptor)
+                     .filter(d -> d.name().equals(JAVA_BASE))
+                     .findFirst().orElseThrow(Error::new);
+
+        check(md, BASE);
+    }
+    @Test
+    public void checkCompact2() {
+        ModuleDescriptor md =
+                MREFS.stream().map(ModuleReference::descriptor)
+                     .filter(d -> d.name().equals(JAVA_COMPACT2))
+                     .findFirst().orElseThrow(Error::new);
+        check(md, COMPACT2);
+    }
+
+    @Test
+    public void checkLoaderDelegation() {
+        Layer boot = Layer.boot();
+        MREFS.stream().map(ModuleReference::descriptor)
+             .forEach(md -> md.requires().stream().forEach(req ->
+                 {
+                     // check if M requires D and D's loader must be either the
+                     // same or an ancestor of M's loader
+                     ClassLoader loader1 = boot.findLoader(md.name());
+                     ClassLoader loader2 = boot.findLoader(req.name());
+                     if (loader1 != loader2 && !isAncestor(loader2, loader1)) {
+                         throw new Error(md.name() + " can't delegate to " +
+                                         "find classes from " + req.name());
+                     }
+                 }));
+    }
+
+    // Returns true if p is an ancestor of cl i.e. class loader 'p' can
+    // be found in the cl's delegation chain
+    private static boolean isAncestor(ClassLoader p, ClassLoader cl) {
+        if (p != null && cl == null) {
+            return false;
+        }
+        ClassLoader acl = cl;
+        do {
+            acl = acl.getParent();
+            if (p == acl) {
+                return true;
+            }
+        } while (acl != null);
+        return false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/modules/scenarios/automaticmodules/RunWithAutomaticModules.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @library /lib/testlibrary
+ * @modules jdk.compiler
+ * @build RunWithAutomaticModules CompilerUtils JarUtils
+ *        jdk.testlibrary.ProcessTools
+ * @run testng RunWithAutomaticModules
+ * @summary Runs tests that make use of automatic modules
+ */
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import static jdk.testlibrary.ProcessTools.*;
+
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+@Test
+public class RunWithAutomaticModules {
+
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path CLASSES_DIR = Paths.get("classes");
+    private static final Path MODS_DIR = Paths.get("mods");
+
+    /**
+     * Basic test that consists of 3 modules:
+     *
+     * basictest - the test itself
+     * httpserver - a JAR file (automatic module) with a dummy HTTP server
+     * logging - a JAR file (automatic module) with a dummy logging library
+     *
+     * The test runs the dummy HTTP server and checks that has the expected
+     * reads and exported packages.
+     *
+     * The HTTP server uses the logging library.
+     */
+
+    public void testBasic() throws Exception {
+        boolean compiled;
+
+        Path loggingSrc = SRC_DIR.resolve("logging");
+        Path loggingClasses = CLASSES_DIR.resolve("logging");
+
+        Path httpServerSrc = SRC_DIR.resolve("httpserver");
+        Path httpServerClasses = CLASSES_DIR.resolve("httpserver");
+
+        String testModule = "basictest";
+        String mainClass = "test.Main";
+
+
+        // compile + create mods/logging-1.0.jar
+
+        compiled = CompilerUtils.compile(loggingSrc, loggingClasses);
+        assertTrue(compiled);
+
+        JarUtils.createJarFile(MODS_DIR.resolve("logging-1.0.jar"),
+                               loggingClasses);
+
+
+        // compile + create mods/httpserver-9.0.0.jar
+
+        compiled = CompilerUtils.compile(httpServerSrc,
+                httpServerClasses,
+                "-cp", loggingClasses.toString());
+        assertTrue(compiled);
+
+        JarUtils.createJarFile(MODS_DIR.resolve("httpserver-9.0.0.jar"),
+                httpServerClasses);
+
+
+        // compile basictest to mods/basictest
+
+        compiled = CompilerUtils
+            .compile(SRC_DIR.resolve(testModule),
+                    MODS_DIR.resolve(testModule),
+                    "-mp", MODS_DIR.toString());
+        assertTrue(compiled);
+
+
+        // launch the test. Need -addmods because nothing explicitly depends on logging
+
+        int exitValue
+            = executeTestJava("-mp", MODS_DIR.toString(),
+                              "-addmods", "logging",
+                              "-m", testModule + "/" + mainClass)
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
+
+        assertTrue(exitValue == 0);
+    }
+
+
+
+    /**
+     * Test using a JAR file with a service provider as an automatic module.
+     *
+     * The consists of 2 modules:
+     *
+     * sptest - the test itself
+     * bananascript - a JAR file (automatic module) with a dummy ScriptEngineFactory
+     *
+     * The test uses ServiceLoader to locate and load ScriptEngineFactory
+     * implementations. It checks that bananascript is located.
+     */
+
+    public void testServiceProvider() throws Exception {
+        boolean compiled;
+
+        Path providerSrc = SRC_DIR.resolve("bananascript");
+        Path providerClasses = CLASSES_DIR.resolve("bananascript");
+
+        String testModule = "sptest";
+        String mainClass = "test.Main";
+
+
+        // create mods/bananascript-0.9.jar
+
+        compiled = CompilerUtils.compile(providerSrc, providerClasses);
+        assertTrue(compiled);
+
+        String config = "META-INF/services/javax.script.ScriptEngineFactory";
+        Path services = providerClasses.resolve(config).getParent();
+        Files.createDirectories(services);
+        Files.copy(providerSrc.resolve(config), providerClasses.resolve(config));
+
+        JarUtils.createJarFile(MODS_DIR.resolve("bananascript-0.9.jar"), providerClasses);
+
+
+        // compile sptest to mods/sptest
+
+        compiled = CompilerUtils
+                .compile(SRC_DIR.resolve(testModule),
+                        MODS_DIR.resolve(testModule),
+                        "-mp", MODS_DIR.toString());
+
+        assertTrue(compiled);
+
+
+        // launch the test
+
+        int exitValue
+            = executeTestJava("-mp", MODS_DIR.toString(),
+                              "-m", testModule + "/" + mainClass)
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
+
+        assertTrue(exitValue == 0);
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/modules/scenarios/automaticmodules/src/bananascript/META-INF/services/javax.script.ScriptEngineFactory	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,2 @@
+# Our test script engine factory
+org.banana.BananaScriptEngineFactory
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/modules/scenarios/automaticmodules/src/bananascript/org/banana/BananaScript.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.banana;
+
+import java.io.Reader;
+import javax.script.Bindings;
+import javax.script.ScriptContext;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineFactory;
+
+public class BananaScript implements ScriptEngine {
+
+    @Override
+    public Object eval(String script, ScriptContext context) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Object eval(Reader reader , ScriptContext context) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Object eval(String script) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Object eval(Reader reader) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Object eval(String script, Bindings n) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Object eval(Reader reader , Bindings n) {
+        throw new RuntimeException();
+    }
+    @Override
+    public void put(String key, Object value) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Object get(String key) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Bindings getBindings(int scope) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public void setBindings(Bindings bindings, int scope) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Bindings createBindings() {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public ScriptContext getContext() {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public void setContext(ScriptContext context) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public ScriptEngineFactory getFactory() {
+        throw new RuntimeException();
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/modules/scenarios/automaticmodules/src/bananascript/org/banana/BananaScriptEngineFactory.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.banana;
+
+import java.util.Arrays;
+import java.util.List;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineFactory;
+
+public class BananaScriptEngineFactory implements ScriptEngineFactory {
+
+    @Override
+    public String getEngineName() {
+        return "BananaScriptEngine";
+    }
+
+    @Override
+    public String getEngineVersion() {
+        return "1.0";
+    }
+
+    @Override
+    public List<String> getExtensions() {
+        return Arrays.asList("banana");
+    }
+
+    @Override
+    public List<String> getMimeTypes() {
+        return Arrays.asList("application/x-bananascript");
+    }
+
+    @Override
+    public List<String> getNames() {
+        return Arrays.asList("BananaScript");
+    }
+
+    @Override
+    public String getLanguageName() {
+        return "BananaScript";
+    }
+
+    @Override
+    public String getLanguageVersion() {
+        return "1.0";
+    }
+
+    @Override
+    public Object getParameter(String key) {
+        return null;
+    }
+
+    @Override
+    public String getMethodCallSyntax(String obj, String m, String... args) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public String getOutputStatement(String toDisplay) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public String getProgram(String... statements) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public ScriptEngine getScriptEngine() {
+        return new BananaScript();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/modules/scenarios/automaticmodules/src/basictest/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module basictest {
+    requires httpserver;  // automatic module
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/modules/scenarios/automaticmodules/src/basictest/test/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package test;
+
+import java.lang.reflect.Layer;
+import java.lang.reflect.Module;
+
+import http.HttpServer;
+
+/**
+ * Basic test using automatic modules.
+ */
+
+public class Main {
+    public static void main(String[] args) throws Exception {
+
+        Module httpModule = HttpServer.class.getModule();
+
+        // automatic modules are named
+        assertTrue(httpModule.isNamed());
+
+        // and read all unnamed modules
+        ClassLoader cl;
+        cl = ClassLoader.getPlatformClassLoader();
+        assertTrue(httpModule.canRead(cl.getUnnamedModule()));
+        cl = ClassLoader.getSystemClassLoader();
+        assertTrue(httpModule.canRead(cl.getUnnamedModule()));
+
+        // and read all modules in the boot Layer
+        Layer layer = Layer.boot();
+        layer.modules().forEach(m -> assertTrue(httpModule.canRead(m)));
+
+        // run code in the automatic modue, ensures access is allowed
+        HttpServer http = HttpServer.create(80);
+        http.start();
+    }
+
+    static void assertTrue(boolean e) {
+        if (!e)
+            throw new RuntimeException();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/modules/scenarios/automaticmodules/src/httpserver/http/HttpServer.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package http;
+
+import java.util.Iterator;
+import java.util.ServiceLoader;
+
+import http.spi.HttpServerProvider;
+import logging.Logger;
+
+/**
+ * A do-nothing HTTP server
+ */
+
+public class HttpServer {
+    private final int port;
+    private final Logger logger;
+
+    protected HttpServer(int port) {
+        this.port = port;
+        this.logger = new Logger();
+    }
+
+    public static HttpServer create(int port) {
+        ServiceLoader<HttpServerProvider> sl
+            = ServiceLoader.load(HttpServerProvider.class);
+        Iterator<HttpServerProvider> iterator = sl.iterator();
+        if (iterator.hasNext()) {
+            HttpServerProvider provider = iterator.next();
+            return provider.createHttpServer(port);
+        } else {
+            return new HttpServer(port) { };
+        }
+    }
+
+    public void start() {
+        logger.log("Start HTTP server on port " + port);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/modules/scenarios/automaticmodules/src/httpserver/http/spi/HttpServerProvider.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package http.spi;
+
+import http.HttpServer;
+
+public abstract class HttpServerProvider {
+
+    protected HttpServerProvider() { }
+
+    public abstract HttpServer createHttpServer(int port);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/modules/scenarios/automaticmodules/src/logging/logging/Logger.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package logging;
+
+/**
+ * A simple logger.
+ */
+
+public class Logger {
+    public Logger() { }
+
+    public void log(String msg) {
+        System.out.println(msg);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/modules/scenarios/automaticmodules/src/sptest/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module sptest {
+    requires java.scripting;
+    uses javax.script.ScriptEngineFactory;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/modules/scenarios/automaticmodules/src/sptest/test/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package test;
+
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Requires;
+import java.lang.module.ModuleDescriptor.Provides;
+import java.lang.reflect.Layer;
+import java.lang.reflect.Module;
+import java.util.Map;
+import java.util.Optional;
+import java.util.ServiceLoader;
+import java.util.Set;
+import java.util.stream.Collectors;
+import javax.script.ScriptEngineFactory;
+
+/**
+ * Test that the automatic module "bananascript" is in the boot Layer and
+ * it behaves as a service provider.
+ */
+
+public class Main {
+
+    public static void main(String[] args) throws Exception {
+
+        Optional<Module> om = Layer.boot().findModule("bananascript");
+        assertTrue(om.isPresent());
+
+        ModuleDescriptor descriptor = om.get().getDescriptor();
+
+        // requires java.base
+        Set<String> requires
+            = descriptor.requires().stream()
+                .map(Requires::name)
+                .collect(Collectors.toSet());
+        assertTrue(requires.size() == 1);
+        assertTrue(requires.contains("java.base"));
+
+        // uses ScriptEngineFactory
+        Map<String, Provides> provides = descriptor.provides();
+        assertTrue(provides.size() == 1);
+        String sn = ScriptEngineFactory.class.getName();
+        assertTrue(provides.containsKey(sn));
+
+        // Check that it is iterated over with ServiceLoader
+        ServiceLoader<ScriptEngineFactory> sl
+            = ServiceLoader.load(ScriptEngineFactory.class);
+        boolean found = false;
+        for (ScriptEngineFactory factory : sl) {
+            String name = factory.getEngineName();
+            System.out.println(name);
+            if (name.equals("BananaScriptEngine"))
+                found = true;
+        }
+        assertTrue(found);
+    }
+
+    static void assertTrue(boolean e) {
+        if (!e)
+            throw new RuntimeException();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/modules/scenarios/container/ContainerTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @library /lib/testlibrary
+ * @modules jdk.jartool/sun.tools.jar
+ *          jdk.compiler
+ * @build ContainerTest CompilerUtils jdk.testlibrary.*
+ * @run testng ContainerTest
+ * @summary Starts a simple container that uses dynamic configurations
+ *          and launches two applications in the same VM
+ */
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import static jdk.testlibrary.ProcessTools.*;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+@Test
+public class ContainerTest {
+
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path MODS_DIR = Paths.get("mods");
+
+    private static final Path MLIB_DIR = Paths.get("mlib");
+    private static final Path APPLIB_DIR = Paths.get("applib");
+
+    private static final String CONTAINER_MODULE = "container";
+    private static final String CONTAINER_MAIN_CLASS = "container.Main";
+
+
+    /**
+     * Creates the container module in mlib/container@1.0.jmod
+     */
+    void buildContainer() throws Exception {
+
+        Path src = SRC_DIR.resolve(CONTAINER_MODULE);
+        Path output = MODS_DIR.resolve(CONTAINER_MODULE);
+
+        boolean compiled = CompilerUtils.compile(src, output);
+        assertTrue(compiled);
+
+        // jar --create ...
+        Path mlib = Files.createDirectories(MLIB_DIR);
+        String classes = output.toString();
+        String jar = mlib.resolve(CONTAINER_MODULE + "@1.0.jar").toString();
+        String[] args = {
+            "--create",
+            "--file=" + jar,
+            "--main-class=" + CONTAINER_MAIN_CLASS,
+            "-C", classes, "."
+        };
+        boolean success
+            = new sun.tools.jar.Main(System.out, System.out, "jar")
+                .run(args);
+        assertTrue(success);
+    }
+
+    /**
+     * Creates app1 and its bundled libraries in applib.
+     */
+    void buildApp1() throws Exception {
+        Path dir = Files.createDirectories(APPLIB_DIR);
+
+        // app1 uses its own copy of JAX-WS
+        boolean compiled
+            = CompilerUtils.compile(SRC_DIR.resolve("java.xml.ws"),
+                                    dir.resolve("java.xml.ws"));
+        assertTrue(compiled);
+
+        compiled = CompilerUtils.compile(SRC_DIR.resolve("app1"),
+                                         dir.resolve("app1"),
+                                         "-upgrademodulepath", dir.toString());
+        assertTrue(compiled);
+    }
+
+    /**
+     * Creates app2 and its bundled libraries in applib.
+     */
+    void buildApp2() throws Exception {
+        Path dir = Files.createDirectories(APPLIB_DIR);
+
+        // app2 uses JAX-RS
+        boolean compiled
+            = CompilerUtils.compile(SRC_DIR.resolve("java.ws.rs"),
+                                    dir.resolve("java.ws.rs"));
+        assertTrue(compiled);
+
+        compiled = CompilerUtils.compile(SRC_DIR.resolve("app2"),
+                                         dir.resolve("app2"),
+                                         "-mp", dir.toString());
+        assertTrue(compiled);
+    }
+
+
+    @BeforeTest
+    public void setup() throws Exception {
+        buildContainer();
+        buildApp1();
+        buildApp2();
+    }
+
+    /**
+     * Launches the container
+     */
+    public void testContainer() throws Exception {
+
+        int exitValue
+            = executeTestJava("-mp", MLIB_DIR.toString(),
+                              "-m", CONTAINER_MODULE)
+                .outputTo(System.out)
+                .errorTo(System.err)
+                .getExitValue();
+
+        assertTrue(exitValue == 0);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/modules/scenarios/container/src/app1/app1/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package app1;
+
+import javax.xml.ws.WebService;
+
+public class Main {
+
+    static void trace(Class<?> c) {
+        System.out.format("%s loaded by %s\n", c, c.getClassLoader());
+    }
+
+    public static void main(String[] args) throws Exception {
+        trace(Main.class);
+
+        WebService ws = new WebService();
+        trace(ws.getClass());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/modules/scenarios/container/src/app1/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+module app1 {
+    requires java.base;
+    requires java.xml.ws;
+    exports app1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/modules/scenarios/container/src/app2/app2/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package app2;
+
+import javax.ws.rs.Client;
+
+public class Main {
+
+    static void trace(Class<?> c) {
+        System.out.format("%s loaded by %s\n", c, c.getClassLoader());
+    }
+
+    public static void main(String[] args) throws Exception {
+        trace(Main.class);
+
+        Client c = new Client();
+        trace(c.getClass());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/modules/scenarios/container/src/app2/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+module app2 {
+    requires java.base;
+    requires java.ws.rs;
+    exports app2;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/modules/scenarios/container/src/container/container/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package container;
+
+import java.io.File;
+import java.lang.module.Configuration;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ResolvedModule;
+import java.lang.reflect.Layer;
+import java.lang.reflect.Method;
+import java.lang.reflect.Module;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Set;
+
+/**
+ * Exercises dynamic configuration.
+ */
+
+public class Main {
+
+    public static void main(String[] args) throws Exception {
+
+        System.out.println("Boot layer");
+        Layer.boot()
+             .modules()
+             .stream()
+             .map(Module::getName)
+             .sorted()
+             .forEach(System.out::println);
+
+        // "start" two applications in their own layers
+        start("applib", "app1", "app1.Main");
+        start("applib", "app2", "app2.Main");
+    }
+
+    static void start(String appModulePath,
+                      String appModuleName,
+                      String appMainClass) throws Exception {
+
+        System.out.format("Starting %s/%s ...%n", appModuleName, appMainClass);
+
+        String[] dirs = appModulePath.split(File.pathSeparator);
+        Path[] paths = new Path[dirs.length];
+        int i = 0;
+        for (String dir: dirs) {
+            paths[i++] = Paths.get(dir);
+        }
+
+        ModuleFinder finder = ModuleFinder.of(paths);
+
+        Configuration cf = Layer.boot().configuration()
+            .resolveRequiresAndUses(finder,
+                                    ModuleFinder.empty(),
+                                    Set.of(appModuleName));
+
+        System.out.println("Resolved");
+        cf.modules().stream()
+          .map(ResolvedModule::name)
+          .sorted()
+          .forEach(mn -> System.out.format("  %s%n", mn));
+
+        // reify the configuration as a Layer
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+        Layer layer = Layer.boot().defineModulesWithManyLoaders(cf, scl);
+
+        // invoke application main method
+        ClassLoader loader = layer.findLoader(appModuleName);
+        Class<?> c = loader.loadClass(appMainClass);
+        Main.class.getModule().addReads(c.getModule());
+        Method mainMethod = c.getMethod("main", String[].class);
+
+        // set TCCL as that is the EE thing to do
+        ClassLoader tccl = Thread.currentThread().getContextClassLoader();
+        try {
+            Thread.currentThread().setContextClassLoader(loader);
+            mainMethod.invoke(null, (Object)new String[0]);
+        } finally {
+            Thread.currentThread().setContextClassLoader(tccl);
+        }
+
+        System.out.println();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/modules/scenarios/container/src/container/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+module container {
+    requires java.se;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/modules/scenarios/container/src/java.ws.rs/javax/ws/rs/Client.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package javax.ws.rs;
+
+public class Client {
+    public Client() { }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/modules/scenarios/container/src/java.ws.rs/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+module java.ws.rs {
+    requires java.base;
+
+    exports javax.ws.rs;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/modules/scenarios/container/src/java.xml.ws/javax/xml/ws/WebService.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package javax.xml.ws;
+
+public class WebService {
+    public WebService() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/modules/scenarios/container/src/java.xml.ws/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+module java.xml.ws {
+    requires java.base;
+
+    exports javax.xml.ws;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/modules/scenarios/overlappingpackages/OverlappingPackagesTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @library /lib/testlibrary
+ * @modules jdk.compiler
+ * @build OverlappingPackagesTest CompilerUtils jdk.testlibrary.*
+ * @run testng OverlappingPackagesTest
+ * @summary Basic test to ensure that startup fails if two or more modules
+ *          in the boot Layer have the same package
+ */
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.List;
+
+import static jdk.testlibrary.ProcessTools.*;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+@Test
+public class OverlappingPackagesTest {
+
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path MODS_DIR = Paths.get("mods");
+
+    // the names of the modules in this test
+    private static List<String> modules = Arrays.asList("m1", "m2", "test");
+
+
+    /**
+     * Compiles all modules used by the test
+     */
+    @BeforeTest
+    public void compileAll() throws Exception {
+        for (String mn : modules) {
+            Path src = SRC_DIR.resolve(mn);
+            Path mods = MODS_DIR.resolve(mn);
+            assertTrue(CompilerUtils.compile(src, mods));
+        }
+        Path srcMisc = SRC_DIR.resolve("misc");
+        Path modsMisc = MODS_DIR.resolve("misc");
+        assertTrue(CompilerUtils.compile(srcMisc.resolve("sun")
+                                                .resolve("misc")
+                                                .resolve("Unsafe.java"),
+                                         modsMisc,
+                                         "-Xmodule:java.base"));
+        assertTrue(CompilerUtils.compile(srcMisc.resolve("module-info.java"),
+                                         modsMisc));
+    }
+
+    /**
+     * Sanity check that the test runs without error.
+     */
+    public void testNoOverlappingPackages() throws Exception {
+        int exitValue
+            = executeTestJava("-mp", MODS_DIR.toString(),
+                              "-m", "test/test.Main")
+                .outputTo(System.out)
+                .errorTo(System.err)
+                .getExitValue();
+
+        assertTrue(exitValue == 0);
+    }
+
+
+    /**
+     * Run the test with "-addmods misc", the misc module has package
+     * sun.misc and so should overlap with the base module.
+     */
+    public void testOverlapWithBaseModule() throws Exception {
+        int exitValue
+            = executeTestJava("-mp", MODS_DIR.toString(),
+                              "-addmods", "misc",
+                              "-m", "test/test.Main")
+                .outputTo(System.out)
+                .errorTo(System.err)
+                .getExitValue();
+
+        assertTrue(exitValue != 0);
+    }
+
+    /**
+     * Run the test with "-addmods m1,m2". Both modules have package p.
+     */
+    public void testOverlap() throws Exception {
+        int exitValue
+            = executeTestJava("-mp", MODS_DIR.toString(),
+                              "-addmods", "m1,m2",
+                              "-m", "test/test.Main")
+                .outputTo(System.out)
+                .errorTo(System.err)
+                .getExitValue();
+
+        assertTrue(exitValue != 0);
+    }
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/modules/scenarios/overlappingpackages/src/m1/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m1 {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/modules/scenarios/overlappingpackages/src/m1/p/C1.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p;
+
+public class C1 { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/modules/scenarios/overlappingpackages/src/m2/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m2 {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/modules/scenarios/overlappingpackages/src/m2/p/C2.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p;
+
+public class C2 { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/modules/scenarios/overlappingpackages/src/misc/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module misc {
+    exports sun.misc;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/modules/scenarios/overlappingpackages/src/misc/sun/misc/Unsafe.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.misc;
+
+public class Unsafe {
+    private Unsafe() { }
+
+    public static long getLong(long address) {
+        return 0L;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/modules/scenarios/overlappingpackages/src/test/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module test {
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/modules/scenarios/overlappingpackages/src/test/test/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package test;
+
+public class Main {
+    public static void main(String[] args) { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/testlibrary/CompilerUtils.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import javax.tools.JavaCompiler;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.StandardLocation;
+import javax.tools.ToolProvider;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * This class consists exclusively of static utility methods for invoking the
+ * java compiler.
+ */
+
+public final class CompilerUtils {
+    private CompilerUtils() { }
+
+    /**
+     * Compile all the java sources in {@code <source>/**} to
+     * {@code <destination>/**}. The destination directory will be created if
+     * it doesn't exist.
+     *
+     * All warnings/errors emitted by the compiler are output to System.out/err.
+     *
+     * @return true if the compilation is successful
+     *
+     * @throws IOException if there is an I/O error scanning the source tree or
+     *                     creating the destination directory
+     */
+    public static boolean compile(Path source, Path destination, String ... options)
+        throws IOException
+    {
+        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+        StandardJavaFileManager jfm = compiler.getStandardFileManager(null, null, null);
+
+        List<Path> sources
+            = Files.find(source, Integer.MAX_VALUE,
+                (file, attrs) -> (file.toString().endsWith(".java")))
+                .collect(Collectors.toList());
+
+        Files.createDirectories(destination);
+        jfm.setLocation(StandardLocation.CLASS_PATH, Collections.EMPTY_LIST);
+        jfm.setLocationFromPaths(StandardLocation.CLASS_OUTPUT,
+                                 Arrays.asList(destination));
+
+        List<String> opts = Arrays.asList(options);
+        JavaCompiler.CompilationTask task
+            = compiler.getTask(null, jfm, null, opts, null,
+                jfm.getJavaFileObjectsFromPaths(sources));
+
+        return task.call();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/testlibrary/JarUtils.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * This class consists exclusively of static utility methods that are useful
+ * for creating and manipulating JAR files.
+ */
+
+public final class JarUtils {
+    private JarUtils() { }
+
+    /**
+     * Creates a JAR file.
+     *
+     * Equivalent to {@code jar cf <jarfile> -C <dir> file...}
+     *
+     * The input files are resolved against the given directory. Any input
+     * files that are directories are processed recursively.
+     */
+    public static void createJarFile(Path jarfile, Path dir, Path... file)
+        throws IOException
+    {
+        // create the target directory
+        Path parent = jarfile.getParent();
+        if (parent != null)
+            Files.createDirectories(parent);
+
+        List<Path> entries = new ArrayList<>();
+        for (Path entry : file) {
+            Files.find(dir.resolve(entry), Integer.MAX_VALUE,
+                        (p, attrs) -> attrs.isRegularFile())
+                    .map(e -> dir.relativize(e))
+                    .forEach(entries::add);
+        }
+
+        try (OutputStream out = Files.newOutputStream(jarfile);
+             JarOutputStream jos = new JarOutputStream(out))
+        {
+            for (Path entry : entries) {
+                String name = toJarEntryName(entry);
+                jos.putNextEntry(new JarEntry(name));
+                Files.copy(dir.resolve(entry), jos);
+            }
+        }
+    }
+
+    /**
+     * Creates a JAR file.
+     *
+     * Equivalent to {@code jar cf <jarfile> -C <dir> file...}
+     *
+     * The input files are resolved against the given directory. Any input
+     * files that are directories are processed recursively.
+     */
+    public static void createJarFile(Path jarfile, Path dir, String... input)
+        throws IOException
+    {
+        Path[] paths = Stream.of(input).map(Paths::get).toArray(Path[]::new);
+        createJarFile(jarfile, dir, paths);
+    }
+
+    /**
+     * Creates a JAR file from the contents of a directory.
+     *
+     * Equivalent to {@code jar cf <jarfile> -C <dir> .}
+     */
+    public static void createJarFile(Path jarfile, Path dir) throws IOException {
+        createJarFile(jarfile, dir, Paths.get("."));
+    }
+
+    /**
+     * Update a JAR file.
+     *
+     * Equivalent to {@code jar uf <jarfile> -C <dir> file...}
+     *
+     * The input files are resolved against the given directory. Any input
+     * files that are directories are processed recursively.
+     */
+    public static void updateJarFile(Path jarfile, Path dir, Path... file)
+        throws IOException
+    {
+        List<Path> entries = new ArrayList<>();
+        for (Path entry : file) {
+            Files.find(dir.resolve(entry), Integer.MAX_VALUE,
+                    (p, attrs) -> attrs.isRegularFile())
+                    .map(e -> dir.relativize(e))
+                    .forEach(entries::add);
+        }
+
+        Set<String> names = entries.stream()
+                .map(JarUtils::toJarEntryName)
+                .collect(Collectors.toSet());
+
+        Path tmpfile = Files.createTempFile("jar", "jar");
+
+        try (OutputStream out = Files.newOutputStream(tmpfile);
+             JarOutputStream jos = new JarOutputStream(out))
+        {
+            // copy existing entries from the original JAR file
+            try (JarFile jf = new JarFile(jarfile.toString())) {
+                Enumeration<JarEntry> jentries = jf.entries();
+                while (jentries.hasMoreElements()) {
+                    JarEntry jentry = jentries.nextElement();
+                    if (!names.contains(jentry.getName())) {
+                        jos.putNextEntry(jentry);
+                        jf.getInputStream(jentry).transferTo(jos);
+                    }
+                }
+            }
+
+            // add the new entries
+            for (Path entry : entries) {
+                String name = toJarEntryName(entry);
+                jos.putNextEntry(new JarEntry(name));
+                Files.copy(dir.resolve(entry), jos);
+            }
+        }
+
+        // replace the original JAR file
+        Files.move(tmpfile, jarfile, StandardCopyOption.REPLACE_EXISTING);
+    }
+
+    /**
+     * Update a JAR file.
+     *
+     * Equivalent to {@code jar uf <jarfile> -C <dir> .}
+     */
+    public static void updateJarFile(Path jarfile, Path dir) throws IOException {
+        updateJarFile(jarfile, dir, Paths.get("."));
+    }
+
+
+    /**
+     * Map a file path to the equivalent name in a JAR file
+     */
+    private static String toJarEntryName(Path file) {
+        Path normalized = file.normalize();
+        return normalized.subpath(0, normalized.getNameCount())  // drop root
+                .toString()
+                .replace(File.separatorChar, '/');
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/testlibrary/ModuleUtils.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReader;
+import java.lang.module.ModuleReference;
+import java.net.URI;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Supplier;
+
+
+/**
+ * This class consists exclusively of static utility methods that are useful
+ * for creating tests for modules.
+ */
+
+public final class ModuleUtils {
+    private ModuleUtils() { }
+
+
+    /**
+     * Returns a ModuleFinder that finds modules with the given module
+     * descriptors.
+     */
+    static ModuleFinder finderOf(ModuleDescriptor... descriptors) {
+
+        // Create a ModuleReference for each module
+        Map<String, ModuleReference> namesToReference = new HashMap<>();
+
+        for (ModuleDescriptor descriptor : descriptors) {
+            String name = descriptor.name();
+
+            URI uri = URI.create("module:/" + name);
+
+            Supplier<ModuleReader> supplier = () -> {
+                throw new UnsupportedOperationException();
+            };
+
+            ModuleReference mref = new ModuleReference(descriptor, uri, supplier);
+
+            namesToReference.put(name, mref);
+        }
+
+        return new ModuleFinder() {
+            @Override
+            public Optional<ModuleReference> find(String name) {
+                Objects.requireNonNull(name);
+                return Optional.ofNullable(namesToReference.get(name));
+            }
+            @Override
+            public Set<ModuleReference> findAll() {
+                return new HashSet<>(namesToReference.values());
+            }
+        };
+    }
+
+}
--- a/test/lib/testlibrary/jdk/testlibrary/OutputAnalyzer.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/lib/testlibrary/jdk/testlibrary/OutputAnalyzer.java	Thu Mar 17 19:04:16 2016 +0000
@@ -26,6 +26,7 @@
 import static jdk.testlibrary.Asserts.*;
 
 import java.io.IOException;
+import java.io.PrintStream;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.regex.Matcher;
@@ -422,6 +423,28 @@
         return output == null ? exitValue : output.getExitValue();
     }
 
+
+    /**
+     * Print the stdout buffer to the given {@code PrintStream}.
+     *
+     * @return this OutputAnalyzer
+     */
+    public OutputAnalyzer outputTo(PrintStream out) {
+        out.println(getStdout());
+        return this;
+    }
+
+    /**
+     * Print the stderr buffer to the given {@code PrintStream}.
+     *
+     * @return this OutputAnalyzer
+     */
+    public OutputAnalyzer errorTo(PrintStream out) {
+        out.println(getStderr());
+        return this;
+    }
+
+
     /**
      * Get the contents of the output buffer (stdout and stderr) as list of strings.
      * Output will be split by system property 'line.separator'.
--- a/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java	Thu Mar 17 19:04:16 2016 +0000
@@ -340,24 +340,31 @@
     }
 
     /**
-     * Executes a test jvm process, waits for it to finish and returns the process output.
-     * The default jvm options from jtreg, test.vm.opts and test.java.opts, are added.
+     * Executes a test java process, waits for it to finish and returns the process output.
+     * The default options from jtreg, test.vm.opts and test.java.opts, are added.
      * The java from the test.jdk is used to execute the command.
      *
      * The command line will be like:
      * {test.jdk}/bin/java {test.vm.opts} {test.java.opts} cmds
      *
-     * The jvm process will have exited before this method returns.
+     * The java process will have exited before this method returns.
      *
      * @param cmds User specifed arguments.
      * @return The output from the process.
      */
-    public static OutputAnalyzer executeTestJvm(String... cmds) throws Exception {
-        ProcessBuilder pb = createJavaProcessBuilder(Utils.addTestJavaOpts(cmds));
+    public static OutputAnalyzer executeTestJava(String... options) throws Exception {
+        ProcessBuilder pb = createJavaProcessBuilder(Utils.addTestJavaOpts(options));
         return executeProcess(pb);
     }
 
     /**
+     * @deprecated Use executeTestJava instead
+     */
+    public static OutputAnalyzer executeTestJvm(String... options) throws Exception {
+        return executeTestJava(options);
+    }
+
+    /**
      * Executes a process, waits for it to finish and returns the process output.
      * The process will have exited before this method returns.
      * @param pb The ProcessBuilder to execute.
--- a/test/sun/awt/shell/ShellFolderMemoryLeak.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/awt/shell/ShellFolderMemoryLeak.java	Thu Mar 17 19:04:16 2016 +0000
@@ -93,6 +93,7 @@
         String command = javaPath + File.separator + "bin" + File.separator
                 + "java -Xmx256M" + arg1 + " -cp "
                 + classPathDir
+                + " -XaddExports:java.desktop/sun.awt.shell=ALL-UNNAMED"
                 + " ShellFolderMemoryLeak " + arg2;
         process = Runtime.getRuntime().exec(command);
         BufferedReader input = null;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/management/StackTraceElementCompositeData/CompatibilityTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,72 @@
+
+import java.util.HashMap;
+import java.util.Map;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+import sun.management.StackTraceElementCompositeData;
+
+import org.testng.annotations.*;
+import static org.testng.Assert.*;
+
+/*
+ * @test
+ * @bug     8139587
+ * @summary Check backward compatibility of StackTraceElementCompositeData
+ * @modules java.management/sun.management
+ * @run testng CompatibilityTest
+ * @author  Jaroslav Bachorik
+ */
+
+public class CompatibilityTest {
+    private static CompositeType compositeTypeV6;
+    private static Map<String, Object> itemsV6;
+    private static CompositeData compositeDataV6;
+
+    @BeforeClass
+    public static void setup() throws Exception {
+        compositeTypeV6 = new CompositeType(
+            StackTraceElement.class.getName(),
+            "StackTraceElement",
+            new String[]{
+                "className", "methodName", "fileName", "nativeMethod", "lineNumber"
+            },
+            new String[]{
+                "className", "methodName", "fileName", "nativeMethod", "lineNumber"
+            },
+            new OpenType[]{
+                SimpleType.STRING,
+                SimpleType.STRING,
+                SimpleType.STRING,
+                SimpleType.BOOLEAN,
+                SimpleType.INTEGER
+            }
+        );
+
+        itemsV6 = new HashMap<>();
+        itemsV6.put("className", "MyClass");
+        itemsV6.put("methodName", "myMethod");
+        itemsV6.put("fileName", "MyClass.java");
+        itemsV6.put("nativeMethod", false);
+        itemsV6.put("lineNumber", 123);
+
+        compositeDataV6 = new CompositeDataSupport(compositeTypeV6, itemsV6);
+    }
+
+    @Test
+    public void testV6Compatibility() throws Exception {
+        StackTraceElement ste = StackTraceElementCompositeData.from(compositeDataV6);
+
+        assertNotNull(ste);
+        assertEquals(ste.getClassName(), "MyClass");
+        assertEquals(ste.getMethodName(), "myMethod");
+        assertEquals(ste.getFileName(), "MyClass.java");
+        assertEquals(ste.isNativeMethod(), false);
+        assertEquals(ste.getLineNumber(), 123);
+
+        assertNull(ste.getModuleName());
+        assertNull(ste.getModuleVersion());
+    }
+}
\ No newline at end of file
--- a/test/sun/management/jmxremote/bootstrap/CustomLauncherTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/management/jmxremote/bootstrap/CustomLauncherTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -150,6 +150,7 @@
             ProcessBuilder client = ProcessTools.createJavaProcessBuilder(
                 "-cp",
                 TEST_CLASSPATH,
+                "-XaddExports:java.management/sun.management=ALL-UNNAMED",
                 "TestManager",
                 String.valueOf(serverPrc.getPid()),
                 port.get(),
--- a/test/sun/management/jmxremote/bootstrap/LocalManagementTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/management/jmxremote/bootstrap/LocalManagementTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -131,6 +131,7 @@
             ProcessBuilder client = ProcessTools.createJavaProcessBuilder(
                 "-cp",
                 TEST_CLASSPATH,
+                "-XaddExports:java.management/sun.management=ALL-UNNAMED",
                 "TestManager",
                 String.valueOf(serverPrc.getPid()),
                 port.get(),
--- a/test/sun/management/jmxremote/bootstrap/RmiBootstrapTest.sh	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/management/jmxremote/bootstrap/RmiBootstrapTest.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -51,6 +51,9 @@
 DEBUGOPTIONS=""
 export DEBUGOPTIONS
 
+EXTRAOPTIONS="-XaddExports:java.management/sun.management=ALL-UNNAMED,java.management/sun.management.jmxremote=ALL-UNNAMED"
+export EXTRAOPTIONS
+
 # Call the common generic test
 #
 # No need to since bug 4267864 is now fixed. 
@@ -58,7 +61,7 @@
 echo -------------------------------------------------------------
 echo Launching test for `basename $0 .sh`
 echo -------------------------------------------------------------
-sh ${TESTSRC}/../RunTest.sh ${DEBUGOPTIONS} ${TESTCLASS}
+sh ${TESTSRC}/../RunTest.sh ${DEBUGOPTIONS} ${EXTRAOPTIONS} ${TESTCLASS}
 result=$?
 restoreFilePermissions `ls ${TESTSRC}/*_test*.in`
 exit $result
--- a/test/sun/management/jmxremote/bootstrap/RmiSslBootstrapTest.sh	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/management/jmxremote/bootstrap/RmiSslBootstrapTest.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -49,12 +49,15 @@
 DEBUGOPTIONS=""
 export DEBUGOPTIONS
 
+EXTRAOPTIONS="-XaddExports:java.management/sun.management=ALL-UNNAMED,java.management/sun.management.jmxremote=ALL-UNNAMED"
+export EXTRAOPTIONS
+
 # Call the common generic test
 #
 echo -------------------------------------------------------------
 echo Launching test for `basename $0 .sh`
 echo -------------------------------------------------------------
-sh ${TESTSRC}/../RunTest.sh ${DEBUGOPTIONS} ${TESTCLASS} \
+sh ${TESTSRC}/../RunTest.sh ${DEBUGOPTIONS} ${EXTRAOPTIONS} ${TESTCLASS} \
     ${TESTCLASSES}/management_ssltest*.properties
 result=$?
 restoreFilePermissions `ls ${TESTSRC}/*_ssltest*.in`
--- a/test/sun/management/jmxremote/bootstrap/RmiSslNoKeyStoreTest.sh	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/management/jmxremote/bootstrap/RmiSslNoKeyStoreTest.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -48,12 +48,15 @@
 DEBUGOPTIONS=""
 export DEBUGOPTIONS
 
+EXTRAOPTIONS="-XaddExports:java.management/sun.management=ALL-UNNAMED,java.management/sun.management.jmxremote=ALL-UNNAMED"
+export EXTRAOPTIONS
+
 # Call the common generic test
 #
 echo -------------------------------------------------------------
 echo Launching test for `basename $0 .sh`
 echo -------------------------------------------------------------
-sh ${TESTSRC}/../RunTest.sh ${DEBUGOPTIONS} ${TESTCLASS} \
+sh ${TESTSRC}/../RunTest.sh ${DEBUGOPTIONS} ${EXTRAOPTIONS} ${TESTCLASS} \
     ${TESTCLASSES}/management_ssltest*.properties
 result=$?
 restoreFilePermissions `ls ${TESTSRC}/*_ssltest*.in`
--- a/test/sun/management/jmxremote/startstop/JMXStatusPerfCountersTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/management/jmxremote/startstop/JMXStatusPerfCountersTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -42,6 +42,7 @@
  *          in the related performance counters.
  * @key intermittent
  * @library /lib/testlibrary
+ * @modules java.management/sun.management
  * @build jdk.testlibrary.* PortAllocator TestApp ManagementAgentJcmd
  * @run testng/othervm -XX:+UsePerfData JMXStatusPerfCountersTest
  */
--- a/test/sun/net/idn/TestStringPrep.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/net/idn/TestStringPrep.java	Thu Mar 17 19:04:16 2016 +0000
@@ -231,7 +231,8 @@
     }
 
     public static void TestNamePrepConformance() throws Exception {
-        InputStream stream = StringPrep.class.getResourceAsStream("uidna.spp");
+        InputStream stream = StringPrep.class.getModule()
+                                             .getResourceAsStream("sun/net/idn/uidna.spp");
         StringPrep namePrep = new StringPrep(stream);
         stream.close();
         int i;
--- a/test/sun/net/util/IPAddressUtilTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/net/util/IPAddressUtilTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -25,6 +25,7 @@
  * @test
  * @bug 8087190
  * @summary Exercise the sun.net.util.IPAddressUtil class
+ * @modules java.base/sun.net.util
  */
 
 import sun.net.util.*;
--- a/test/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxy.sh	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxy.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -28,6 +28,7 @@
 # @test
 # @bug 4423074
 # @summary Need to rebase all the duplicated classes from Merlin
+# @modules java.base/sun.net.www
 
 HOSTNAME=`uname -n`
 OS=`uname -s`
@@ -50,9 +51,12 @@
     ;;
 esac
 
-${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . \
+EXTRAOPTS="-XaddExports:java.base/sun.net.www=ALL-UNNAMED"
+
+${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ${EXTRAOPTS} -d . \
     ${TESTSRC}${FS}OriginServer.java \
     ${TESTSRC}${FS}ProxyTunnelServer.java \
     ${TESTSRC}${FS}PostThruProxy.java
-${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} PostThruProxy ${HOSTNAME} ${TESTSRC}
+${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${EXTRAOPTS} \
+    PostThruProxy ${HOSTNAME} ${TESTSRC}
 exit
--- a/test/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxyWithAuth.sh	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxyWithAuth.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -28,6 +28,7 @@
 # @test
 # @bug 4423074
 # @summary Need to rebase all the duplicated classes from Merlin
+# @modules java.base/sun.net.www
 
 HOSTNAME=`uname -n`
 OS=`uname -s`
@@ -50,8 +51,11 @@
     ;;
 esac
 
-${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . ${TESTSRC}${FS}OriginServer.java \
+EXTRAOPTS="-XaddExports:java.base/sun.net.www=ALL-UNNAMED"
+${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ${EXTRAOPTS} \
+    -d . ${TESTSRC}${FS}OriginServer.java \
     ${TESTSRC}${FS}ProxyTunnelServer.java \
     ${TESTSRC}${FS}PostThruProxyWithAuth.java
-${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} PostThruProxyWithAuth ${HOSTNAME} ${TESTSRC}
+${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${EXTRAOPTS} \
+    PostThruProxyWithAuth ${HOSTNAME} ${TESTSRC}
 exit
--- a/test/sun/net/www/protocol/jrt/Basic.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/net/www/protocol/jrt/Basic.java	Thu Mar 17 19:04:16 2016 +0000
@@ -38,26 +38,6 @@
 
 public class Basic {
 
-    @DataProvider(name = "resources")
-    public Object[][] resources() {
-        Object[][] data = {
-            { "java/lang/Object.class",   "jrt:/java.base/java/lang/Object.class" },
-            { "java/awt/Component.class", "jrt:/java.desktop/java/awt/Component.class" },
-            { "jdk/internal/DoesNotExist", null },
-        };
-        return data;
-    }
-
-    @Test(dataProvider = "resources")
-    public void testResources(String name, String expectedUrlString) throws Exception {
-        URL url = ClassLoader.getSystemResource(name);
-        if (url == null) {
-            assertTrue(expectedUrlString == null);
-        } else {
-            assertEquals(url.toString(), expectedUrlString);
-        }
-    }
-
     @DataProvider(name = "urls")
     public Object[][] urls() {
         Object[][] data = {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/net/www/protocol/jrt/OtherResources.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
+
+/**
+ * Access a jrt:/ resource in an observable module that is not in the boot
+ * layer and hence not known to the built-in class loaders.
+ */
+
+public class OtherResources {
+    public static void main(String[] args) throws IOException {
+
+        // check that java.desktop is not in the set of readable modules
+        try {
+            Class.forName("java.awt.Component");
+            throw new RuntimeException("Need to run with -limitmods java.base");
+        } catch (ClassNotFoundException expected) { }
+
+        // access resource in the java.desktop module
+        URL url = new URL("jrt:/java.desktop/java/awt/Component.class");
+        URLConnection uc = url.openConnection();
+        System.out.println(uc.getInputStream());
+    }
+}
--- a/test/sun/net/www/protocol/jrt/WithSecurityManager.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/net/www/protocol/jrt/WithSecurityManager.java	Thu Mar 17 19:04:16 2016 +0000
@@ -29,6 +29,8 @@
  */
 
 import java.io.InputStream;
+import java.io.IOException;
+import java.net.URL;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
@@ -36,8 +38,8 @@
 public class WithSecurityManager {
     public static void main(String[] args) throws Exception {
         String home = System.getProperty("java.home");
-        Path bootmodules = Paths.get(home, "lib", "modules", "bootmodules.jimage");
-        if (Files.notExists(bootmodules)) {
+        Path modules = Paths.get(home, "lib", "modules");
+        if (!Files.isRegularFile(modules)) {
             System.out.println("This runtime is not jimage, test skipped");
             return;
         }
@@ -55,7 +57,13 @@
 
         System.setSecurityManager(new SecurityManager());
 
-        InputStream in = ClassLoader.getSystemResourceAsStream("java/lang/Object.class");
+        InputStream in = null;
+        URL url = new URL("jrt:/java.base/java/lang/Object.class");
+        if (url != null) {
+            try {
+                in = url.openStream();
+            } catch (IOException ignore) { }
+        }
         if (in == null && allow)
             throw new RuntimeException("access expected");
         if (in != null && !allow)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/net/www/protocol/jrt/other_resources.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,45 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+# @test
+# @build OtherResources
+# @run shell other_resources.sh
+# @summary Access a jrt:/ resource in an observable module that is not in
+#  the boot layer and hence not known to the built-in class loaders. This
+#  test is a shell test because the run tag doesn't support -limitmods.
+
+set -e
+
+if [ -z "$TESTJAVA" ]; then
+  if [ $# -lt 1 ]; then exit 1; fi
+  TESTJAVA="$1"; shift
+  COMPILEJAVA="${TESTJAVA}"
+  TESTSRC="`pwd`"
+  TESTCLASSES="`pwd`"
+fi
+
+JAVA="$TESTJAVA/bin/java ${TESTVMOPTS}"
+$JAVA -limitmods java.base -cp $TESTCLASSES OtherResources
+
+exit 0
+
--- a/test/sun/reflect/Reflection/GetCallerClassTest.sh	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/reflect/Reflection/GetCallerClassTest.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -55,14 +55,16 @@
 rm -rf ${BCP}
 mkdir ${BCP}
 
+EXTRAOPTS="-XaddExports:java.base/sun.reflect=ALL-UNNAMED"
+
 # Compile GetCallerClass in bootclasspath
-${COMPILEJAVA}/bin/javac ${TESTTOOLVMOPTS} \
+${COMPILEJAVA}/bin/javac ${TESTTOOLVMOPTS} ${EXTRAOPTS} \
      -XDignore.symbol.file \
      -d ${BCP} ${TESTSRC}/GetCallerClass.java  || exit 1
 
-${COMPILEJAVA}/bin/javac ${TESTTOOLVMOPTS} \
-     -XDignore.symbol.file -Xbootclasspath/a:${BCP} \
+${COMPILEJAVA}/bin/javac ${TESTTOOLVMOPTS} ${EXTRAOPTS} \
+     -XDignore.symbol.file -cp ${BCP} \
      -d ${TESTCLASSES} ${TESTSRC}/GetCallerClassTest.java  || exit 2
 
-${TESTJAVA}/bin/java ${TESTVMOPTS} -Xbootclasspath/a:${BCP} \
+${TESTJAVA}/bin/java ${TESTVMOPTS} ${EXTRAOPTS} -Xbootclasspath/a:${BCP} \
      -cp ${TESTCLASSES} GetCallerClassTest || exit 3
--- a/test/sun/reflect/constantPool/ConstantPoolTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/reflect/constantPool/ConstantPoolTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -25,7 +25,8 @@
  * @test
  * @bug 8141615
  * @summary Tests new public methods at sun.reflect.ConstantPool
- * @modules java.base/sun.reflect
+ * @modules java.base/jdk.internal.misc
+ *          java.base/sun.reflect
  * @library /lib/testlibrary
  * @compile ConstantPoolTestDummy.jasm
  * @run main sun.reflect.constantPool.ConstantPoolTest
--- a/test/sun/rmi/runtime/Log/6409194/NoConsoleOutput.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/rmi/runtime/Log/6409194/NoConsoleOutput.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -66,9 +66,13 @@
 
         // We instantiate a JavaVM that should not produce any console output
         // (neither on standard output, nor on standard err streams).
-        JavaVM vm = new JavaVM(DoRMIStuff.class.getName(),
-            "-Djava.util.logging.config.file=" + loggingPropertiesFile,
-                               "", out, err);
+        JavaVM vm = new JavaVM(
+                DoRMIStuff.class.getName(),
+                "-XaddExports:java.rmi/sun.rmi.registry=ALL-UNNAMED,"
+                + "java.rmi/sun.rmi.server=ALL-UNNAMED,java.rmi/sun.rmi.transport=ALL-UNNAMED,"
+                + "java.rmi/sun.rmi.transport.tcp=ALL-UNNAMED"
+                + " -Djava.util.logging.config.file="
+                + loggingPropertiesFile, "", out, err);
         vm.execute();
 
         /*
--- a/test/sun/security/krb5/auto/HttpNegotiateServer.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/security/krb5/auto/HttpNegotiateServer.java	Thu Mar 17 19:04:16 2016 +0000
@@ -24,6 +24,14 @@
 /*
  * @test
  * @bug 6578647 6829283
+ * @modules java.base/sun.net.spi.nameservice
+ *          java.base/sun.security.util
+ *          java.security.jgss/sun.security.jgss
+ *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5.internal
+ *          java.security.jgss/sun.security.krb5.internal.ccache
+ *          java.security.jgss/sun.security.krb5.internal.crypto
+ *          java.security.jgss/sun.security.krb5.internal.ktab
  * @run main/othervm HttpNegotiateServer
  * @summary Undefined requesting URL in java.net.Authenticator.getPasswordAuthentication()
  * @summary HTTP/Negotiate: Authenticator triggered again when user cancels the first one
--- a/test/sun/security/krb5/config/ConfPlusProp.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/security/krb5/config/ConfPlusProp.java	Thu Mar 17 19:04:16 2016 +0000
@@ -25,6 +25,7 @@
  * @bug 6857795
  * @bug 6858589
  * @bug 6972005
+ * @modules java.security.jgss/sun.security.krb5
  * @compile -XDignore.symbol.file ConfPlusProp.java
  * @run main/othervm ConfPlusProp
  * @summary krb5.conf ignored if system properties on realm and kdc are provided
--- a/test/sun/security/krb5/config/DNS.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/security/krb5/config/DNS.java	Thu Mar 17 19:04:16 2016 +0000
@@ -21,7 +21,14 @@
  * questions.
  */
 
-// See dns.sh.
+/*
+ * @test
+ * @bug 8002344
+ * @summary Krb5LoginModule config class does not return proper KDC list from DNS
+ * @modules java.security.jgss/sun.security.krb5
+ * @build java.naming/javax.naming.spi.NamingManager
+ * @run main/othervm DNS
+ */
 import sun.security.krb5.Config;
 import sun.security.krb5.KrbException;
 
--- a/test/sun/security/krb5/config/NamingManager.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package javax.naming.spi;
-
-import java.util.Hashtable;
-import javax.naming.Context;
-import javax.naming.NamingException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.Attributes;
-import javax.naming.directory.BasicAttribute;
-import javax.naming.directory.BasicAttributes;
-import javax.naming.directory.InitialDirContext;
-
-/**
- * A fake javax.naming.spi.NamingManager. It allows reading a DNS
- * record without contacting a real server.
- *
- * See DNS.java and dns.sh.
- */
-public class NamingManager {
-    NamingManager() {}
-    public static Context getURLContext(
-            String scheme, Hashtable<?,?> environment)
-            throws NamingException {
-        return new InitialDirContext() {
-            public Attributes getAttributes(String name, String[] attrIds)
-                    throws NamingException {
-                return new BasicAttributes() {
-                    public Attribute get(String attrID) {
-                        BasicAttribute ba  = new BasicAttribute(attrID);
-                        ba.add("1 1 99 b.com.");
-                        ba.add("0 0 88 a.com.");    // 2nd has higher priority
-                        return ba;
-                    }
-                };
-            }
-        };
-    }
-}
--- a/test/sun/security/krb5/config/dns.sh	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-#
-# Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-# @test
-# @bug 8002344
-# @summary Krb5LoginModule config class does not return proper KDC list from DNS
-#
-
-env
-
-if [ "${TESTJAVA}" = "" ] ; then
-  JAVAC_CMD=`which javac`
-  TESTJAVA=`dirname $JAVAC_CMD`/..
-  COMPILEJAVA="${TESTJAVA}"
-fi
-
-if [ "${TESTSRC}" = "" ] ; then
-   TESTSRC="."
-fi
-
-$COMPILEJAVA/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . \
-   ${TESTSRC}/NamingManager.java ${TESTSRC}/DNS.java
-$TESTJAVA/bin/java ${TESTVMOPTS} -Xbootclasspath/p:. DNS
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/krb5/config/java.naming/javax/naming/spi/NamingManager.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.naming.spi;
+
+import java.util.Hashtable;
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttribute;
+import javax.naming.directory.BasicAttributes;
+import javax.naming.directory.InitialDirContext;
+
+/**
+ * A fake javax.naming.spi.NamingManager. It allows reading a DNS
+ * record without contacting a real server.
+ *
+ * See DNS.java and dns.sh.
+ */
+public class NamingManager {
+    NamingManager() {}
+    public static Context getURLContext(
+            String scheme, Hashtable<?,?> environment)
+            throws NamingException {
+        return new InitialDirContext() {
+            public Attributes getAttributes(String name, String[] attrIds)
+                    throws NamingException {
+                return new BasicAttributes() {
+                    public Attribute get(String attrID) {
+                        BasicAttribute ba  = new BasicAttribute(attrID);
+                        ba.add("1 1 99 b.com.");
+                        ba.add("0 0 88 a.com.");    // 2nd has higher priority
+                        return ba;
+                    }
+                };
+            }
+        };
+    }
+}
--- a/test/sun/security/krb5/tools/ktcheck.sh	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/security/krb5/tools/ktcheck.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -24,6 +24,9 @@
 # @test
 # @bug 6950546
 # @summary "ktab -d name etype" to "ktab -d name [-e etype] [kvno | all | old]"
+# @modules java.security.jgss/sun.security.krb5.internal.ktab
+#          java.security.jgss/sun.security.krb5
+# @compile KtabCheck.java
 # @run shell ktcheck.sh
 #
 
@@ -54,11 +57,12 @@
 KEYTAB=ktab.tmp
 
 rm $KEYTAB
-${TESTJAVA}${FS}bin${FS}javac -d . ${TESTSRC}${FS}KtabCheck.java
 
 EXTRA_OPTIONS="-Djava.security.krb5.conf=${TESTSRC}${FS}onlythree.conf"
 KTAB="${TESTJAVA}${FS}bin${FS}ktab -J${EXTRA_OPTIONS} -k $KEYTAB -f"
-CHECK="${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${EXTRA_OPTIONS} KtabCheck $KEYTAB"
+CHECK="${TESTJAVA}${FS}bin${FS}java -cp ${TESTCLASSES} ${TESTVMOPTS} ${EXTRA_OPTIONS} \
+        -XaddExports:java.security.jgss/sun.security.krb5.internal.ktab=ALL-UNNAMED,java.security.jgss/sun.security.krb5=ALL-UNNAMED \
+        KtabCheck $KEYTAB"
 
 echo ${EXTRA_OPTIONS}
 
--- a/test/sun/security/mscapi/IsSunMSCAPIAvailable.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/security/mscapi/IsSunMSCAPIAvailable.java	Thu Mar 17 19:04:16 2016 +0000
@@ -21,8 +21,12 @@
  * questions.
  */
 
-/**
- * @see IsSunMSCAPIAvailable.sh
+/*
+ * @test
+ * @bug 6318171 6931562
+ * @requires os.family == "windows"
+ * @modules jdk.crypto.mscapi/sun.security.mscapi
+ * @run main/othervm IsSunMSCAPIAvailable
  */
 
 import java.security.Provider;
--- a/test/sun/security/mscapi/IsSunMSCAPIAvailable.sh	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-#!/bin/sh
-
-#
-# Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-
-# @test
-# @bug 6318171 6931562
-# @requires os.family == "windows"
-# @run shell IsSunMSCAPIAvailable.sh
-# @summary Basic test of the Microsoft CryptoAPI provider.
-
-OS=`uname -s`
-case "$OS" in
-    Windows* | CYGWIN* )
-
-    # 'uname -m' does not give us enough information -
-    #  should rely on $PROCESSOR_IDENTIFIER (as is done in Defs-windows.gmk),
-    #  but JTREG does not pass this env variable when executing a shell script.
-    #
-    #  execute test program - rely on it to exit if platform unsupported
-
-	${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . ${TESTSRC}\\IsSunMSCAPIAvailable.java
-	${TESTJAVA}/bin/java ${TESTVMOPTS} IsSunMSCAPIAvailable
-	exit
-	;;
-
-    * )
-        echo "This test is not intended for '$OS' - passing test"
-        exit 0
-        ;;
-esac
-
--- a/test/sun/security/mscapi/PublicKeyInterop.sh	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/security/mscapi/PublicKeyInterop.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -25,7 +25,6 @@
 
 # @test
 # @bug 6888925
-# @modules java.base/sun.security.util
 # @requires os.family == "windows"
 # @run shell PublicKeyInterop.sh
 # @summary SunMSCAPI's Cipher can't use RSA public keys obtained from other
@@ -62,9 +61,11 @@
 	    -noprompt
 
         echo
-	echo "Running the test..."
-        ${TESTJAVA}/bin/javac ${TESTTOOLVMOPTS} ${TESTJAVACOPTS} -d . ${TESTSRC}\\PublicKeyInterop.java
-        ${TESTJAVA}/bin/java ${TESTVMOPTS} PublicKeyInterop
+        echo "Running the test..."
+        ${TESTJAVA}/bin/javac -XaddExports:java.base/sun.security.util=ALL-UNNAMED \
+            ${TESTTOOLVMOPTS} ${TESTJAVACOPTS} -d . ${TESTSRC}\\PublicKeyInterop.java
+        ${TESTJAVA}/bin/java -XaddExports:java.base/sun.security.util=ALL-UNNAMED \
+            ${TESTVMOPTS} PublicKeyInterop
 
         rc=$?
 
--- a/test/sun/security/mscapi/ShortRSAKey1024.sh	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/security/mscapi/ShortRSAKey1024.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -88,9 +88,11 @@
 
         echo
         echo "Running the test..."
-        ${TESTJAVA}${FS}bin${FS}javac ${TESTTOOLVMOPTS} ${TESTJAVACOPTS} -d . \
+        ${TESTJAVA}${FS}bin${FS}javac -XaddExports:java.base/sun.security.util=ALL-UNNAMED \
+            ${TESTTOOLVMOPTS} ${TESTJAVACOPTS} -d . \
             ${TESTSRC}${FS}ShortRSAKeyWithinTLS.java
-        ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ShortRSAKeyWithinTLS 7106773.$BITS $BITS \
+        ${TESTJAVA}${FS}bin${FS}java -XaddExports:java.base/sun.security.util=ALL-UNNAMED \
+            ${TESTVMOPTS} ShortRSAKeyWithinTLS 7106773.$BITS $BITS \
             TLSv1.2 TLS_DHE_RSA_WITH_AES_128_CBC_SHA
 
         rc=$?
--- a/test/sun/security/pkcs11/KeyStore/ClientAuth.sh	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/security/pkcs11/KeyStore/ClientAuth.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -126,7 +126,7 @@
 
 # compile test
 ${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \
-	-classpath ${TESTSRC}${FS}..${PS}${TESTSRC}${FS}loader.jar \
+	-classpath ${TESTSRC} \
 	-d ${TESTCLASSES} \
 	${TESTSRC}${FS}ClientAuth.java \
 	${TESTSRC}${FS}..${FS}PKCS11Test.java
@@ -134,7 +134,7 @@
 # run test
 echo "Run ClientAuth ..."
 ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} \
-	-classpath ${TESTCLASSES}${PS}${TESTSRC}${FS}loader.jar \
+	-classpath ${TESTCLASSES} \
 	-DDIR=${TESTSRC}${FS}ClientAuthData${FS} \
 	-DCUSTOM_DB_DIR=${TESTCLASSES} \
 	-DCUSTOM_P11_CONFIG=${TESTSRC}${FS}ClientAuthData${FS}p11-nss.txt \
@@ -155,7 +155,7 @@
 # run test with specified TLS protocol and cipher suite
 echo "Run ClientAuth TLSv1.2 TLS_DHE_RSA_WITH_AES_128_CBC_SHA"
 ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} \
-	-classpath ${TESTCLASSES}${PS}${TESTSRC}${FS}loader.jar \
+	-classpath ${TESTCLASSES} \
 	-DDIR=${TESTSRC}${FS}ClientAuthData${FS} \
 	-DCUSTOM_DB_DIR=${TESTCLASSES} \
 	-DCUSTOM_P11_CONFIG=${TESTSRC}${FS}ClientAuthData${FS}p11-nss.txt \
--- a/test/sun/security/pkcs11/Provider/Login.policy	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/security/pkcs11/Provider/Login.policy	Thu Mar 17 19:04:16 2016 +0000
@@ -1,6 +1,7 @@
 grant {
     permission java.util.PropertyPermission "*", "read, write";
     permission java.lang.RuntimePermission "loadLibrary.*";
+    permission java.lang.RuntimePermission "accessClassInPackage.apple.*";
     permission java.lang.RuntimePermission "accessClassInPackage.sun.*";
     permission java.lang.RuntimePermission "getProtectionDomain";
     permission java.security.SecurityPermission "putProviderProperty.*";
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/provider/PolicyFile/Modules.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8047771
+ * @summary check permissions and principals from various modules
+ * @run main/othervm/java.security.policy==modules.policy Modules
+ */
+
+import java.security.AccessController;
+import java.security.Permission;
+import java.security.Principal;
+import java.security.PrivilegedAction;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import javax.security.auth.Subject;
+
+public class Modules {
+
+    private final static Permission[] perms = new Permission[] {
+        // java.base module
+        new java.io.SerializablePermission("enableSubstitution"),
+        new java.lang.reflect.ReflectPermission("suppressAccessChecks"),
+        new java.nio.file.LinkPermission("hard"),
+        new javax.net.ssl.SSLPermission("getSSLSessionContext"),
+        new javax.security.auth.AuthPermission("doAsPrivileged"),
+        new javax.security.auth.PrivateCredentialPermission("* * \"*\"",
+                                                            "read"),
+        // java.base module (@jdk.Exported Permissions)
+        new jdk.net.NetworkPermission("setOption.SO_FLOW_SLA"),
+        // java.desktop module
+        new java.awt.AWTPermission("createRobot"),
+        new javax.sound.sampled.AudioPermission("play"),
+        // java.logging module
+        new java.util.logging.LoggingPermission("control", ""),
+        // java.management module
+        new java.lang.management.ManagementPermission("control"),
+        new javax.management.MBeanPermission("*", "getAttribute"),
+        new javax.management.MBeanServerPermission("createMBeanServer"),
+        new javax.management.MBeanTrustPermission("register"),
+        new javax.management.remote.SubjectDelegationPermission("*"),
+        // java.security.jgss module
+        new javax.security.auth.kerberos.DelegationPermission("\"*\" \"*\""),
+        new javax.security.auth.kerberos.ServicePermission("*", "accept"),
+        // java.sql module
+        new java.sql.SQLPermission("setLog"),
+        // java.xml.bind module
+        new javax.xml.bind.JAXBPermission("setDatatypeConverter"),
+        // java.xml.ws module
+        new javax.xml.ws.WebServicePermission("publishEndpoint"),
+        // java.smartcardio module
+        new javax.smartcardio.CardPermission("*", "*"),
+        // jdk.attach module (@jdk.Exported Permissions)
+        new com.sun.tools.attach.AttachPermission("attachVirtualMachine"),
+        // jdk.jdi module (@jdk.Exported Permissions)
+        new com.sun.jdi.JDIPermission("virtualMachineManager"),
+        // jdk.security.jgss module (@jdk.Exported Permissions)
+        new com.sun.security.jgss.InquireSecContextPermission("*"),
+    };
+
+    private final static Principal[] princs = new Principal[] {
+        // java.base module
+        new javax.security.auth.x500.X500Principal("CN=Duke"),
+        // java.management module
+        new javax.management.remote.JMXPrincipal("Duke"),
+        // java.security.jgss module
+        new javax.security.auth.kerberos.KerberosPrincipal("duke@openjdk.org"),
+        new com.sun.security.auth.UserPrincipal("Duke"),
+        new com.sun.security.auth.NTDomainPrincipal("openjdk.org"),
+        new com.sun.security.auth.NTSid(
+            "S-1-5-21-3623811015-3361044348-30300820-1013"),
+        new com.sun.security.auth.NTUserPrincipal("Duke"),
+        new com.sun.security.auth.UnixNumericUserPrincipal("0"),
+        new com.sun.security.auth.UnixPrincipal("duke"),
+    };
+
+    public static void main(String[] args) throws Exception {
+
+        for (Permission perm : perms) {
+            AccessController.checkPermission(perm);
+        }
+
+        Permission princPerm = new java.util.PropertyPermission("user.home",
+                                                                "read");
+        Set<Principal> princSet = new HashSet<>(Arrays.asList(princs));
+        Subject subject = new Subject(true, princSet, Collections.emptySet(),
+                                      Collections.emptySet());
+        PrivilegedAction<Void> pa = () -> {
+            AccessController.checkPermission(princPerm);
+            return null;
+        };
+        Subject.doAsPrivileged(subject, pa, null);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/provider/PolicyFile/modules.policy	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,67 @@
+grant {
+    // java.base module
+    permission java.io.SerializablePermission "enableSubstitution";
+    permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
+    permission java.nio.file.LinkPermission "hard";
+    permission javax.net.ssl.SSLPermission "getSSLSessionContext";
+    permission javax.security.auth.AuthPermission "doAsPrivileged";
+    permission javax.security.auth.PrivateCredentialPermission "* * \"*\"",
+                                                               "read";
+    // java.base module (@jdk.Exported Permissions)
+    permission jdk.net.NetworkPermission "setOption.SO_FLOW_SLA";
+    // java.desktop module
+    permission java.awt.AWTPermission "createRobot";
+    permission javax.sound.sampled.AudioPermission "play";
+    // java.logging module
+    permission java.util.logging.LoggingPermission "control", "";
+    // java.management module
+    permission java.lang.management.ManagementPermission "control";
+    permission javax.management.MBeanPermission "*", "getAttribute";
+    permission javax.management.MBeanServerPermission "createMBeanServer";
+    permission javax.management.MBeanTrustPermission "register";
+    permission javax.management.remote.SubjectDelegationPermission "*";
+    // java.security.jgss module
+    permission javax.security.auth.kerberos.DelegationPermission "\"*\" \"*\"";
+    permission javax.security.auth.kerberos.ServicePermission "*", "accept";
+    // java.sql module
+    permission java.sql.SQLPermission "setLog";
+    // javax.xml.bind module
+    permission javax.xml.bind.JAXBPermission "setDatatypeConverter";
+    // javax.xml.ws module
+    permission javax.xml.ws.WebServicePermission "publishEndpoint";
+    // java.smartcardio module
+    permission javax.smartcardio.CardPermission "*", "*";
+    // jdk.attach module (@jdk.Exported Permissions)
+    permission com.sun.tools.attach.AttachPermission "attachVirtualMachine";
+    // jdk.jdi module (@jdk.Exported Permissions)
+    permission com.sun.jdi.JDIPermission "virtualMachineManager";
+    // jdk.security.jgss module (@jdk.Exported Permissions)
+    permission com.sun.security.jgss.InquireSecContextPermission "*"; 
+};
+
+grant
+    // java.base module
+    principal javax.security.auth.x500.X500Principal "CN=Duke",
+    // java.management module
+    principal javax.management.remote.JMXPrincipal "Duke",
+    // java.security.jgss module
+    principal javax.security.auth.kerberos.KerberosPrincipal "duke@openjdk.org",
+    // jdk.security.auth module (@jdk.Exported Principals)
+    principal com.sun.security.auth.UserPrincipal "Duke",
+    principal com.sun.security.auth.NTDomainPrincipal "openjdk.org",
+    principal com.sun.security.auth.NTSid
+        "S-1-5-21-3623811015-3361044348-30300820-1013",
+    principal com.sun.security.auth.NTUserPrincipal "Duke",
+    principal com.sun.security.auth.UnixNumericUserPrincipal "0",
+    principal com.sun.security.auth.UnixPrincipal "duke" {
+    permission java.util.PropertyPermission "user.home", "read";
+};
+
+grant
+    // java.security.jgss module
+    principal javax.security.auth.kerberos.KerberosPrincipal "duke@openjdk.org"
+{
+    // test that ${{self}} expansion works 
+    permission javax.security.auth.kerberos.ServicePermission "${{self}}",
+                                                              "accept";
+};
--- a/test/sun/security/provider/certpath/OCSP/OCSPSingleExtensions.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/security/provider/certpath/OCSP/OCSPSingleExtensions.java	Thu Mar 17 19:04:16 2016 +0000
@@ -26,16 +26,16 @@
  * @bug 8074064
  * @summary OCSPResponse.SingleResponse objects do not parse singleExtensions
  * @modules java.base/sun.security.x509
- * @run main/othervm sun.security.provider.certpath.OCSPSingleExtensions
+ *          java.base/sun.security.provider.certpath
+ * @run main/othervm OCSPSingleExtensions
  */
 
-package sun.security.provider.certpath;
-
 import java.io.*;
 import java.util.*;
 import java.security.cert.*;
 
 import sun.security.x509.SerialNumber;
+import sun.security.provider.certpath.*;
 
 /*
  * Tester note:
--- a/test/sun/security/ssl/StatusStapling/BogusStatusRequest.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-import java.io.IOException;
-
-final class BogusStatusRequest implements StatusRequest {
-    BogusStatusRequest() { }
-
-    @Override
-    public int length() { return 0; }
-
-    @Override
-    public void send(HandshakeOutStream s) throws IOException { }
-
-    @Override
-    public String toString() {
-        return "BogusStatusRequest";
-    }
-}
--- a/test/sun/security/ssl/StatusStapling/CertStatusReqExtensionTests.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,346 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-/*
- * @test
- * @bug 8046321
- * @summary OCSP Stapling for TLS (CertStatusReqExtension tests)
- * @build CertStatusReqExtensionTests BogusStatusRequest TestCase TestUtils
- * @run main/othervm sun.security.ssl.CertStatusReqExtensionTests
- */
-
-import java.io.IOException;
-import java.util.*;
-import java.nio.ByteBuffer;
-
-/*
- * Checks that the hash value for a certificate's issuer name is generated
- * correctly. Requires any certificate that is not self-signed.
- *
- * NOTE: this test uses Sun private classes which are subject to change.
- */
-public class CertStatusReqExtensionTests {
-
-    private static final boolean debug = false;
-
-    // Default status_request extension (type = ocsp, OCSPStatusRequest
-    // with no responder IDs or extensions
-    private static final byte[] CSRE_DEF_OSR = {1, 0, 0, 0, 0};
-
-    // A status_request extension using a user-defined type (0xFF) and
-    // an underlying no-Responder ID/no-extension OCSPStatusRequest
-    private static final byte[] CSRE_TYPE_FF = {-1, 0, 0, 0, 0};
-
-    // A CertStatusReqExtension with 5 ResponderIds and 1 Extension
-    private static final byte[] CSRE_REQ_RID_EXTS = {
-           1,    0,  -13,    0,   59,  -95,   57,   48,
-          55,   49,   16,   48,   14,    6,    3,   85,
-           4,   10,   19,    7,   83,  111,  109,  101,
-          73,  110,   99,   49,   16,   48,   14,    6,
-           3,   85,    4,   11,   19,    7,   83,  111,
-         109,  101,   80,   75,   73,   49,   17,   48,
-          15,    6,    3,   85,    4,    3,   19,    8,
-          83,  111,  109,  101,   79,   67,   83,   80,
-           0,   68,  -95,   66,   48,   64,   49,   13,
-          48,   11,    6,    3,   85,    4,   10,   19,
-           4,   79,  104,   77,  121,   49,   14,   48,
-          12,    6,    3,   85,    4,   11,   19,    5,
-          66,  101,   97,  114,  115,   49,   15,   48,
-          13,    6,    3,   85,    4,   11,   19,    6,
-          84,  105,  103,  101,  114,  115,   49,   14,
-          48,   12,    6,    3,   85,    4,    3,   19,
-           5,   76,  105,  111,  110,  115,    0,   58,
-         -95,   56,   48,   54,   49,   16,   48,   14,
-           6,    3,   85,    4,   10,   19,    7,   67,
-         111,  109,  112,   97,  110,  121,   49,   13,
-          48,   11,    6,    3,   85,    4,   11,   19,
-           4,   87,  101,  115,  116,   49,   19,   48,
-          17,    6,    3,   85,    4,    3,   19,   10,
-          82,  101,  115,  112,  111,  110,  100,  101,
-         114,   49,    0,   24,  -94,   22,    4,   20,
-         -67,  -36,  114,  121,   92,  -79,  116,   -1,
-         102, -107,    7,  -21,   18, -113,   64,   76,
-          96,   -7,  -66,  -63,    0,   24,  -94,   22,
-           4,   20,  -51,  -69,  107,  -82,  -39,  -87,
-          45,   25,   41,   28,  -76,  -68,  -11, -110,
-         -94,  -97,   62,   47,   58, -125,    0,   51,
-          48,   49,   48,   47,    6,    9,   43,    6,
-           1,    5,    5,    7,   48,    1,    2,    4,
-          34,    4,   32,  -26,  -81, -120,  -61, -127,
-         -79,    0,  -39,  -54,   49,    3,  -51,  -57,
-         -85,   19, -126,   94,   -2,   21,   26,   98,
-           6,  105,  -35,  -37,  -29,  -73,  101,   53,
-          44,   15,  -19
-    };
-
-    public static void main(String[] args) throws Exception {
-        Map<String, TestCase> testList =
-                new LinkedHashMap<String, TestCase>() {{
-            put("CTOR (default)", testCtorDefault);
-            put("CTOR (int, StatusRequest)", testCtorStatReqs);
-            put("CTOR (HandshakeInStream, length, getReqType, getRequest)",
-                    testCtorInStream);
-        }};
-
-        TestUtils.runTests(testList);
-    }
-
-    public static final TestCase testCtorDefault = new TestCase() {
-        @Override
-        public Map.Entry<Boolean, String> runTest() {
-            Boolean pass = Boolean.FALSE;
-            String message = null;
-            try {
-                CertStatusReqExtension csreDef = new CertStatusReqExtension();
-                HandshakeOutStream hsout =
-                        new HandshakeOutStream(null);
-                csreDef.send(hsout);
-                TestUtils.valueCheck(wrapExtData(null), hsout.toByteArray());
-
-                // The length should be 4 (2 bytes for the type, 2 for the
-                // encoding of zero-length
-                if (csreDef.length() != 4) {
-                    throw new RuntimeException("Incorrect length from " +
-                            "default object.  Expected 4, got " +
-                            csreDef.length());
-                }
-
-                // Since there's no data, there are no status_type or request
-                // data fields defined.  Both should return null in this case
-                if (csreDef.getType() != null) {
-                    throw new RuntimeException("Default CSRE returned " +
-                            "non-null status_type");
-                } else if (csreDef.getRequest() != null) {
-                    throw new RuntimeException("Default CSRE returned " +
-                            "non-null request object");
-                }
-
-                pass = Boolean.TRUE;
-            } catch (Exception e) {
-                e.printStackTrace(System.out);
-                message = e.getClass().getName();
-            }
-
-            return new AbstractMap.SimpleEntry<>(pass, message);
-        }
-    };
-
-    public static final TestCase testCtorStatReqs = new TestCase() {
-        @Override
-        public Map.Entry<Boolean, String> runTest() {
-            Boolean pass = Boolean.FALSE;
-            String message = null;
-            try {
-                HandshakeOutStream hsout =
-                        new HandshakeOutStream(null);
-                StatusRequest basicStatReq = new OCSPStatusRequest();
-
-                // Create an extension using a default-style OCSPStatusRequest
-                // (no responder IDs, no extensions).
-                CertStatusReqExtension csre1 = new CertStatusReqExtension(
-                        StatusRequestType.OCSP, basicStatReq);
-                csre1.send(hsout);
-                TestUtils.valueCheck(wrapExtData(CSRE_DEF_OSR),
-                        hsout.toByteArray());
-                hsout.reset();
-
-                // Create the extension using a StatusRequestType not already
-                // instantiated as a static StatusRequestType
-                // (e.g. OCSP/OCSP_MULTI)
-                CertStatusReqExtension csre2 =
-                        new CertStatusReqExtension(StatusRequestType.get(-1),
-                                basicStatReq);
-                csre2.send(hsout);
-                TestUtils.valueCheck(wrapExtData(CSRE_TYPE_FF),
-                        hsout.toByteArray());
-
-                // Create the extension using a StatusRequest that
-                // does not match the status_type field
-                // This should throw an IllegalArgumentException
-                try {
-                    CertStatusReqExtension csreBadRequest =
-                            new CertStatusReqExtension(StatusRequestType.OCSP,
-                                    new BogusStatusRequest());
-                    throw new RuntimeException("Constructor accepted a " +
-                            "StatusRequest that is inconsistent with " +
-                            "the status_type");
-                } catch (IllegalArgumentException iae) { }
-
-                // We don't allow a null value for the StatusRequestType
-                // parameter in this constructor.
-                try {
-                    CertStatusReqExtension csreBadRequest =
-                            new CertStatusReqExtension(null, basicStatReq);
-                    throw new RuntimeException("Constructor accepted a " +
-                            "null StatusRequestType");
-                } catch (NullPointerException npe) { }
-
-                // We also don't allow a null value for the StatusRequest
-                // parameter in this constructor.
-                try {
-                    CertStatusReqExtension csreBadRequest =
-                            new CertStatusReqExtension(StatusRequestType.OCSP,
-                                    null);
-                    throw new RuntimeException("Constructor accepted a " +
-                            "null StatusRequest");
-                } catch (NullPointerException npe) { }
-
-                pass = Boolean.TRUE;
-            } catch (Exception e) {
-                e.printStackTrace(System.out);
-                message = e.getClass().getName();
-            }
-
-            return new AbstractMap.SimpleEntry<>(pass, message);
-        }
-    };
-
-    // Test the constructor that builds the ob ject using data from
-    // a HandshakeInStream
-    // This also tests the length, getReqType and getRequest methods
-    public static final TestCase testCtorInStream = new TestCase() {
-        @Override
-        public Map.Entry<Boolean, String> runTest() {
-            Boolean pass = Boolean.FALSE;
-            String message = null;
-            OCSPStatusRequest osr;
-
-            try {
-                // To simulate the extension coming in a ServerHello, the
-                // type and length would already be read by HelloExtensions
-                // and there is no extension data
-                HandshakeInStream hsis = new HandshakeInStream();
-                hsis.incomingRecord(ByteBuffer.wrap(new byte[0]));
-                CertStatusReqExtension csre =
-                        new CertStatusReqExtension(hsis, hsis.available());
-                // Verify length/type/request
-                if (csre.length() != 4) {
-                     throw new RuntimeException("Invalid length: received " +
-                            csre.length() + ", expected 4");
-                } else if (csre.getType() != null) {
-                    throw new RuntimeException("Non-null type from default " +
-                            "extension");
-                } else if (csre.getRequest() != null) {
-                    throw new RuntimeException("Non-null request from default " +
-                            "extension");
-                }
-
-                // Try the an extension with a default OCSPStatusRequest
-                hsis = new HandshakeInStream();
-                hsis.incomingRecord(ByteBuffer.wrap(CSRE_DEF_OSR));
-                csre = new CertStatusReqExtension(hsis, hsis.available());
-                if (csre.length() != (CSRE_DEF_OSR.length + 4)) {
-                    throw new RuntimeException("Invalid length: received " +
-                            csre.length() + ", expected " +
-                            CSRE_DEF_OSR.length + 4);
-                } else if (!csre.getType().equals(StatusRequestType.OCSP)) {
-                    throw new RuntimeException("Unknown status_type: " +
-                            String.format("0x%02X", csre.getType().id));
-                } else {
-                    osr = (OCSPStatusRequest)csre.getRequest();
-                    if (!osr.getResponderIds().isEmpty() ||
-                            !osr.getExtensions().isEmpty()) {
-                        throw new RuntimeException("Non-default " +
-                                "OCSPStatusRequest found in extension");
-                    }
-                }
-
-                // Try with a non-default extension
-                hsis = new HandshakeInStream();
-                hsis.incomingRecord(ByteBuffer.wrap(CSRE_REQ_RID_EXTS));
-                csre = new CertStatusReqExtension(hsis, hsis.available());
-                if (csre.length() != (CSRE_REQ_RID_EXTS.length + 4)) {
-                    throw new RuntimeException("Invalid length: received " +
-                            csre.length() + ", expected " +
-                            CSRE_REQ_RID_EXTS.length + 4);
-                } else if (!(csre.getType().equals(StatusRequestType.OCSP))) {
-                    throw new RuntimeException("Unknown status_type: " +
-                            String.format("0x%02X", csre.getType().id));
-                } else {
-                    osr = (OCSPStatusRequest)csre.getRequest();
-                    if (osr.getResponderIds().size() != 5 ||
-                            osr.getExtensions().size() != 1) {
-                        throw new RuntimeException("Incorrect number of " +
-                                "ResponderIds or Extensions found in " +
-                                "OCSPStatusRequest");
-                    }
-                }
-
-                // Create a CSRE that asserts status_request and has the
-                // proper length, but really is a bunch of random junk inside
-                // In this case, it will create an UnknownStatusRequest to
-                // handle the unparseable data.
-                byte[] junkData = new byte[48];
-                Random r = new Random(System.currentTimeMillis());
-                r.nextBytes(junkData);
-                junkData[0] = 7;        // Ensure it isn't a valid status_type
-                hsis = new HandshakeInStream();
-                hsis.incomingRecord(ByteBuffer.wrap(junkData));
-                csre = new CertStatusReqExtension(hsis, hsis.available());
-                StatusRequest sr = csre.getRequest();
-                if (!(sr instanceof UnknownStatusRequest)) {
-                    throw new RuntimeException("Expected returned status " +
-                            "request to be of type UnknownStatusRequest but " +
-                            "received " + sr.getClass().getName());
-                } else if (csre.length() != (junkData.length + 4)) {
-                    throw new RuntimeException("Invalid length: received " +
-                            csre.length() + ", expected " +
-                            junkData.length + 4);
-                }
-
-                // Set the leading byte to 1 (OCSP type) and run again
-                // It should pass the argument check and fail trying to parse
-                // the underlying StatusRequest.
-                junkData[0] = (byte)StatusRequestType.OCSP.id;
-                hsis = new HandshakeInStream();
-                hsis.incomingRecord(ByteBuffer.wrap(junkData));
-                try {
-                    csre = new CertStatusReqExtension(hsis, hsis.available());
-                    throw new RuntimeException("Expected CTOR exception did " +
-                            "not occur");
-                } catch (IOException ioe) { }
-
-                pass = Boolean.TRUE;
-            } catch (Exception e) {
-                e.printStackTrace(System.out);
-                message = e.getClass().getName();
-            }
-
-            return new AbstractMap.SimpleEntry<>(pass, message);
-        }
-    };
-
-    // Take CSRE extension data and add extension type and length decorations
-    private static byte[] wrapExtData(byte[] extData) {
-        int bufferLen = (extData != null ? extData.length : 0) + 4;
-        ByteBuffer bb = ByteBuffer.allocate(bufferLen);
-        bb.putShort((short)ExtensionType.EXT_STATUS_REQUEST.id);
-        bb.putShort((short)(extData != null ? extData.length: 0));
-        if (extData != null) {
-            bb.put(extData);
-        }
-        return bb.array();
-    }
-}
--- a/test/sun/security/ssl/StatusStapling/CertStatusReqItemV2Tests.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,463 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-/*
- * @test
- * @bug 8046321
- * @summary OCSP Stapling for TLS (CertStatusReqItemv2 tests)
- * @build CertStatusReqItemV2Tests BogusStatusRequest TestCase TestUtils
- * @run main/othervm sun.security.ssl.CertStatusReqItemV2Tests
- */
-
-import java.security.cert.*;
-import java.util.*;
-import java.nio.ByteBuffer;
-import javax.net.ssl.SSLException;
-import javax.security.auth.x500.X500Principal;
-import sun.security.provider.certpath.ResponderId;
-import sun.security.provider.certpath.OCSPNonceExtension;
-
-/*
- * Checks that the hash value for a certificate's issuer name is generated
- * correctly. Requires any certificate that is not self-signed.
- *
- * NOTE: this test uses Sun private classes which are subject to change.
- */
-public class CertStatusReqItemV2Tests {
-
-    private static final boolean debug = false;
-
-    private static final byte[] DEF_CSRIV2_OCSP_MULTI_BYTES = {
-           2,    0,    4,    0,    0,    0,    0
-    };
-
-    private static final byte[] DEF_CSRIV2_OCSP_BYTES = {
-           1,    0,    4,    0,    0,    0,    0
-    };
-
-    // This is a CSRIV2 (ocsp_multi) that has a single
-    // responder ID and no extensions.
-    private static final byte[] CSRIV2_1RID = {
-            2,    0,   32,     0,   28,    0,   26,  -95,
-           24,   48,   22,    49,   20,   48,   18,    6,
-            3,   85,    4,     3,   19,   11,   79,   67,
-           83,   80,   32,    83,  105,  103,  110,  101,
-          114,    0 ,   0
-    };
-
-    // This is a CSRIV2 (ocsp_multi) that has a single
-    // responder ID and no extensions.  The request_length
-    // field is too short in this case.
-    private static final byte[] CSRIV2_LENGTH_TOO_SHORT = {
-            2,    0,   27,     0,   28,    0,   26,  -95,
-           24,   48,   22,    49,   20,   48,   18,    6,
-            3,   85,    4,     3,   19,   11,   79,   67,
-           83,   80,   32,    83,  105,  103,  110,  101,
-          114,    0 ,   0
-    };
-
-    // This is a CSRIV2 (ocsp_multi) that has a single
-    // responder ID and no extensions.  The request_length
-    // field is too long in this case.
-    private static final byte[] CSRIV2_LENGTH_TOO_LONG = {
-            2,    0,   54,     0,   28,    0,   26,  -95,
-           24,   48,   22,    49,   20,   48,   18,    6,
-            3,   85,    4,     3,   19,   11,   79,   67,
-           83,   80,   32,    83,  105,  103,  110,  101,
-          114,    0 ,   0
-    };
-
-    // A CSRIV2 (ocsp) with one Responder ID (byName: CN=OCSP Signer)
-    // and a nonce extension (32 bytes).
-    private static final byte[] CSRIV2_OCSP_1RID_1EXT = {
-            1,    0,   83,    0,   28,    0,   26,  -95,
-           24,   48,   22,   49,   20,   48,   18,    6,
-            3,   85,    4,    3,   19,   11,   79,   67,
-           83,   80,   32,   83,  105,  103,  110,  101,
-          114,    0,   51,   48,   49,   48,   47,    6,
-            9,   43,    6,    1,    5,    5,    7,   48,
-            1,    2,    4,   34,    4,   32,  -34,  -83,
-          -66,  -17,  -34,  -83,  -66,  -17,  -34,  -83,
-          -66,  -17,  -34,  -83,  -66,  -17,  -34,  -83,
-          -66,  -17,  -34,  -83,  -66,  -17,  -34,  -83,
-          -66,  -17,  -34,  -83,  -66,  -17
-    };
-
-    public static void main(String[] args) throws Exception {
-        Map<String, TestCase> testList =
-                new LinkedHashMap<String, TestCase>() {{
-            put("CTOR (Default)", testCtorTypeStatReq);
-            put("CTOR (Byte array)", testCtorByteArray);
-            put("CTOR (invalid lengths)", testCtorInvalidLengths);
-        }};
-
-        TestUtils.runTests(testList);
-    }
-
-    public static final TestCase testCtorTypeStatReq = new TestCase() {
-        @Override
-        public Map.Entry<Boolean, String> runTest() {
-            Boolean pass = Boolean.FALSE;
-            String message = null;
-            try {
-                // Attempt to create CSRIv2 objects using null pointers
-                // for either parameter.  In either case NPE should be thrown
-                CertStatusReqItemV2 csriNull;
-                try {
-                    csriNull = new CertStatusReqItemV2(null,
-                            new OCSPStatusRequest());
-                    throw new RuntimeException("Did not catch expected NPE " +
-                            "for null status_type parameter");
-                } catch (NullPointerException npe) { }
-
-                try {
-                    csriNull = new CertStatusReqItemV2(StatusRequestType.OCSP,
-                            null);
-                    throw new RuntimeException("Did not catch expected NPE " +
-                            "for null StatusRequest parameter");
-                } catch (NullPointerException npe) { }
-
-                // Create an "ocsp_multi" type request using a default
-                // (no Responder IDs, no Extensions) OCSPStatusRequest
-                CertStatusReqItemV2 csriMulti =
-                        new CertStatusReqItemV2(StatusRequestType.OCSP_MULTI,
-                                new OCSPStatusRequest());
-                HandshakeOutStream hsout = new HandshakeOutStream(null);
-                csriMulti.send(hsout);
-                TestUtils.valueCheck(DEF_CSRIV2_OCSP_MULTI_BYTES,
-                        hsout.toByteArray());
-                hsout.reset();
-
-                // Create an "ocsp" type request using a default
-                // (no Responder IDs, no Extensions) OCSPStatusRequest
-                CertStatusReqItemV2 csriSingle =
-                        new CertStatusReqItemV2(StatusRequestType.OCSP,
-                                new OCSPStatusRequest(new LinkedList<>(),
-                                        new LinkedList<>()));
-                csriSingle.send(hsout);
-                TestUtils.valueCheck(DEF_CSRIV2_OCSP_BYTES,
-                        hsout.toByteArray());
-
-                // Create the CertStatusRequestItemV2 with a user-defined
-                // StatusRequestType value
-                CertStatusReqItemV2 csriNine =
-                        new CertStatusReqItemV2(StatusRequestType.get(9),
-                                new OCSPStatusRequest(null, null));
-                if (csriNine.getType().id != 9) {
-                    throw new RuntimeException("Expected status_type = 9, " +
-                            "got " + csriNine.getType().id);
-                } else {
-                    StatusRequest sr = csriNine.getRequest();
-                    if (!(sr instanceof OCSPStatusRequest)) {
-                        throw new RuntimeException("Expected " +
-                                "OCSPStatusRequest, got " +
-                                sr.getClass().getName());
-                    }
-                }
-
-                // Create the CertStatusRequestItemV2 with a StatusRequest
-                // that does not match the status_type argument.
-                // We expect IllegalArgumentException in this case.
-                try {
-                    CertStatusReqItemV2 csriBadSR = new CertStatusReqItemV2(
-                            StatusRequestType.OCSP_MULTI,
-                            new BogusStatusRequest());
-                    throw new RuntimeException("Constructor accepted a " +
-                            "StatusRequest that is inconsistent with " +
-                            "the status_type");
-                } catch (IllegalArgumentException iae) {
-                    // The expected result...nothing to do here
-                }
-
-                pass = Boolean.TRUE;
-            } catch (Exception e) {
-                e.printStackTrace(System.out);
-                message = e.getClass().getName();
-            }
-
-            return new AbstractMap.SimpleEntry<>(pass, message);
-        }
-    };
-
-    // Test the constructor form that takes the data from a byte array
-    public static final TestCase testCtorByteArray = new TestCase() {
-        @Override
-        public Map.Entry<Boolean, String> runTest() {
-            Boolean pass = Boolean.FALSE;
-            String message = null;
-            try {
-                StatusRequestType sType;
-                StatusRequest sReq;
-                ResponderId checkRid =
-                        new ResponderId(new X500Principal("CN=OCSP Signer"));
-                Extension checkExt = new OCSPNonceExtension(32);
-
-                CertStatusReqItemV2 csriv =
-                        new CertStatusReqItemV2(CSRIV2_OCSP_1RID_1EXT);
-                sType = csriv.getType();
-                if (sType != StatusRequestType.OCSP) {
-                    throw new RuntimeException("Unexpected StatusRequestType " +
-                            sType.getClass().getName());
-                }
-
-                sReq = csriv.getRequest();
-                if (sReq instanceof OCSPStatusRequest) {
-                    OCSPStatusRequest osr = (OCSPStatusRequest)sReq;
-                    List<ResponderId> ridList = osr.getResponderIds();
-                    List<Extension> extList = osr.getExtensions();
-
-                    if (ridList.size() != 1 || !ridList.contains(checkRid)) {
-                        throw new RuntimeException("Responder list mismatch");
-                    } else if (extList.size() !=  1 ||
-                            !extList.get(0).getId().equals(checkExt.getId())) {
-                        throw new RuntimeException("Extension list mismatch");
-                    }
-                } else {
-                    throw new RuntimeException("Expected OCSPStatusRequest " +
-                            "from decoded bytes, got " +
-                            sReq.getClass().getName());
-                }
-
-                // Create a CSRIV2 out of random data.  A non-OCSP/OCSP_MULTI
-                // type will be forcibly set and the outer length field will
-                // be correct.
-                // The constructor should create a StatusRequestType object
-                // and an UnknownStatusRequest object consisting of the
-                // data segment.
-                byte[] junkData = new byte[48];
-                Random r = new Random(System.currentTimeMillis());
-                r.nextBytes(junkData);
-                junkData[0] = 7;        // status_type = 7
-                junkData[1] = 0;
-                junkData[2] = 45;       // request_length = 45
-                csriv = new CertStatusReqItemV2(junkData);
-
-                sType = csriv.getType();
-                sReq = csriv.getRequest();
-                if (sType.id != junkData[0]) {
-                    throw new RuntimeException("StatusRequestType mismatch: " +
-                            "expected 7, got " + sType.id);
-                }
-                if (sReq instanceof UnknownStatusRequest) {
-                    // Verify the underlying StatusRequest bytes have been
-                    // preserved correctly.
-                    HandshakeOutStream hsout = new HandshakeOutStream(null);
-                    sReq.send(hsout);
-                    byte[] srDataOut = hsout.toByteArray();
-                    TestUtils.valueCheck(srDataOut, junkData, 0, 3,
-                            srDataOut.length);
-                } else {
-                    throw new RuntimeException("StatusRequest mismatch: " +
-                            "expected UnknownStatusRequest, got " +
-                            sReq.getClass().getName());
-                }
-
-                // Test the parsing of the default OCSP/OCSP_MULTI extensions
-                // and make sure the underlying StatusRequestType and
-                // StatusRequest objects are correct.
-                csriv = new CertStatusReqItemV2(DEF_CSRIV2_OCSP_MULTI_BYTES);
-                sType = csriv.getType();
-                sReq = csriv.getRequest();
-                if (sType != StatusRequestType.OCSP_MULTI) {
-                    throw new RuntimeException("StatusRequestType mismatch: " +
-                            "expected OCSP_MULTI (2), got " + sType.id);
-                }
-                if (!(sReq instanceof OCSPStatusRequest)) {
-                    throw new RuntimeException("StatusRequest mismatch: " +
-                            "expected OCSPStatusRequest, got " +
-                            sReq.getClass().getName());
-                }
-
-                csriv = new CertStatusReqItemV2(DEF_CSRIV2_OCSP_BYTES);
-                sType = csriv.getType();
-                sReq = csriv.getRequest();
-                if (sType != StatusRequestType.OCSP) {
-                    throw new RuntimeException("StatusRequestType mismatch: " +
-                            "expected OCSP (1), got " + sType.id);
-                }
-                if (!(sReq instanceof OCSPStatusRequest)) {
-                    throw new RuntimeException("StatusRequest mismatch: " +
-                            "expected OCSPStatusRequest, got " +
-                            sReq.getClass().getName());
-                }
-
-                pass = Boolean.TRUE;
-            } catch (Exception e) {
-                e.printStackTrace(System.out);
-                message = e.getClass().getName();
-            }
-
-            return new AbstractMap.SimpleEntry<>(pass, message);
-        }
-    };
-
-    public static final TestCase testCtorInvalidLengths = new TestCase() {
-        @Override
-        public Map.Entry<Boolean, String> runTest() {
-            Boolean pass = Boolean.FALSE;
-            String message = null;
-            try {
-                try {
-                    CertStatusReqItemV2 csriTooShort =
-                            new CertStatusReqItemV2(CSRIV2_LENGTH_TOO_SHORT);
-                    throw new RuntimeException("Expected exception not thrown");
-                } catch (SSLException ssle) { }
-
-                try {
-                    CertStatusReqItemV2 csriTooLong =
-                            new CertStatusReqItemV2(CSRIV2_LENGTH_TOO_LONG);
-                    throw new RuntimeException("Expected exception not thrown");
-                } catch (SSLException ssle) { }
-
-                pass = Boolean.TRUE;
-            } catch (Exception e) {
-                e.printStackTrace(System.out);
-                message = e.getClass().getName();
-            }
-
-            return new AbstractMap.SimpleEntry<>(pass, message);
-        }
-    };
-
-    // Test the constructor form that takes the data from HandshakeInputStream
-    public static final TestCase testCtorInputStream = new TestCase() {
-        @Override
-        public Map.Entry<Boolean, String> runTest() {
-            Boolean pass = Boolean.FALSE;
-            String message = null;
-            try {
-                StatusRequestType sType;
-                StatusRequest sReq;
-                ResponderId checkRid =
-                        new ResponderId(new X500Principal("CN=OCSP Signer"));
-                Extension checkExt = new OCSPNonceExtension(32);
-
-                HandshakeInStream hsis = new HandshakeInStream();
-                hsis.incomingRecord(ByteBuffer.wrap(CSRIV2_OCSP_1RID_1EXT));
-                CertStatusReqItemV2 csriv = new CertStatusReqItemV2(hsis);
-                sType = csriv.getType();
-                if (sType != StatusRequestType.OCSP) {
-                    throw new RuntimeException("Unexpected StatusRequestType " +
-                            sType.getClass().getName());
-                }
-
-                sReq = csriv.getRequest();
-                if (sReq instanceof OCSPStatusRequest) {
-                    OCSPStatusRequest osr = (OCSPStatusRequest)sReq;
-                    List<ResponderId> ridList = osr.getResponderIds();
-                    List<Extension> extList = osr.getExtensions();
-
-                    if (ridList.size() != 1 || !ridList.contains(checkRid)) {
-                        throw new RuntimeException("Responder list mismatch");
-                    } else if (extList.size() !=  1 ||
-                            !extList.get(0).getId().equals(checkExt.getId())) {
-                        throw new RuntimeException("Extension list mismatch");
-                    }
-                } else {
-                    throw new RuntimeException("Expected OCSPStatusRequest " +
-                            "from decoded bytes, got " +
-                            sReq.getClass().getName());
-                }
-
-                // Create a CSRIV2 out of random data.  A non-OCSP/OCSP_MULTI
-                // type will be forcibly set and the outer length field will
-                // be correct.
-                // The constructor should create a StatusRequestType object
-                // and an UnknownStatusRequest object consisting of the
-                // data segment.
-                byte[] junkData = new byte[48];
-                Random r = new Random(System.currentTimeMillis());
-                r.nextBytes(junkData);
-                junkData[0] = 7;        // status_type = 7
-                junkData[1] = 0;
-                junkData[2] = 45;       // request_length = 45
-                hsis = new HandshakeInStream();
-                hsis.incomingRecord(ByteBuffer.wrap(junkData));
-                csriv = new CertStatusReqItemV2(hsis);
-
-                sType = csriv.getType();
-                sReq = csriv.getRequest();
-                if (sType.id != junkData[0]) {
-                    throw new RuntimeException("StatusRequestType mismatch: " +
-                            "expected 7, got " + sType.id);
-                }
-                if (sReq instanceof UnknownStatusRequest) {
-                    // Verify the underlying StatusRequest bytes have been
-                    // preserved correctly.
-                    HandshakeOutStream hsout = new HandshakeOutStream(null);
-                    sReq.send(hsout);
-                    byte[] srDataOut = hsout.toByteArray();
-                    TestUtils.valueCheck(srDataOut, junkData, 0, 3,
-                            srDataOut.length);
-                } else {
-                    throw new RuntimeException("StatusRequest mismatch: " +
-                            "expected UnknownStatusRequest, got " +
-                            sReq.getClass().getName());
-                }
-
-                // Test the parsing of the default OCSP/OCSP_MULTI extensions
-                // and make sure the underlying StatusRequestType and
-                // StatusRequest objects are correct.
-                hsis = new HandshakeInStream();
-                hsis.incomingRecord(
-                        ByteBuffer.wrap(DEF_CSRIV2_OCSP_MULTI_BYTES));
-                csriv = new CertStatusReqItemV2(hsis);
-                sType = csriv.getType();
-                sReq = csriv.getRequest();
-                if (sType != StatusRequestType.OCSP_MULTI) {
-                    throw new RuntimeException("StatusRequestType mismatch: " +
-                            "expected OCSP_MULTI (2), got " + sType.id);
-                }
-                if (!(sReq instanceof OCSPStatusRequest)) {
-                    throw new RuntimeException("StatusRequest mismatch: " +
-                            "expected OCSPStatusRequest, got " +
-                            sReq.getClass().getName());
-                }
-
-                hsis = new HandshakeInStream();
-                hsis.incomingRecord(ByteBuffer.wrap(DEF_CSRIV2_OCSP_BYTES));
-                csriv = new CertStatusReqItemV2(hsis);
-                sType = csriv.getType();
-                sReq = csriv.getRequest();
-                if (sType != StatusRequestType.OCSP) {
-                    throw new RuntimeException("StatusRequestType mismatch: " +
-                            "expected OCSP (1), got " + sType.id);
-                }
-                if (!(sReq instanceof OCSPStatusRequest)) {
-                    throw new RuntimeException("StatusRequest mismatch: " +
-                            "expected OCSPStatusRequest, got " +
-                            sReq.getClass().getName());
-                }
-
-                pass = Boolean.TRUE;
-            } catch (Exception e) {
-                e.printStackTrace(System.out);
-                message = e.getClass().getName();
-            }
-
-            return new AbstractMap.SimpleEntry<>(pass, message);
-        }
-    };
-}
--- a/test/sun/security/ssl/StatusStapling/CertStatusReqListV2ExtensionTests.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,413 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-/*
- * @test
- * @bug 8046321
- * @summary OCSP Stapling for TLS (CertStatusReqListV2Extension tests)
- * @build CertStatusReqListV2ExtensionTests TestCase TestUtils
- * @run main/othervm sun.security.ssl.CertStatusReqListV2ExtensionTests
- */
-
-import java.io.IOException;
-import java.util.*;
-import java.nio.ByteBuffer;
-import javax.net.ssl.*;
-
-/*
- * Checks that the hash value for a certificate's issuer name is generated
- * correctly. Requires any certificate that is not self-signed.
- *
- * NOTE: this test uses Sun private classes which are subject to change.
- */
-public class CertStatusReqListV2ExtensionTests {
-
-    private static final boolean debug = false;
-
-    // Default status_request_v2 extension with two items
-    // 1. Type = ocsp_multi, OCSPStatusRequest is default
-    // 2. Type = ocsp, OCSPStatusRequest is default
-    private static final byte[] CSRLV2_DEF = {
-           0,   14,    2,    0,    4,    0,    0,    0,
-           0,    1,    0,    4,    0,    0,    0,    0
-    };
-
-    // A status_request_v2 where the item list length is
-    // longer than the provided data
-    private static final byte[] CSRLV2_LEN_TOO_LONG = {
-           0,   18,    2,    0,    4,    0,    0,    0,
-           0,    1,    0,    4,    0,    0,    0,    0
-    };
-
-    // A status_request_v2 where the item list length is
-    // shorter than the provided data
-    private static final byte[] CSRLV2_LEN_TOO_SHORT = {
-           0,   11,    2,    0,    4,    0,    0,    0,
-           0,    1,    0,    4,    0,    0,    0,    0
-    };
-
-    // A status_request_v2 extension with a zero-length
-    // certificate_status_req_list (not allowed by the spec)
-    private static final byte[] CSRLV2_INVALID_ZEROLEN = {0, 0};
-
-    // A status_request_v2 extension with two items (ocsp_multi and ocsp)
-    // using OCSPStatusRequests with 5 ResponderIds and 1 Extension each.
-    private static final byte[] CSRLV2_TWO_NON_DEF_ITEMS = {
-            2,   90,    2,    1,   42,    0,  -13,    0,
-           59,  -95,   57,   48,   55,   49,   16,   48,
-           14,    6,    3,   85,    4,   10,   19,    7,
-           83,  111,  109,  101,   73,  110,   99,   49,
-           16,   48,   14,    6,    3,   85,    4,   11,
-           19,    7,   83,  111,  109,  101,   80,   75,
-           73,   49,   17,   48,   15,    6,    3,   85,
-            4,    3,   19,    8,   83,  111,  109,  101,
-           79,   67,   83,   80,    0,   68,  -95,   66,
-           48,   64,   49,   13,   48,   11,    6,    3,
-           85,    4,   10,   19,    4,   79,  104,   77,
-          121,   49,   14,   48,   12,    6,    3,   85,
-            4,   11,   19,    5,   66,  101,   97,  114,
-          115,   49,   15,   48,   13,    6,    3,   85,
-            4,   11,   19,    6,   84,  105,  103,  101,
-          114,  115,   49,   14,   48,   12,    6,    3,
-           85,    4,    3,   19,    5,   76,  105,  111,
-          110,  115,    0,   58,  -95,   56,   48,   54,
-           49,   16,   48,   14,    6,    3,   85,    4,
-           10,   19,    7,   67,  111,  109,  112,   97,
-          110,  121,   49,   13,   48,   11,    6,    3,
-           85,    4,   11,   19,    4,   87,  101,  115,
-          116,   49,   19,   48,   17,    6,    3,   85,
-            4,    3,   19,   10,   82,  101,  115,  112,
-          111,  110,  100,  101,  114,   49,    0,   24,
-          -94,   22,    4,   20,  -67,  -36,  114,  121,
-           92,  -79,  116,   -1,  102, -107,    7,  -21,
-           18, -113,   64,   76,   96,   -7,  -66,  -63,
-            0,   24,  -94,   22,    4,   20,  -51,  -69,
-          107,  -82,  -39,  -87,   45,   25,   41,   28,
-          -76,  -68,  -11, -110,  -94,  -97,   62,   47,
-           58, -125,    0,   51,   48,   49,   48,   47,
-            6,    9,   43,    6,    1,    5,    5,    7,
-           48,    1,    2,    4,   34,    4,   32,  -26,
-          -81, -120,  -61, -127,  -79,    0,  -39,  -54,
-           49,    3,  -51,  -57,  -85,   19, -126,   94,
-           -2,   21,   26,   98,    6,  105,  -35,  -37,
-          -29,  -73,  101,   53,   44,   15,  -19,    1,
-            1,   42,    0,  -13,    0,   59,  -95,   57,
-           48,   55,   49,   16,   48,   14,    6,    3,
-           85,    4,   10,   19,    7,   83,  111,  109,
-          101,   73,  110,   99,   49,   16,   48,   14,
-            6,    3,   85,    4,   11,   19,    7,   83,
-          111,  109,  101,   80,   75,   73,   49,   17,
-           48,   15,    6,    3,   85,    4,    3,   19,
-            8,   83,  111,  109,  101,   79,   67,   83,
-           80,    0,   68,  -95,   66,   48,   64,   49,
-           13,   48,   11,    6,    3,   85,    4,   10,
-           19,    4,   79,  104,   77,  121,   49,   14,
-           48,   12,    6,    3,   85,    4,   11,   19,
-            5,   66,  101,   97,  114,  115,   49,   15,
-           48,   13,    6,    3,   85,    4,   11,   19,
-            6,   84,  105,  103,  101,  114,  115,   49,
-           14,   48,   12,    6,    3,   85,    4,    3,
-           19,    5,   76,  105,  111,  110,  115,    0,
-           58,  -95,   56,   48,   54,   49,   16,   48,
-           14,    6,    3,   85,    4,   10,   19,    7,
-           67,  111,  109,  112,   97,  110,  121,   49,
-           13,   48,   11,    6,    3,   85,    4,   11,
-           19,    4,   87,  101,  115,  116,   49,   19,
-           48,   17,    6,    3,   85,    4,    3,   19,
-           10,   82,  101,  115,  112,  111,  110,  100,
-          101,  114,   49,    0,   24,  -94,   22,    4,
-           20,  -67,  -36,  114,  121,   92,  -79,  116,
-           -1,  102, -107,    7,  -21,   18, -113,   64,
-           76,   96,   -7,  -66,  -63,    0,   24,  -94,
-           22,    4,   20,  -51,  -69,  107,  -82,  -39,
-          -87,   45,   25,   41,   28,  -76,  -68,  -11,
-         -110,  -94,  -97,   62,   47,   58, -125,    0,
-           51,   48,   49,   48,   47,    6,    9,   43,
-            6,    1,    5,    5,    7,   48,    1,    2,
-            4,   34,    4,   32,  -26,  -81, -120,  -61,
-         -127,  -79,    0,  -39,  -54,   49,    3,  -51,
-          -57,  -85,   19, -126,   94,   -2,   21,   26,
-           98,    6,  105,  -35,  -37,  -29,  -73,  101,
-           53,   44,   15,  -19
-    };
-
-    public static void main(String[] args) throws Exception {
-        Map<String, TestCase> testList =
-                new LinkedHashMap<String, TestCase>() {{
-            put("CTOR (default)", testCtorDefault);
-            put("CTOR (List<CertStatusReqItemV2)", testCtorItemList);
-            put("CTOR (HandshakeInStream, getRequestList",
-                    testCtorInStream);
-        }};
-
-        TestUtils.runTests(testList);
-    }
-
-    public static final TestCase testCtorDefault = new TestCase() {
-        @Override
-        public Map.Entry<Boolean, String> runTest() {
-            Boolean pass = Boolean.FALSE;
-            String message = null;
-            try {
-                CertStatusReqListV2Extension csrlV2 =
-                        new CertStatusReqListV2Extension();
-                HandshakeOutStream hsout = new HandshakeOutStream(null);
-                csrlV2.send(hsout);
-                TestUtils.valueCheck(wrapExtData(new byte[0]),
-                        hsout.toByteArray());
-
-                // The length should be 4 (2 bytes for the type, 2 for the
-                // encoding of zero-length
-                if (csrlV2.length() != 4) {
-                    throw new RuntimeException("Incorrect length from " +
-                            "default object.  Expected 4, got " +
-                            csrlV2.length());
-                }
-
-                // Since there's no data, there are no status_type or request
-                // data fields defined.  An empty, unmodifiable list should be
-                // returned when obtained from the extension.
-                List<CertStatusReqItemV2> itemList = csrlV2.getRequestItems();
-                if (!itemList.isEmpty()) {
-                    throw new RuntimeException("Default CSRLV2 returned " +
-                            "non-empty request list");
-                } else {
-                    try {
-                        itemList.add(new CertStatusReqItemV2(
-                                StatusRequestType.OCSP_MULTI,
-                                new OCSPStatusRequest()));
-                        throw new RuntimeException("Returned itemList is " +
-                                "modifiable!");
-                    } catch (UnsupportedOperationException uoe) { }
-                }
-
-                pass = Boolean.TRUE;
-            } catch (Exception e) {
-                e.printStackTrace(System.out);
-                message = e.getClass().getName();
-            }
-
-            return new AbstractMap.SimpleEntry<>(pass, message);
-        }
-    };
-
-    public static final TestCase testCtorItemList = new TestCase() {
-        @Override
-        public Map.Entry<Boolean, String> runTest() {
-            Boolean pass = Boolean.FALSE;
-            String message = null;
-            OCSPStatusRequest osr = new OCSPStatusRequest();
-            List<CertStatusReqItemV2> noItems = Collections.emptyList();
-            List<CertStatusReqItemV2> defList =
-                    new ArrayList<CertStatusReqItemV2>() {{
-                add(new CertStatusReqItemV2(StatusRequestType.OCSP_MULTI, osr));
-                add(new CertStatusReqItemV2(StatusRequestType.OCSP, osr));
-            }};
-            List<CertStatusReqItemV2> unknownTypesList =
-                    new ArrayList<CertStatusReqItemV2>() {{
-                add(new CertStatusReqItemV2(StatusRequestType.get(8),
-                        new UnknownStatusRequest(new byte[0])));
-                add(new CertStatusReqItemV2(StatusRequestType.get(12),
-                        new UnknownStatusRequest(new byte[5])));
-            }};
-
-            try {
-                HandshakeOutStream hsout = new HandshakeOutStream(null);
-                StatusRequest basicStatReq = new OCSPStatusRequest();
-
-                // Create an extension using a default-style OCSPStatusRequest
-                // (no responder IDs, no extensions).
-                CertStatusReqListV2Extension csrlv2 =
-                        new CertStatusReqListV2Extension(defList);
-                csrlv2.send(hsout);
-                TestUtils.valueCheck(wrapExtData(CSRLV2_DEF),
-                        hsout.toByteArray());
-                hsout.reset();
-
-                // Create the extension using a StatusRequestType not already
-                // instantiated as a static StatusRequestType
-                // (e.g. OCSP/OCSP_MULTI)
-                csrlv2 = new CertStatusReqListV2Extension(unknownTypesList);
-                List<CertStatusReqItemV2> itemList = csrlv2.getRequestItems();
-                if (itemList.size() != unknownTypesList.size()) {
-                    throw new RuntimeException("Custom CSRLV2 returned " +
-                            "an incorrect number of items: expected " +
-                            unknownTypesList.size() + ", got " +
-                            itemList.size());
-                } else {
-                    // Verify that the list is unmodifiable
-                    try {
-                        itemList.add(new CertStatusReqItemV2(
-                                StatusRequestType.OCSP_MULTI,
-                                new OCSPStatusRequest()));
-                        throw new RuntimeException("Returned itemList is " +
-                                "modifiable!");
-                    } catch (UnsupportedOperationException uoe) { }
-                }
-
-                // Pass a null value for the item list.  This should throw
-                // an exception
-                try {
-                    CertStatusReqListV2Extension csrlv2Null =
-                            new CertStatusReqListV2Extension(null);
-                    throw new RuntimeException("Constructor accepted a " +
-                            "null request list");
-                } catch (NullPointerException npe) { }
-
-                pass = Boolean.TRUE;
-            } catch (Exception e) {
-                e.printStackTrace(System.out);
-                message = e.getClass().getName();
-            }
-
-            return new AbstractMap.SimpleEntry<>(pass, message);
-        }
-    };
-
-    // Test the constructor that builds the ob ject using data from
-    // a HandshakeInStream
-    // This also tests the length, getReqType and getRequest methods
-    public static final TestCase testCtorInStream = new TestCase() {
-        @Override
-        public Map.Entry<Boolean, String> runTest() {
-            Boolean pass = Boolean.FALSE;
-            String message = null;
-            OCSPStatusRequest osr;
-            CertStatusReqListV2Extension csrlv2;
-
-            try {
-                // To simulate the extension coming in a ServerHello, the
-                // type and length would already be read by HelloExtensions
-                // and there is no extension data
-                HandshakeInStream hsis = new HandshakeInStream();
-                hsis.incomingRecord(ByteBuffer.wrap(new byte[0]));
-                csrlv2 = new CertStatusReqListV2Extension(hsis,
-                        hsis.available());
-
-                // Verify length/request list
-                if (csrlv2.length() != 4) {
-                     throw new RuntimeException("Invalid length: received " +
-                            csrlv2.length() + ", expected 4");
-                } else {
-                    List<CertStatusReqItemV2> itemList =
-                            csrlv2.getRequestItems();
-                    if (!itemList.isEmpty()) {
-                        throw new RuntimeException("Default CSRLV2 returned " +
-                                "non-empty request list");
-                    } else {
-                        try {
-                            itemList.add(new CertStatusReqItemV2(
-                                    StatusRequestType.OCSP_MULTI,
-                                    new OCSPStatusRequest()));
-                            throw new RuntimeException("Returned itemList is " +
-                                    "modifiable!");
-                        } catch (UnsupportedOperationException uoe) { }
-                    }
-                }
-
-                // Try the an extension with our basic client-generated
-                // status_request_v2 (2 items, ocsp_multi and ocsp, each with
-                // a default OCSPStatusRequest
-                hsis = new HandshakeInStream();
-                hsis.incomingRecord(ByteBuffer.wrap(CSRLV2_DEF));
-                csrlv2 = new CertStatusReqListV2Extension(hsis,
-                        hsis.available());
-                if (csrlv2.length() != (CSRLV2_DEF.length + 4)) {
-                    throw new RuntimeException("Invalid length: received " +
-                            csrlv2.length() + ", expected " +
-                            CSRLV2_DEF.length + 4);
-                } else {
-                    List<CertStatusReqItemV2> itemList =
-                            csrlv2.getRequestItems();
-                    if (itemList.size() != 2) {
-                        throw new RuntimeException("Unexpected number of " +
-                                "items request list, expected 2, got " +
-                                itemList.size());
-                    } else {
-                        try {
-                            itemList.add(new CertStatusReqItemV2(
-                                    StatusRequestType.OCSP_MULTI,
-                                    new OCSPStatusRequest()));
-                            throw new RuntimeException("Returned itemList is " +
-                                    "modifiable!");
-                        } catch (UnsupportedOperationException uoe) { }
-                    }
-                }
-
-                // Try incoming data with an illegal zero-length
-                // certificate_status_req_list
-                try {
-                    hsis = new HandshakeInStream();
-                    hsis.incomingRecord(
-                            ByteBuffer.wrap(CSRLV2_INVALID_ZEROLEN));
-                    csrlv2 = new CertStatusReqListV2Extension(hsis,
-                            hsis.available());
-                    throw new RuntimeException("Unxpected successful " +
-                            "object construction");
-                } catch (SSLException ssle) { }
-
-                // Try extensions where the certificate_status_req_list length
-                // is either too long or too short
-                try {
-                    hsis = new HandshakeInStream();
-                    hsis.incomingRecord(ByteBuffer.wrap(CSRLV2_LEN_TOO_LONG));
-                    csrlv2 = new CertStatusReqListV2Extension(hsis,
-                            hsis.available());
-                    throw new RuntimeException("Unxpected successful " +
-                            "object construction");
-                } catch (SSLException ssle) { }
-
-                try {
-                    hsis = new HandshakeInStream();
-                    hsis.incomingRecord(ByteBuffer.wrap(CSRLV2_LEN_TOO_SHORT));
-                    csrlv2 = new CertStatusReqListV2Extension(hsis,
-                            hsis.available());
-                    throw new RuntimeException("Unxpected successful " +
-                            "object construction");
-                } catch (SSLException ssle) { }
-
-                pass = Boolean.TRUE;
-            } catch (Exception e) {
-                e.printStackTrace(System.out);
-                message = e.getClass().getName();
-            }
-
-            return new AbstractMap.SimpleEntry<>(pass, message);
-        }
-    };
-
-    // Take CSRE extension data and add extension type and length decorations
-    private static byte[] wrapExtData(byte[] extData) {
-        int bufferLen = extData.length + 4;
-        ByteBuffer bb = ByteBuffer.allocate(bufferLen);
-
-        bb.putShort((short)ExtensionType.EXT_STATUS_REQUEST_V2.id);
-        bb.putShort((short)extData.length);
-        if (extData.length != 0) {
-            bb.put(extData);
-        }
-        return bb.array();
-    }
-}
--- a/test/sun/security/ssl/StatusStapling/OCSPStatusRequestTests.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,340 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-/*
- * @test
- * @bug 8046321
- * @summary OCSP Stapling for TLS (OCSPStatusRequestTests tests)
- * @build OCSPStatusRequestTests TestCase TestUtils
- * @run main/othervm sun.security.ssl.OCSPStatusRequestTests
- */
-
-import java.security.cert.*;
-import java.util.*;
-import java.nio.ByteBuffer;
-import javax.security.auth.x500.X500Principal;
-import sun.security.provider.certpath.ResponderId;
-import sun.security.provider.certpath.OCSPNonceExtension;
-
-/*
- * Checks that the hash value for a certificate's issuer name is generated
- * correctly. Requires any certificate that is not self-signed.
- *
- * NOTE: this test uses Sun private classes which are subject to change.
- */
-public class OCSPStatusRequestTests {
-
-    private static final boolean debug = false;
-
-    // The default (no Responder IDs or Extensions)
-    private static final byte[] DEF_OCSPREQ_BYTES = { 0, 0, 0, 0 };
-
-    // OCSP Extension with one Responder ID (byName: CN=OCSP Signer) and
-    // a nonce extension (32 bytes).
-    private static final byte[] OCSPREQ_1RID_1EXT = {
-            0,   28,    0,   26,  -95,   24,   48,   22,
-           49,   20,   48,   18,    6,    3,   85,    4,
-            3,   19,   11,   79,   67,   83,   80,   32,
-           83,  105,  103,  110,  101,  114,    0,   51,
-           48,   49,   48,   47,    6,    9,   43,    6,
-            1,    5,    5,    7,   48,    1,    2,    4,
-           34,    4,   32,  -34,  -83,  -66,  -17,  -34,
-          -83,  -66,  -17,  -34,  -83,  -66,  -17,  -34,
-          -83,  -66,  -17,  -34,  -83,  -66,  -17,  -34,
-          -83,  -66,  -17,  -34,  -83,  -66,  -17,  -34,
-          -83,  -66,  -17
-    };
-
-    public static void main(String[] args) throws Exception {
-        Map<String, TestCase> testList =
-                new LinkedHashMap<String, TestCase>() {{
-            put("CTOR (default)", testCtorDefault);
-            put("CTOR (Responder Id and Extension)", testCtorRidsExts);
-            put("CTOR (HandshakeInStream)", testCtorInStream);
-            put("CTOR (byte array)", testCtorByteArray);
-            put("Length tests", testLength);
-            put("Equals tests", testEquals);
-        }};
-
-        TestUtils.runTests(testList);
-    }
-
-    // Test the default constructor and its encoding
-    public static final TestCase testCtorDefault = new TestCase() {
-        @Override
-        public Map.Entry<Boolean, String> runTest() {
-            Boolean pass = Boolean.FALSE;
-            String message = null;
-            try {
-                // Create a OCSPStatusRequest with a single ResponderId
-                // and Extension
-                OCSPStatusRequest osrDefault = new OCSPStatusRequest();
-                HandshakeOutStream hsout = new HandshakeOutStream(null);
-                osrDefault.send(hsout);
-                System.out.println("Encoded Result:");
-                TestUtils.dumpBytes(hsout.toByteArray());
-
-                TestUtils.valueCheck(DEF_OCSPREQ_BYTES, hsout.toByteArray());
-                pass = Boolean.TRUE;
-            } catch (Exception e) {
-                e.printStackTrace(System.out);
-                message = e.getClass().getName();
-            }
-
-            return new AbstractMap.SimpleEntry<>(pass, message);
-        }
-    };
-
-    // Test the constructor form that allows the user to specify zero
-    // or more ResponderId objects and/or Extensions
-    public static final TestCase testCtorRidsExts = new TestCase() {
-        @Override
-        public Map.Entry<Boolean, String> runTest() {
-            Boolean pass = Boolean.FALSE;
-            String message = null;
-            try {
-                List<ResponderId> ridList = new LinkedList<ResponderId>() {{
-                    add(new ResponderId(new X500Principal("CN=OCSP Signer")));
-                }};
-                List<Extension> extList = new LinkedList<Extension>() {{
-                    add(new OCSPNonceExtension(32));
-                }};
-
-                // Default-style OCSPStatusRequest using both empty Lists and
-                // null inputs
-                OCSPStatusRequest osrDef1 =
-                        new OCSPStatusRequest(new LinkedList<ResponderId>(),
-                                null);
-                OCSPStatusRequest osrDef2 =
-                        new OCSPStatusRequest(null,
-                                new LinkedList<Extension>());
-                HandshakeOutStream hsout = new HandshakeOutStream(null);
-                osrDef1.send(hsout);
-                System.out.println("Encoded Result:");
-                TestUtils.dumpBytes(hsout.toByteArray());
-                TestUtils.valueCheck(DEF_OCSPREQ_BYTES, hsout.toByteArray());
-
-                hsout.reset();
-                osrDef2.send(hsout);
-                System.out.println("Encoded Result:");
-                TestUtils.dumpBytes(hsout.toByteArray());
-                TestUtils.valueCheck(DEF_OCSPREQ_BYTES, hsout.toByteArray());
-
-                hsout.reset();
-                OCSPStatusRequest osrWithItems =
-                        new OCSPStatusRequest(ridList, extList);
-                osrWithItems.send(hsout);
-                System.out.println("Encoded Result:");
-                byte[] encodedData = hsout.toByteArray();
-                TestUtils.dumpBytes(encodedData);
-                // Check everything except the last 32 bytes (nonce data)
-                TestUtils.valueCheck(OCSPREQ_1RID_1EXT, encodedData, 0, 0,
-                        encodedData.length - 32);
-
-                pass = Boolean.TRUE;
-            } catch (Exception e) {
-                e.printStackTrace(System.out);
-                message = e.getClass().getName();
-            }
-
-            return new AbstractMap.SimpleEntry<>(pass, message);
-        }
-    };
-
-    // Test the constructor that builds the ob ject using data from
-    // a HandshakeInStream
-    public static final TestCase testCtorInStream = new TestCase() {
-        @Override
-        public Map.Entry<Boolean, String> runTest() {
-            Boolean pass = Boolean.FALSE;
-            String message = null;
-            try {
-                ResponderId checkRid =
-                        new ResponderId(new X500Principal("CN=OCSP Signer"));
-                Extension checkExt = new OCSPNonceExtension(32);
-
-                HandshakeInStream hsis = new HandshakeInStream();
-                hsis.incomingRecord(ByteBuffer.wrap(OCSPREQ_1RID_1EXT));
-                OCSPStatusRequest osr = new OCSPStatusRequest(hsis);
-
-                List<ResponderId> ridList = osr.getResponderIds();
-                List<Extension> extList = osr.getExtensions();
-
-                if (ridList.size() != 1 || !ridList.contains(checkRid)) {
-                    throw new RuntimeException("Responder list mismatch");
-                } else if (extList.size() !=  1 ||
-                        !extList.get(0).getId().equals(checkExt.getId())) {
-                    throw new RuntimeException("Extension list mismatch");
-                }
-
-                pass = Boolean.TRUE;
-            } catch (Exception e) {
-                e.printStackTrace(System.out);
-                message = e.getClass().getName();
-            }
-
-            return new AbstractMap.SimpleEntry<>(pass, message);
-        }
-    };
-
-    // Test the constructor form that takes the data from a byte array
-    public static final TestCase testCtorByteArray = new TestCase() {
-        @Override
-        public Map.Entry<Boolean, String> runTest() {
-            Boolean pass = Boolean.FALSE;
-            String message = null;
-            try {
-                ResponderId checkRid =
-                        new ResponderId(new X500Principal("CN=OCSP Signer"));
-                Extension checkExt = new OCSPNonceExtension(32);
-
-                OCSPStatusRequest osr =
-                        new OCSPStatusRequest(OCSPREQ_1RID_1EXT);
-
-                List<ResponderId> ridList = osr.getResponderIds();
-                List<Extension> extList = osr.getExtensions();
-
-                if (ridList.size() != 1 || !ridList.contains(checkRid)) {
-                    throw new RuntimeException("Responder list mismatch");
-                } else if (extList.size() !=  1 ||
-                        !extList.get(0).getId().equals(checkExt.getId())) {
-                    throw new RuntimeException("Extension list mismatch");
-                }
-                pass = Boolean.TRUE;
-            } catch (Exception e) {
-                e.printStackTrace(System.out);
-                message = e.getClass().getName();
-            }
-
-            return new AbstractMap.SimpleEntry<>(pass, message);
-        }
-    };
-
-    // Test the length functions for both default and non-default
-    // OCSPStatusRequest objects
-    public static final TestCase testLength = new TestCase() {
-        @Override
-        public Map.Entry<Boolean, String> runTest() {
-            Boolean pass = Boolean.FALSE;
-            String message = null;
-            try {
-                HandshakeInStream hsis = new HandshakeInStream();
-                hsis.incomingRecord(ByteBuffer.wrap(OCSPREQ_1RID_1EXT));
-                OCSPStatusRequest osr = new OCSPStatusRequest(hsis);
-                OCSPStatusRequest osrDefault = new OCSPStatusRequest();
-
-                if (osrDefault.length() != DEF_OCSPREQ_BYTES.length) {
-                    throw new RuntimeException("Invalid length for default: " +
-                            "Expected" + DEF_OCSPREQ_BYTES.length +
-                            ", received " + osrDefault.length());
-                } else if (osr.length() != OCSPREQ_1RID_1EXT.length) {
-                    throw new RuntimeException("Invalid length for default: " +
-                            "Expected" + OCSPREQ_1RID_1EXT.length +
-                            ", received " + osr.length());
-                }
-
-                pass = Boolean.TRUE;
-            } catch (Exception e) {
-                e.printStackTrace(System.out);
-                message = e.getClass().getName();
-            }
-
-            return new AbstractMap.SimpleEntry<>(pass, message);
-        }
-    };
-
-    // Test the equals method with default and non-default objects
-    public static final TestCase testEquals = new TestCase() {
-        @Override
-        public Map.Entry<Boolean, String> runTest() {
-            Boolean pass = Boolean.FALSE;
-            String message = null;
-            try {
-                // Make two different lists with the same ResponderId values
-                // and also make a extension list
-                List<ResponderId> ridList1 = new LinkedList<ResponderId>() {{
-                    add(new ResponderId(new X500Principal("CN=OCSP Signer")));
-                }};
-                List<ResponderId> ridList2 = new LinkedList<ResponderId>() {{
-                    add(new ResponderId(new X500Principal("CN=OCSP Signer")));
-                }};
-                List<Extension> extList = new LinkedList<Extension>() {{
-                    add(new OCSPNonceExtension(32));
-                }};
-
-                // We expect two default OCSP objects to be equal
-                OCSPStatusRequest osrDefault = new OCSPStatusRequest();
-                if (!osrDefault.equals(new OCSPStatusRequest())) {
-                    throw new RuntimeException("Default OCSPStatusRequest" +
-                            " equality test failed");
-                }
-
-                // null test (expect false return)
-                if (osrDefault.equals(null)) {
-                    throw new RuntimeException("OCSPStatusRequest matched" +
-                            " unexpectedly");
-                }
-
-                // Self-reference test
-                OCSPStatusRequest osrSelfRef = osrDefault;
-                if (!osrDefault.equals(osrSelfRef)) {
-                    throw new RuntimeException("Default OCSPStatusRequest" +
-                            " equality test failed");
-                }
-
-                // Two OCSPStatusRequests with matching ResponderIds should
-                // be considered equal
-                OCSPStatusRequest osrByList1 =
-                        new OCSPStatusRequest(ridList1, null);
-                OCSPStatusRequest osrByList2 = new OCSPStatusRequest(ridList2,
-                        Collections.emptyList());
-                if (!osrByList1.equals(osrByList2)) {
-                    throw new RuntimeException("Single Responder ID " +
-                            "OCSPStatusRequest equality test failed");
-                }
-
-                // We expect OCSPStatusRequests with different nonces to be
-                // considered unequal.
-                HandshakeInStream hsis = new HandshakeInStream();
-                hsis.incomingRecord(ByteBuffer.wrap(OCSPREQ_1RID_1EXT));
-                OCSPStatusRequest osrStream = new OCSPStatusRequest(hsis);
-                OCSPStatusRequest osrRidExt = new OCSPStatusRequest(ridList1,
-                        extList);
-                if (osrStream.equals(osrRidExt)) {
-                    throw new RuntimeException("OCSPStatusRequest matched" +
-                            " unexpectedly");
-                }
-
-                pass = Boolean.TRUE;
-            } catch (Exception e) {
-                e.printStackTrace(System.out);
-                message = e.getClass().getName();
-            }
-
-            return new AbstractMap.SimpleEntry<>(pass, message);
-        }
-    };
-
-}
--- a/test/sun/security/ssl/StatusStapling/StatusResponseManagerTests.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,455 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-/*
- * @test
- * @bug 8046321
- * @summary OCSP Stapling for TLS (StatusResponseManager tests)
- * @library ../../../../java/security/testlibrary
- * @build CertificateBuilder SimpleOCSPServer
- * @build StatusResponseManagerTests TestCase TestUtils
- * @run main/othervm -Djavax.net.debug=ssl:respmgr
- *      sun.security.ssl.StatusResponseManagerTests
- */
-
-import java.io.IOException;
-import java.math.BigInteger;
-import java.security.cert.*;
-import java.util.*;
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.KeyStore;
-import java.security.PublicKey;
-import java.util.concurrent.TimeUnit;
-
-import sun.security.testlibrary.SimpleOCSPServer;
-import sun.security.testlibrary.CertificateBuilder;
-
-/*
- * Checks that the hash value for a certificate's issuer name is generated
- * correctly. Requires any certificate that is not self-signed.
- *
- * NOTE: this test uses Sun private classes which are subject to change.
- */
-public class StatusResponseManagerTests {
-
-    private static final boolean debug = true;
-    private static final boolean ocspDebug = false;
-
-    // PKI components we will need for this test
-    static String passwd = "passphrase";
-    static String ROOT_ALIAS = "root";
-    static String INT_ALIAS = "intermediate";
-    static String SSL_ALIAS = "ssl";
-    static KeyStore rootKeystore;           // Root CA Keystore
-    static KeyStore intKeystore;            // Intermediate CA Keystore
-    static KeyStore serverKeystore;         // SSL Server Keystore
-    static KeyStore trustStore;             // SSL Client trust store
-    static X509Certificate rootCert;
-    static X509Certificate intCert;
-    static X509Certificate sslCert;
-    static SimpleOCSPServer rootOcsp;       // Root CA OCSP Responder
-    static int rootOcspPort;                // Port number for root OCSP
-    static SimpleOCSPServer intOcsp;        // Intermediate CA OCSP Responder
-    static int intOcspPort;                 // Port number for intermed. OCSP
-
-    static X509Certificate[] chain;
-
-    public static void main(String[] args) throws Exception {
-        Map<String, TestCase> testList =
-                new LinkedHashMap<String, TestCase>() {{
-            put("Basic OCSP fetch test", testOcspFetch);
-            put("Clear StatusResponseManager cache", testClearSRM);
-            put("Basic OCSP_MULTI fetch test", testOcspMultiFetch);
-            put("Test Cache Expiration", testCacheExpiry);
-        }};
-
-        // Create the CAs and OCSP responders
-        createPKI();
-
-        // Grab the certificates and make a chain we can reuse for tests
-        sslCert = (X509Certificate)serverKeystore.getCertificate(SSL_ALIAS);
-        intCert = (X509Certificate)intKeystore.getCertificate(INT_ALIAS);
-        rootCert = (X509Certificate)rootKeystore.getCertificate(ROOT_ALIAS);
-        chain = new X509Certificate[3];
-        chain[0] = sslCert;
-        chain[1] = intCert;
-        chain[2] = rootCert;
-
-        TestUtils.runTests(testList);
-
-        intOcsp.stop();
-        rootOcsp.stop();
-    }
-
-    // Test a simple RFC 6066 server-side fetch
-    public static final TestCase testOcspFetch = new TestCase() {
-        @Override
-        public Map.Entry<Boolean, String> runTest() {
-            StatusResponseManager srm = new StatusResponseManager();
-            Boolean pass = Boolean.FALSE;
-            String message = null;
-            StatusRequest oReq = new OCSPStatusRequest();
-
-            try {
-                // Get OCSP responses for non-root certs in the chain
-                Map<X509Certificate, byte[]> responseMap = srm.get(
-                        StatusRequestType.OCSP, oReq, chain, 5000,
-                        TimeUnit.MILLISECONDS);
-
-                // There should be one entry in the returned map and
-                // one entry in the cache when the operation is complete.
-                if (responseMap.size() != 1) {
-                    message = "Incorrect number of responses: expected 1, got "
-                            + responseMap.size();
-                } else if (!responseMap.containsKey(sslCert)) {
-                    message = "Response map key is incorrect, expected " +
-                            sslCert.getSubjectX500Principal().toString();
-                } else if (srm.size() != 1) {
-                    message = "Incorrect number of cache entries: " +
-                            "expected 1, got " + srm.size();
-                } else {
-                    pass = Boolean.TRUE;
-                }
-            } catch (Exception e) {
-                e.printStackTrace(System.out);
-                message = e.getClass().getName();
-            }
-
-            return new AbstractMap.SimpleEntry<>(pass, message);
-        }
-    };
-
-    // Test clearing the StatusResponseManager cache.
-    public static final TestCase testClearSRM = new TestCase() {
-        @Override
-        public Map.Entry<Boolean, String> runTest() {
-            StatusResponseManager srm = new StatusResponseManager();
-            Boolean pass = Boolean.FALSE;
-            String message = null;
-            StatusRequest oReq = new OCSPStatusRequest();
-
-            try {
-                // Get OCSP responses for non-root certs in the chain
-                srm.get(StatusRequestType.OCSP_MULTI, oReq, chain, 5000,
-                        TimeUnit.MILLISECONDS);
-
-                // There should be two entries in the returned map and
-                // two entries in the cache when the operation is complete.
-                if (srm.size() != 2) {
-                    message = "Incorrect number of responses: expected 2, got "
-                            + srm.size();
-                } else {
-                    // Next, clear the SRM, then check the size again
-                    srm.clear();
-                    if (srm.size() != 0) {
-                        message = "Incorrect number of responses: expected 0," +
-                                " got " + srm.size();
-                    } else {
-                        pass = Boolean.TRUE;
-                    }
-                }
-            } catch (Exception e) {
-                e.printStackTrace(System.out);
-                message = e.getClass().getName();
-            }
-
-            return new AbstractMap.SimpleEntry<>(pass, message);
-        }
-    };
-
-    // Test a simple RFC 6961 server-side fetch
-    public static final TestCase testOcspMultiFetch = new TestCase() {
-        @Override
-        public Map.Entry<Boolean, String> runTest() {
-            StatusResponseManager srm = new StatusResponseManager();
-            Boolean pass = Boolean.FALSE;
-            String message = null;
-            StatusRequest oReq = new OCSPStatusRequest();
-
-            try {
-                // Get OCSP responses for non-root certs in the chain
-                Map<X509Certificate, byte[]> responseMap = srm.get(
-                        StatusRequestType.OCSP_MULTI, oReq, chain, 5000,
-                        TimeUnit.MILLISECONDS);
-
-                // There should be two entries in the returned map and
-                // two entries in the cache when the operation is complete.
-                if (responseMap.size() != 2) {
-                    message = "Incorrect number of responses: expected 2, got "
-                            + responseMap.size();
-                } else if (!responseMap.containsKey(sslCert) ||
-                        !responseMap.containsKey(intCert)) {
-                    message = "Response map keys are incorrect, expected " +
-                            sslCert.getSubjectX500Principal().toString() +
-                            " and " +
-                            intCert.getSubjectX500Principal().toString();
-                } else if (srm.size() != 2) {
-                    message = "Incorrect number of cache entries: " +
-                            "expected 2, got " + srm.size();
-                } else {
-                    pass = Boolean.TRUE;
-                }
-            } catch (Exception e) {
-                e.printStackTrace(System.out);
-                message = e.getClass().getName();
-            }
-
-            return new AbstractMap.SimpleEntry<>(pass, message);
-        }
-    };
-
-    // Test cache expiration
-    public static final TestCase testCacheExpiry = new TestCase() {
-        @Override
-        public Map.Entry<Boolean, String> runTest() {
-            // For this test, we will set the cache expiry to 5 seconds
-            System.setProperty("jdk.tls.stapling.cacheLifetime", "5");
-            StatusResponseManager srm = new StatusResponseManager();
-            Boolean pass = Boolean.FALSE;
-            String message = null;
-            StatusRequest oReq = new OCSPStatusRequest();
-
-            try {
-                // Get OCSP responses for non-root certs in the chain
-                srm.get(StatusRequestType.OCSP_MULTI, oReq, chain, 5000,
-                        TimeUnit.MILLISECONDS);
-
-                // There should be two entries in the returned map and
-                // two entries in the cache when the operation is complete.
-                if (srm.size() != 2) {
-                    message = "Incorrect number of responses: expected 2, got "
-                            + srm.size();
-                } else {
-                    // Next, wait for more than 5 seconds so the responses
-                    // in the SRM will expire.
-                    Thread.sleep(7000);
-                    if (srm.size() != 0) {
-                        message = "Incorrect number of responses: expected 0," +
-                                " got " + srm.size();
-                    } else {
-                        pass = Boolean.TRUE;
-                    }
-                }
-            } catch (Exception e) {
-                e.printStackTrace(System.out);
-                message = e.getClass().getName();
-            }
-
-            // Set the cache lifetime back to the default
-            System.setProperty("jdk.tls.stapling.cacheLifetime", "");
-            return new AbstractMap.SimpleEntry<>(pass, message);
-        }
-    };
-
-    /**
-     * Creates the PKI components necessary for this test, including
-     * Root CA, Intermediate CA and SSL server certificates, the keystores
-     * for each entity, a client trust store, and starts the OCSP responders.
-     */
-    private static void createPKI() throws Exception {
-        CertificateBuilder cbld = new CertificateBuilder();
-        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
-        keyGen.initialize(2048);
-        KeyStore.Builder keyStoreBuilder =
-                KeyStore.Builder.newInstance("PKCS12", null,
-                        new KeyStore.PasswordProtection(passwd.toCharArray()));
-
-        // Generate Root, IntCA, EE keys
-        KeyPair rootCaKP = keyGen.genKeyPair();
-        log("Generated Root CA KeyPair");
-        KeyPair intCaKP = keyGen.genKeyPair();
-        log("Generated Intermediate CA KeyPair");
-        KeyPair sslKP = keyGen.genKeyPair();
-        log("Generated SSL Cert KeyPair");
-
-        // Set up the Root CA Cert
-        cbld.setSubjectName("CN=Root CA Cert, O=SomeCompany");
-        cbld.setPublicKey(rootCaKP.getPublic());
-        cbld.setSerialNumber(new BigInteger("1"));
-        // Make a 3 year validity starting from 60 days ago
-        long start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(60);
-        long end = start + TimeUnit.DAYS.toMillis(1085);
-        cbld.setValidity(new Date(start), new Date(end));
-        addCommonExts(cbld, rootCaKP.getPublic(), rootCaKP.getPublic());
-        addCommonCAExts(cbld);
-        // Make our Root CA Cert!
-        X509Certificate rootCert = cbld.build(null, rootCaKP.getPrivate(),
-                "SHA256withRSA");
-        log("Root CA Created:\n" + certInfo(rootCert));
-
-        // Now build a keystore and add the keys and cert
-        rootKeystore = keyStoreBuilder.getKeyStore();
-        Certificate[] rootChain = {rootCert};
-        rootKeystore.setKeyEntry(ROOT_ALIAS, rootCaKP.getPrivate(),
-                passwd.toCharArray(), rootChain);
-
-        // Now fire up the OCSP responder
-        rootOcsp = new SimpleOCSPServer(rootKeystore, passwd, ROOT_ALIAS, null);
-        rootOcsp.enableLog(ocspDebug);
-        rootOcsp.setNextUpdateInterval(3600);
-        rootOcsp.start();
-        Thread.sleep(1000);         // Give the server a second to start up
-        rootOcspPort = rootOcsp.getPort();
-        String rootRespURI = "http://localhost:" + rootOcspPort;
-        log("Root OCSP Responder URI is " + rootRespURI);
-
-        // Now that we have the root keystore and OCSP responder we can
-        // create our intermediate CA.
-        cbld.reset();
-        cbld.setSubjectName("CN=Intermediate CA Cert, O=SomeCompany");
-        cbld.setPublicKey(intCaKP.getPublic());
-        cbld.setSerialNumber(new BigInteger("100"));
-        // Make a 2 year validity starting from 30 days ago
-        start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(30);
-        end = start + TimeUnit.DAYS.toMillis(730);
-        cbld.setValidity(new Date(start), new Date(end));
-        addCommonExts(cbld, intCaKP.getPublic(), rootCaKP.getPublic());
-        addCommonCAExts(cbld);
-        cbld.addAIAExt(Collections.singletonList(rootRespURI));
-        // Make our Intermediate CA Cert!
-        X509Certificate intCaCert = cbld.build(rootCert, rootCaKP.getPrivate(),
-                "SHA256withRSA");
-        log("Intermediate CA Created:\n" + certInfo(intCaCert));
-
-        // Provide intermediate CA cert revocation info to the Root CA
-        // OCSP responder.
-        Map<BigInteger, SimpleOCSPServer.CertStatusInfo> revInfo =
-            new HashMap<>();
-        revInfo.put(intCaCert.getSerialNumber(),
-                new SimpleOCSPServer.CertStatusInfo(
-                        SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD));
-        rootOcsp.updateStatusDb(revInfo);
-
-        // Now build a keystore and add the keys, chain and root cert as a TA
-        intKeystore = keyStoreBuilder.getKeyStore();
-        Certificate[] intChain = {intCaCert, rootCert};
-        intKeystore.setKeyEntry(INT_ALIAS, intCaKP.getPrivate(),
-                passwd.toCharArray(), intChain);
-        intKeystore.setCertificateEntry(ROOT_ALIAS, rootCert);
-
-        // Now fire up the Intermediate CA OCSP responder
-        intOcsp = new SimpleOCSPServer(intKeystore, passwd,
-                INT_ALIAS, null);
-        intOcsp.enableLog(ocspDebug);
-        intOcsp.setNextUpdateInterval(3600);
-        intOcsp.start();
-        Thread.sleep(1000);
-        intOcspPort = intOcsp.getPort();
-        String intCaRespURI = "http://localhost:" + intOcspPort;
-        log("Intermediate CA OCSP Responder URI is " + intCaRespURI);
-
-        // Last but not least, let's make our SSLCert and add it to its own
-        // Keystore
-        cbld.reset();
-        cbld.setSubjectName("CN=SSLCertificate, O=SomeCompany");
-        cbld.setPublicKey(sslKP.getPublic());
-        cbld.setSerialNumber(new BigInteger("4096"));
-        // Make a 1 year validity starting from 7 days ago
-        start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7);
-        end = start + TimeUnit.DAYS.toMillis(365);
-        cbld.setValidity(new Date(start), new Date(end));
-
-        // Add extensions
-        addCommonExts(cbld, sslKP.getPublic(), intCaKP.getPublic());
-        boolean[] kuBits = {true, false, true, false, false, false,
-            false, false, false};
-        cbld.addKeyUsageExt(kuBits);
-        List<String> ekuOids = new ArrayList<>();
-        ekuOids.add("1.3.6.1.5.5.7.3.1");
-        ekuOids.add("1.3.6.1.5.5.7.3.2");
-        cbld.addExtendedKeyUsageExt(ekuOids);
-        cbld.addSubjectAltNameDNSExt(Collections.singletonList("localhost"));
-        cbld.addAIAExt(Collections.singletonList(intCaRespURI));
-        // Make our SSL Server Cert!
-        X509Certificate sslCert = cbld.build(intCaCert, intCaKP.getPrivate(),
-                "SHA256withRSA");
-        log("SSL Certificate Created:\n" + certInfo(sslCert));
-
-        // Provide SSL server cert revocation info to the Intermeidate CA
-        // OCSP responder.
-        revInfo = new HashMap<>();
-        revInfo.put(sslCert.getSerialNumber(),
-                new SimpleOCSPServer.CertStatusInfo(
-                        SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD));
-        intOcsp.updateStatusDb(revInfo);
-
-        // Now build a keystore and add the keys, chain and root cert as a TA
-        serverKeystore = keyStoreBuilder.getKeyStore();
-        Certificate[] sslChain = {sslCert, intCaCert, rootCert};
-        serverKeystore.setKeyEntry(SSL_ALIAS, sslKP.getPrivate(),
-                passwd.toCharArray(), sslChain);
-        serverKeystore.setCertificateEntry(ROOT_ALIAS, rootCert);
-
-        // And finally a Trust Store for the client
-        trustStore = keyStoreBuilder.getKeyStore();
-        trustStore.setCertificateEntry(ROOT_ALIAS, rootCert);
-    }
-
-    private static void addCommonExts(CertificateBuilder cbld,
-            PublicKey subjKey, PublicKey authKey) throws IOException {
-        cbld.addSubjectKeyIdExt(subjKey);
-        cbld.addAuthorityKeyIdExt(authKey);
-    }
-
-    private static void addCommonCAExts(CertificateBuilder cbld)
-            throws IOException {
-        cbld.addBasicConstraintsExt(true, true, -1);
-        // Set key usage bits for digitalSignature, keyCertSign and cRLSign
-        boolean[] kuBitSettings = {true, false, false, false, false, true,
-            true, false, false};
-        cbld.addKeyUsageExt(kuBitSettings);
-    }
-
-    /**
-     * Helper routine that dumps only a few cert fields rather than
-     * the whole toString() output.
-     *
-     * @param cert An X509Certificate to be displayed
-     *
-     * @return The {@link String} output of the issuer, subject and
-     * serial number
-     */
-    private static String certInfo(X509Certificate cert) {
-        StringBuilder sb = new StringBuilder();
-        sb.append("Issuer: ").append(cert.getIssuerX500Principal()).
-                append("\n");
-        sb.append("Subject: ").append(cert.getSubjectX500Principal()).
-                append("\n");
-        sb.append("Serial: ").append(cert.getSerialNumber()).append("\n");
-        return sb.toString();
-    }
-
-    /**
-     * Log a message on stdout
-     *
-     * @param message The message to log
-     */
-    private static void log(String message) {
-        if (debug) {
-            System.out.println(message);
-        }
-    }
-}
--- a/test/sun/security/ssl/StatusStapling/TEST.properties	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/security/ssl/StatusStapling/TEST.properties	Thu Mar 17 19:04:16 2016 +0000
@@ -1,1 +1,6 @@
+modules = \
+    java.base/sun.security.provider.certpath \
+    java.base/sun.security.util \
+    java.base/sun.security.x509 \
+    java.base/sun.security.ssl
 bootclasspath.dirs=.
--- a/test/sun/security/ssl/StatusStapling/TestCase.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-import java.util.Map;
-
-public interface TestCase {
-    Map.Entry<Boolean, String> runTest();
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/StatusStapling/TestRun.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8046321
+ * @library ../../../../java/security/testlibrary
+ * @build CertificateBuilder SimpleOCSPServer
+ * @run main/othervm java.base/sun.security.ssl.CertStatusReqExtensionTests
+ * @run main/othervm java.base/sun.security.ssl.CertStatusReqItemV2Tests
+ * @run main/othervm java.base/sun.security.ssl.CertStatusReqListV2ExtensionTests
+ * @run main/othervm java.base/sun.security.ssl.OCSPStatusRequestTests
+ * @run main/othervm -Djavax.net.debug=ssl:respmgr java.base/sun.security.ssl.StatusResponseManagerTests
+ * @summary OCSP Stapling for TLS
+ */
+
--- a/test/sun/security/ssl/StatusStapling/TestUtils.java	Tue Mar 15 13:48:26 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,124 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.Map;
-
-public class TestUtils {
-
-    // private constructor to prevent instantiation for this utility class
-    private TestUtils() {
-        throw new AssertionError();
-    }
-
-    public static void runTests(Map<String, TestCase> testList) {
-        int testNo = 0;
-        int numberFailed = 0;
-        Map.Entry<Boolean, String> result;
-
-        System.out.println("============ Tests ============");
-        for (String testName : testList.keySet()) {
-            System.out.println("Test " + ++testNo + ": " + testName);
-            result = testList.get(testName).runTest();
-            System.out.print("Result: " + (result.getKey() ? "PASS" : "FAIL"));
-            System.out.println(" " +
-                    (result.getValue() != null ? result.getValue() : ""));
-            System.out.println("-------------------------------------------");
-            if (!result.getKey()) {
-                numberFailed++;
-            }
-        }
-
-        System.out.println("End Results: " + (testList.size() - numberFailed) +
-                " Passed" + ", " + numberFailed + " Failed.");
-        if (numberFailed > 0) {
-            throw new RuntimeException(
-                    "One or more tests failed, see test output for details");
-        }
-    }
-
-    public static void dumpBytes(byte[] data) {
-        dumpBytes(ByteBuffer.wrap(data));
-    }
-
-    public static void dumpBytes(ByteBuffer data) {
-        int i = 0;
-
-        data.mark();
-        while (data.hasRemaining()) {
-            if (i % 16 == 0 && i != 0) {
-                System.out.print("\n");
-            }
-            System.out.print(String.format("%02X ", data.get()));
-            i++;
-        }
-        System.out.print("\n");
-        data.reset();
-    }
-
-    public static void valueCheck(byte[] array1, byte[] array2) {
-        if (!Arrays.equals(array1, array2)) {
-            throw new RuntimeException("Array mismatch");
-        }
-    }
-
-    // Compares a range of bytes at specific offsets in each array
-    public static void valueCheck(byte[] array1, byte[] array2, int skip1,
-            int skip2, int length) {
-        ByteBuffer buf1 = ByteBuffer.wrap(array1);
-        ByteBuffer buf2 = ByteBuffer.wrap(array2);
-
-        // Skip past however many bytes are requested in both buffers
-        buf1.position(skip1);
-        buf2.position(skip2);
-
-        // Reset the limits on each buffer to account for the length
-        buf1.limit(buf1.position() + length);
-        buf2.limit(buf2.position() + length);
-
-        if (!buf1.equals(buf2)) {
-            throw new RuntimeException("Array range mismatch");
-        }
-    }
-
-    // Concatenate 1 or more arrays
-    public static byte[] gatherBuffers(byte[]... arrays) {
-        int totalLength = 0;
-        for (byte[] ar : arrays) {
-            totalLength += ar != null ? ar.length : 0;
-        }
-
-        byte[] resultBuf = new byte[totalLength];
-        int offset = 0;
-        for (byte[] ar : arrays) {
-            if (ar != null) {
-                System.arraycopy(ar, 0, resultBuf, offset, ar.length);
-                offset += ar.length;
-            }
-        }
-        return resultBuf;
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/BogusStatusRequest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ssl;
+
+import java.io.IOException;
+
+final class BogusStatusRequest implements StatusRequest {
+    BogusStatusRequest() { }
+
+    @Override
+    public int length() { return 0; }
+
+    @Override
+    public void send(HandshakeOutStream s) throws IOException { }
+
+    @Override
+    public String toString() {
+        return "BogusStatusRequest";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/CertStatusReqExtensionTests.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ssl;
+
+import java.io.IOException;
+import java.util.*;
+import java.nio.ByteBuffer;
+
+/*
+ * Checks that the hash value for a certificate's issuer name is generated
+ * correctly. Requires any certificate that is not self-signed.
+ *
+ * NOTE: this test uses Sun private classes which are subject to change.
+ */
+public class CertStatusReqExtensionTests {
+
+    private static final boolean debug = false;
+
+    // Default status_request extension (type = ocsp, OCSPStatusRequest
+    // with no responder IDs or extensions
+    private static final byte[] CSRE_DEF_OSR = {1, 0, 0, 0, 0};
+
+    // A status_request extension using a user-defined type (0xFF) and
+    // an underlying no-Responder ID/no-extension OCSPStatusRequest
+    private static final byte[] CSRE_TYPE_FF = {-1, 0, 0, 0, 0};
+
+    // A CertStatusReqExtension with 5 ResponderIds and 1 Extension
+    private static final byte[] CSRE_REQ_RID_EXTS = {
+           1,    0,  -13,    0,   59,  -95,   57,   48,
+          55,   49,   16,   48,   14,    6,    3,   85,
+           4,   10,   19,    7,   83,  111,  109,  101,
+          73,  110,   99,   49,   16,   48,   14,    6,
+           3,   85,    4,   11,   19,    7,   83,  111,
+         109,  101,   80,   75,   73,   49,   17,   48,
+          15,    6,    3,   85,    4,    3,   19,    8,
+          83,  111,  109,  101,   79,   67,   83,   80,
+           0,   68,  -95,   66,   48,   64,   49,   13,
+          48,   11,    6,    3,   85,    4,   10,   19,
+           4,   79,  104,   77,  121,   49,   14,   48,
+          12,    6,    3,   85,    4,   11,   19,    5,
+          66,  101,   97,  114,  115,   49,   15,   48,
+          13,    6,    3,   85,    4,   11,   19,    6,
+          84,  105,  103,  101,  114,  115,   49,   14,
+          48,   12,    6,    3,   85,    4,    3,   19,
+           5,   76,  105,  111,  110,  115,    0,   58,
+         -95,   56,   48,   54,   49,   16,   48,   14,
+           6,    3,   85,    4,   10,   19,    7,   67,
+         111,  109,  112,   97,  110,  121,   49,   13,
+          48,   11,    6,    3,   85,    4,   11,   19,
+           4,   87,  101,  115,  116,   49,   19,   48,
+          17,    6,    3,   85,    4,    3,   19,   10,
+          82,  101,  115,  112,  111,  110,  100,  101,
+         114,   49,    0,   24,  -94,   22,    4,   20,
+         -67,  -36,  114,  121,   92,  -79,  116,   -1,
+         102, -107,    7,  -21,   18, -113,   64,   76,
+          96,   -7,  -66,  -63,    0,   24,  -94,   22,
+           4,   20,  -51,  -69,  107,  -82,  -39,  -87,
+          45,   25,   41,   28,  -76,  -68,  -11, -110,
+         -94,  -97,   62,   47,   58, -125,    0,   51,
+          48,   49,   48,   47,    6,    9,   43,    6,
+           1,    5,    5,    7,   48,    1,    2,    4,
+          34,    4,   32,  -26,  -81, -120,  -61, -127,
+         -79,    0,  -39,  -54,   49,    3,  -51,  -57,
+         -85,   19, -126,   94,   -2,   21,   26,   98,
+           6,  105,  -35,  -37,  -29,  -73,  101,   53,
+          44,   15,  -19
+    };
+
+    public static void main(String[] args) throws Exception {
+        Map<String, TestCase> testList =
+                new LinkedHashMap<String, TestCase>() {{
+            put("CTOR (default)", testCtorDefault);
+            put("CTOR (int, StatusRequest)", testCtorStatReqs);
+            put("CTOR (HandshakeInStream, length, getReqType, getRequest)",
+                    testCtorInStream);
+        }};
+
+        TestUtils.runTests(testList);
+    }
+
+    public static final TestCase testCtorDefault = new TestCase() {
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+            try {
+                CertStatusReqExtension csreDef = new CertStatusReqExtension();
+                HandshakeOutStream hsout =
+                        new HandshakeOutStream(null);
+                csreDef.send(hsout);
+                TestUtils.valueCheck(wrapExtData(null), hsout.toByteArray());
+
+                // The length should be 4 (2 bytes for the type, 2 for the
+                // encoding of zero-length
+                if (csreDef.length() != 4) {
+                    throw new RuntimeException("Incorrect length from " +
+                            "default object.  Expected 4, got " +
+                            csreDef.length());
+                }
+
+                // Since there's no data, there are no status_type or request
+                // data fields defined.  Both should return null in this case
+                if (csreDef.getType() != null) {
+                    throw new RuntimeException("Default CSRE returned " +
+                            "non-null status_type");
+                } else if (csreDef.getRequest() != null) {
+                    throw new RuntimeException("Default CSRE returned " +
+                            "non-null request object");
+                }
+
+                pass = Boolean.TRUE;
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+
+    public static final TestCase testCtorStatReqs = new TestCase() {
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+            try {
+                HandshakeOutStream hsout =
+                        new HandshakeOutStream(null);
+                StatusRequest basicStatReq = new OCSPStatusRequest();
+
+                // Create an extension using a default-style OCSPStatusRequest
+                // (no responder IDs, no extensions).
+                CertStatusReqExtension csre1 = new CertStatusReqExtension(
+                        StatusRequestType.OCSP, basicStatReq);
+                csre1.send(hsout);
+                TestUtils.valueCheck(wrapExtData(CSRE_DEF_OSR),
+                        hsout.toByteArray());
+                hsout.reset();
+
+                // Create the extension using a StatusRequestType not already
+                // instantiated as a static StatusRequestType
+                // (e.g. OCSP/OCSP_MULTI)
+                CertStatusReqExtension csre2 =
+                        new CertStatusReqExtension(StatusRequestType.get(-1),
+                                basicStatReq);
+                csre2.send(hsout);
+                TestUtils.valueCheck(wrapExtData(CSRE_TYPE_FF),
+                        hsout.toByteArray());
+
+                // Create the extension using a StatusRequest that
+                // does not match the status_type field
+                // This should throw an IllegalArgumentException
+                try {
+                    CertStatusReqExtension csreBadRequest =
+                            new CertStatusReqExtension(StatusRequestType.OCSP,
+                                    new BogusStatusRequest());
+                    throw new RuntimeException("Constructor accepted a " +
+                            "StatusRequest that is inconsistent with " +
+                            "the status_type");
+                } catch (IllegalArgumentException iae) { }
+
+                // We don't allow a null value for the StatusRequestType
+                // parameter in this constructor.
+                try {
+                    CertStatusReqExtension csreBadRequest =
+                            new CertStatusReqExtension(null, basicStatReq);
+                    throw new RuntimeException("Constructor accepted a " +
+                            "null StatusRequestType");
+                } catch (NullPointerException npe) { }
+
+                // We also don't allow a null value for the StatusRequest
+                // parameter in this constructor.
+                try {
+                    CertStatusReqExtension csreBadRequest =
+                            new CertStatusReqExtension(StatusRequestType.OCSP,
+                                    null);
+                    throw new RuntimeException("Constructor accepted a " +
+                            "null StatusRequest");
+                } catch (NullPointerException npe) { }
+
+                pass = Boolean.TRUE;
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+
+    // Test the constructor that builds the ob ject using data from
+    // a HandshakeInStream
+    // This also tests the length, getReqType and getRequest methods
+    public static final TestCase testCtorInStream = new TestCase() {
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+            OCSPStatusRequest osr;
+
+            try {
+                // To simulate the extension coming in a ServerHello, the
+                // type and length would already be read by HelloExtensions
+                // and there is no extension data
+                HandshakeInStream hsis = new HandshakeInStream();
+                hsis.incomingRecord(ByteBuffer.wrap(new byte[0]));
+                CertStatusReqExtension csre =
+                        new CertStatusReqExtension(hsis, hsis.available());
+                // Verify length/type/request
+                if (csre.length() != 4) {
+                     throw new RuntimeException("Invalid length: received " +
+                            csre.length() + ", expected 4");
+                } else if (csre.getType() != null) {
+                    throw new RuntimeException("Non-null type from default " +
+                            "extension");
+                } else if (csre.getRequest() != null) {
+                    throw new RuntimeException("Non-null request from default " +
+                            "extension");
+                }
+
+                // Try the an extension with a default OCSPStatusRequest
+                hsis = new HandshakeInStream();
+                hsis.incomingRecord(ByteBuffer.wrap(CSRE_DEF_OSR));
+                csre = new CertStatusReqExtension(hsis, hsis.available());
+                if (csre.length() != (CSRE_DEF_OSR.length + 4)) {
+                    throw new RuntimeException("Invalid length: received " +
+                            csre.length() + ", expected " +
+                            CSRE_DEF_OSR.length + 4);
+                } else if (!csre.getType().equals(StatusRequestType.OCSP)) {
+                    throw new RuntimeException("Unknown status_type: " +
+                            String.format("0x%02X", csre.getType().id));
+                } else {
+                    osr = (OCSPStatusRequest)csre.getRequest();
+                    if (!osr.getResponderIds().isEmpty() ||
+                            !osr.getExtensions().isEmpty()) {
+                        throw new RuntimeException("Non-default " +
+                                "OCSPStatusRequest found in extension");
+                    }
+                }
+
+                // Try with a non-default extension
+                hsis = new HandshakeInStream();
+                hsis.incomingRecord(ByteBuffer.wrap(CSRE_REQ_RID_EXTS));
+                csre = new CertStatusReqExtension(hsis, hsis.available());
+                if (csre.length() != (CSRE_REQ_RID_EXTS.length + 4)) {
+                    throw new RuntimeException("Invalid length: received " +
+                            csre.length() + ", expected " +
+                            CSRE_REQ_RID_EXTS.length + 4);
+                } else if (!(csre.getType().equals(StatusRequestType.OCSP))) {
+                    throw new RuntimeException("Unknown status_type: " +
+                            String.format("0x%02X", csre.getType().id));
+                } else {
+                    osr = (OCSPStatusRequest)csre.getRequest();
+                    if (osr.getResponderIds().size() != 5 ||
+                            osr.getExtensions().size() != 1) {
+                        throw new RuntimeException("Incorrect number of " +
+                                "ResponderIds or Extensions found in " +
+                                "OCSPStatusRequest");
+                    }
+                }
+
+                // Create a CSRE that asserts status_request and has the
+                // proper length, but really is a bunch of random junk inside
+                // In this case, it will create an UnknownStatusRequest to
+                // handle the unparseable data.
+                byte[] junkData = new byte[48];
+                Random r = new Random(System.currentTimeMillis());
+                r.nextBytes(junkData);
+                junkData[0] = 7;        // Ensure it isn't a valid status_type
+                hsis = new HandshakeInStream();
+                hsis.incomingRecord(ByteBuffer.wrap(junkData));
+                csre = new CertStatusReqExtension(hsis, hsis.available());
+                StatusRequest sr = csre.getRequest();
+                if (!(sr instanceof UnknownStatusRequest)) {
+                    throw new RuntimeException("Expected returned status " +
+                            "request to be of type UnknownStatusRequest but " +
+                            "received " + sr.getClass().getName());
+                } else if (csre.length() != (junkData.length + 4)) {
+                    throw new RuntimeException("Invalid length: received " +
+                            csre.length() + ", expected " +
+                            junkData.length + 4);
+                }
+
+                // Set the leading byte to 1 (OCSP type) and run again
+                // It should pass the argument check and fail trying to parse
+                // the underlying StatusRequest.
+                junkData[0] = (byte)StatusRequestType.OCSP.id;
+                hsis = new HandshakeInStream();
+                hsis.incomingRecord(ByteBuffer.wrap(junkData));
+                try {
+                    csre = new CertStatusReqExtension(hsis, hsis.available());
+                    throw new RuntimeException("Expected CTOR exception did " +
+                            "not occur");
+                } catch (IOException ioe) { }
+
+                pass = Boolean.TRUE;
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+
+    // Take CSRE extension data and add extension type and length decorations
+    private static byte[] wrapExtData(byte[] extData) {
+        int bufferLen = (extData != null ? extData.length : 0) + 4;
+        ByteBuffer bb = ByteBuffer.allocate(bufferLen);
+        bb.putShort((short)ExtensionType.EXT_STATUS_REQUEST.id);
+        bb.putShort((short)(extData != null ? extData.length: 0));
+        if (extData != null) {
+            bb.put(extData);
+        }
+        return bb.array();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/CertStatusReqItemV2Tests.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,455 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ssl;
+
+import java.security.cert.*;
+import java.util.*;
+import java.nio.ByteBuffer;
+import javax.net.ssl.SSLException;
+import javax.security.auth.x500.X500Principal;
+import sun.security.provider.certpath.ResponderId;
+import sun.security.provider.certpath.OCSPNonceExtension;
+
+/*
+ * Checks that the hash value for a certificate's issuer name is generated
+ * correctly. Requires any certificate that is not self-signed.
+ *
+ * NOTE: this test uses Sun private classes which are subject to change.
+ */
+public class CertStatusReqItemV2Tests {
+
+    private static final boolean debug = false;
+
+    private static final byte[] DEF_CSRIV2_OCSP_MULTI_BYTES = {
+           2,    0,    4,    0,    0,    0,    0
+    };
+
+    private static final byte[] DEF_CSRIV2_OCSP_BYTES = {
+           1,    0,    4,    0,    0,    0,    0
+    };
+
+    // This is a CSRIV2 (ocsp_multi) that has a single
+    // responder ID and no extensions.
+    private static final byte[] CSRIV2_1RID = {
+            2,    0,   32,     0,   28,    0,   26,  -95,
+           24,   48,   22,    49,   20,   48,   18,    6,
+            3,   85,    4,     3,   19,   11,   79,   67,
+           83,   80,   32,    83,  105,  103,  110,  101,
+          114,    0 ,   0
+    };
+
+    // This is a CSRIV2 (ocsp_multi) that has a single
+    // responder ID and no extensions.  The request_length
+    // field is too short in this case.
+    private static final byte[] CSRIV2_LENGTH_TOO_SHORT = {
+            2,    0,   27,     0,   28,    0,   26,  -95,
+           24,   48,   22,    49,   20,   48,   18,    6,
+            3,   85,    4,     3,   19,   11,   79,   67,
+           83,   80,   32,    83,  105,  103,  110,  101,
+          114,    0 ,   0
+    };
+
+    // This is a CSRIV2 (ocsp_multi) that has a single
+    // responder ID and no extensions.  The request_length
+    // field is too long in this case.
+    private static final byte[] CSRIV2_LENGTH_TOO_LONG = {
+            2,    0,   54,     0,   28,    0,   26,  -95,
+           24,   48,   22,    49,   20,   48,   18,    6,
+            3,   85,    4,     3,   19,   11,   79,   67,
+           83,   80,   32,    83,  105,  103,  110,  101,
+          114,    0 ,   0
+    };
+
+    // A CSRIV2 (ocsp) with one Responder ID (byName: CN=OCSP Signer)
+    // and a nonce extension (32 bytes).
+    private static final byte[] CSRIV2_OCSP_1RID_1EXT = {
+            1,    0,   83,    0,   28,    0,   26,  -95,
+           24,   48,   22,   49,   20,   48,   18,    6,
+            3,   85,    4,    3,   19,   11,   79,   67,
+           83,   80,   32,   83,  105,  103,  110,  101,
+          114,    0,   51,   48,   49,   48,   47,    6,
+            9,   43,    6,    1,    5,    5,    7,   48,
+            1,    2,    4,   34,    4,   32,  -34,  -83,
+          -66,  -17,  -34,  -83,  -66,  -17,  -34,  -83,
+          -66,  -17,  -34,  -83,  -66,  -17,  -34,  -83,
+          -66,  -17,  -34,  -83,  -66,  -17,  -34,  -83,
+          -66,  -17,  -34,  -83,  -66,  -17
+    };
+
+    public static void main(String[] args) throws Exception {
+        Map<String, TestCase> testList =
+                new LinkedHashMap<String, TestCase>() {{
+            put("CTOR (Default)", testCtorTypeStatReq);
+            put("CTOR (Byte array)", testCtorByteArray);
+            put("CTOR (invalid lengths)", testCtorInvalidLengths);
+        }};
+
+        TestUtils.runTests(testList);
+    }
+
+    public static final TestCase testCtorTypeStatReq = new TestCase() {
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+            try {
+                // Attempt to create CSRIv2 objects using null pointers
+                // for either parameter.  In either case NPE should be thrown
+                CertStatusReqItemV2 csriNull;
+                try {
+                    csriNull = new CertStatusReqItemV2(null,
+                            new OCSPStatusRequest());
+                    throw new RuntimeException("Did not catch expected NPE " +
+                            "for null status_type parameter");
+                } catch (NullPointerException npe) { }
+
+                try {
+                    csriNull = new CertStatusReqItemV2(StatusRequestType.OCSP,
+                            null);
+                    throw new RuntimeException("Did not catch expected NPE " +
+                            "for null StatusRequest parameter");
+                } catch (NullPointerException npe) { }
+
+                // Create an "ocsp_multi" type request using a default
+                // (no Responder IDs, no Extensions) OCSPStatusRequest
+                CertStatusReqItemV2 csriMulti =
+                        new CertStatusReqItemV2(StatusRequestType.OCSP_MULTI,
+                                new OCSPStatusRequest());
+                HandshakeOutStream hsout = new HandshakeOutStream(null);
+                csriMulti.send(hsout);
+                TestUtils.valueCheck(DEF_CSRIV2_OCSP_MULTI_BYTES,
+                        hsout.toByteArray());
+                hsout.reset();
+
+                // Create an "ocsp" type request using a default
+                // (no Responder IDs, no Extensions) OCSPStatusRequest
+                CertStatusReqItemV2 csriSingle =
+                        new CertStatusReqItemV2(StatusRequestType.OCSP,
+                                new OCSPStatusRequest(new LinkedList<>(),
+                                        new LinkedList<>()));
+                csriSingle.send(hsout);
+                TestUtils.valueCheck(DEF_CSRIV2_OCSP_BYTES,
+                        hsout.toByteArray());
+
+                // Create the CertStatusRequestItemV2 with a user-defined
+                // StatusRequestType value
+                CertStatusReqItemV2 csriNine =
+                        new CertStatusReqItemV2(StatusRequestType.get(9),
+                                new OCSPStatusRequest(null, null));
+                if (csriNine.getType().id != 9) {
+                    throw new RuntimeException("Expected status_type = 9, " +
+                            "got " + csriNine.getType().id);
+                } else {
+                    StatusRequest sr = csriNine.getRequest();
+                    if (!(sr instanceof OCSPStatusRequest)) {
+                        throw new RuntimeException("Expected " +
+                                "OCSPStatusRequest, got " +
+                                sr.getClass().getName());
+                    }
+                }
+
+                // Create the CertStatusRequestItemV2 with a StatusRequest
+                // that does not match the status_type argument.
+                // We expect IllegalArgumentException in this case.
+                try {
+                    CertStatusReqItemV2 csriBadSR = new CertStatusReqItemV2(
+                            StatusRequestType.OCSP_MULTI,
+                            new BogusStatusRequest());
+                    throw new RuntimeException("Constructor accepted a " +
+                            "StatusRequest that is inconsistent with " +
+                            "the status_type");
+                } catch (IllegalArgumentException iae) {
+                    // The expected result...nothing to do here
+                }
+
+                pass = Boolean.TRUE;
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+
+    // Test the constructor form that takes the data from a byte array
+    public static final TestCase testCtorByteArray = new TestCase() {
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+            try {
+                StatusRequestType sType;
+                StatusRequest sReq;
+                ResponderId checkRid =
+                        new ResponderId(new X500Principal("CN=OCSP Signer"));
+                Extension checkExt = new OCSPNonceExtension(32);
+
+                CertStatusReqItemV2 csriv =
+                        new CertStatusReqItemV2(CSRIV2_OCSP_1RID_1EXT);
+                sType = csriv.getType();
+                if (sType != StatusRequestType.OCSP) {
+                    throw new RuntimeException("Unexpected StatusRequestType " +
+                            sType.getClass().getName());
+                }
+
+                sReq = csriv.getRequest();
+                if (sReq instanceof OCSPStatusRequest) {
+                    OCSPStatusRequest osr = (OCSPStatusRequest)sReq;
+                    List<ResponderId> ridList = osr.getResponderIds();
+                    List<Extension> extList = osr.getExtensions();
+
+                    if (ridList.size() != 1 || !ridList.contains(checkRid)) {
+                        throw new RuntimeException("Responder list mismatch");
+                    } else if (extList.size() !=  1 ||
+                            !extList.get(0).getId().equals(checkExt.getId())) {
+                        throw new RuntimeException("Extension list mismatch");
+                    }
+                } else {
+                    throw new RuntimeException("Expected OCSPStatusRequest " +
+                            "from decoded bytes, got " +
+                            sReq.getClass().getName());
+                }
+
+                // Create a CSRIV2 out of random data.  A non-OCSP/OCSP_MULTI
+                // type will be forcibly set and the outer length field will
+                // be correct.
+                // The constructor should create a StatusRequestType object
+                // and an UnknownStatusRequest object consisting of the
+                // data segment.
+                byte[] junkData = new byte[48];
+                Random r = new Random(System.currentTimeMillis());
+                r.nextBytes(junkData);
+                junkData[0] = 7;        // status_type = 7
+                junkData[1] = 0;
+                junkData[2] = 45;       // request_length = 45
+                csriv = new CertStatusReqItemV2(junkData);
+
+                sType = csriv.getType();
+                sReq = csriv.getRequest();
+                if (sType.id != junkData[0]) {
+                    throw new RuntimeException("StatusRequestType mismatch: " +
+                            "expected 7, got " + sType.id);
+                }
+                if (sReq instanceof UnknownStatusRequest) {
+                    // Verify the underlying StatusRequest bytes have been
+                    // preserved correctly.
+                    HandshakeOutStream hsout = new HandshakeOutStream(null);
+                    sReq.send(hsout);
+                    byte[] srDataOut = hsout.toByteArray();
+                    TestUtils.valueCheck(srDataOut, junkData, 0, 3,
+                            srDataOut.length);
+                } else {
+                    throw new RuntimeException("StatusRequest mismatch: " +
+                            "expected UnknownStatusRequest, got " +
+                            sReq.getClass().getName());
+                }
+
+                // Test the parsing of the default OCSP/OCSP_MULTI extensions
+                // and make sure the underlying StatusRequestType and
+                // StatusRequest objects are correct.
+                csriv = new CertStatusReqItemV2(DEF_CSRIV2_OCSP_MULTI_BYTES);
+                sType = csriv.getType();
+                sReq = csriv.getRequest();
+                if (sType != StatusRequestType.OCSP_MULTI) {
+                    throw new RuntimeException("StatusRequestType mismatch: " +
+                            "expected OCSP_MULTI (2), got " + sType.id);
+                }
+                if (!(sReq instanceof OCSPStatusRequest)) {
+                    throw new RuntimeException("StatusRequest mismatch: " +
+                            "expected OCSPStatusRequest, got " +
+                            sReq.getClass().getName());
+                }
+
+                csriv = new CertStatusReqItemV2(DEF_CSRIV2_OCSP_BYTES);
+                sType = csriv.getType();
+                sReq = csriv.getRequest();
+                if (sType != StatusRequestType.OCSP) {
+                    throw new RuntimeException("StatusRequestType mismatch: " +
+                            "expected OCSP (1), got " + sType.id);
+                }
+                if (!(sReq instanceof OCSPStatusRequest)) {
+                    throw new RuntimeException("StatusRequest mismatch: " +
+                            "expected OCSPStatusRequest, got " +
+                            sReq.getClass().getName());
+                }
+
+                pass = Boolean.TRUE;
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+
+    public static final TestCase testCtorInvalidLengths = new TestCase() {
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+            try {
+                try {
+                    CertStatusReqItemV2 csriTooShort =
+                            new CertStatusReqItemV2(CSRIV2_LENGTH_TOO_SHORT);
+                    throw new RuntimeException("Expected exception not thrown");
+                } catch (SSLException ssle) { }
+
+                try {
+                    CertStatusReqItemV2 csriTooLong =
+                            new CertStatusReqItemV2(CSRIV2_LENGTH_TOO_LONG);
+                    throw new RuntimeException("Expected exception not thrown");
+                } catch (SSLException ssle) { }
+
+                pass = Boolean.TRUE;
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+
+    // Test the constructor form that takes the data from HandshakeInputStream
+    public static final TestCase testCtorInputStream = new TestCase() {
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+            try {
+                StatusRequestType sType;
+                StatusRequest sReq;
+                ResponderId checkRid =
+                        new ResponderId(new X500Principal("CN=OCSP Signer"));
+                Extension checkExt = new OCSPNonceExtension(32);
+
+                HandshakeInStream hsis = new HandshakeInStream();
+                hsis.incomingRecord(ByteBuffer.wrap(CSRIV2_OCSP_1RID_1EXT));
+                CertStatusReqItemV2 csriv = new CertStatusReqItemV2(hsis);
+                sType = csriv.getType();
+                if (sType != StatusRequestType.OCSP) {
+                    throw new RuntimeException("Unexpected StatusRequestType " +
+                            sType.getClass().getName());
+                }
+
+                sReq = csriv.getRequest();
+                if (sReq instanceof OCSPStatusRequest) {
+                    OCSPStatusRequest osr = (OCSPStatusRequest)sReq;
+                    List<ResponderId> ridList = osr.getResponderIds();
+                    List<Extension> extList = osr.getExtensions();
+
+                    if (ridList.size() != 1 || !ridList.contains(checkRid)) {
+                        throw new RuntimeException("Responder list mismatch");
+                    } else if (extList.size() !=  1 ||
+                            !extList.get(0).getId().equals(checkExt.getId())) {
+                        throw new RuntimeException("Extension list mismatch");
+                    }
+                } else {
+                    throw new RuntimeException("Expected OCSPStatusRequest " +
+                            "from decoded bytes, got " +
+                            sReq.getClass().getName());
+                }
+
+                // Create a CSRIV2 out of random data.  A non-OCSP/OCSP_MULTI
+                // type will be forcibly set and the outer length field will
+                // be correct.
+                // The constructor should create a StatusRequestType object
+                // and an UnknownStatusRequest object consisting of the
+                // data segment.
+                byte[] junkData = new byte[48];
+                Random r = new Random(System.currentTimeMillis());
+                r.nextBytes(junkData);
+                junkData[0] = 7;        // status_type = 7
+                junkData[1] = 0;
+                junkData[2] = 45;       // request_length = 45
+                hsis = new HandshakeInStream();
+                hsis.incomingRecord(ByteBuffer.wrap(junkData));
+                csriv = new CertStatusReqItemV2(hsis);
+
+                sType = csriv.getType();
+                sReq = csriv.getRequest();
+                if (sType.id != junkData[0]) {
+                    throw new RuntimeException("StatusRequestType mismatch: " +
+                            "expected 7, got " + sType.id);
+                }
+                if (sReq instanceof UnknownStatusRequest) {
+                    // Verify the underlying StatusRequest bytes have been
+                    // preserved correctly.
+                    HandshakeOutStream hsout = new HandshakeOutStream(null);
+                    sReq.send(hsout);
+                    byte[] srDataOut = hsout.toByteArray();
+                    TestUtils.valueCheck(srDataOut, junkData, 0, 3,
+                            srDataOut.length);
+                } else {
+                    throw new RuntimeException("StatusRequest mismatch: " +
+                            "expected UnknownStatusRequest, got " +
+                            sReq.getClass().getName());
+                }
+
+                // Test the parsing of the default OCSP/OCSP_MULTI extensions
+                // and make sure the underlying StatusRequestType and
+                // StatusRequest objects are correct.
+                hsis = new HandshakeInStream();
+                hsis.incomingRecord(
+                        ByteBuffer.wrap(DEF_CSRIV2_OCSP_MULTI_BYTES));
+                csriv = new CertStatusReqItemV2(hsis);
+                sType = csriv.getType();
+                sReq = csriv.getRequest();
+                if (sType != StatusRequestType.OCSP_MULTI) {
+                    throw new RuntimeException("StatusRequestType mismatch: " +
+                            "expected OCSP_MULTI (2), got " + sType.id);
+                }
+                if (!(sReq instanceof OCSPStatusRequest)) {
+                    throw new RuntimeException("StatusRequest mismatch: " +
+                            "expected OCSPStatusRequest, got " +
+                            sReq.getClass().getName());
+                }
+
+                hsis = new HandshakeInStream();
+                hsis.incomingRecord(ByteBuffer.wrap(DEF_CSRIV2_OCSP_BYTES));
+                csriv = new CertStatusReqItemV2(hsis);
+                sType = csriv.getType();
+                sReq = csriv.getRequest();
+                if (sType != StatusRequestType.OCSP) {
+                    throw new RuntimeException("StatusRequestType mismatch: " +
+                            "expected OCSP (1), got " + sType.id);
+                }
+                if (!(sReq instanceof OCSPStatusRequest)) {
+                    throw new RuntimeException("StatusRequest mismatch: " +
+                            "expected OCSPStatusRequest, got " +
+                            sReq.getClass().getName());
+                }
+
+                pass = Boolean.TRUE;
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/CertStatusReqListV2ExtensionTests.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,405 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ssl;
+
+import java.io.IOException;
+import java.util.*;
+import java.nio.ByteBuffer;
+import javax.net.ssl.*;
+
+/*
+ * Checks that the hash value for a certificate's issuer name is generated
+ * correctly. Requires any certificate that is not self-signed.
+ *
+ * NOTE: this test uses Sun private classes which are subject to change.
+ */
+public class CertStatusReqListV2ExtensionTests {
+
+    private static final boolean debug = false;
+
+    // Default status_request_v2 extension with two items
+    // 1. Type = ocsp_multi, OCSPStatusRequest is default
+    // 2. Type = ocsp, OCSPStatusRequest is default
+    private static final byte[] CSRLV2_DEF = {
+           0,   14,    2,    0,    4,    0,    0,    0,
+           0,    1,    0,    4,    0,    0,    0,    0
+    };
+
+    // A status_request_v2 where the item list length is
+    // longer than the provided data
+    private static final byte[] CSRLV2_LEN_TOO_LONG = {
+           0,   18,    2,    0,    4,    0,    0,    0,
+           0,    1,    0,    4,    0,    0,    0,    0
+    };
+
+    // A status_request_v2 where the item list length is
+    // shorter than the provided data
+    private static final byte[] CSRLV2_LEN_TOO_SHORT = {
+           0,   11,    2,    0,    4,    0,    0,    0,
+           0,    1,    0,    4,    0,    0,    0,    0
+    };
+
+    // A status_request_v2 extension with a zero-length
+    // certificate_status_req_list (not allowed by the spec)
+    private static final byte[] CSRLV2_INVALID_ZEROLEN = {0, 0};
+
+    // A status_request_v2 extension with two items (ocsp_multi and ocsp)
+    // using OCSPStatusRequests with 5 ResponderIds and 1 Extension each.
+    private static final byte[] CSRLV2_TWO_NON_DEF_ITEMS = {
+            2,   90,    2,    1,   42,    0,  -13,    0,
+           59,  -95,   57,   48,   55,   49,   16,   48,
+           14,    6,    3,   85,    4,   10,   19,    7,
+           83,  111,  109,  101,   73,  110,   99,   49,
+           16,   48,   14,    6,    3,   85,    4,   11,
+           19,    7,   83,  111,  109,  101,   80,   75,
+           73,   49,   17,   48,   15,    6,    3,   85,
+            4,    3,   19,    8,   83,  111,  109,  101,
+           79,   67,   83,   80,    0,   68,  -95,   66,
+           48,   64,   49,   13,   48,   11,    6,    3,
+           85,    4,   10,   19,    4,   79,  104,   77,
+          121,   49,   14,   48,   12,    6,    3,   85,
+            4,   11,   19,    5,   66,  101,   97,  114,
+          115,   49,   15,   48,   13,    6,    3,   85,
+            4,   11,   19,    6,   84,  105,  103,  101,
+          114,  115,   49,   14,   48,   12,    6,    3,
+           85,    4,    3,   19,    5,   76,  105,  111,
+          110,  115,    0,   58,  -95,   56,   48,   54,
+           49,   16,   48,   14,    6,    3,   85,    4,
+           10,   19,    7,   67,  111,  109,  112,   97,
+          110,  121,   49,   13,   48,   11,    6,    3,
+           85,    4,   11,   19,    4,   87,  101,  115,
+          116,   49,   19,   48,   17,    6,    3,   85,
+            4,    3,   19,   10,   82,  101,  115,  112,
+          111,  110,  100,  101,  114,   49,    0,   24,
+          -94,   22,    4,   20,  -67,  -36,  114,  121,
+           92,  -79,  116,   -1,  102, -107,    7,  -21,
+           18, -113,   64,   76,   96,   -7,  -66,  -63,
+            0,   24,  -94,   22,    4,   20,  -51,  -69,
+          107,  -82,  -39,  -87,   45,   25,   41,   28,
+          -76,  -68,  -11, -110,  -94,  -97,   62,   47,
+           58, -125,    0,   51,   48,   49,   48,   47,
+            6,    9,   43,    6,    1,    5,    5,    7,
+           48,    1,    2,    4,   34,    4,   32,  -26,
+          -81, -120,  -61, -127,  -79,    0,  -39,  -54,
+           49,    3,  -51,  -57,  -85,   19, -126,   94,
+           -2,   21,   26,   98,    6,  105,  -35,  -37,
+          -29,  -73,  101,   53,   44,   15,  -19,    1,
+            1,   42,    0,  -13,    0,   59,  -95,   57,
+           48,   55,   49,   16,   48,   14,    6,    3,
+           85,    4,   10,   19,    7,   83,  111,  109,
+          101,   73,  110,   99,   49,   16,   48,   14,
+            6,    3,   85,    4,   11,   19,    7,   83,
+          111,  109,  101,   80,   75,   73,   49,   17,
+           48,   15,    6,    3,   85,    4,    3,   19,
+            8,   83,  111,  109,  101,   79,   67,   83,
+           80,    0,   68,  -95,   66,   48,   64,   49,
+           13,   48,   11,    6,    3,   85,    4,   10,
+           19,    4,   79,  104,   77,  121,   49,   14,
+           48,   12,    6,    3,   85,    4,   11,   19,
+            5,   66,  101,   97,  114,  115,   49,   15,
+           48,   13,    6,    3,   85,    4,   11,   19,
+            6,   84,  105,  103,  101,  114,  115,   49,
+           14,   48,   12,    6,    3,   85,    4,    3,
+           19,    5,   76,  105,  111,  110,  115,    0,
+           58,  -95,   56,   48,   54,   49,   16,   48,
+           14,    6,    3,   85,    4,   10,   19,    7,
+           67,  111,  109,  112,   97,  110,  121,   49,
+           13,   48,   11,    6,    3,   85,    4,   11,
+           19,    4,   87,  101,  115,  116,   49,   19,
+           48,   17,    6,    3,   85,    4,    3,   19,
+           10,   82,  101,  115,  112,  111,  110,  100,
+          101,  114,   49,    0,   24,  -94,   22,    4,
+           20,  -67,  -36,  114,  121,   92,  -79,  116,
+           -1,  102, -107,    7,  -21,   18, -113,   64,
+           76,   96,   -7,  -66,  -63,    0,   24,  -94,
+           22,    4,   20,  -51,  -69,  107,  -82,  -39,
+          -87,   45,   25,   41,   28,  -76,  -68,  -11,
+         -110,  -94,  -97,   62,   47,   58, -125,    0,
+           51,   48,   49,   48,   47,    6,    9,   43,
+            6,    1,    5,    5,    7,   48,    1,    2,
+            4,   34,    4,   32,  -26,  -81, -120,  -61,
+         -127,  -79,    0,  -39,  -54,   49,    3,  -51,
+          -57,  -85,   19, -126,   94,   -2,   21,   26,
+           98,    6,  105,  -35,  -37,  -29,  -73,  101,
+           53,   44,   15,  -19
+    };
+
+    public static void main(String[] args) throws Exception {
+        Map<String, TestCase> testList =
+                new LinkedHashMap<String, TestCase>() {{
+            put("CTOR (default)", testCtorDefault);
+            put("CTOR (List<CertStatusReqItemV2)", testCtorItemList);
+            put("CTOR (HandshakeInStream, getRequestList",
+                    testCtorInStream);
+        }};
+
+        TestUtils.runTests(testList);
+    }
+
+    public static final TestCase testCtorDefault = new TestCase() {
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+            try {
+                CertStatusReqListV2Extension csrlV2 =
+                        new CertStatusReqListV2Extension();
+                HandshakeOutStream hsout = new HandshakeOutStream(null);
+                csrlV2.send(hsout);
+                TestUtils.valueCheck(wrapExtData(new byte[0]),
+                        hsout.toByteArray());
+
+                // The length should be 4 (2 bytes for the type, 2 for the
+                // encoding of zero-length
+                if (csrlV2.length() != 4) {
+                    throw new RuntimeException("Incorrect length from " +
+                            "default object.  Expected 4, got " +
+                            csrlV2.length());
+                }
+
+                // Since there's no data, there are no status_type or request
+                // data fields defined.  An empty, unmodifiable list should be
+                // returned when obtained from the extension.
+                List<CertStatusReqItemV2> itemList = csrlV2.getRequestItems();
+                if (!itemList.isEmpty()) {
+                    throw new RuntimeException("Default CSRLV2 returned " +
+                            "non-empty request list");
+                } else {
+                    try {
+                        itemList.add(new CertStatusReqItemV2(
+                                StatusRequestType.OCSP_MULTI,
+                                new OCSPStatusRequest()));
+                        throw new RuntimeException("Returned itemList is " +
+                                "modifiable!");
+                    } catch (UnsupportedOperationException uoe) { }
+                }
+
+                pass = Boolean.TRUE;
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+
+    public static final TestCase testCtorItemList = new TestCase() {
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+            OCSPStatusRequest osr = new OCSPStatusRequest();
+            List<CertStatusReqItemV2> noItems = Collections.emptyList();
+            List<CertStatusReqItemV2> defList =
+                    new ArrayList<CertStatusReqItemV2>() {{
+                add(new CertStatusReqItemV2(StatusRequestType.OCSP_MULTI, osr));
+                add(new CertStatusReqItemV2(StatusRequestType.OCSP, osr));
+            }};
+            List<CertStatusReqItemV2> unknownTypesList =
+                    new ArrayList<CertStatusReqItemV2>() {{
+                add(new CertStatusReqItemV2(StatusRequestType.get(8),
+                        new UnknownStatusRequest(new byte[0])));
+                add(new CertStatusReqItemV2(StatusRequestType.get(12),
+                        new UnknownStatusRequest(new byte[5])));
+            }};
+
+            try {
+                HandshakeOutStream hsout = new HandshakeOutStream(null);
+                StatusRequest basicStatReq = new OCSPStatusRequest();
+
+                // Create an extension using a default-style OCSPStatusRequest
+                // (no responder IDs, no extensions).
+                CertStatusReqListV2Extension csrlv2 =
+                        new CertStatusReqListV2Extension(defList);
+                csrlv2.send(hsout);
+                TestUtils.valueCheck(wrapExtData(CSRLV2_DEF),
+                        hsout.toByteArray());
+                hsout.reset();
+
+                // Create the extension using a StatusRequestType not already
+                // instantiated as a static StatusRequestType
+                // (e.g. OCSP/OCSP_MULTI)
+                csrlv2 = new CertStatusReqListV2Extension(unknownTypesList);
+                List<CertStatusReqItemV2> itemList = csrlv2.getRequestItems();
+                if (itemList.size() != unknownTypesList.size()) {
+                    throw new RuntimeException("Custom CSRLV2 returned " +
+                            "an incorrect number of items: expected " +
+                            unknownTypesList.size() + ", got " +
+                            itemList.size());
+                } else {
+                    // Verify that the list is unmodifiable
+                    try {
+                        itemList.add(new CertStatusReqItemV2(
+                                StatusRequestType.OCSP_MULTI,
+                                new OCSPStatusRequest()));
+                        throw new RuntimeException("Returned itemList is " +
+                                "modifiable!");
+                    } catch (UnsupportedOperationException uoe) { }
+                }
+
+                // Pass a null value for the item list.  This should throw
+                // an exception
+                try {
+                    CertStatusReqListV2Extension csrlv2Null =
+                            new CertStatusReqListV2Extension(null);
+                    throw new RuntimeException("Constructor accepted a " +
+                            "null request list");
+                } catch (NullPointerException npe) { }
+
+                pass = Boolean.TRUE;
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+
+    // Test the constructor that builds the ob ject using data from
+    // a HandshakeInStream
+    // This also tests the length, getReqType and getRequest methods
+    public static final TestCase testCtorInStream = new TestCase() {
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+            OCSPStatusRequest osr;
+            CertStatusReqListV2Extension csrlv2;
+
+            try {
+                // To simulate the extension coming in a ServerHello, the
+                // type and length would already be read by HelloExtensions
+                // and there is no extension data
+                HandshakeInStream hsis = new HandshakeInStream();
+                hsis.incomingRecord(ByteBuffer.wrap(new byte[0]));
+                csrlv2 = new CertStatusReqListV2Extension(hsis,
+                        hsis.available());
+
+                // Verify length/request list
+                if (csrlv2.length() != 4) {
+                     throw new RuntimeException("Invalid length: received " +
+                            csrlv2.length() + ", expected 4");
+                } else {
+                    List<CertStatusReqItemV2> itemList =
+                            csrlv2.getRequestItems();
+                    if (!itemList.isEmpty()) {
+                        throw new RuntimeException("Default CSRLV2 returned " +
+                                "non-empty request list");
+                    } else {
+                        try {
+                            itemList.add(new CertStatusReqItemV2(
+                                    StatusRequestType.OCSP_MULTI,
+                                    new OCSPStatusRequest()));
+                            throw new RuntimeException("Returned itemList is " +
+                                    "modifiable!");
+                        } catch (UnsupportedOperationException uoe) { }
+                    }
+                }
+
+                // Try the an extension with our basic client-generated
+                // status_request_v2 (2 items, ocsp_multi and ocsp, each with
+                // a default OCSPStatusRequest
+                hsis = new HandshakeInStream();
+                hsis.incomingRecord(ByteBuffer.wrap(CSRLV2_DEF));
+                csrlv2 = new CertStatusReqListV2Extension(hsis,
+                        hsis.available());
+                if (csrlv2.length() != (CSRLV2_DEF.length + 4)) {
+                    throw new RuntimeException("Invalid length: received " +
+                            csrlv2.length() + ", expected " +
+                            CSRLV2_DEF.length + 4);
+                } else {
+                    List<CertStatusReqItemV2> itemList =
+                            csrlv2.getRequestItems();
+                    if (itemList.size() != 2) {
+                        throw new RuntimeException("Unexpected number of " +
+                                "items request list, expected 2, got " +
+                                itemList.size());
+                    } else {
+                        try {
+                            itemList.add(new CertStatusReqItemV2(
+                                    StatusRequestType.OCSP_MULTI,
+                                    new OCSPStatusRequest()));
+                            throw new RuntimeException("Returned itemList is " +
+                                    "modifiable!");
+                        } catch (UnsupportedOperationException uoe) { }
+                    }
+                }
+
+                // Try incoming data with an illegal zero-length
+                // certificate_status_req_list
+                try {
+                    hsis = new HandshakeInStream();
+                    hsis.incomingRecord(
+                            ByteBuffer.wrap(CSRLV2_INVALID_ZEROLEN));
+                    csrlv2 = new CertStatusReqListV2Extension(hsis,
+                            hsis.available());
+                    throw new RuntimeException("Unxpected successful " +
+                            "object construction");
+                } catch (SSLException ssle) { }
+
+                // Try extensions where the certificate_status_req_list length
+                // is either too long or too short
+                try {
+                    hsis = new HandshakeInStream();
+                    hsis.incomingRecord(ByteBuffer.wrap(CSRLV2_LEN_TOO_LONG));
+                    csrlv2 = new CertStatusReqListV2Extension(hsis,
+                            hsis.available());
+                    throw new RuntimeException("Unxpected successful " +
+                            "object construction");
+                } catch (SSLException ssle) { }
+
+                try {
+                    hsis = new HandshakeInStream();
+                    hsis.incomingRecord(ByteBuffer.wrap(CSRLV2_LEN_TOO_SHORT));
+                    csrlv2 = new CertStatusReqListV2Extension(hsis,
+                            hsis.available());
+                    throw new RuntimeException("Unxpected successful " +
+                            "object construction");
+                } catch (SSLException ssle) { }
+
+                pass = Boolean.TRUE;
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+
+    // Take CSRE extension data and add extension type and length decorations
+    private static byte[] wrapExtData(byte[] extData) {
+        int bufferLen = extData.length + 4;
+        ByteBuffer bb = ByteBuffer.allocate(bufferLen);
+
+        bb.putShort((short)ExtensionType.EXT_STATUS_REQUEST_V2.id);
+        bb.putShort((short)extData.length);
+        if (extData.length != 0) {
+            bb.put(extData);
+        }
+        return bb.array();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/OCSPStatusRequestTests.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,332 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ssl;
+
+import java.security.cert.*;
+import java.util.*;
+import java.nio.ByteBuffer;
+import javax.security.auth.x500.X500Principal;
+import sun.security.provider.certpath.ResponderId;
+import sun.security.provider.certpath.OCSPNonceExtension;
+
+/*
+ * Checks that the hash value for a certificate's issuer name is generated
+ * correctly. Requires any certificate that is not self-signed.
+ *
+ * NOTE: this test uses Sun private classes which are subject to change.
+ */
+public class OCSPStatusRequestTests {
+
+    private static final boolean debug = false;
+
+    // The default (no Responder IDs or Extensions)
+    private static final byte[] DEF_OCSPREQ_BYTES = { 0, 0, 0, 0 };
+
+    // OCSP Extension with one Responder ID (byName: CN=OCSP Signer) and
+    // a nonce extension (32 bytes).
+    private static final byte[] OCSPREQ_1RID_1EXT = {
+            0,   28,    0,   26,  -95,   24,   48,   22,
+           49,   20,   48,   18,    6,    3,   85,    4,
+            3,   19,   11,   79,   67,   83,   80,   32,
+           83,  105,  103,  110,  101,  114,    0,   51,
+           48,   49,   48,   47,    6,    9,   43,    6,
+            1,    5,    5,    7,   48,    1,    2,    4,
+           34,    4,   32,  -34,  -83,  -66,  -17,  -34,
+          -83,  -66,  -17,  -34,  -83,  -66,  -17,  -34,
+          -83,  -66,  -17,  -34,  -83,  -66,  -17,  -34,
+          -83,  -66,  -17,  -34,  -83,  -66,  -17,  -34,
+          -83,  -66,  -17
+    };
+
+    public static void main(String[] args) throws Exception {
+        Map<String, TestCase> testList =
+                new LinkedHashMap<String, TestCase>() {{
+            put("CTOR (default)", testCtorDefault);
+            put("CTOR (Responder Id and Extension)", testCtorRidsExts);
+            put("CTOR (HandshakeInStream)", testCtorInStream);
+            put("CTOR (byte array)", testCtorByteArray);
+            put("Length tests", testLength);
+            put("Equals tests", testEquals);
+        }};
+
+        TestUtils.runTests(testList);
+    }
+
+    // Test the default constructor and its encoding
+    public static final TestCase testCtorDefault = new TestCase() {
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+            try {
+                // Create a OCSPStatusRequest with a single ResponderId
+                // and Extension
+                OCSPStatusRequest osrDefault = new OCSPStatusRequest();
+                HandshakeOutStream hsout = new HandshakeOutStream(null);
+                osrDefault.send(hsout);
+                System.out.println("Encoded Result:");
+                TestUtils.dumpBytes(hsout.toByteArray());
+
+                TestUtils.valueCheck(DEF_OCSPREQ_BYTES, hsout.toByteArray());
+                pass = Boolean.TRUE;
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+
+    // Test the constructor form that allows the user to specify zero
+    // or more ResponderId objects and/or Extensions
+    public static final TestCase testCtorRidsExts = new TestCase() {
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+            try {
+                List<ResponderId> ridList = new LinkedList<ResponderId>() {{
+                    add(new ResponderId(new X500Principal("CN=OCSP Signer")));
+                }};
+                List<Extension> extList = new LinkedList<Extension>() {{
+                    add(new OCSPNonceExtension(32));
+                }};
+
+                // Default-style OCSPStatusRequest using both empty Lists and
+                // null inputs
+                OCSPStatusRequest osrDef1 =
+                        new OCSPStatusRequest(new LinkedList<ResponderId>(),
+                                null);
+                OCSPStatusRequest osrDef2 =
+                        new OCSPStatusRequest(null,
+                                new LinkedList<Extension>());
+                HandshakeOutStream hsout = new HandshakeOutStream(null);
+                osrDef1.send(hsout);
+                System.out.println("Encoded Result:");
+                TestUtils.dumpBytes(hsout.toByteArray());
+                TestUtils.valueCheck(DEF_OCSPREQ_BYTES, hsout.toByteArray());
+
+                hsout.reset();
+                osrDef2.send(hsout);
+                System.out.println("Encoded Result:");
+                TestUtils.dumpBytes(hsout.toByteArray());
+                TestUtils.valueCheck(DEF_OCSPREQ_BYTES, hsout.toByteArray());
+
+                hsout.reset();
+                OCSPStatusRequest osrWithItems =
+                        new OCSPStatusRequest(ridList, extList);
+                osrWithItems.send(hsout);
+                System.out.println("Encoded Result:");
+                byte[] encodedData = hsout.toByteArray();
+                TestUtils.dumpBytes(encodedData);
+                // Check everything except the last 32 bytes (nonce data)
+                TestUtils.valueCheck(OCSPREQ_1RID_1EXT, encodedData, 0, 0,
+                        encodedData.length - 32);
+
+                pass = Boolean.TRUE;
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+
+    // Test the constructor that builds the ob ject using data from
+    // a HandshakeInStream
+    public static final TestCase testCtorInStream = new TestCase() {
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+            try {
+                ResponderId checkRid =
+                        new ResponderId(new X500Principal("CN=OCSP Signer"));
+                Extension checkExt = new OCSPNonceExtension(32);
+
+                HandshakeInStream hsis = new HandshakeInStream();
+                hsis.incomingRecord(ByteBuffer.wrap(OCSPREQ_1RID_1EXT));
+                OCSPStatusRequest osr = new OCSPStatusRequest(hsis);
+
+                List<ResponderId> ridList = osr.getResponderIds();
+                List<Extension> extList = osr.getExtensions();
+
+                if (ridList.size() != 1 || !ridList.contains(checkRid)) {
+                    throw new RuntimeException("Responder list mismatch");
+                } else if (extList.size() !=  1 ||
+                        !extList.get(0).getId().equals(checkExt.getId())) {
+                    throw new RuntimeException("Extension list mismatch");
+                }
+
+                pass = Boolean.TRUE;
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+
+    // Test the constructor form that takes the data from a byte array
+    public static final TestCase testCtorByteArray = new TestCase() {
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+            try {
+                ResponderId checkRid =
+                        new ResponderId(new X500Principal("CN=OCSP Signer"));
+                Extension checkExt = new OCSPNonceExtension(32);
+
+                OCSPStatusRequest osr =
+                        new OCSPStatusRequest(OCSPREQ_1RID_1EXT);
+
+                List<ResponderId> ridList = osr.getResponderIds();
+                List<Extension> extList = osr.getExtensions();
+
+                if (ridList.size() != 1 || !ridList.contains(checkRid)) {
+                    throw new RuntimeException("Responder list mismatch");
+                } else if (extList.size() !=  1 ||
+                        !extList.get(0).getId().equals(checkExt.getId())) {
+                    throw new RuntimeException("Extension list mismatch");
+                }
+                pass = Boolean.TRUE;
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+
+    // Test the length functions for both default and non-default
+    // OCSPStatusRequest objects
+    public static final TestCase testLength = new TestCase() {
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+            try {
+                HandshakeInStream hsis = new HandshakeInStream();
+                hsis.incomingRecord(ByteBuffer.wrap(OCSPREQ_1RID_1EXT));
+                OCSPStatusRequest osr = new OCSPStatusRequest(hsis);
+                OCSPStatusRequest osrDefault = new OCSPStatusRequest();
+
+                if (osrDefault.length() != DEF_OCSPREQ_BYTES.length) {
+                    throw new RuntimeException("Invalid length for default: " +
+                            "Expected" + DEF_OCSPREQ_BYTES.length +
+                            ", received " + osrDefault.length());
+                } else if (osr.length() != OCSPREQ_1RID_1EXT.length) {
+                    throw new RuntimeException("Invalid length for default: " +
+                            "Expected" + OCSPREQ_1RID_1EXT.length +
+                            ", received " + osr.length());
+                }
+
+                pass = Boolean.TRUE;
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+
+    // Test the equals method with default and non-default objects
+    public static final TestCase testEquals = new TestCase() {
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+            try {
+                // Make two different lists with the same ResponderId values
+                // and also make a extension list
+                List<ResponderId> ridList1 = new LinkedList<ResponderId>() {{
+                    add(new ResponderId(new X500Principal("CN=OCSP Signer")));
+                }};
+                List<ResponderId> ridList2 = new LinkedList<ResponderId>() {{
+                    add(new ResponderId(new X500Principal("CN=OCSP Signer")));
+                }};
+                List<Extension> extList = new LinkedList<Extension>() {{
+                    add(new OCSPNonceExtension(32));
+                }};
+
+                // We expect two default OCSP objects to be equal
+                OCSPStatusRequest osrDefault = new OCSPStatusRequest();
+                if (!osrDefault.equals(new OCSPStatusRequest())) {
+                    throw new RuntimeException("Default OCSPStatusRequest" +
+                            " equality test failed");
+                }
+
+                // null test (expect false return)
+                if (osrDefault.equals(null)) {
+                    throw new RuntimeException("OCSPStatusRequest matched" +
+                            " unexpectedly");
+                }
+
+                // Self-reference test
+                OCSPStatusRequest osrSelfRef = osrDefault;
+                if (!osrDefault.equals(osrSelfRef)) {
+                    throw new RuntimeException("Default OCSPStatusRequest" +
+                            " equality test failed");
+                }
+
+                // Two OCSPStatusRequests with matching ResponderIds should
+                // be considered equal
+                OCSPStatusRequest osrByList1 =
+                        new OCSPStatusRequest(ridList1, null);
+                OCSPStatusRequest osrByList2 = new OCSPStatusRequest(ridList2,
+                        Collections.emptyList());
+                if (!osrByList1.equals(osrByList2)) {
+                    throw new RuntimeException("Single Responder ID " +
+                            "OCSPStatusRequest equality test failed");
+                }
+
+                // We expect OCSPStatusRequests with different nonces to be
+                // considered unequal.
+                HandshakeInStream hsis = new HandshakeInStream();
+                hsis.incomingRecord(ByteBuffer.wrap(OCSPREQ_1RID_1EXT));
+                OCSPStatusRequest osrStream = new OCSPStatusRequest(hsis);
+                OCSPStatusRequest osrRidExt = new OCSPStatusRequest(ridList1,
+                        extList);
+                if (osrStream.equals(osrRidExt)) {
+                    throw new RuntimeException("OCSPStatusRequest matched" +
+                            " unexpectedly");
+                }
+
+                pass = Boolean.TRUE;
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/StatusResponseManagerTests.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,444 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ssl;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.cert.*;
+import java.util.*;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.PublicKey;
+import java.util.concurrent.TimeUnit;
+
+import sun.security.testlibrary.SimpleOCSPServer;
+import sun.security.testlibrary.CertificateBuilder;
+
+/*
+ * Checks that the hash value for a certificate's issuer name is generated
+ * correctly. Requires any certificate that is not self-signed.
+ *
+ * NOTE: this test uses Sun private classes which are subject to change.
+ */
+public class StatusResponseManagerTests {
+
+    private static final boolean debug = true;
+    private static final boolean ocspDebug = false;
+
+    // PKI components we will need for this test
+    static String passwd = "passphrase";
+    static String ROOT_ALIAS = "root";
+    static String INT_ALIAS = "intermediate";
+    static String SSL_ALIAS = "ssl";
+    static KeyStore rootKeystore;           // Root CA Keystore
+    static KeyStore intKeystore;            // Intermediate CA Keystore
+    static KeyStore serverKeystore;         // SSL Server Keystore
+    static KeyStore trustStore;             // SSL Client trust store
+    static X509Certificate rootCert;
+    static X509Certificate intCert;
+    static X509Certificate sslCert;
+    static SimpleOCSPServer rootOcsp;       // Root CA OCSP Responder
+    static int rootOcspPort;                // Port number for root OCSP
+    static SimpleOCSPServer intOcsp;        // Intermediate CA OCSP Responder
+    static int intOcspPort;                 // Port number for intermed. OCSP
+
+    static X509Certificate[] chain;
+
+    public static void main(String[] args) throws Exception {
+        Map<String, TestCase> testList =
+                new LinkedHashMap<String, TestCase>() {{
+            put("Basic OCSP fetch test", testOcspFetch);
+            put("Clear StatusResponseManager cache", testClearSRM);
+            put("Basic OCSP_MULTI fetch test", testOcspMultiFetch);
+            put("Test Cache Expiration", testCacheExpiry);
+        }};
+
+        // Create the CAs and OCSP responders
+        createPKI();
+
+        // Grab the certificates and make a chain we can reuse for tests
+        sslCert = (X509Certificate)serverKeystore.getCertificate(SSL_ALIAS);
+        intCert = (X509Certificate)intKeystore.getCertificate(INT_ALIAS);
+        rootCert = (X509Certificate)rootKeystore.getCertificate(ROOT_ALIAS);
+        chain = new X509Certificate[3];
+        chain[0] = sslCert;
+        chain[1] = intCert;
+        chain[2] = rootCert;
+
+        TestUtils.runTests(testList);
+
+        intOcsp.stop();
+        rootOcsp.stop();
+    }
+
+    // Test a simple RFC 6066 server-side fetch
+    public static final TestCase testOcspFetch = new TestCase() {
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            StatusResponseManager srm = new StatusResponseManager();
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+            StatusRequest oReq = new OCSPStatusRequest();
+
+            try {
+                // Get OCSP responses for non-root certs in the chain
+                Map<X509Certificate, byte[]> responseMap = srm.get(
+                        StatusRequestType.OCSP, oReq, chain, 5000,
+                        TimeUnit.MILLISECONDS);
+
+                // There should be one entry in the returned map and
+                // one entry in the cache when the operation is complete.
+                if (responseMap.size() != 1) {
+                    message = "Incorrect number of responses: expected 1, got "
+                            + responseMap.size();
+                } else if (!responseMap.containsKey(sslCert)) {
+                    message = "Response map key is incorrect, expected " +
+                            sslCert.getSubjectX500Principal().toString();
+                } else if (srm.size() != 1) {
+                    message = "Incorrect number of cache entries: " +
+                            "expected 1, got " + srm.size();
+                } else {
+                    pass = Boolean.TRUE;
+                }
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+
+    // Test clearing the StatusResponseManager cache.
+    public static final TestCase testClearSRM = new TestCase() {
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            StatusResponseManager srm = new StatusResponseManager();
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+            StatusRequest oReq = new OCSPStatusRequest();
+
+            try {
+                // Get OCSP responses for non-root certs in the chain
+                srm.get(StatusRequestType.OCSP_MULTI, oReq, chain, 5000,
+                        TimeUnit.MILLISECONDS);
+
+                // There should be two entries in the returned map and
+                // two entries in the cache when the operation is complete.
+                if (srm.size() != 2) {
+                    message = "Incorrect number of responses: expected 2, got "
+                            + srm.size();
+                } else {
+                    // Next, clear the SRM, then check the size again
+                    srm.clear();
+                    if (srm.size() != 0) {
+                        message = "Incorrect number of responses: expected 0," +
+                                " got " + srm.size();
+                    } else {
+                        pass = Boolean.TRUE;
+                    }
+                }
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+
+    // Test a simple RFC 6961 server-side fetch
+    public static final TestCase testOcspMultiFetch = new TestCase() {
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            StatusResponseManager srm = new StatusResponseManager();
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+            StatusRequest oReq = new OCSPStatusRequest();
+
+            try {
+                // Get OCSP responses for non-root certs in the chain
+                Map<X509Certificate, byte[]> responseMap = srm.get(
+                        StatusRequestType.OCSP_MULTI, oReq, chain, 5000,
+                        TimeUnit.MILLISECONDS);
+
+                // There should be two entries in the returned map and
+                // two entries in the cache when the operation is complete.
+                if (responseMap.size() != 2) {
+                    message = "Incorrect number of responses: expected 2, got "
+                            + responseMap.size();
+                } else if (!responseMap.containsKey(sslCert) ||
+                        !responseMap.containsKey(intCert)) {
+                    message = "Response map keys are incorrect, expected " +
+                            sslCert.getSubjectX500Principal().toString() +
+                            " and " +
+                            intCert.getSubjectX500Principal().toString();
+                } else if (srm.size() != 2) {
+                    message = "Incorrect number of cache entries: " +
+                            "expected 2, got " + srm.size();
+                } else {
+                    pass = Boolean.TRUE;
+                }
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+
+    // Test cache expiration
+    public static final TestCase testCacheExpiry = new TestCase() {
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            // For this test, we will set the cache expiry to 5 seconds
+            System.setProperty("jdk.tls.stapling.cacheLifetime", "5");
+            StatusResponseManager srm = new StatusResponseManager();
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+            StatusRequest oReq = new OCSPStatusRequest();
+
+            try {
+                // Get OCSP responses for non-root certs in the chain
+                srm.get(StatusRequestType.OCSP_MULTI, oReq, chain, 5000,
+                        TimeUnit.MILLISECONDS);
+
+                // There should be two entries in the returned map and
+                // two entries in the cache when the operation is complete.
+                if (srm.size() != 2) {
+                    message = "Incorrect number of responses: expected 2, got "
+                            + srm.size();
+                } else {
+                    // Next, wait for more than 5 seconds so the responses
+                    // in the SRM will expire.
+                    Thread.sleep(7000);
+                    if (srm.size() != 0) {
+                        message = "Incorrect number of responses: expected 0," +
+                                " got " + srm.size();
+                    } else {
+                        pass = Boolean.TRUE;
+                    }
+                }
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            // Set the cache lifetime back to the default
+            System.setProperty("jdk.tls.stapling.cacheLifetime", "");
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+
+    /**
+     * Creates the PKI components necessary for this test, including
+     * Root CA, Intermediate CA and SSL server certificates, the keystores
+     * for each entity, a client trust store, and starts the OCSP responders.
+     */
+    private static void createPKI() throws Exception {
+        CertificateBuilder cbld = new CertificateBuilder();
+        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
+        keyGen.initialize(2048);
+        KeyStore.Builder keyStoreBuilder =
+                KeyStore.Builder.newInstance("PKCS12", null,
+                        new KeyStore.PasswordProtection(passwd.toCharArray()));
+
+        // Generate Root, IntCA, EE keys
+        KeyPair rootCaKP = keyGen.genKeyPair();
+        log("Generated Root CA KeyPair");
+        KeyPair intCaKP = keyGen.genKeyPair();
+        log("Generated Intermediate CA KeyPair");
+        KeyPair sslKP = keyGen.genKeyPair();
+        log("Generated SSL Cert KeyPair");
+
+        // Set up the Root CA Cert
+        cbld.setSubjectName("CN=Root CA Cert, O=SomeCompany");
+        cbld.setPublicKey(rootCaKP.getPublic());
+        cbld.setSerialNumber(new BigInteger("1"));
+        // Make a 3 year validity starting from 60 days ago
+        long start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(60);
+        long end = start + TimeUnit.DAYS.toMillis(1085);
+        cbld.setValidity(new Date(start), new Date(end));
+        addCommonExts(cbld, rootCaKP.getPublic(), rootCaKP.getPublic());
+        addCommonCAExts(cbld);
+        // Make our Root CA Cert!
+        X509Certificate rootCert = cbld.build(null, rootCaKP.getPrivate(),
+                "SHA256withRSA");
+        log("Root CA Created:\n" + certInfo(rootCert));
+
+        // Now build a keystore and add the keys and cert
+        rootKeystore = keyStoreBuilder.getKeyStore();
+        Certificate[] rootChain = {rootCert};
+        rootKeystore.setKeyEntry(ROOT_ALIAS, rootCaKP.getPrivate(),
+                passwd.toCharArray(), rootChain);
+
+        // Now fire up the OCSP responder
+        rootOcsp = new SimpleOCSPServer(rootKeystore, passwd, ROOT_ALIAS, null);
+        rootOcsp.enableLog(ocspDebug);
+        rootOcsp.setNextUpdateInterval(3600);
+        rootOcsp.start();
+        Thread.sleep(1000);         // Give the server a second to start up
+        rootOcspPort = rootOcsp.getPort();
+        String rootRespURI = "http://localhost:" + rootOcspPort;
+        log("Root OCSP Responder URI is " + rootRespURI);
+
+        // Now that we have the root keystore and OCSP responder we can
+        // create our intermediate CA.
+        cbld.reset();
+        cbld.setSubjectName("CN=Intermediate CA Cert, O=SomeCompany");
+        cbld.setPublicKey(intCaKP.getPublic());
+        cbld.setSerialNumber(new BigInteger("100"));
+        // Make a 2 year validity starting from 30 days ago
+        start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(30);
+        end = start + TimeUnit.DAYS.toMillis(730);
+        cbld.setValidity(new Date(start), new Date(end));
+        addCommonExts(cbld, intCaKP.getPublic(), rootCaKP.getPublic());
+        addCommonCAExts(cbld);
+        cbld.addAIAExt(Collections.singletonList(rootRespURI));
+        // Make our Intermediate CA Cert!
+        X509Certificate intCaCert = cbld.build(rootCert, rootCaKP.getPrivate(),
+                "SHA256withRSA");
+        log("Intermediate CA Created:\n" + certInfo(intCaCert));
+
+        // Provide intermediate CA cert revocation info to the Root CA
+        // OCSP responder.
+        Map<BigInteger, SimpleOCSPServer.CertStatusInfo> revInfo =
+            new HashMap<>();
+        revInfo.put(intCaCert.getSerialNumber(),
+                new SimpleOCSPServer.CertStatusInfo(
+                        SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD));
+        rootOcsp.updateStatusDb(revInfo);
+
+        // Now build a keystore and add the keys, chain and root cert as a TA
+        intKeystore = keyStoreBuilder.getKeyStore();
+        Certificate[] intChain = {intCaCert, rootCert};
+        intKeystore.setKeyEntry(INT_ALIAS, intCaKP.getPrivate(),
+                passwd.toCharArray(), intChain);
+        intKeystore.setCertificateEntry(ROOT_ALIAS, rootCert);
+
+        // Now fire up the Intermediate CA OCSP responder
+        intOcsp = new SimpleOCSPServer(intKeystore, passwd,
+                INT_ALIAS, null);
+        intOcsp.enableLog(ocspDebug);
+        intOcsp.setNextUpdateInterval(3600);
+        intOcsp.start();
+        Thread.sleep(1000);
+        intOcspPort = intOcsp.getPort();
+        String intCaRespURI = "http://localhost:" + intOcspPort;
+        log("Intermediate CA OCSP Responder URI is " + intCaRespURI);
+
+        // Last but not least, let's make our SSLCert and add it to its own
+        // Keystore
+        cbld.reset();
+        cbld.setSubjectName("CN=SSLCertificate, O=SomeCompany");
+        cbld.setPublicKey(sslKP.getPublic());
+        cbld.setSerialNumber(new BigInteger("4096"));
+        // Make a 1 year validity starting from 7 days ago
+        start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7);
+        end = start + TimeUnit.DAYS.toMillis(365);
+        cbld.setValidity(new Date(start), new Date(end));
+
+        // Add extensions
+        addCommonExts(cbld, sslKP.getPublic(), intCaKP.getPublic());
+        boolean[] kuBits = {true, false, true, false, false, false,
+            false, false, false};
+        cbld.addKeyUsageExt(kuBits);
+        List<String> ekuOids = new ArrayList<>();
+        ekuOids.add("1.3.6.1.5.5.7.3.1");
+        ekuOids.add("1.3.6.1.5.5.7.3.2");
+        cbld.addExtendedKeyUsageExt(ekuOids);
+        cbld.addSubjectAltNameDNSExt(Collections.singletonList("localhost"));
+        cbld.addAIAExt(Collections.singletonList(intCaRespURI));
+        // Make our SSL Server Cert!
+        X509Certificate sslCert = cbld.build(intCaCert, intCaKP.getPrivate(),
+                "SHA256withRSA");
+        log("SSL Certificate Created:\n" + certInfo(sslCert));
+
+        // Provide SSL server cert revocation info to the Intermeidate CA
+        // OCSP responder.
+        revInfo = new HashMap<>();
+        revInfo.put(sslCert.getSerialNumber(),
+                new SimpleOCSPServer.CertStatusInfo(
+                        SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD));
+        intOcsp.updateStatusDb(revInfo);
+
+        // Now build a keystore and add the keys, chain and root cert as a TA
+        serverKeystore = keyStoreBuilder.getKeyStore();
+        Certificate[] sslChain = {sslCert, intCaCert, rootCert};
+        serverKeystore.setKeyEntry(SSL_ALIAS, sslKP.getPrivate(),
+                passwd.toCharArray(), sslChain);
+        serverKeystore.setCertificateEntry(ROOT_ALIAS, rootCert);
+
+        // And finally a Trust Store for the client
+        trustStore = keyStoreBuilder.getKeyStore();
+        trustStore.setCertificateEntry(ROOT_ALIAS, rootCert);
+    }
+
+    private static void addCommonExts(CertificateBuilder cbld,
+            PublicKey subjKey, PublicKey authKey) throws IOException {
+        cbld.addSubjectKeyIdExt(subjKey);
+        cbld.addAuthorityKeyIdExt(authKey);
+    }
+
+    private static void addCommonCAExts(CertificateBuilder cbld)
+            throws IOException {
+        cbld.addBasicConstraintsExt(true, true, -1);
+        // Set key usage bits for digitalSignature, keyCertSign and cRLSign
+        boolean[] kuBitSettings = {true, false, false, false, false, true,
+            true, false, false};
+        cbld.addKeyUsageExt(kuBitSettings);
+    }
+
+    /**
+     * Helper routine that dumps only a few cert fields rather than
+     * the whole toString() output.
+     *
+     * @param cert An X509Certificate to be displayed
+     *
+     * @return The {@link String} output of the issuer, subject and
+     * serial number
+     */
+    private static String certInfo(X509Certificate cert) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("Issuer: ").append(cert.getIssuerX500Principal()).
+                append("\n");
+        sb.append("Subject: ").append(cert.getSubjectX500Principal()).
+                append("\n");
+        sb.append("Serial: ").append(cert.getSerialNumber()).append("\n");
+        return sb.toString();
+    }
+
+    /**
+     * Log a message on stdout
+     *
+     * @param message The message to log
+     */
+    private static void log(String message) {
+        if (debug) {
+            System.out.println(message);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/TestCase.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ssl;
+
+import java.util.Map;
+
+public interface TestCase {
+    Map.Entry<Boolean, String> runTest();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/TestUtils.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ssl;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Map;
+
+public class TestUtils {
+
+    // private constructor to prevent instantiation for this utility class
+    private TestUtils() {
+        throw new AssertionError();
+    }
+
+    public static void runTests(Map<String, TestCase> testList) {
+        int testNo = 0;
+        int numberFailed = 0;
+        Map.Entry<Boolean, String> result;
+
+        System.out.println("============ Tests ============");
+        for (String testName : testList.keySet()) {
+            System.out.println("Test " + ++testNo + ": " + testName);
+            result = testList.get(testName).runTest();
+            System.out.print("Result: " + (result.getKey() ? "PASS" : "FAIL"));
+            System.out.println(" " +
+                    (result.getValue() != null ? result.getValue() : ""));
+            System.out.println("-------------------------------------------");
+            if (!result.getKey()) {
+                numberFailed++;
+            }
+        }
+
+        System.out.println("End Results: " + (testList.size() - numberFailed) +
+                " Passed" + ", " + numberFailed + " Failed.");
+        if (numberFailed > 0) {
+            throw new RuntimeException(
+                    "One or more tests failed, see test output for details");
+        }
+    }
+
+    public static void dumpBytes(byte[] data) {
+        dumpBytes(ByteBuffer.wrap(data));
+    }
+
+    public static void dumpBytes(ByteBuffer data) {
+        int i = 0;
+
+        data.mark();
+        while (data.hasRemaining()) {
+            if (i % 16 == 0 && i != 0) {
+                System.out.print("\n");
+            }
+            System.out.print(String.format("%02X ", data.get()));
+            i++;
+        }
+        System.out.print("\n");
+        data.reset();
+    }
+
+    public static void valueCheck(byte[] array1, byte[] array2) {
+        if (!Arrays.equals(array1, array2)) {
+            throw new RuntimeException("Array mismatch");
+        }
+    }
+
+    // Compares a range of bytes at specific offsets in each array
+    public static void valueCheck(byte[] array1, byte[] array2, int skip1,
+            int skip2, int length) {
+        ByteBuffer buf1 = ByteBuffer.wrap(array1);
+        ByteBuffer buf2 = ByteBuffer.wrap(array2);
+
+        // Skip past however many bytes are requested in both buffers
+        buf1.position(skip1);
+        buf2.position(skip2);
+
+        // Reset the limits on each buffer to account for the length
+        buf1.limit(buf1.position() + length);
+        buf2.limit(buf2.position() + length);
+
+        if (!buf1.equals(buf2)) {
+            throw new RuntimeException("Array range mismatch");
+        }
+    }
+
+    // Concatenate 1 or more arrays
+    public static byte[] gatherBuffers(byte[]... arrays) {
+        int totalLength = 0;
+        for (byte[] ar : arrays) {
+            totalLength += ar != null ? ar.length : 0;
+        }
+
+        byte[] resultBuf = new byte[totalLength];
+        int offset = 0;
+        for (byte[] ar : arrays) {
+            if (ar != null) {
+                System.arraycopy(ar, 0, resultBuf, offset, ar.length);
+                offset += ar.length;
+            }
+        }
+        return resultBuf;
+    }
+}
--- a/test/sun/security/tools/jarsigner/ts.sh	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/security/tools/jarsigner/ts.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -24,6 +24,11 @@
 # @test
 # @bug 6543842 6543440 6939248 8009636 8024302
 # @summary checking response of timestamp
+# @modules java.base/sun.misc
+#          java.base/sun.security.pkcs
+#          java.base/sun.security.timestamp
+#          java.base/sun.security.x509
+#          java.base/sun.security.util
 #
 # @run shell/timeout=600 ts.sh
 
@@ -90,6 +95,7 @@
         $KT -alias ca -gencert -ext eku:critical=cs | \
         $KT -alias tsbad3 -importcert
 
-$JAVAC -d . ${TESTSRC}/TimestampCheck.java
-$JAVA ${TESTVMOPTS} "-Dtest.tool.vm.opts=${TESTTOOLVMOPTS}" TimestampCheck
+EXTRAOPTS="-XaddExports:java.base/sun.misc=ALL-UNNAMED,java.base/sun.security.pkcs=ALL-UNNAMED,java.base/sun.security.timestamp=ALL-UNNAMED,java.base/sun.security.x509=ALL-UNNAMED,java.base/sun.security.util=ALL-UNNAMED"
+$JAVAC ${EXTRAOPTS} -d . ${TESTSRC}/TimestampCheck.java
+$JAVA ${TESTVMOPTS} ${EXTRAOPTS} "-Dtest.tool.vm.opts=${TESTTOOLVMOPTS}" TimestampCheck
 
--- a/test/sun/security/tools/keytool/autotest.sh	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/security/tools/keytool/autotest.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -100,7 +100,9 @@
 
 echo "Using NSS lib at $LIBNAME"
 
-${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . -XDignore.symbol.file \
+EXTRAOPTS="-XaddExports:java.base/sun.security.tools.keytool=ALL-UNNAMED,java.base/sun.security.util=ALL-UNNAMED,java.base/sun.security.x509=ALL-UNNAMED"
+
+${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ${EXTRAOPTS} -d . -XDignore.symbol.file \
         ${TESTSRC}${FS}KeyToolTest.java || exit 10
 
 NSS=${TESTSRC}${FS}..${FS}..${FS}pkcs11${FS}nss
@@ -113,7 +115,7 @@
 chmod u+w key3.db
 chmod u+w cert8.db
 
-echo | ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -Dnss \
+echo | ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${EXTRAOPTS} -Dnss \
    -Dnss.lib=${LIBNAME} \
    KeyToolTest
 status=$?
--- a/test/sun/security/tools/keytool/standard.sh	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/security/tools/keytool/standard.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -57,9 +57,11 @@
     ;;
 esac
 
-${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . -XDignore.symbol.file ${TESTSRC}${FS}KeyToolTest.java || exit 10
+EXTRAOPTS="-XaddExports:java.base/sun.security.tools.keytool=ALL-UNNAMED,java.base/sun.security.util=ALL-UNNAMED,java.base/sun.security.x509=ALL-UNNAMED"
 
-echo | ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -Dfile KeyToolTest
+${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ${EXTRAOPTS} -d . -XDignore.symbol.file ${TESTSRC}${FS}KeyToolTest.java || exit 10
+
+echo | ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${EXTRAOPTS} -Dfile KeyToolTest
 status=$?
 
 exit $status
--- a/test/sun/security/util/Oid/OidEquals.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/security/util/Oid/OidEquals.java	Thu Mar 17 19:04:16 2016 +0000
@@ -25,6 +25,7 @@
  * @test
  * @bug 8022444
  * @summary Test ObjectIdentifier.equals(Object obj)
+ * @modules java.base/sun.security.util
  */
 
 import sun.security.util.ObjectIdentifier;
--- a/test/sun/security/validator/certreplace.sh	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/security/validator/certreplace.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -25,6 +25,7 @@
 # @bug 6948803
 # @summary CertPath validation regression caused by SHA1 replacement root
 #  and MD2 disable feature
+# @modules java.base/sun.security.validator
 #
 
 if [ "${TESTSRC}" = "" ] ; then
@@ -82,5 +83,6 @@
 
 # 5. Build and run test
 
-$JAVAC ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . ${TESTSRC}${FS}CertReplace.java
-$JAVA ${TESTVMOPTS} CertReplace certreplace.jks certreplace.certs
+EXTRAOPTS="-XaddExports:java.base/sun.security.validator=ALL-UNNAMED"
+$JAVAC ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ${EXTRAOPTS} -d . ${TESTSRC}${FS}CertReplace.java
+$JAVA ${TESTVMOPTS} ${EXTRAOPTS} CertReplace certreplace.jks certreplace.certs
--- a/test/sun/security/validator/samedn.sh	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/security/validator/samedn.sh	Thu Mar 17 19:04:16 2016 +0000
@@ -25,6 +25,7 @@
 # @bug 6958869
 # @summary regression: PKIXValidator fails when multiple trust anchors
 # have same dn
+# @modules java.base/sun.security.validator
 #
 
 if [ "${TESTSRC}" = "" ] ; then
@@ -78,6 +79,7 @@
 # 5. Build and run test. Make sure the CA certs are ignored for validity check.
 # Check both, one of them might be dropped out of map in old codes.
 
-$JAVAC ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . ${TESTSRC}${FS}CertReplace.java
-$JAVA ${TESTVMOPTS} CertReplace samedn.jks samedn1.certs || exit 1
-$JAVA ${TESTVMOPTS} CertReplace samedn.jks samedn2.certs || exit 2
+EXTRAOPTS="-XaddExports:java.base/sun.security.validator=ALL-UNNAMED"
+$JAVAC ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ${EXTRAOPTS} -d . ${TESTSRC}${FS}CertReplace.java
+$JAVA ${TESTVMOPTS} ${EXTRAOPTS} CertReplace samedn.jks samedn1.certs || exit 1
+$JAVA ${TESTVMOPTS} ${EXTRAOPTS} CertReplace samedn.jks samedn2.certs || exit 2
--- a/test/sun/security/x509/URICertStore/ExtensionsWithLDAP.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/security/x509/URICertStore/ExtensionsWithLDAP.java	Thu Mar 17 19:04:16 2016 +0000
@@ -51,6 +51,7 @@
  * @test
  * @bug 8134708
  * @summary Check if LDAP resources from CRLDP and AIA extensions can be loaded
+ * @modules java.base/sun.net.spi.nameservice
  * @run main/othervm ExtensionsWithLDAP
  */
 public class ExtensionsWithLDAP {
--- a/test/sun/tools/jconsole/ResourceCheckTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/tools/jconsole/ResourceCheckTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -32,6 +32,7 @@
 
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
+import java.lang.reflect.Module;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -68,7 +69,8 @@
         // Ensure that all Message fields have a corresponding key/value
         // in the resource bundle and that mnemonics can be looked
         // up where applicable.
-        ResourceBundle rb = ResourceBundle.getBundle(RESOURCE_BUNDLE);
+        Module module = sun.tools.jconsole.Messages.class.getModule();
+        ResourceBundle rb = ResourceBundle.getBundle(RESOURCE_BUNDLE, module);
         for (Field field : Messages.class.getFields()) {
             if (isResourceKeyField(field)) {
                 String resourceKey = field.getName();
--- a/test/sun/tools/jhsdb/SAGetoptTest.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/tools/jhsdb/SAGetoptTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -25,6 +25,7 @@
  /*
  * @test
  * @summary unit test for SAGetopt function
+ * @modules jdk.hotspot.agent/sun.jvm.hotspot
  * @compile -XDignore.symbol.file SAGetoptTest.java
  * @run main SAGetoptTest
  */
--- a/test/sun/util/resources/TimeZone/Bug4640234.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/sun/util/resources/TimeZone/Bug4640234.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,7 @@
  *          ISO country codes.
  *          The test program also displays which timezone, country and
  *          language names are not translated
+ * @modules java.base/sun.util.resources
  */
 
 
@@ -49,6 +50,7 @@
 import java.util.ResourceBundle;
 import java.util.TimeZone;
 
+import sun.util.resources.LocaleData;
 
 public class Bug4640234  {
     static SimpleDateFormat sdfEn = new SimpleDateFormat("zzzz", Locale.US);
@@ -84,8 +86,8 @@
             String[] countries = locEn.getISOCountries();
             String[] languages = locEn.getISOLanguages();
 
-            ResourceBundle resEn = ResourceBundle.getBundle(
-                    "sun.util.resources.LocaleNames", locEn);
+            ResourceBundle resEn = LocaleData.getBundle("sun.util.resources.LocaleNames",
+                                                        locEn);
             Map<String, String> countryMapEn = getList(resEn, true);
             Map<String, String> languageMapEn = getList(resEn, false);
 
@@ -94,8 +96,8 @@
             Map<String, String> languageMap;
 
             for (Locale locale : locales2Test) {
-                resLoc = ResourceBundle.getBundle(
-                    "sun.util.resources.LocaleNames", locale);
+                resLoc = LocaleData.getBundle("sun.util.resources.LocaleNames",
+                                              locale);
 
                 sdfLoc = new SimpleDateFormat("zzzz", locale);
                 sdfLocShort = new SimpleDateFormat("z", locale);
@@ -257,18 +259,20 @@
 
         if (nameEn == null) {
             // We should not get here but test is a MUST have
-            return new String[] {"", MessageFormat.format(notFoundMessage,
-                new String[] {"English", ISOCode})};
+            return new String[] {"",
+                                 MessageFormat.format(notFoundMessage, "English", ISOCode)};
         }
 
         if (nameLoc == null) {
-            return new String[] {"", MessageFormat.format(notFoundMessage,
-                new String[] {locale.getDisplayName(), ISOCode})};
+            return new String[] {"",
+                                 MessageFormat.format(notFoundMessage,
+                                                      locale.getDisplayName(), ISOCode)};
         }
 
         if (nameEn.equals(nameLoc)) {
             return new String[] {MessageFormat.format(notLocalizedMessage,
-                new String[] {locale.getDisplayName(), ISOCode}), ""};
+                                                      locale.getDisplayName(), ISOCode),
+                                 ""};
         }
 
         return new String[] {"", ""};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jar/compat/CLICompatibility.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,633 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.*;
+import java.lang.reflect.Method;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+import java.util.jar.JarOutputStream;
+import java.util.stream.Stream;
+
+import jdk.testlibrary.FileUtils;
+import jdk.testlibrary.JDKToolFinder;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+
+import static java.lang.String.format;
+import static java.lang.System.out;
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.testng.Assert.assertTrue;
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @build jdk.testlibrary.FileUtils jdk.testlibrary.JDKToolFinder
+ * @run testng CLICompatibility
+ * @summary Basic test for compatibility of CLI options
+ */
+
+public class CLICompatibility {
+    static final Path TEST_CLASSES = Paths.get(System.getProperty("test.classes", "."));
+    static final Path USER_DIR = Paths.get(System.getProperty("user.dir"));
+
+    final boolean legacyOnly;  // for running on older JDK's ( test validation )
+
+    // Resources we know to exist, that can be used for creating jar files.
+    static final String RES1 = "CLICompatibility.class";
+    static final String RES2 = "CLICompatibility$Result.class";
+
+    @BeforeTest
+    public void setupResourcesForJar() throws Exception {
+        // Copy the files that we are going to use for creating/updating test
+        // jar files, so that they can be referred to without '-C dir'
+        Files.copy(TEST_CLASSES.resolve(RES1), USER_DIR.resolve(RES1));
+        Files.copy(TEST_CLASSES.resolve(RES2), USER_DIR.resolve(RES2));
+    }
+
+    static final IOConsumer<InputStream> ASSERT_CONTAINS_RES1 = in -> {
+        try (JarInputStream jin = new JarInputStream(in)) {
+            assertTrue(jarContains(jin, RES1), "Failed to find " + RES1);
+        }
+    };
+    static final IOConsumer<InputStream> ASSERT_CONTAINS_RES2 = in -> {
+        try (JarInputStream jin = new JarInputStream(in)) {
+            assertTrue(jarContains(jin, RES2), "Failed to find " + RES2);
+        }
+    };
+    static final IOConsumer<InputStream> ASSERT_CONTAINS_MAINFEST = in -> {
+        try (JarInputStream jin = new JarInputStream(in)) {
+            assertTrue(jin.getManifest() != null, "No META-INF/MANIFEST.MF");
+        }
+    };
+    static final IOConsumer<InputStream> ASSERT_DOES_NOT_CONTAIN_MAINFEST = in -> {
+        try (JarInputStream jin = new JarInputStream(in)) {
+            assertTrue(jin.getManifest() == null, "Found unexpected META-INF/MANIFEST.MF");
+        }
+    };
+
+    static final FailCheckerWithMessage FAIL_TOO_MANY_MAIN_OPS =
+        new FailCheckerWithMessage("You must specify one of -ctxui options",
+        /* legacy */ "{ctxui}[vfmn0Me] [jar-file] [manifest-file] [entry-point] [-C dir] files");
+
+    // Create
+
+    @Test
+    public void createBadArgs() {
+        final FailCheckerWithMessage FAIL_CREATE_NO_ARGS = new FailCheckerWithMessage(
+                "'c' flag requires manifest or input files to be specified!");
+
+        jar("c")
+            .assertFailure()
+            .resultChecker(FAIL_CREATE_NO_ARGS);
+
+        jar("-c")
+            .assertFailure()
+            .resultChecker(FAIL_CREATE_NO_ARGS);
+
+        if (!legacyOnly)
+            jar("--create")
+                .assertFailure()
+                .resultChecker(FAIL_CREATE_NO_ARGS);
+
+        jar("ct")
+            .assertFailure()
+            .resultChecker(FAIL_TOO_MANY_MAIN_OPS);
+
+        jar("-ct")
+            .assertFailure()
+            .resultChecker(FAIL_TOO_MANY_MAIN_OPS);
+
+        if (!legacyOnly)
+            jar("--create --list")
+                .assertFailure()
+                .resultChecker(FAIL_TOO_MANY_MAIN_OPS);
+    }
+
+    @Test
+    public void createWriteToFile() throws IOException {
+        Path path = Paths.get("createJarFile.jar");  // for creating
+        String jn = path.toString();
+        for (String opts : new String[]{"cf " + jn, "-cf " + jn, "--create --file=" + jn}) {
+            if (legacyOnly && opts.startsWith("--"))
+                continue;
+
+            jar(opts, RES1)
+                .assertSuccess()
+                .resultChecker(r -> {
+                    ASSERT_CONTAINS_RES1.accept(Files.newInputStream(path));
+                    ASSERT_CONTAINS_MAINFEST.accept(Files.newInputStream(path));
+                });
+        }
+        FileUtils.deleteFileIfExistsWithRetry(path);
+    }
+
+    @Test
+    public void createWriteToStdout() throws IOException {
+        for (String opts : new String[]{"c", "-c", "--create"}) {
+            if (legacyOnly && opts.startsWith("--"))
+                continue;
+
+            jar(opts, RES1)
+                .assertSuccess()
+                .resultChecker(r -> {
+                    ASSERT_CONTAINS_RES1.accept(r.stdoutAsStream());
+                    ASSERT_CONTAINS_MAINFEST.accept(r.stdoutAsStream());
+                });
+        }
+    }
+
+    @Test
+    public void createWriteToStdoutNoManifest() throws IOException {
+        for (String opts : new String[]{"cM", "-cM", "--create --no-manifest"} ){
+            if (legacyOnly && opts.startsWith("--"))
+                continue;
+
+            jar(opts, RES1)
+                .assertSuccess()
+                .resultChecker(r -> {
+                    ASSERT_CONTAINS_RES1.accept(r.stdoutAsStream());
+                    ASSERT_DOES_NOT_CONTAIN_MAINFEST.accept(r.stdoutAsStream());
+                });
+        }
+    }
+
+    // Update
+
+    @Test
+    public void updateBadArgs() {
+        final FailCheckerWithMessage FAIL_UPDATE_NO_ARGS = new FailCheckerWithMessage(
+                "'u' flag requires manifest, 'e' flag or input files to be specified!");
+
+        jar("u")
+            .assertFailure()
+            .resultChecker(FAIL_UPDATE_NO_ARGS);
+
+        jar("-u")
+            .assertFailure()
+            .resultChecker(FAIL_UPDATE_NO_ARGS);
+
+        if (!legacyOnly)
+            jar("--update")
+                .assertFailure()
+                .resultChecker(FAIL_UPDATE_NO_ARGS);
+
+        jar("ut")
+            .assertFailure()
+            .resultChecker(FAIL_TOO_MANY_MAIN_OPS);
+
+        jar("-ut")
+            .assertFailure()
+            .resultChecker(FAIL_TOO_MANY_MAIN_OPS);
+
+        if (!legacyOnly)
+            jar("--update --list")
+                .assertFailure()
+                .resultChecker(FAIL_TOO_MANY_MAIN_OPS);
+    }
+
+    @Test
+    public void updateReadFileWriteFile() throws IOException {
+        Path path = Paths.get("updateReadWriteStdout.jar");  // for updating
+        String jn = path.toString();
+
+        for (String opts : new String[]{"uf " + jn, "-uf " + jn, "--update --file=" + jn}) {
+            if (legacyOnly && opts.startsWith("--"))
+                continue;
+
+            createJar(path, RES1);
+            jar(opts, RES2)
+                .assertSuccess()
+                .resultChecker(r -> {
+                    ASSERT_CONTAINS_RES1.accept(Files.newInputStream(path));
+                    ASSERT_CONTAINS_RES2.accept(Files.newInputStream(path));
+                    ASSERT_CONTAINS_MAINFEST.accept(Files.newInputStream(path));
+                });
+        }
+        FileUtils.deleteFileIfExistsWithRetry(path);
+    }
+
+    @Test
+    public void updateReadStdinWriteStdout() throws IOException {
+        Path path = Paths.get("updateReadStdinWriteStdout.jar");
+
+        for (String opts : new String[]{"u", "-u", "--update"}) {
+            if (legacyOnly && opts.startsWith("--"))
+                continue;
+
+            createJar(path, RES1);
+            jarWithStdin(path.toFile(), opts, RES2)
+                .assertSuccess()
+                .resultChecker(r -> {
+                    ASSERT_CONTAINS_RES1.accept(r.stdoutAsStream());
+                    ASSERT_CONTAINS_RES2.accept(r.stdoutAsStream());
+                    ASSERT_CONTAINS_MAINFEST.accept(r.stdoutAsStream());
+                });
+        }
+        FileUtils.deleteFileIfExistsWithRetry(path);
+    }
+
+    @Test
+    public void updateReadStdinWriteStdoutNoManifest() throws IOException {
+        Path path = Paths.get("updateReadStdinWriteStdoutNoManifest.jar");
+
+        for (String opts : new String[]{"uM", "-uM", "--update --no-manifest"} ){
+            if (legacyOnly && opts.startsWith("--"))
+                continue;
+
+            createJar(path, RES1);
+            jarWithStdin(path.toFile(), opts, RES2)
+                .assertSuccess()
+                .resultChecker(r -> {
+                    ASSERT_CONTAINS_RES1.accept(r.stdoutAsStream());
+                    ASSERT_CONTAINS_RES2.accept(r.stdoutAsStream());
+                    ASSERT_DOES_NOT_CONTAIN_MAINFEST.accept(r.stdoutAsStream());
+                });
+        }
+        FileUtils.deleteFileIfExistsWithRetry(path);
+    }
+
+    // List
+
+    @Test
+    public void listBadArgs() {
+        jar("te")
+            .assertFailure()
+            .resultChecker(FAIL_TOO_MANY_MAIN_OPS);
+
+        jar("-te")
+            .assertFailure()
+            .resultChecker(FAIL_TOO_MANY_MAIN_OPS);
+
+        if (!legacyOnly)
+            jar("--list --extract")
+                .assertFailure()
+                .resultChecker(FAIL_TOO_MANY_MAIN_OPS);
+    }
+
+    @Test
+    public void listReadFromFileWriteToStdout() throws IOException {
+        Path path = Paths.get("listReadFromFileWriteToStdout.jar");  // for listing
+        createJar(path, RES1);
+        String jn = path.toString();
+
+        for (String opts : new String[]{"tf " + jn, "-tf " + jn, "--list --file " + jn}) {
+            if (legacyOnly && opts.startsWith("--"))
+                continue;
+
+            jar(opts)
+                .assertSuccess()
+                .resultChecker(r ->
+                    assertTrue(r.output.contains("META-INF/MANIFEST.MF") && r.output.contains(RES1),
+                               "Failed, got [" + r.output + "]")
+                );
+        }
+        FileUtils.deleteFileIfExistsWithRetry(path);
+    }
+
+    @Test
+    public void listReadFromStdinWriteToStdout() throws IOException {
+        Path path = Paths.get("listReadFromStdinWriteToStdout.jar");
+        createJar(path, RES1);
+
+        for (String opts : new String[]{"t", "-t", "--list"} ){
+            if (legacyOnly && opts.startsWith("--"))
+                continue;
+
+            jarWithStdin(path.toFile(), opts)
+                .assertSuccess()
+                .resultChecker(r ->
+                    assertTrue(r.output.contains("META-INF/MANIFEST.MF") && r.output.contains(RES1),
+                               "Failed, got [" + r.output + "]")
+                );
+        }
+        FileUtils.deleteFileIfExistsWithRetry(path);
+    }
+
+    // Extract
+
+    @Test
+    public void extractBadArgs() {
+        jar("xi")
+            .assertFailure()
+            .resultChecker(FAIL_TOO_MANY_MAIN_OPS);
+
+        jar("-xi")
+            .assertFailure()
+            .resultChecker(FAIL_TOO_MANY_MAIN_OPS);
+
+        if (!legacyOnly)
+            jar("--extract --generate-index")
+                .assertFailure()
+                .resultChecker(FAIL_TOO_MANY_MAIN_OPS);
+    }
+
+    @Test
+    public void extractReadFromStdin() throws IOException {
+        Path path = Paths.get("extract");
+        Path jarPath = path.resolve("extractReadFromStdin.jar"); // for extracting
+        createJar(jarPath, RES1);
+
+        for (String opts : new String[]{"x" ,"-x", "--extract"}) {
+            if (legacyOnly && opts.startsWith("--"))
+                continue;
+
+            jarWithStdinAndWorkingDir(jarPath.toFile(), path.toFile(), opts)
+                .assertSuccess()
+                .resultChecker(r ->
+                    assertTrue(Files.exists(path.resolve(RES1)),
+                               "Expected to find:" + path.resolve(RES1))
+                );
+            FileUtils.deleteFileIfExistsWithRetry(path.resolve(RES1));
+        }
+        FileUtils.deleteFileTreeWithRetry(path);
+    }
+
+    @Test
+    public void extractReadFromFile() throws IOException {
+        Path path = Paths.get("extract");
+        String jn = "extractReadFromFile.jar";
+        Path jarPath = path.resolve(jn);
+        createJar(jarPath, RES1);
+
+        for (String opts : new String[]{"xf "+jn ,"-xf "+jn, "--extract --file "+jn}) {
+            if (legacyOnly && opts.startsWith("--"))
+                continue;
+
+            jarWithStdinAndWorkingDir(null, path.toFile(), opts)
+                .assertSuccess()
+                .resultChecker(r ->
+                    assertTrue(Files.exists(path.resolve(RES1)),
+                               "Expected to find:" + path.resolve(RES1))
+                );
+            FileUtils.deleteFileIfExistsWithRetry(path.resolve(RES1));
+        }
+        FileUtils.deleteFileTreeWithRetry(path);
+    }
+
+    // Basic help
+
+    @Test
+    public void helpBadOptionalArg() {
+        if (legacyOnly)
+            return;
+
+        jar("--help:")
+            .assertFailure();
+
+        jar("--help:blah")
+            .assertFailure();
+    }
+
+    @Test
+    public void help() {
+        if (legacyOnly)
+            return;
+
+        jar("-h")
+            .assertSuccess()
+            .resultChecker(r ->
+                assertTrue(r.output.startsWith("Usage: jar [OPTION...] [-C dir] files"),
+                           "Failed, got [" + r.output + "]")
+            );
+
+        jar("--help")
+            .assertSuccess()
+            .resultChecker(r ->
+                assertTrue(r.output.startsWith("Usage: jar [OPTION...] [-C dir] files"),
+                           "Failed, got [" + r.output + "]")
+            );
+
+        jar("--help:compat")
+            .assertSuccess()
+            .resultChecker(r ->
+                assertTrue(r.output.startsWith("Compatibility Interface:"),
+                           "Failed, got [" + r.output + "]")
+            );
+    }
+
+    // -- Infrastructure
+
+    static boolean jarContains(JarInputStream jis, String entryName)
+        throws IOException
+    {
+        JarEntry e;
+        boolean found = false;
+        while((e = jis.getNextJarEntry()) != null) {
+            if (e.getName().equals(entryName))
+                return true;
+        }
+        return false;
+    }
+
+    /* Creates a simple jar with entries of size 0, good enough for testing */
+    static void createJar(Path path, String... entries) throws IOException {
+        FileUtils.deleteFileIfExistsWithRetry(path);
+        Path parent = path.getParent();
+        if (parent != null)
+            Files.createDirectories(parent);
+        try (OutputStream out = Files.newOutputStream(path);
+             JarOutputStream jos = new JarOutputStream(out)) {
+            JarEntry je = new JarEntry("META-INF/MANIFEST.MF");
+            jos.putNextEntry(je);
+            jos.closeEntry();
+
+            for (String entry : entries) {
+                je = new JarEntry(entry);
+                jos.putNextEntry(je);
+                jos.closeEntry();
+            }
+        }
+    }
+
+    static class FailCheckerWithMessage implements Consumer<Result> {
+        final String[] messages;
+        FailCheckerWithMessage(String... m) {
+            messages = m;
+        }
+        @Override
+        public void accept(Result r) {
+            //out.printf("%s%n", r.output);
+            boolean found = false;
+            for (String m : messages) {
+                if (r.output.contains(m)) {
+                    found = true;
+                    break;
+                }
+            }
+            assertTrue(found,
+                       "Excepted out to contain one of: " + Arrays.asList(messages)
+                           + " but got: " + r.output);
+        }
+    }
+
+    static Result jar(String... args) {
+        return jarWithStdinAndWorkingDir(null, null, args);
+    }
+
+    static Result jarWithStdin(File stdinSource, String... args) {
+        return jarWithStdinAndWorkingDir(stdinSource, null, args);
+    }
+
+    static Result jarWithStdinAndWorkingDir(File stdinFrom,
+                                            File workingDir,
+                                            String... args) {
+        String jar = getJDKTool("jar");
+        List<String> commands = new ArrayList<>();
+        commands.add(jar);
+        Stream.of(args).map(s -> s.split(" "))
+                       .flatMap(Arrays::stream)
+                       .forEach(x -> commands.add(x));
+        ProcessBuilder p = new ProcessBuilder(commands);
+        if (stdinFrom != null)
+            p.redirectInput(stdinFrom);
+        if (workingDir != null)
+            p.directory(workingDir);
+        return run(p);
+    }
+
+    static Result run(ProcessBuilder pb) {
+        Process p;
+        byte[] stdout, stderr;
+        out.printf("Running: %s%n", pb.command());
+        try {
+            p = pb.start();
+        } catch (IOException e) {
+            throw new RuntimeException(
+                    format("Couldn't start process '%s'", pb.command()), e);
+        }
+
+        String output;
+        try {
+            stdout = readAllBytes(p.getInputStream());
+            stderr = readAllBytes(p.getErrorStream());
+
+            output = toString(stdout, stderr);
+        } catch (IOException e) {
+            throw new RuntimeException(
+                    format("Couldn't read process output '%s'", pb.command()), e);
+        }
+
+        try {
+            p.waitFor();
+        } catch (InterruptedException e) {
+            throw new RuntimeException(
+                    format("Process hasn't finished '%s'", pb.command()), e);
+        }
+        return new Result(p.exitValue(), stdout, stderr, output);
+    }
+
+    static final Path JAVA_HOME = Paths.get(System.getProperty("java.home"));
+
+    static String getJDKTool(String name) {
+        try {
+            return JDKToolFinder.getJDKTool(name);
+        } catch (Exception x) {
+            Path j = JAVA_HOME.resolve("bin").resolve(name);
+            if (Files.exists(j))
+                return j.toString();
+            j = JAVA_HOME.resolve("..").resolve("bin").resolve(name);
+            if (Files.exists(j))
+                return j.toString();
+            throw new RuntimeException(x);
+        }
+    }
+
+    static String toString(byte[] ba1, byte[] ba2) {
+        return (new String(ba1, UTF_8)).concat(new String(ba2, UTF_8));
+    }
+
+    static class Result {
+        final int exitValue;
+        final byte[] stdout;
+        final byte[] stderr;
+        final String output;
+
+        private Result(int exitValue, byte[] stdout, byte[] stderr, String output) {
+            this.exitValue = exitValue;
+            this.stdout = stdout;
+            this.stderr = stderr;
+            this.output = output;
+        }
+
+        InputStream stdoutAsStream() { return new ByteArrayInputStream(stdout); }
+
+        Result assertSuccess() { assertTrue(exitValue == 0, output); return this; }
+        Result assertFailure() { assertTrue(exitValue != 0, output); return this; }
+
+        Result resultChecker(IOConsumer<Result> r) {
+            try {  r.accept(this); return this; }
+            catch (IOException x) { throw new UncheckedIOException(x); }
+        }
+
+        Result resultChecker(FailCheckerWithMessage c) { c.accept(this); return this; }
+    }
+
+    interface IOConsumer<T> { void accept(T t) throws IOException ;  }
+
+    // readAllBytes implementation so the test can be run pre 1.9 ( legacyOnly )
+    static byte[] readAllBytes(InputStream is) throws IOException {
+        byte[] buf = new byte[8192];
+        int capacity = buf.length;
+        int nread = 0;
+        int n;
+        for (;;) {
+            // read to EOF which may read more or less than initial buffer size
+            while ((n = is.read(buf, nread, capacity - nread)) > 0)
+                nread += n;
+
+            // if the last call to read returned -1, then we're done
+            if (n < 0)
+                break;
+
+            // need to allocate a larger buffer
+            capacity = capacity << 1;
+
+            buf = Arrays.copyOf(buf, capacity);
+        }
+        return (capacity == nread) ? buf : Arrays.copyOf(buf, nread);
+    }
+
+    // Standalone entry point for running with, possibly older, JDKs.
+    public static void main(String[] args) throws Throwable {
+        boolean legacyOnly = false;
+        if (args.length != 0 && args[0].equals("legacyOnly"))
+            legacyOnly = true;
+
+        CLICompatibility test = new CLICompatibility(legacyOnly);
+        for (Method m : CLICompatibility.class.getDeclaredMethods()) {
+            if (m.getAnnotation(Test.class) != null) {
+                System.out.println("Invoking " + m.getName());
+                m.invoke(test);
+            }
+        }
+    }
+    CLICompatibility(boolean legacyOnly) { this.legacyOnly = legacyOnly; }
+    CLICompatibility() { this.legacyOnly = false; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jar/modularJar/Basic.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,797 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.*;
+import java.lang.reflect.Method;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.*;
+import java.util.function.Consumer;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.StandardLocation;
+import javax.tools.ToolProvider;
+
+import jdk.testlibrary.FileUtils;
+import jdk.testlibrary.JDKToolFinder;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+
+import static java.lang.String.format;
+import static java.lang.System.out;
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @build jdk.testlibrary.FileUtils jdk.testlibrary.JDKToolFinder
+ * @compile Basic.java
+ * @run testng Basic
+ * @summary Basic test for Modular jars
+ */
+
+public class Basic {
+    static final Path TEST_SRC = Paths.get(System.getProperty("test.src", "."));
+    static final Path TEST_CLASSES = Paths.get(System.getProperty("test.classes", "."));
+    static final Path MODULE_CLASSES = TEST_CLASSES.resolve("build");
+
+    // Details based on the checked in module source
+    static TestModuleData FOO = new TestModuleData("foo",
+                                                   "1.123",
+                                                   "jdk.test.foo.Foo",
+                                                   "Hello World!!!", null,
+                                                   "jdk.test.foo.internal");
+    static TestModuleData BAR = new TestModuleData("bar",
+                                                   "4.5.6.7",
+                                                   "jdk.test.bar.Bar",
+                                                   "Hello from Bar!", null,
+                                                   "jdk.test.bar",
+                                                   "jdk.test.bar.internal");
+
+    static class TestModuleData {
+        final String moduleName;
+        final String mainClass;
+        final String version;
+        final String message;
+        final String hashes;
+        final Set<String> conceals;
+        TestModuleData(String mn, String v, String mc, String m, String h, String... pkgs) {
+            moduleName = mn; mainClass = mc; version = v; message = m; hashes = h;
+            conceals = new HashSet<>();
+            Stream.of(pkgs).forEach(conceals::add);
+        }
+        TestModuleData(String mn, String v, String mc, String m, String h, Set<String> pkgs) {
+            moduleName = mn; mainClass = mc; version = v; message = m; hashes = h;
+            conceals = pkgs;
+        }
+        static TestModuleData from(String s) {
+            try {
+                BufferedReader reader = new BufferedReader(new StringReader(s));
+                String line;
+                String message = null;
+                String name = null, version = null, mainClass = null;
+                String hashes = null;
+                Set<String> conceals = null;
+                while ((line = reader.readLine()) != null) {
+                    if (line.startsWith("message:")) {
+                        message = line.substring("message:".length());
+                    } else if (line.startsWith("nameAndVersion:")) {
+                        line = line.substring("nameAndVersion:".length());
+                        int i = line.indexOf('@');
+                        if (i != -1) {
+                            name = line.substring(0, i);
+                            version = line.substring(i + 1, line.length());
+                        } else {
+                            name = line;
+                        }
+                    } else if (line.startsWith("mainClass:")) {
+                        mainClass = line.substring("mainClass:".length());
+                    } else if (line.startsWith("hashes:")) {
+                        hashes = line.substring("hashes:".length());
+                    }  else if (line.startsWith("conceals:")) {
+                        line = line.substring("conceals:".length());
+                        conceals = new HashSet<>();
+                        int i = line.indexOf(',');
+                        if (i != -1) {
+                            String[] p = line.split(",");
+                            Stream.of(p).forEach(conceals::add);
+                        } else {
+                            conceals.add(line);
+                        }
+                    } else {
+                        throw new AssertionError("Unknown value " + line);
+                    }
+                }
+
+                return new TestModuleData(name, version, mainClass, message, hashes, conceals);
+            } catch (IOException x) {
+                throw new UncheckedIOException(x);
+            }
+        }
+    }
+
+    static void assertModuleData(Result r, TestModuleData expected) {
+        //out.printf("%s%n", r.output);
+        TestModuleData received = TestModuleData.from(r.output);
+        if (expected.message != null)
+            assertTrue(expected.message.equals(received.message),
+                       "Expected message:", expected.message, ", got:", received.message);
+        assertTrue(expected.moduleName.equals(received.moduleName),
+                   "Expected moduleName: ", expected.moduleName, ", got:", received.moduleName);
+        assertTrue(expected.version.equals(received.version),
+                   "Expected version: ", expected.version, ", got:", received.version);
+        assertTrue(expected.mainClass.equals(received.mainClass),
+                   "Expected mainClass: ", expected.mainClass, ", got:", received.mainClass);
+        expected.conceals.forEach(p -> assertTrue(received.conceals.contains(p),
+                                                  "Expected ", p, ", in ", received.conceals));
+        received.conceals.forEach(p -> assertTrue(expected.conceals.contains(p),
+                                                  "Expected ", p, ", in ", expected.conceals));
+    }
+
+    @BeforeTest
+    public void compileModules() throws Exception {
+        compileModule(FOO.moduleName);
+        compileModule(BAR.moduleName, MODULE_CLASSES);
+        compileModule("baz");  // for service provider consistency checking
+    }
+
+    @Test
+    public void createFoo() throws IOException {
+        Path mp = Paths.get("createFoo");
+        createTestDir(mp);
+        Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName);
+        Path modularJar = mp.resolve(FOO.moduleName + ".jar");
+
+        jar("--create",
+            "--file=" + modularJar.toString(),
+            "--main-class=" + FOO.mainClass,
+            "--module-version=" + FOO.version,
+            "--no-manifest",
+            "-C", modClasses.toString(), ".")
+            .assertSuccess();
+        java(mp, FOO.moduleName + "/" + FOO.mainClass)
+            .assertSuccess()
+            .resultChecker(r -> assertModuleData(r, FOO));
+
+        try (InputStream fis = Files.newInputStream(modularJar);
+             JarInputStream jis = new JarInputStream(fis)) {
+            assertTrue(!jarContains(jis, "./"),
+                       "Unexpected ./ found in ", modularJar.toString());
+        }
+    }
+
+    @Test
+    public void updateFoo() throws IOException {
+        Path mp = Paths.get("updateFoo");
+        createTestDir(mp);
+        Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName);
+        Path modularJar = mp.resolve(FOO.moduleName + ".jar");
+
+        jar("--create",
+            "--file=" + modularJar.toString(),
+            "--no-manifest",
+            "-C", modClasses.toString(), "jdk")
+            .assertSuccess();
+        jar("--update",
+            "--file=" + modularJar.toString(),
+            "--main-class=" + FOO.mainClass,
+            "--module-version=" + FOO.version,
+            "--no-manifest",
+            "-C", modClasses.toString(), "module-info.class")
+            .assertSuccess();
+        java(mp, FOO.moduleName + "/" + FOO.mainClass)
+            .assertSuccess()
+            .resultChecker(r -> assertModuleData(r, FOO));
+    }
+
+    @Test
+    public void partialUpdateFooMainClass() throws IOException {
+        Path mp = Paths.get("partialUpdateFooMainClass");
+        createTestDir(mp);
+        Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName);
+        Path modularJar = mp.resolve(FOO.moduleName + ".jar");
+
+        // A "bad" main class in first create ( and no version )
+        jar("--create",
+            "--file=" + modularJar.toString(),
+            "--main-class=" + "IAmNotTheEntryPoint",
+            "--no-manifest",
+            "-C", modClasses.toString(), ".")  // includes module-info.class
+           .assertSuccess();
+        jar("--update",
+            "--file=" + modularJar.toString(),
+            "--main-class=" + FOO.mainClass,
+            "--module-version=" + FOO.version,
+            "--no-manifest")
+            .assertSuccess();
+        java(mp, FOO.moduleName + "/" + FOO.mainClass)
+            .assertSuccess()
+            .resultChecker(r -> assertModuleData(r, FOO));
+    }
+
+    @Test
+    public void partialUpdateFooVersion() throws IOException {
+        Path mp = Paths.get("partialUpdateFooVersion");
+        createTestDir(mp);
+        Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName);
+        Path modularJar = mp.resolve(FOO.moduleName + ".jar");
+
+        // A "bad" version in first create ( and no main class )
+        jar("--create",
+            "--file=" + modularJar.toString(),
+            "--module-version=" + "100000000",
+            "--no-manifest",
+            "-C", modClasses.toString(), ".")  // includes module-info.class
+            .assertSuccess();
+        jar("--update",
+            "--file=" + modularJar.toString(),
+            "--main-class=" + FOO.mainClass,
+            "--module-version=" + FOO.version,
+            "--no-manifest")
+            .assertSuccess();
+        java(mp, FOO.moduleName + "/" + FOO.mainClass)
+            .assertSuccess()
+            .resultChecker(r -> assertModuleData(r, FOO));
+    }
+
+    @Test
+    public void partialUpdateFooNotAllFiles() throws IOException {
+        Path mp = Paths.get("partialUpdateFooNotAllFiles");
+        createTestDir(mp);
+        Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName);
+        Path modularJar = mp.resolve(FOO.moduleName + ".jar");
+
+        // Not all files, and none from non-exported packages,
+        // i.e. no concealed list in first create
+        jar("--create",
+            "--file=" + modularJar.toString(),
+            "--no-manifest",
+            "-C", modClasses.toString(), "module-info.class",
+            "-C", modClasses.toString(), "jdk/test/foo/Foo.class")
+            .assertSuccess();
+        jar("--update",
+            "--file=" + modularJar.toString(),
+            "--main-class=" + FOO.mainClass,
+            "--module-version=" + FOO.version,
+            "--no-manifest",
+            "-C", modClasses.toString(), "jdk/test/foo/internal/Message.class")
+            .assertSuccess();
+        java(mp, FOO.moduleName + "/" + FOO.mainClass)
+            .assertSuccess()
+            .resultChecker(r -> assertModuleData(r, FOO));
+    }
+
+    @Test
+    public void partialUpdateFooAllFilesAndAttributes() throws IOException {
+        Path mp = Paths.get("partialUpdateFooAllFilesAndAttributes");
+        createTestDir(mp);
+        Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName);
+        Path modularJar = mp.resolve(FOO.moduleName + ".jar");
+
+        // all attributes and files
+        jar("--create",
+            "--file=" + modularJar.toString(),
+            "--main-class=" + FOO.mainClass,
+            "--module-version=" + FOO.version,
+            "--no-manifest",
+            "-C", modClasses.toString(), ".")
+            .assertSuccess();
+        jar("--update",
+            "--file=" + modularJar.toString(),
+            "--main-class=" + FOO.mainClass,
+            "--module-version=" + FOO.version,
+            "--no-manifest",
+            "-C", modClasses.toString(), ".")
+            .assertSuccess();
+        java(mp, FOO.moduleName + "/" + FOO.mainClass)
+            .assertSuccess()
+            .resultChecker(r -> assertModuleData(r, FOO));
+    }
+
+    @Test
+    public void partialUpdateFooModuleInfo() throws IOException {
+        Path mp = Paths.get("partialUpdateFooModuleInfo");
+        createTestDir(mp);
+        Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName);
+        Path modularJar = mp.resolve(FOO.moduleName + ".jar");
+        Path barModInfo = MODULE_CLASSES.resolve(BAR.moduleName);
+
+        jar("--create",
+            "--file=" + modularJar.toString(),
+            "--main-class=" + FOO.mainClass,
+            "--module-version=" + FOO.version,
+            "--no-manifest",
+            "-C", modClasses.toString(), ".")
+            .assertSuccess();
+        jar("--update",
+            "--file=" + modularJar.toString(),
+            "--no-manifest",
+            "-C", barModInfo.toString(), "module-info.class")  // stuff in bar's info
+            .assertSuccess();
+        jar("-p",
+            "--file=" + modularJar.toString())
+            .assertSuccess()
+            .resultChecker(r -> {
+                // Expect similar output: "Name:bar,  Requires: foo,...
+                // Conceals: jdk.test.foo, jdk.test.foo.internal"
+                Pattern p = Pattern.compile("\\s+Name:\\s+bar\\s+Requires:\\s+foo");
+                assertTrue(p.matcher(r.output).find(),
+                           "Expecting to find \"Name: bar, Requires: foo,...\"",
+                           "in output, but did not: [" + r.output + "]");
+                p = Pattern.compile(
+                        "Conceals:\\s+jdk.test.foo\\s+jdk.test.foo.internal");
+                assertTrue(p.matcher(r.output).find(),
+                           "Expecting to find \"Conceals: jdk.test.foo,...\"",
+                           "in output, but did not: [" + r.output + "]");
+            });
+    }
+
+    @Test
+    public void dependencesFooBar() throws IOException {
+        Path mp = Paths.get("dependencesFooBar");
+        createTestDir(mp);
+
+        Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName);
+        Path modularJar = mp.resolve(FOO.moduleName + ".jar");
+        jar("--create",
+            "--file=" + modularJar.toString(),
+            "--main-class=" + FOO.mainClass,
+            "--module-version=" + FOO.version,
+            "--no-manifest",
+            "-C", modClasses.toString(), ".")
+            .assertSuccess();
+
+        modClasses = MODULE_CLASSES.resolve(BAR.moduleName);
+        modularJar = mp.resolve(BAR.moduleName + ".jar");
+        jar("--create",
+            "--file=" + modularJar.toString(),
+            "--main-class=" + BAR.mainClass,
+            "--module-version=" + BAR.version,
+            "--modulepath=" + mp.toString(),
+            "--hash-dependencies=" + "foo",  // dependency on foo
+            "--no-manifest",
+            "-C", modClasses.toString(), ".")
+            .assertSuccess();
+
+        java(mp, BAR.moduleName + "/" + BAR.mainClass,
+             "-XaddExports:java.base/jdk.internal.module=bar")
+            .assertSuccess()
+            .resultChecker(r -> {
+                assertModuleData(r, BAR);
+                TestModuleData received = TestModuleData.from(r.output);
+                assertTrue(received.hashes != null, "Expected non-null hashes value.");
+            });
+    }
+
+    @Test
+    public void badDependencyFooBar() throws IOException {
+        Path mp = Paths.get("badDependencyFooBar");
+        createTestDir(mp);
+
+        Path fooClasses = MODULE_CLASSES.resolve(FOO.moduleName);
+        Path fooJar = mp.resolve(FOO.moduleName + ".jar");
+        jar("--create",
+            "--file=" + fooJar.toString(),
+            "--main-class=" + FOO.mainClass,
+            "--module-version=" + FOO.version,
+            "--no-manifest",
+            "-C", fooClasses.toString(), ".").assertSuccess();
+
+        Path barClasses = MODULE_CLASSES.resolve(BAR.moduleName);
+        Path barJar = mp.resolve(BAR.moduleName + ".jar");
+        jar("--create",
+            "--file=" + barJar.toString(),
+            "--main-class=" + BAR.mainClass,
+            "--module-version=" + BAR.version,
+            "--modulepath=" + mp.toString(),
+            "--hash-dependencies=" + "foo",  // dependency on foo
+            "--no-manifest",
+            "-C", barClasses.toString(), ".").assertSuccess();
+
+        // Rebuild foo.jar with a change that will cause its hash to be different
+        FileUtils.deleteFileWithRetry(fooJar);
+        jar("--create",
+            "--file=" + fooJar.toString(),
+            "--main-class=" + FOO.mainClass,
+            "--module-version=" + FOO.version + ".1", // a newer version
+            "--no-manifest",
+            "-C", fooClasses.toString(), ".").assertSuccess();
+
+        java(mp, BAR.moduleName + "/" + BAR.mainClass,
+             "-XaddExports:java.base/jdk.internal.module=bar")
+            .assertFailure()
+            .resultChecker(r -> {
+                // Expect similar output: "java.lang.module.ResolutionException: Hash
+                // of foo (WdktSIQSkd4+CEacpOZoeDrCosMATNrIuNub9b5yBeo=) differs to
+                // expected hash (iepvdv8xTeVrFgMtUhcFnmetSub6qQHCHc92lSaSEg0=)"
+                Pattern p = Pattern.compile(".*Hash of foo.*differs to expected hash.*");
+                assertTrue(p.matcher(r.output).find(),
+                      "Expecting error message containing \"Hash of foo ... differs to"
+                              + " expected hash...\" but got: [", r.output + "]");
+            });
+    }
+
+    @Test
+    public void badOptionsFoo() throws IOException {
+        Path mp = Paths.get("badOptionsFoo");
+        createTestDir(mp);
+        Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName);
+        Path modularJar = mp.resolve(FOO.moduleName + ".jar");
+
+        jar("--create",
+            "--file=" + modularJar.toString(),
+            "--module-version=" + 1.1,   // no module-info.class
+            "-C", modClasses.toString(), "jdk")
+            .assertFailure();      // TODO: expected failure message
+
+         jar("--create",
+             "--file=" + modularJar.toString(),
+             "--hash-dependencies=" + ".*",   // no module-info.class
+             "-C", modClasses.toString(), "jdk")
+             .assertFailure();      // TODO: expected failure message
+    }
+
+    @Test
+    public void servicesCreateWithoutFailure() throws IOException {
+        Path mp = Paths.get("servicesCreateWithoutFailure");
+        createTestDir(mp);
+        Path modClasses = MODULE_CLASSES.resolve("baz");
+        Path modularJar = mp.resolve("baz" + ".jar");
+
+        // Positive test, create
+        jar("--create",
+            "--file=" + modularJar.toString(),
+            "-C", modClasses.toString(), "module-info.class",
+            "-C", modClasses.toString(), "jdk/test/baz/BazService.class",
+            "-C", modClasses.toString(), "jdk/test/baz/internal/BazServiceImpl.class")
+            .assertSuccess();
+    }
+
+    @Test
+    public void servicesCreateWithoutServiceImpl() throws IOException {
+        Path mp = Paths.get("servicesWithoutServiceImpl");
+        createTestDir(mp);
+        Path modClasses = MODULE_CLASSES.resolve("baz");
+        Path modularJar = mp.resolve("baz" + ".jar");
+
+        // Omit service impl
+        jar("--create",
+            "--file=" + modularJar.toString(),
+            "-C", modClasses.toString(), "module-info.class",
+            "-C", modClasses.toString(), "jdk/test/baz/BazService.class")
+            .assertFailure();
+    }
+
+    @Test
+    public void servicesUpdateWithoutFailure() throws IOException {
+        Path mp = Paths.get("servicesUpdateWithoutFailure");
+        createTestDir(mp);
+        Path modClasses = MODULE_CLASSES.resolve("baz");
+        Path modularJar = mp.resolve("baz" + ".jar");
+
+        // Positive test, update
+        jar("--create",
+            "--file=" + modularJar.toString(),
+            "-C", modClasses.toString(), "jdk/test/baz/BazService.class",
+            "-C", modClasses.toString(), "jdk/test/baz/internal/BazServiceImpl.class")
+            .assertSuccess();
+        jar("--update",
+            "--file=" + modularJar.toString(),
+            "-C", modClasses.toString(), "module-info.class")
+            .assertSuccess();
+    }
+
+    @Test
+    public void servicesUpdateWithoutServiceImpl() throws IOException {
+        Path mp = Paths.get("servicesUpdateWithoutServiceImpl");
+        createTestDir(mp);
+        Path modClasses = MODULE_CLASSES.resolve("baz");
+        Path modularJar = mp.resolve("baz" + ".jar");
+
+        // Omit service impl
+        jar("--create",
+            "--file=" + modularJar.toString(),
+            "-C", modClasses.toString(), "jdk/test/baz/BazService.class")
+            .assertSuccess();
+        jar("--update",
+            "--file=" + modularJar.toString(),
+            "-C", modClasses.toString(), "module-info.class")
+            .assertFailure();
+    }
+
+    @Test
+    public void printModuleDescriptorFoo() throws IOException {
+        Path mp = Paths.get("printModuleDescriptorFoo");
+        createTestDir(mp);
+        Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName);
+        Path modularJar = mp.resolve(FOO.moduleName + ".jar");
+
+        jar("--create",
+            "--file=" + modularJar.toString(),
+            "--main-class=" + FOO.mainClass,
+            "--module-version=" + FOO.version,
+            "--no-manifest",
+            "-C", modClasses.toString(), ".")
+            .assertSuccess();
+
+        for (String option : new String[]  {"--print-module-descriptor", "-p" }) {
+            jar(option,
+                "--file=" + modularJar.toString())
+                .assertSuccess()
+                .resultChecker(r ->
+                    assertTrue(r.output.contains(FOO.moduleName + "@" + FOO.version),
+                               "Expected to find ", FOO.moduleName + "@" + FOO.version,
+                               " in [", r.output, "]")
+                );
+        }
+    }
+
+    @Test
+    public void printModuleDescriptorFooFromStdin() throws IOException {
+        Path mp = Paths.get("printModuleDescriptorFooFromStdin");
+        createTestDir(mp);
+        Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName);
+        Path modularJar = mp.resolve(FOO.moduleName + ".jar");
+
+        jar("--create",
+            "--file=" + modularJar.toString(),
+            "--main-class=" + FOO.mainClass,
+            "--module-version=" + FOO.version,
+            "--no-manifest",
+            "-C", modClasses.toString(), ".")
+            .assertSuccess();
+
+        for (String option : new String[]  {"--print-module-descriptor", "-p" }) {
+            jarWithStdin(modularJar.toFile(),
+                         option)
+                         .assertSuccess()
+                         .resultChecker(r ->
+                             assertTrue(r.output.contains(FOO.moduleName + "@" + FOO.version),
+                                "Expected to find ", FOO.moduleName + "@" + FOO.version,
+                                " in [", r.output, "]")
+                );
+        }
+    }
+
+    // -- Infrastructure
+
+    static Result jarWithStdin(File stdinSource, String... args) {
+        String jar = getJDKTool("jar");
+        List<String> commands = new ArrayList<>();
+        commands.add(jar);
+        Stream.of(args).forEach(x -> commands.add(x));
+        ProcessBuilder p = new ProcessBuilder(commands);
+        if (stdinSource != null)
+            p.redirectInput(stdinSource);
+        return run(p);
+    }
+
+    static Result jar(String... args) {
+        return jarWithStdin(null, args);
+    }
+
+    static Path compileModule(String mn) throws IOException {
+        return compileModule(mn, null);
+    }
+
+    static Path compileModule(String mn, Path mp)
+        throws IOException
+    {
+        Path fooSourcePath = TEST_SRC.resolve("src").resolve(mn);
+        Path build = Files.createDirectories(MODULE_CLASSES.resolve(mn));
+        javac(build, mp, fileList(fooSourcePath));
+        return build;
+    }
+
+    // Re-enable when there is support in javax.tools for module path
+//    static void javac(Path dest, Path... sourceFiles) throws IOException {
+//        out.printf("Compiling %d source files %s%n", sourceFiles.length,
+//                   Arrays.asList(sourceFiles));
+//        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+//        try (StandardJavaFileManager fileManager =
+//                     compiler.getStandardFileManager(null, null, null)) {
+//
+//            List<File> files = Stream.of(sourceFiles)
+//                                     .map(p -> p.toFile())
+//                                     .collect(Collectors.toList());
+//            List<File> dests = Stream.of(dest)
+//                                     .map(p -> p.toFile())
+//                                     .collect(Collectors.toList());
+//            Iterable<? extends JavaFileObject> compilationUnits =
+//                    fileManager.getJavaFileObjectsFromFiles(files);
+//            fileManager.setLocation(StandardLocation.CLASS_OUTPUT, dests);
+//            JavaCompiler.CompilationTask task =
+//                    compiler.getTask(null, fileManager, null, null, null, compilationUnits);
+//            boolean passed = task.call();
+//            if (!passed)
+//                throw new RuntimeException("Error compiling " + files);
+//        }
+//    }
+
+    static void javac(Path dest, Path... sourceFiles) throws IOException {
+        javac(dest, null, sourceFiles);
+    }
+
+    static void javac(Path dest, Path modulePath, Path... sourceFiles)
+        throws IOException
+    {
+        String javac = getJDKTool("javac");
+
+        List<String> commands = new ArrayList<>();
+        commands.add(javac);
+        commands.add("-d");
+        commands.add(dest.toString());
+        if (dest.toString().contains("bar"))
+            commands.add("-XaddExports:java.base/jdk.internal.module=bar");
+        if (modulePath != null) {
+            commands.add("-mp");
+            commands.add(modulePath.toString());
+        }
+        Stream.of(sourceFiles).map(Object::toString).forEach(x -> commands.add(x));
+
+        quickFail(run(new ProcessBuilder(commands)));
+    }
+
+    static Result java(Path modulePath, String entryPoint, String... args) {
+        String java = getJDKTool("java");
+
+        List<String> commands = new ArrayList<>();
+        commands.add(java);
+        Stream.of(args).forEach(x -> commands.add(x));
+        commands.add("-mp");
+        commands.add(modulePath.toString());
+        commands.add("-m");
+        commands.add(entryPoint);
+
+        return run(new ProcessBuilder(commands));
+    }
+
+    static Path[] fileList(Path directory) throws IOException {
+        final List<Path> filePaths = new ArrayList<>();
+        Files.walkFileTree(directory, new SimpleFileVisitor<Path>() {
+            @Override
+            public FileVisitResult visitFile(Path file,
+                                             BasicFileAttributes attrs) {
+                filePaths.add(file);
+                return FileVisitResult.CONTINUE;
+            }
+        });
+        return filePaths.toArray(new Path[filePaths.size()]);
+    }
+
+    static void createTestDir(Path p) throws IOException{
+        if (Files.exists(p))
+            FileUtils.deleteFileTreeWithRetry(p);
+        Files.createDirectory(p);
+    }
+
+    static boolean jarContains(JarInputStream jis, String entryName)
+        throws IOException
+    {
+        JarEntry e;
+        while((e = jis.getNextJarEntry()) != null) {
+            if (e.getName().equals(entryName))
+                return true;
+        }
+        return false;
+    }
+
+    static void quickFail(Result r) {
+        if (r.ec != 0)
+            throw new RuntimeException(r.output);
+    }
+
+    static Result run(ProcessBuilder pb) {
+        Process p;
+        out.printf("Running: %s%n", pb.command());
+        try {
+            p = pb.start();
+        } catch (IOException e) {
+            throw new RuntimeException(
+                    format("Couldn't start process '%s'", pb.command()), e);
+        }
+
+        String output;
+        try {
+            output = toString(p.getInputStream(), p.getErrorStream());
+        } catch (IOException e) {
+            throw new RuntimeException(
+                    format("Couldn't read process output '%s'", pb.command()), e);
+        }
+
+        try {
+            p.waitFor();
+        } catch (InterruptedException e) {
+            throw new RuntimeException(
+                    format("Process hasn't finished '%s'", pb.command()), e);
+        }
+        return new Result(p.exitValue(), output);
+    }
+
+    static final String DEFAULT_IMAGE_BIN = System.getProperty("java.home")
+            + File.separator + "bin" + File.separator;
+
+    static String getJDKTool(String name) {
+        try {
+            return JDKToolFinder.getJDKTool(name);
+        } catch (Exception x) {
+            return DEFAULT_IMAGE_BIN + name;
+        }
+    }
+
+    static String toString(InputStream in1, InputStream in2) throws IOException {
+        try (ByteArrayOutputStream dst = new ByteArrayOutputStream();
+             InputStream concatenated = new SequenceInputStream(in1, in2)) {
+            concatenated.transferTo(dst);
+            return new String(dst.toByteArray(), "UTF-8");
+        }
+    }
+
+    static class Result {
+        final int ec;
+        final String output;
+
+        private Result(int ec, String output) {
+            this.ec = ec;
+            this.output = output;
+        }
+        Result assertSuccess() {
+            assertTrue(ec == 0, "Expected ec 0, got: ", ec, " , output [", output, "]");
+            return this;
+        }
+        Result assertFailure() {
+            assertTrue(ec != 0, "Expected ec != 0, got:", ec, " , output [", output, "]");
+            return this;
+        }
+        Result resultChecker(Consumer<Result> r) { r.accept(this); return this; }
+    }
+
+    static void assertTrue(boolean cond, Object ... failedArgs) {
+        if (cond)
+            return;
+        StringBuilder sb = new StringBuilder();
+        for (Object o : failedArgs)
+            sb.append(o);
+        org.testng.Assert.assertTrue(false, sb.toString());
+    }
+
+    // Standalone entry point.
+    public static void main(String[] args) throws Throwable {
+        Basic test = new Basic();
+        test.compileModules();
+        for (Method m : Basic.class.getDeclaredMethods()) {
+            if (m.getAnnotation(Test.class) != null) {
+                System.out.println("Invoking " + m.getName());
+                m.invoke(test);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jar/modularJar/src/bar/jdk/test/bar/Bar.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.bar;
+
+import java.lang.module.ModuleDescriptor;
+import java.lang.reflect.Method;
+import java.util.Optional;
+import java.util.StringJoiner;
+
+import jdk.internal.module.Hasher;
+import jdk.test.bar.internal.Message;
+
+public class Bar {
+    public static void main(String[] args) throws Exception {
+        System.out.println("message:" + Message.get());
+
+        ModuleDescriptor md = Bar.class.getModule().getDescriptor();
+        System.out.println("nameAndVersion:" + md.toNameAndVersion());
+        System.out.println("mainClass:" + md.mainClass().get());
+
+        Method m = ModuleDescriptor.class.getDeclaredMethod("hashes");
+        m.setAccessible(true);
+        Optional<Hasher.DependencyHashes> optHashes =
+                (Optional<Hasher.DependencyHashes>) m.invoke(md);
+
+        System.out.println("hashes:" + optHashes.get().hashFor("foo"));
+
+        StringJoiner sj = new StringJoiner(",");
+        md.conceals().forEach(sj::add);
+        System.out.println("conceals:" + sj.toString());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jar/modularJar/src/bar/jdk/test/bar/internal/Message.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.bar.internal;
+
+public class Message  {
+    public static String get() {
+        return "Hello from Bar!";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jar/modularJar/src/bar/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module bar {
+    requires foo;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jar/modularJar/src/baz/jdk/test/baz/BazService.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.baz;
+
+public interface BazService {
+    void doSomething();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jar/modularJar/src/baz/jdk/test/baz/internal/BazServiceImpl.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.baz.internal;
+
+import jdk.test.baz.BazService;
+
+public class BazServiceImpl implements jdk.test.baz.BazService {
+    @Override public void doSomething() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jar/modularJar/src/baz/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module baz {
+    exports jdk.test.baz;
+    provides jdk.test.baz.BazService with jdk.test.baz.internal.BazServiceImpl;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jar/modularJar/src/foo/jdk/test/foo/Foo.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.foo;
+
+import java.lang.module.ModuleDescriptor;
+import java.util.StringJoiner;
+
+import jdk.test.foo.internal.Message;
+
+public class Foo {
+    public static void main(String[] args) {
+        System.out.println("message:" + Message.get());
+
+        ModuleDescriptor md = Foo.class.getModule().getDescriptor();
+        System.out.println("nameAndVersion:" + md.toNameAndVersion());
+        System.out.println("mainClass:" + md.mainClass().get());
+
+        StringJoiner sj = new StringJoiner(",");
+        md.conceals().forEach(sj::add);
+        System.out.println("conceals:" + sj.toString());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jar/modularJar/src/foo/jdk/test/foo/internal/Message.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.foo.internal;
+
+public class Message  {
+    public static String get() {
+        return "Hello World!!!";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jar/modularJar/src/foo/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module foo {
+    exports jdk.test.foo;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jimage/JImageTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.io.File;
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystemNotFoundException;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.ProviderNotFoundException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+
+import tests.Helper;
+import tests.JImageGenerator;
+import tests.JImageValidator;
+
+import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
+
+/*
+ * jimage testing.
+ * @test
+ * @summary Test jimage tool
+ * @library ../lib
+ * @modules java.base/jdk.internal.jimage
+ *          jdk.jdeps/com.sun.tools.classfile
+ *          jdk.jlink/jdk.tools.jmod
+ *          jdk.jlink/jdk.tools.jimage
+ *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.compiler
+ * @run build JImageTest
+ * @run build tests.*
+ * @run main/othervm -verbose:gc -Xmx1g JImageTest
+*/
+public class JImageTest {
+
+    public static void main(String[] args) throws Exception {
+        List<String> bootClasses = new ArrayList<>();
+
+        FileSystem fs;
+        try {
+            fs = FileSystems.getFileSystem(URI.create("jrt:/"));
+        } catch (ProviderNotFoundException | FileSystemNotFoundException e) {
+            System.out.println("Not an image build, test skipped.");
+            return;
+        }
+
+        // Build the set of locations expected in the Image
+        Consumer<Path> c = (p) -> {
+               // take only the .class resources.
+               if (Files.isRegularFile(p) && p.toString().endsWith(".class")
+                       && !p.toString().endsWith("module-info.class")) {
+                   String loc = p.toString().substring("/modules".length());
+                   bootClasses.add(loc);
+               }
+           };
+
+        Path javabase = fs.getPath("/modules/java.base");
+        Path mgtbase = fs.getPath("/modules/java.management");
+        try (Stream<Path> stream = Files.walk(javabase)) {
+            stream.forEach(c);
+        }
+        try (Stream<Path> stream = Files.walk(mgtbase)) {
+            stream.forEach(c);
+        }
+
+        if (bootClasses.isEmpty()) {
+            throw new RuntimeException("No boot class to check against");
+        }
+
+        File jdkHome = new File(System.getProperty("test.jdk"));
+        // JPRT not yet ready for jmods
+        Helper helper = Helper.newHelper();
+        if (helper == null) {
+            System.err.println("Test not run, NO jmods directory");
+            return;
+        }
+
+        // Generate the sample image
+        String module = "mod1";
+        String[] classes = {module + ".Main"};
+        helper.generateDefaultJModule(module, Arrays.asList(classes), "java.management");
+
+        Path image = helper.generateDefaultImage(module).assertSuccess();
+        Path extractedDir = JImageGenerator.getJImageTask()
+                .dir(helper.createNewExtractedDir("modules"))
+                .image(image.resolve("lib").resolve("modules"))
+                .extract().assertSuccess();
+
+        Path recreatedImage = JImageGenerator.getJImageTask()
+                .dir(extractedDir)
+                .image(helper.createNewRecreatedDir(extractedDir.getFileName().toString()))
+                .recreate().assertSuccess();
+        JImageValidator.validate(recreatedImage, bootClasses, Collections.emptyList());
+
+        // Check replacing the boot image by recreated one
+        Path destFile = image.resolve("lib").resolve("modules");
+        Files.copy(recreatedImage, destFile, REPLACE_EXISTING);
+        JImageValidator validator = new JImageValidator(module, Collections.emptyList(),
+                image.toFile(), Collections.emptyList(), Collections.emptyList());
+        validator.validate();
+
+        Path recreatedImage2 = JImageGenerator.getJImageTask()
+                .dir(extractedDir)
+                .option("--compress").option("2")
+                .image(helper.createNewRecreatedDir(extractedDir.getFileName().toString()))
+                .recreate().assertSuccess();
+        JImageValidator.validate(recreatedImage2, bootClasses, Collections.emptyList());
+
+        Path recreatedImage3 = JImageGenerator.getJImageTask()
+                .dir(extractedDir)
+                .option("--strip-debug")
+                .image(helper.createNewRecreatedDir(extractedDir.getFileName().toString()))
+                .recreate().assertSuccess();
+        JImageValidator.validate(recreatedImage3, bootClasses, Collections.emptyList());
+
+        Path recreatedImage4 = JImageGenerator.getJImageTask()
+                .dir(extractedDir)
+                .option("--exclude-resources")
+                .option("*.jcov, */META-INF/*")
+                .image(helper.createNewRecreatedDir(extractedDir.getFileName().toString()))
+                .recreate().assertSuccess();
+        List<String> unexpectedPaths = new ArrayList<>();
+        unexpectedPaths.add(".jcov");
+        unexpectedPaths.add("/META-INF/");
+        JImageValidator.validate(recreatedImage4, bootClasses, unexpectedPaths);
+
+        Path recreatedImage5 = JImageGenerator.getJImageTask()
+                .dir(extractedDir)
+                .option("--compress")
+                .option("2")
+                .option("--strip-debug")
+                .option("--exclude-resources")
+                .option("*.jcov, */META-INF/*")
+                .image(helper.createNewRecreatedDir(extractedDir.getFileName().toString()))
+                .recreate().assertSuccess();
+        JImageValidator.validate(recreatedImage5, bootClasses, unexpectedPaths);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jimage/JImageToolTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @build jdk.testlibrary.*
+ * @summary Test to see if jimage tool extracts and recreates correctly.
+ * @run main/timeout=360 JImageToolTest
+ */
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import jdk.testlibrary.ProcessTools;
+
+/**
+ * Basic test for jimage tool.
+ */
+public class JImageToolTest {
+    private static void jimage(String... jimageArgs) throws Exception {
+        ArrayList<String> args = new ArrayList<>();
+        args.add("-ms8m");
+        args.add("jdk.tools.jimage.Main");
+        args.addAll(Arrays.asList(jimageArgs));
+
+        ProcessBuilder builder = ProcessTools.createJavaProcessBuilder(args.toArray(new String[args.size()]));
+        int res = builder.inheritIO().start().waitFor();
+
+        if (res != 0) {
+            throw new RuntimeException("JImageToolTest FAILED");
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        String home = System.getProperty("java.home");
+        Path jimagePath = Paths.get(home, "bin", "jimage");
+        Path modulesimagePath = Paths.get(home, "lib", "modules");
+
+        if (Files.exists(jimagePath) && Files.exists(modulesimagePath)) {
+            String jimage = jimagePath.toAbsolutePath().toString();
+            String bootimage = modulesimagePath.toAbsolutePath().toString();
+            String extractDir = Paths.get(".", "extract").toAbsolutePath().toString();
+            String recreateImage = Paths.get(".", "recreate").toAbsolutePath().toString();
+            String relativeRecreateImage = Paths.get(".", "recreate2").toString();
+            jimage("extract", "--dir", extractDir, bootimage);
+            jimage("recreate", "--dir", extractDir, recreateImage);
+            jimage("recreate", "--dir", extractDir, relativeRecreateImage);
+            System.out.println("Test successful");
+         } else {
+            System.out.println("Test skipped, not an images build");
+         }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jimage/VerifyJimage.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Deque;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ConcurrentLinkedDeque;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import jdk.internal.jimage.BasicImageReader;
+import jdk.internal.jimage.ImageLocation;
+
+/*
+ * @test
+ * @summary Verify jimage
+ * @modules java.base/jdk.internal.jimage
+ */
+
+/**
+ * This test runs in two modes:
+ * (1) No argument: it verifies the jimage by loading all classes in the runtime
+ * (2) path of exploded modules: it compares bytes of each file in the exploded
+ *     module with the entry in jimage
+ *
+ * FIXME: exception thrown when findLocation from jimage by multiple threads
+ * -Djdk.test.threads=<n> to specify the number of threads.
+ */
+public class VerifyJimage {
+    private static final String MODULE_INFO = "module-info.class";
+    private static final Deque<String> failed = new ConcurrentLinkedDeque<>();
+
+    public static void main(String... args) throws Exception {
+
+        String home = System.getProperty("java.home");
+        Path bootimagePath = Paths.get(home, "lib", "modules");
+        if (Files.notExists(bootimagePath)) {
+             System.out.println("Test skipped, not an images build");
+             return;
+        }
+
+        long start = System.nanoTime();
+        int numThreads = Integer.getInteger("jdk.test.threads", 1);
+        List<JImageReader> readers = newJImageReaders();
+        VerifyJimage verify = new VerifyJimage(readers, numThreads);
+        if (args.length == 0) {
+            // load classes from jimage
+            verify.loadClasses();
+        } else {
+            Path dir = Paths.get(args[0]);
+            if (Files.notExists(dir) || !Files.isDirectory(dir)) {
+                throw new RuntimeException("Invalid argument: " + dir);
+            }
+            verify.compareExplodedModules(dir);
+        }
+        verify.waitForCompletion();
+        long end = System.nanoTime();
+        int entries = readers.stream()
+                             .mapToInt(JImageReader::entries)
+                             .sum();
+        System.out.format("%d entries %d files verified: %d ms %d errors%n",
+                          entries, verify.count.get(),
+                          TimeUnit.NANOSECONDS.toMillis(end - start), failed.size());
+        for (String f : failed) {
+            System.err.println(f);
+        }
+        if (!failed.isEmpty()) {
+            throw new AssertionError("Test failed");
+        }
+    }
+
+    private final AtomicInteger count = new AtomicInteger(0);
+    private final List<JImageReader> readers;
+    private final ExecutorService pool;
+
+    VerifyJimage(List<JImageReader> readers, int numThreads) {
+        this.readers = readers;
+        this.pool = Executors.newFixedThreadPool(numThreads);
+    }
+
+    private void waitForCompletion() throws InterruptedException {
+        pool.shutdown();
+        pool.awaitTermination(20, TimeUnit.SECONDS);
+    }
+
+    private void compareExplodedModules(Path dir) throws IOException {
+        System.out.println("comparing jimage with " + dir);
+
+        try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
+            for (Path mdir : stream) {
+                if (Files.isDirectory(mdir)) {
+                    pool.execute(new Runnable() {
+                        @Override
+                        public void run() {
+                            try {
+                                Files.find(mdir, Integer.MAX_VALUE, (Path p, BasicFileAttributes attr)
+                                           -> !Files.isDirectory(p) &&
+                                              !mdir.relativize(p).toString().startsWith("_") &&
+                                              !p.getFileName().toString().equals("MANIFEST.MF"))
+                                     .forEach(p -> compare(mdir, p, readers));
+                            } catch (IOException e) {
+                                throw new UncheckedIOException(e);
+                            }
+                        }
+                    });
+                }
+            }
+        }
+    }
+
+    private final List<String> BOOT_RESOURCES = Arrays.asList(
+        "java.base/META-INF/services/java.nio.file.spi.FileSystemProvider"
+    );
+    private final List<String> EXT_RESOURCES = Arrays.asList(
+        "jdk.zipfs/META-INF/services/java.nio.file.spi.FileSystemProvider"
+    );
+    private final List<String> APP_RESOURCES = Arrays.asList(
+        "jdk.hotspot.agent/META-INF/services/com.sun.jdi.connect.Connector",
+        "jdk.jdi/META-INF/services/com.sun.jdi.connect.Connector"
+    );
+
+    private void compare(Path mdir, Path p, List<JImageReader> readers) {
+        String entry = p.getFileName().toString().equals(MODULE_INFO)
+                ? mdir.getFileName().toString() + "/" + MODULE_INFO
+                : mdir.relativize(p).toString().replace(File.separatorChar, '/');
+
+        count.incrementAndGet();
+        String file = mdir.getFileName().toString() + "/" + entry;
+        if (APP_RESOURCES.contains(file)) {
+            // skip until the service config file is merged
+            System.out.println("Skipped " + file);
+            return;
+        }
+
+        String jimage = "modules";
+        JImageReader reader = readers.stream()
+                .filter(r -> r.findLocation(entry) != null)
+                .filter(r -> jimage.isEmpty() || r.imageName().equals(jimage))
+                .findFirst().orElse(null);
+        if (reader == null) {
+            failed.add(entry + " not found: " + p.getFileName().toString());
+        } else {
+            reader.compare(entry, p);
+        }
+    }
+
+    private void loadClasses() {
+        ClassLoader loader = ClassLoader.getSystemClassLoader();
+        for (JImageReader reader : readers) {
+            Arrays.stream(reader.getEntryNames())
+                    .filter(n -> n.endsWith(".class") && !n.endsWith(MODULE_INFO))
+                    .forEach(n -> {
+                        String cn = removeModule(n).replaceAll("\\.class$", "").replace('/', '.');
+                        count.incrementAndGet();
+                        try {
+                            Class.forName(cn, false, loader);
+                        } catch (ClassNotFoundException e) {
+                            failed.add(reader.imageName() + ": " + cn + " not found");
+                        }
+                    });
+        }
+    }
+
+    private String removeModule(String path) {
+        int index = path.indexOf('/', 1);
+        return path.substring(index + 1, path.length());
+    }
+
+    private static List<JImageReader> newJImageReaders() throws IOException {
+        String home = System.getProperty("java.home");
+        Path jimage = Paths.get(home, "lib", "modules");
+        JImageReader reader = new JImageReader(jimage);
+        List<JImageReader> result = new ArrayList<>();
+        System.out.println("opened " + jimage);
+        result.add(reader);
+        return result;
+    }
+
+    static class JImageReader extends BasicImageReader {
+        final Path jimage;
+        JImageReader(Path p) throws IOException {
+            super(p);
+            this.jimage = p;
+        }
+
+        String imageName() {
+            return jimage.getFileName().toString();
+        }
+
+        int entries() {
+            return getHeader().getTableLength();
+        }
+
+        void compare(String entry, Path p) {
+            try {
+                byte[] bytes = Files.readAllBytes(p);
+                byte[] imagebytes = getResource(entry);
+                if (!Arrays.equals(bytes, imagebytes)) {
+                    failed.add(imageName() + ": bytes differs than " + p.toString());
+                }
+            } catch (IOException e) {
+                throw new UncheckedIOException(e);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/CheckExecutable.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2015 SAP SE. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8132475
+ * @summary Check that jlink creates executables in the bin directory
+ *          that are are executable by all users
+ * @run main CheckExecutable
+ * @author Volker Simonis
+ */
+
+import java.io.IOException;
+import java.nio.file.*;
+import java.nio.file.attribute.PosixFilePermission;
+import static java.nio.file.attribute.PosixFilePermission.*;
+import java.util.EnumSet;
+import java.util.Set;
+
+public class CheckExecutable {
+
+    // The bin directory may contain non-executable files (see 8132704)
+    private static final String IGNORE = "glob:{*.diz,jmc.ini}";
+
+    public static void main(String args[]) throws IOException {
+        String JAVA_HOME = System.getProperty("java.home");
+        Path bin = Paths.get(JAVA_HOME, "bin");
+
+        PathMatcher matcher = FileSystems.getDefault().getPathMatcher(IGNORE);
+
+        try (DirectoryStream<Path> stream = Files.newDirectoryStream(bin)) {
+            EnumSet<PosixFilePermission> execPerms
+                = EnumSet.of(GROUP_EXECUTE, OTHERS_EXECUTE, OWNER_EXECUTE);
+
+            for (Path entry : stream) {
+                Path file = entry.getFileName();
+                if (!Files.isRegularFile(entry) || matcher.matches(file)) {
+                    continue;
+                }
+
+                if (!Files.isExecutable(entry))
+                    throw new RuntimeException(entry + " is not executable!");
+
+                try {
+                    Set<PosixFilePermission> perm
+                        = Files.getPosixFilePermissions(entry);
+                    if (!perm.containsAll(execPerms)) {
+                        throw new RuntimeException(entry
+                            + " has not all executable permissions!\n"
+                            + "Should have: " + execPerms + "\nbut has: " + perm);
+                    }
+                } catch (UnsupportedOperationException uoe) { }
+
+            }
+
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/CustomPluginTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import tests.Helper;
+import tests.JImageGenerator;
+import tests.Result;
+
+/*
+ * @test
+ * @summary Test custom plugin
+ * @author Jean-Francois Denise
+ * @library ../lib
+ * @modules java.base/jdk.internal.jimage
+ *          jdk.jdeps/com.sun.tools.classfile
+ *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jmod
+ *          jdk.jlink/jdk.tools.jimage
+ *          jdk.compiler
+ * @build tests.*
+ * @run main/othervm CustomPluginTest
+ */
+
+public class CustomPluginTest {
+
+    public static void main(String[] args) throws Exception {
+        new CustomPluginTest().test();
+    }
+
+    private void test() throws Exception {
+        Helper helper = Helper.newHelper();
+        if (helper == null) {
+            System.err.println("Test not run");
+            return;
+        }
+        helper.generateDefaultModules();
+        Path jmod = registerServices(helper);
+        Path pluginModulePath = jmod.getParent();
+
+        testHelloProvider(helper, pluginModulePath);
+        testCustomPlugins(helper, pluginModulePath);
+    }
+
+    private void testCustomPlugins(Helper helper, Path pluginModulePath) {
+        Result result = JImageGenerator.getJLinkTask()
+                .option("--list-plugins")
+                .pluginModulePath(pluginModulePath)
+                .output(helper.createNewImageDir("customplugin"))
+                .call();
+        if (result.getExitCode() != 0) {
+            System.err.println(result.getMessage());
+            throw new AssertionError("jlink crashed: " + result.getExitCode());
+        }
+        List<String> customPlugins = Stream.of(result.getMessage().split("\n"))
+                .filter(s -> s.startsWith("Plugin Name:"))
+                .filter(s -> s.contains("custom"))
+                .collect(Collectors.toList());
+        if (customPlugins.size() != 1) {
+            System.err.println(result.getMessage());
+            throw new AssertionError("Found plugins: " + customPlugins);
+        }
+    }
+
+    private Path registerServices(Helper helper) throws IOException {
+        String name = "customplugin";
+        Path src = Paths.get(System.getProperty("test.src")).resolve(name);
+        Path classes = helper.getJmodClassesDir().resolve(name);
+        JImageGenerator.compile(src, classes, "-XaddExports:jdk.jlink/jdk.tools.jlink.internal=customplugin");
+        return JImageGenerator.getJModTask()
+                .addClassPath(classes)
+                .jmod(helper.getJmodDir().resolve(name + ".jmod"))
+                .create().assertSuccess();
+    }
+
+    private void testHelloProvider(Helper helper, Path pluginModulePath) throws IOException {
+        Path pluginFile = Paths.get("customplugin.txt");
+        if (Files.exists(pluginFile)) {
+            throw new AssertionError("Custom plugin output file already exists");
+        }
+        String customplugin = "customplugin";
+        {
+            // Add the path but not the option, plugin musn't be called
+            JImageGenerator.getJLinkTask()
+                    .modulePath(helper.defaultModulePath())
+                    .pluginModulePath(pluginModulePath)
+                    .output(helper.createNewImageDir(customplugin))
+                    .addMods(customplugin)
+                    .call().assertSuccess();
+        }
+
+        if (Files.exists(pluginFile)) {
+            throw new AssertionError("Custom plugin output file exists, plugin "
+                    + " called although shouldn't have been");
+        }
+
+        { // Add the path and the option, plugin should be called.
+            JImageGenerator.getJLinkTask()
+                    .modulePath(helper.defaultModulePath())
+                    .addMods(customplugin)
+                    .pluginModulePath(pluginModulePath)
+                    .output(helper.createNewImageDir(customplugin))
+                    .option("--hello")
+                    .call().assertSuccess();
+        }
+
+        if (!Files.exists(pluginFile)) {
+            throw new AssertionError("Custom plugin not called");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/DefaultProviderTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import jdk.tools.jlink.internal.PluginRepository;
+import jdk.tools.jlink.plugin.Plugin;
+import jdk.tools.jlink.plugin.PluginException;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.TransformerPlugin;
+import tests.Helper;
+
+/*
+ * @test
+ * @summary Test plugins enabled by default
+ * @author Jean-Francois Denise
+ * @library ../lib
+ * @modules java.base/jdk.internal.jimage
+ *          jdk.jdeps/com.sun.tools.classfile
+ *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jmod
+ *          jdk.jlink/jdk.tools.jimage
+ *          jdk.compiler
+ * @build tests.*
+ * @run main/othervm DefaultProviderTest
+ */
+public class DefaultProviderTest {
+    private static final String NAME = "disable-toto";
+    private final static Map<String, Object> expectedOptions = new HashMap<>();
+
+    static {
+        expectedOptions.put("disable-toto", "false");
+        expectedOptions.put("option1", "value1");
+        expectedOptions.put("option2", "value2");
+    }
+
+    private static class Custom implements TransformerPlugin {
+        private boolean enabled = true;
+
+        @Override
+        public Set<PluginType> getType() {
+            Set<PluginType> set = new HashSet<>();
+            set.add(CATEGORY.TRANSFORMER);
+            return Collections.unmodifiableSet(set);
+        }
+
+        @Override
+        public Set<STATE> getState() {
+             return enabled ? EnumSet.of(STATE.AUTO_ENABLED, STATE.FUNCTIONAL)
+                : EnumSet.of(STATE.DISABLED);
+        }
+
+        @Override
+        public void visit(Pool in, Pool out) {
+            if (!enabled) {
+                throw new PluginException(NAME + " was set");
+            }
+
+            DefaultProviderTest.isNewPluginsCalled = true;
+            in.visit((Pool.ModuleData content) -> {
+                return content;
+            }, out);
+        }
+
+        @Override
+        public String getName() {
+            return NAME;
+        }
+
+        @Override
+        public String getDescription() {
+            return NAME;
+        }
+
+        @Override
+        public boolean hasArguments() {
+            return true;
+        }
+
+        @Override
+        public void configure(Map<String, String> config) {
+            if (config.containsKey(NAME)) {
+                enabled = !Boolean.parseBoolean(config.get(NAME));
+            }
+
+            if (enabled) {
+                DefaultProviderTest.receivedOptions = config;
+            } else {
+                DefaultProviderTest.receivedOptions = null;
+            }
+        }
+    }
+
+    private static boolean isNewPluginsCalled;
+    private static Map<String, String> receivedOptions;
+
+    private static void reset() {
+        isNewPluginsCalled = false;
+        receivedOptions = null;
+    }
+
+    public static void main(String[] args) throws Exception {
+        Helper helper = Helper.newHelper();
+        if (helper == null) {
+            System.err.println("Test not run");
+            return;
+        }
+        helper.generateDefaultModules();
+        test(helper, new Custom());
+    }
+
+    private static void test(Helper helper, Plugin plugin) throws Exception {
+        PluginRepository.registerPlugin(plugin);
+
+        {
+            String[] userOptions = {};
+            Path imageDir = helper.generateDefaultImage(userOptions, "composite2").assertSuccess();
+            helper.checkImage(imageDir, "composite2", null, null);
+            if (!isNewPluginsCalled) {
+                throw new Exception("Should have been called");
+            }
+            reset();
+        }
+
+        {
+            String[] userOptions = {"--disable-toto=false:option1=value1:option2=value2"};
+            Path imageDir = helper.generateDefaultImage(userOptions, "composite2").assertSuccess();
+            helper.checkImage(imageDir, "composite2", null, null);
+            if (!isNewPluginsCalled) {
+                throw new Exception("Should have been called");
+            }
+            if (!receivedOptions.equals(expectedOptions)) {
+                throw new Exception("Optional options " + receivedOptions + " are not expected one "
+                        + expectedOptions);
+            }
+            System.err.println("OPTIONS " + receivedOptions);
+            reset();
+        }
+
+        {
+            String[] userOptions = {"--disable-toto=true:option1=value1"};
+            Path imageDir = helper.generateDefaultImage(userOptions, "composite2").assertSuccess();
+            helper.checkImage(imageDir, "composite2", null, null);
+            if (isNewPluginsCalled) {
+                throw new Exception("Should not have been called");
+            }
+            if (receivedOptions != null) {
+                throw new Exception("Optional options are not expected");
+            }
+            reset();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/ImageFileCreatorTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteOrder;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Stream;
+import jdk.tools.jlink.internal.Archive;
+import jdk.tools.jlink.internal.ImageFileCreator;
+import jdk.tools.jlink.internal.ImagePluginStack;
+import jdk.tools.jlink.plugin.ExecutableImage;
+import jdk.tools.jlink.builder.ImageBuilder;
+import jdk.tools.jlink.plugin.Pool;
+
+
+/*
+ * @test
+ * @summary ImageFileCreator class test
+ * @author Jean-Francois Denise
+ * @modules jdk.jlink/jdk.tools.jlink.internal
+ *          java.base/jdk.internal.jimage
+ * @run main/othervm -verbose:gc -Xmx1g ImageFileCreatorTest
+ */
+public class ImageFileCreatorTest {
+
+    private static class TestArchive implements Archive {
+
+        private final String name;
+        private final List<Entry> entries = new ArrayList<>();
+
+        private TestArchive(String name, List<String> entries) {
+            this.name = name;
+            for (String p : entries) {
+                this.entries.add(new TestEntry(p, p));
+            }
+        }
+
+        @Override
+        public String moduleName() {
+            return name;
+        }
+
+        @Override
+        public Stream<Entry> entries() {
+            return entries.stream();
+        }
+
+        @Override
+        public Path getPath() {
+            return null;
+        }
+
+        @Override
+        public void open() throws IOException {
+        }
+
+        @Override
+        public void close() throws IOException {
+        }
+
+        private class TestEntry extends Entry {
+
+            TestEntry(String path, String name) {
+                super(TestArchive.this, path, name, Entry.EntryType.CLASS_OR_RESOURCE);
+            }
+
+            @Override
+            public long size() {
+                return 0;
+            }
+
+            @Override
+            public InputStream stream() throws IOException {
+                return new ByteArrayInputStream(new byte[0]);
+            }
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+
+        {
+            List<String> entries = new ArrayList<>();
+            entries.add("classes/class");
+            test(entries);
+        }
+
+        {
+            // Add an entry that is a directory, that is wrong
+            List<String> entries = new ArrayList<>();
+            entries.add("classes");
+            entries.add("classes/class");
+            test(entries);
+        }
+
+        {
+            // Add an entry that is wrongly prefixed by /
+            // /bad//classes/class is the resource added
+            // /bad/classes/class is the metadata node built.
+            List<String> entries = new ArrayList<>();
+            entries.add("/classes/class");
+            test(entries);
+        }
+
+        {
+            // Trailing '/' is wrong
+            List<String> entries = new ArrayList<>();
+            entries.add("classes/class/");
+            test(entries);
+        }
+
+        {
+            // Too much '/' characters
+            List<String> entries = new ArrayList<>();
+            entries.add("classes//class/");
+            test(entries);
+        }
+
+        {
+            // Too much '/' characters
+            List<String> entries = new ArrayList<>();
+            entries.add("classes/////class/");
+            test(entries);
+        }
+
+        {
+            // Single '/' character
+            List<String> entries = new ArrayList<>();
+            entries.add("/");
+            test(entries);
+        }
+
+        {
+            // 2 '/' characters
+            List<String> entries = new ArrayList<>();
+            entries.add("//");
+            test(entries);
+        }
+
+        {
+            // 3 '/' characters
+            List<String> entries = new ArrayList<>();
+            entries.add("///");
+            test(entries);
+        }
+
+        {
+            // no character
+            List<String> entries = new ArrayList<>();
+            entries.add("");
+            test(entries);
+        }
+
+        {
+            // all together
+            List<String> entries = new ArrayList<>();
+            entries.add("");
+            entries.add("///");
+            entries.add("//");
+            entries.add("/");
+            entries.add("classes/////class/");
+            entries.add("classes//class/");
+            entries.add("classes/class/");
+            entries.add("/classes/class");
+            entries.add("classes");
+            entries.add("classes/class");
+            test(entries);
+        }
+
+    }
+
+    private static void test(List<String> entries) throws Exception {
+        TestArchive arch = new TestArchive("bad", entries);
+        Set<Archive> archives = new HashSet<>();
+        archives.add(arch);
+        ImageBuilder noopBuilder = new ImageBuilder() {
+
+            @Override
+            public DataOutputStream getJImageOutputStream() {
+                return new DataOutputStream(new ByteArrayOutputStream());
+            }
+
+            @Override
+            public ExecutableImage getExecutableImage() {
+                return null;
+            }
+
+            @Override
+            public void storeFiles(Pool content, String bom) {
+
+            }
+
+        };
+
+        ImagePluginStack stack = new ImagePluginStack(noopBuilder, Collections.emptyList(),
+                null, Collections.emptyList(), "");
+
+        ImageFileCreator.create(archives, ByteOrder.nativeOrder(), stack);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/ImageFilePoolTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Test a pool containing external files.
+ * @author Andrei Eremeev
+ * @modules jdk.jlink/jdk.tools.jlink.internal
+ * @run build ImageFilePoolTest
+ * @run main ImageFilePoolTest
+ */
+
+import java.io.ByteArrayInputStream;
+import jdk.tools.jlink.internal.PoolImpl;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.Pool.ModuleDataType;
+import jdk.tools.jlink.plugin.Pool.Visitor;
+
+public class ImageFilePoolTest {
+    public static void main(String[] args) throws Exception {
+        new ImageFilePoolTest().test();
+    }
+
+    public void test() throws Exception {
+        checkNegative();
+        checkVisitor();
+    }
+
+    private static final String SUFFIX = "END";
+
+    private void checkVisitor() throws Exception {
+        Pool input = new PoolImpl();
+        for (int i = 0; i < 1000; ++i) {
+            String module = "module" + (i / 100);
+            input.add(new InMemoryImageFile(module, "/" + module + "/java/class" + i,
+                    ModuleDataType.CONFIG, "class" + i));
+        }
+        if (input.getContent().size() != 1000) {
+            throw new AssertionError();
+        }
+        Pool output = new PoolImpl();
+        ResourceVisitor visitor = new ResourceVisitor();
+        input.visit(visitor, output);
+        if (visitor.getAmountBefore() == 0) {
+            throw new AssertionError("Resources not found");
+        }
+        if (visitor.getAmountBefore() != input.getContent().size()) {
+            throw new AssertionError("Number of visited resources. Expected: " +
+                    visitor.getAmountBefore() + ", got: " + input.getContent().size());
+        }
+        if (visitor.getAmountAfter() != output.getContent().size()) {
+            throw new AssertionError("Number of added resources. Expected: " +
+                    visitor.getAmountAfter() + ", got: " + output.getContent().size());
+        }
+        for (ModuleData outFile : output.getContent()) {
+            String path = outFile.getPath().replaceAll(SUFFIX + "$", "");
+            ModuleData inFile = input.get(path);
+            if (inFile == null) {
+                throw new AssertionError("Unknown resource: " + path);
+            }
+        }
+    }
+
+    private static class ResourceVisitor implements Visitor {
+
+        private int amountBefore;
+        private int amountAfter;
+
+        @Override
+        public ModuleData visit(ModuleData file) {
+            int index = ++amountBefore % 3;
+            switch (index) {
+                case 0:
+                    ++amountAfter;
+                    return new InMemoryImageFile(file.getModule(), file.getPath() + SUFFIX,
+                            file.getType(), file.getPath());
+                case 1:
+                    ++amountAfter;
+                    return new InMemoryImageFile(file.getModule(), file.getPath(),
+                            file.getType(), file.getPath());
+            }
+            return null;
+        }
+
+        public int getAmountAfter() {
+            return amountAfter;
+        }
+
+        public int getAmountBefore() {
+            return amountBefore;
+        }
+    }
+
+    private void checkNegative() throws Exception {
+        PoolImpl input = new PoolImpl();
+        try {
+            input.add(null);
+            throw new AssertionError("NullPointerException is not thrown");
+        } catch (NullPointerException e) {
+            // expected
+        }
+        try {
+            input.contains(null);
+            throw new AssertionError("NullPointerException is not thrown");
+        } catch (NullPointerException e) {
+            // expected
+        }
+        if (input.get("unknown") != null) {
+            throw new AssertionError("ImageFilePool does not return null for unknown file");
+        }
+        if (input.contains(new InMemoryImageFile("", "unknown", ModuleDataType.CONFIG, "unknown"))) {
+            throw new AssertionError("'contain' returns true for unknown file");
+        }
+        input.add(new InMemoryImageFile("", "/aaa/bbb", ModuleDataType.CONFIG, ""));
+        try {
+            input.add(new InMemoryImageFile("", "/aaa/bbb", ModuleDataType.CONFIG, ""));
+            throw new AssertionError("Exception expected");
+        } catch (Exception e) {
+            // expected
+        }
+        input.setReadOnly();
+        try {
+            input.add(new InMemoryImageFile("", "/aaa/ccc", ModuleDataType.CONFIG, ""));
+            throw new AssertionError("Exception expected");
+        } catch (Exception e) {
+            // expected
+        }
+    }
+
+    private static class InMemoryImageFile extends ModuleData {
+        public InMemoryImageFile(String module, String path, ModuleDataType type, String content) {
+            super(module, path, type, new ByteArrayInputStream(content.getBytes()), content.getBytes().length);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/IntegrationTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,376 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import jdk.tools.jlink.Jlink;
+import jdk.tools.jlink.Jlink.JlinkConfiguration;
+import jdk.tools.jlink.Jlink.PluginsConfiguration;
+import jdk.tools.jlink.builder.DefaultImageBuilder;
+import jdk.tools.jlink.plugin.ExecutableImage;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.PostProcessorPlugin;
+import jdk.tools.jlink.plugin.TransformerPlugin;
+import jdk.tools.jlink.internal.plugins.DefaultCompressPlugin;
+import jdk.tools.jlink.internal.plugins.StripDebugPlugin;
+import jdk.tools.jlink.plugin.Plugin;
+
+import tests.Helper;
+import tests.JImageGenerator;
+
+/*
+ * @test
+ * @summary Test integration API
+ * @author Jean-Francois Denise
+ * @library ../lib
+ * @modules java.base/jdk.internal.jimage
+ *          jdk.jdeps/com.sun.tools.classfile
+ *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jlink.internal.plugins
+ *          jdk.jlink/jdk.tools.jmod
+ *          jdk.jlink/jdk.tools.jimage
+ *          jdk.compiler
+ * @build tests.*
+ * @run main IntegrationTest
+ */
+public class IntegrationTest {
+
+    private static final List<Integer> ordered = new ArrayList<>();
+
+    public static class MyPostProcessor implements PostProcessorPlugin {
+
+        public static final String NAME = "mypostprocessor";
+
+        @Override
+        public List<String> process(ExecutableImage image) {
+            try {
+                Files.createFile(image.getHome().resolve("toto.txt"));
+                return null;
+            } catch (IOException ex) {
+                throw new UncheckedIOException(ex);
+            }
+        }
+
+        @Override
+        public String getName() {
+            return NAME;
+        }
+
+        @Override
+        public Set<PluginType> getType() {
+            Set<PluginType> set = new HashSet<>();
+            set.add(CATEGORY.PROCESSOR);
+            return Collections.unmodifiableSet(set);
+        }
+
+        @Override
+        public void configure(Map<String, String> config) {
+            throw new UnsupportedOperationException("Shouldn't be called");
+        }
+    }
+
+    public static class MyPlugin1 implements TransformerPlugin {
+
+        Integer index;
+        Set<String> after;
+        Set<String> before;
+
+        private MyPlugin1(Integer index, Set<String> after, Set<String> before) {
+            this.index = index;
+            this.after = after;
+            this.before = before;
+        }
+
+        @Override
+        public Set<String> isAfter() {
+            return after;
+        }
+
+        @Override
+        public Set<String> isBefore() {
+            return before;
+        }
+
+        @Override
+        public String getName() {
+            return NAME + index;
+        }
+
+        @Override
+        public void visit(Pool in, Pool out) {
+            System.err.println(NAME + index);
+            ordered.add(index);
+            in.visit((file) -> {
+                return file;
+            }, out);
+        }
+
+        @Override
+        public Set<PluginType> getType() {
+            Set<PluginType> set = new HashSet<>();
+            set.add(CATEGORY.TRANSFORMER);
+            return Collections.unmodifiableSet(set);
+        }
+
+        @Override
+        public String getDescription() {
+            return null;
+        }
+
+        @Override
+        public String getOption() {
+            return null;
+        }
+        static final String NAME = "myprovider";
+        static final String INDEX = "INDEX";
+
+        @Override
+        public void configure(Map<String, String> config) {
+            throw new UnsupportedOperationException("Shouldn't be called");
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+
+        Helper helper = Helper.newHelper();
+        if (helper == null) {
+            System.err.println("Test not run");
+            return;
+        }
+        apitest();
+        test();
+        testOrder();
+        testCycleOrder();
+    }
+
+    private static void apitest() throws Exception {
+        boolean failed = false;
+        Jlink jl = new Jlink();
+
+        try {
+            jl.build(null);
+            failed = true;
+        } catch (Exception ex) {
+            // XXX OK
+        }
+        if (failed) {
+            throw new Exception("Should have failed");
+        }
+        System.out.println(jl);
+
+        JlinkConfiguration config
+                = new JlinkConfiguration(null, null, null, null);
+
+        System.out.println(config);
+
+        Plugin p = Jlink.newPlugin("toto", Collections.emptyMap(), null);
+        if (p != null) {
+            throw new Exception("Plugin should be null");
+        }
+
+        Plugin p2 = Jlink.newPlugin("compress", Collections.emptyMap(), null);
+        if (p2 == null) {
+            throw new Exception("Plugin should not be null");
+        }
+    }
+
+    private static void test() throws Exception {
+        Jlink jlink = new Jlink();
+        Path output = Paths.get("integrationout");
+        List<Path> modulePaths = new ArrayList<>();
+        File jmods
+                = JImageGenerator.getJModsDir(new File(System.getProperty("test.jdk")));
+        modulePaths.add(jmods.toPath());
+        Set<String> mods = new HashSet<>();
+        mods.add("java.management");
+        Set<String> limits = new HashSet<>();
+        limits.add("java.management");
+        JlinkConfiguration config = new Jlink.JlinkConfiguration(output,
+                modulePaths, mods, limits, null);
+
+        List<Plugin> lst = new ArrayList<>();
+
+        //Strip debug
+        {
+            Map<String, String> config1 = new HashMap<>();
+            config1.put(StripDebugPlugin.NAME, "");
+            Plugin strip = Jlink.newPlugin("strip-debug", config1, null);
+            lst.add(strip);
+        }
+        // compress
+        {
+            Map<String, String> config1 = new HashMap<>();
+            config1.put(DefaultCompressPlugin.NAME, "2");
+            Plugin compress
+                    = Jlink.newPlugin("compress", config1, null);
+            lst.add(compress);
+        }
+        // Post processor
+        {
+            lst.add(new MyPostProcessor());
+        }
+        // Image builder
+        DefaultImageBuilder builder = new DefaultImageBuilder(true, output);
+        PluginsConfiguration plugins
+                = new Jlink.PluginsConfiguration(lst, builder, null);
+
+        jlink.build(config, plugins);
+
+        if (!Files.exists(output)) {
+            throw new AssertionError("Directory not created");
+        }
+        File jimage = new File(output.toString(), "lib" + File.separator + "modules");
+        if (!jimage.exists()) {
+            throw new AssertionError("jimage not generated");
+        }
+        File bom = new File(output.toString(), "bom");
+        if (!bom.exists()) {
+            throw new AssertionError("bom not generated");
+        }
+        File release = new File(output.toString(), "release");
+        if (!release.exists()) {
+            throw new AssertionError("release not generated");
+        }
+
+        if (!Files.exists(output.resolve("toto.txt"))) {
+            throw new AssertionError("Post processing not called");
+        }
+
+    }
+
+    private static void testOrder() throws Exception {
+        Jlink jlink = new Jlink();
+        Path output = Paths.get("integrationout2");
+        List<Path> modulePaths = new ArrayList<>();
+        File jmods
+                = JImageGenerator.getJModsDir(new File(System.getProperty("test.jdk")));
+        modulePaths.add(jmods.toPath());
+        Set<String> mods = new HashSet<>();
+        mods.add("java.management");
+        Set<String> limits = new HashSet<>();
+        limits.add("java.management");
+        JlinkConfiguration config = new Jlink.JlinkConfiguration(output,
+                modulePaths, mods, limits, null);
+
+        List<Plugin> lst = new ArrayList<>();
+
+        // Order is Plug1>Plug2>Plug3
+        // Plug1
+
+
+        // TRANSFORMER 3, must be after 2.
+        {
+            Set<String> after = new HashSet<>();
+            after.add(MyPlugin1.NAME+"2");
+            lst.add(new MyPlugin1(3, after, Collections.emptySet()));
+        }
+
+        // TRANSFORMER 2, must be after 1.
+        {
+            Set<String> after = new HashSet<>();
+            after.add(MyPlugin1.NAME+"1");
+            lst.add(new MyPlugin1(2, after, Collections.emptySet()));
+        }
+
+        // TRANSFORMER 1
+        {
+            Set<String> before = new HashSet<>();
+            before.add(MyPlugin1.NAME+"2");
+            lst.add(new MyPlugin1(1, Collections.emptySet(), before));
+        }
+
+        // Image builder
+        DefaultImageBuilder builder = new DefaultImageBuilder(false, output);
+        PluginsConfiguration plugins
+                = new Jlink.PluginsConfiguration(lst, builder, null);
+
+        jlink.build(config, plugins);
+
+        if (ordered.isEmpty()) {
+            throw new AssertionError("Plugins not called");
+        }
+        List<Integer> clone = new ArrayList<>();
+        clone.addAll(ordered);
+        Collections.sort(clone);
+        if (!clone.equals(ordered)) {
+            throw new AssertionError("Ordered is not properly sorted" + ordered);
+        }
+    }
+
+    private static void testCycleOrder() throws Exception {
+        Jlink jlink = new Jlink();
+        Path output = Paths.get("integrationout3");
+        List<Path> modulePaths = new ArrayList<>();
+        File jmods
+                = JImageGenerator.getJModsDir(new File(System.getProperty("test.jdk")));
+        modulePaths.add(jmods.toPath());
+        Set<String> mods = new HashSet<>();
+        mods.add("java.management");
+        Set<String> limits = new HashSet<>();
+        limits.add("java.management");
+        JlinkConfiguration config = new Jlink.JlinkConfiguration(output,
+                modulePaths, mods, limits, null);
+
+        List<Plugin> lst = new ArrayList<>();
+
+        // packager 1
+        {
+            Set<String> before = new HashSet<>();
+            before.add(MyPlugin1.NAME+"2");
+            lst.add(new MyPlugin1(1, Collections.emptySet(), before));
+        }
+
+        // packager 2
+        {
+            Set<String> before = new HashSet<>();
+            before.add(MyPlugin1.NAME+"1");
+            lst.add(new MyPlugin1(2, Collections.emptySet(), before));
+        }
+
+        // Image builder
+        DefaultImageBuilder builder = new DefaultImageBuilder(false, output);
+        PluginsConfiguration plugins
+                = new Jlink.PluginsConfiguration(lst, builder, null);
+        boolean failed = false;
+        try {
+            jlink.build(config, plugins);
+            failed = true;
+        } catch (Exception ex) {
+            // XXX OK
+        }
+        if (failed) {
+            throw new AssertionError("Should have failed");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/JLink2Test.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+ /*
+ * @test
+ * @summary Test image creation
+ * @author Jean-Francois Denise
+ * @library ../lib
+ * @modules java.base/jdk.internal.jimage
+ *          jdk.jdeps/com.sun.tools.classfile
+ *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jmod
+ *          jdk.jlink/jdk.tools.jimage
+ *          jdk.compiler
+ * @build tests.*
+ * @run main/othervm -verbose:gc -Xmx1g JLink2Test
+ */
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.lang.reflect.Layer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
+import jdk.tools.jlink.internal.PluginRepository;
+import jdk.tools.jlink.plugin.Plugin;
+
+import tests.Helper;
+import tests.JImageGenerator;
+import tests.JImageValidator;
+
+public class JLink2Test {
+
+    public static void main(String[] args) throws Exception {
+        Helper helper = Helper.newHelper();
+        if (helper == null) {
+            System.err.println("Test not run");
+            return;
+        }
+        helper.generateDefaultModules();
+
+        // This test case must be first one, the JlinkTask is clean
+        // and reveals possible bug related to plugin options in defaults
+        // e. g.: --genbom
+        testBomFile(helper);
+        testSameNames(helper);
+        testModulePath(helper);
+        testOptions();
+    }
+
+    private static void testModulePath(Helper helper) throws IOException {
+        Path doesNotExist = helper.createNewImageDir("doesnotexist");
+        Path jar = helper.getJarDir().resolve("bad.jar");
+        JImageGenerator.getJLinkTask()
+                .pluginModulePath(doesNotExist)
+                .option("--help")
+                .call().assertSuccess();
+        Files.createFile(jar);
+        JImageGenerator.getJLinkTask()
+                .pluginModulePath(jar)
+                .option("--help")
+                .call().assertFailure("(\n|\r|.)*Error: Invalid modules in the plugins path: (\n|\r|.)*");
+        JImageGenerator.getJLinkTask()
+                .pluginModulePath(jar.getParent())
+                .option("--help")
+                .call().assertFailure("Error: Invalid modules in the plugins path: .*zip file is empty(\n|\r|.)*");
+        try (JarOutputStream out = new JarOutputStream(new FileOutputStream(jar.toFile()))) {
+            JarEntry entry = new JarEntry("class");
+            out.putNextEntry(entry);
+            out.write("AAAA".getBytes());
+            out.closeEntry();
+        }
+        JImageGenerator.getJLinkTask()
+                .pluginModulePath(jar.getParent())
+                .output(helper.createNewImageDir("crash"))
+                .addJmods(helper.getStdJmodsDir())
+                .addJmods(jar.getParent())
+                .addMods("bad")
+                .call().assertFailure("(\n|\r|.)*Error: jdk.tools.jlink.plugin.PluginException: module-info.class not found for bad module(\n|\r|.)*");
+        try (JarOutputStream out = new JarOutputStream(new FileOutputStream(jar.toFile()))) {
+            JarEntry entry = new JarEntry("classes");
+            out.putNextEntry(entry);
+            out.closeEntry();
+
+            entry = new JarEntry("classes/class");
+            out.putNextEntry(entry);
+            out.write("AAAA".getBytes());
+            out.closeEntry();
+        }
+        JImageGenerator.getJLinkTask()
+                .pluginModulePath(jar.getParent())
+                .output(helper.createNewImageDir("bad"))
+                .addJmods(jar.getParent())
+                .addJars(helper.getStdJmodsDir())
+                .addMods("bad")
+                .call().assertFailure("(\n|\r|.)*Error: jdk.tools.jlink.plugin.PluginException: module-info.class not found for bad module(\n|\r|.)*");
+    }
+
+    private static void testSameNames(Helper helper) throws Exception {
+        // Multiple modules with the same name in modulepath, take the first one in the path.
+        // First jmods then jars. So jmods are found, jars are hidden.
+        String[] jarClasses = {"amodule.jar.Main"};
+        String[] jmodsClasses = {"amodule.jmods.Main"};
+        helper.generateDefaultJarModule("amodule", Arrays.asList(jarClasses));
+        helper.generateDefaultJModule("amodule", Arrays.asList(jmodsClasses));
+        List<String> okLocations = new ArrayList<>();
+        okLocations.addAll(Helper.toLocation("amodule", Arrays.asList(jmodsClasses)));
+        Path image = helper.generateDefaultImage(new String[0], "amodule").assertSuccess();
+        JImageValidator validator = new JImageValidator("amodule", okLocations,
+                image.toFile(), Collections.emptyList(), Collections.emptyList());
+        validator.validate();
+    }
+
+    private static void testBomFile(Helper helper) throws Exception {
+        String[] userOptions = {
+            "--compress",
+            "2",
+            "--addmods",
+            "bomzip",
+            "--strip-debug",
+            "--genbom",
+            "--exclude-resources",
+            "*.jcov,*/META-INF/*"};
+        String moduleName = "bomzip";
+        helper.generateDefaultJModule(moduleName, "composite2");
+        Path imgDir = helper.generateDefaultImage(userOptions, moduleName).assertSuccess();
+        helper.checkImage(imgDir, moduleName, userOptions, null, null);
+        File bom = new File(imgDir.toFile(), "bom");
+        if (!bom.exists()) {
+            throw new RuntimeException(bom.getAbsolutePath() + " not generated");
+        }
+        String bomcontent = new String(Files.readAllBytes(bom.toPath()));
+        if (!bomcontent.contains("--strip-debug")
+                || !bomcontent.contains("--compress")
+                || !bomcontent.contains("--genbom")
+                || !bomcontent.contains("--exclude-resources *.jcov,"
+                        + "*/META-INF/*")
+                || !bomcontent.contains("--addmods bomzip")) {
+            throw new Exception("Not expected content in " + bom);
+        }
+    }
+
+    private static void testOptions() throws Exception {
+        List<Plugin> builtInPlugins = new ArrayList<>();
+        builtInPlugins.addAll(PluginRepository.getPlugins(Layer.boot()));
+        if(builtInPlugins.isEmpty()) {
+            throw new Exception("No builtin plugins");
+        }
+        List<String> options = new ArrayList<>();
+        for (Plugin p : builtInPlugins) {
+            if (p.getOption() == null) {
+                throw new Exception("Null option for " + p.getName());
+            }
+            if (options.contains(p.getName())) {
+                throw new Exception("Option " + p.getOption() + " used more than once");
+            }
+            options.add(p.getName());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/JLinkNegativeTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,355 @@
+/**
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Negative tests for jlink
+ * @bug 8130861
+ * @author Andrei Eremeev
+ * @library ../lib
+ * @modules java.base/jdk.internal.jimage
+ *          java.base/jdk.internal.module
+ *          jdk.jdeps/com.sun.tools.classfile
+ *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jmod
+ *          jdk.jlink/jdk.tools.jimage
+ *          jdk.compiler
+ * @build tests.*
+ * @run testng JLinkNegativeTest
+ */
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.module.ModuleDescriptor;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import jdk.internal.module.ModuleInfoWriter;
+import org.testng.SkipException;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import tests.Helper;
+import tests.JImageGenerator;
+import tests.JImageGenerator.InMemoryFile;
+import tests.Result;
+
+@Test
+public class JLinkNegativeTest {
+
+    private Helper helper;
+
+    @BeforeClass
+    public void setUp() throws IOException {
+        helper = Helper.newHelper();
+        if (helper == null) {
+            throw new SkipException("Not run");
+        }
+        helper.generateDefaultModules();
+    }
+
+    private void deleteDirectory(Path dir) throws IOException {
+        Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
+            @Override
+            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+                Files.delete(file);
+                return FileVisitResult.CONTINUE;
+            }
+
+            @Override
+            public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
+                Files.delete(dir);
+                return FileVisitResult.CONTINUE;
+            }
+        });
+    }
+
+    public void testModuleNotExist() {
+        helper.generateDefaultImage("failure1").assertFailure("Error: Module failure1 not found");
+    }
+
+    public void testNotExistInAddMods() {
+        // cannot find jmod from --addmods
+        JImageGenerator.getJLinkTask()
+                .modulePath(".")
+                .addMods("not_exist")
+                .output(helper.getImageDir().resolve("failure2"))
+                .call().assertFailure("Error: Module not_exist not found");
+    }
+
+    public void test() throws IOException {
+        helper.generateDefaultJModule("failure3");
+        Path image = helper.generateDefaultImage("failure3").assertSuccess();
+        JImageGenerator.getJLinkTask()
+                .modulePath(helper.defaultModulePath())
+                .output(image)
+                .addMods("leaf1")
+                .limitMods("leaf1")
+                .call().assertFailure("Error: directory already exists: .*failure3.image(\n|\r|.)*");
+    }
+
+    public void testOutputIsFile() throws IOException {
+        // output == file
+        Path image = helper.createNewImageDir("failure4");
+        Files.createFile(image);
+        JImageGenerator.getJLinkTask()
+                .modulePath(helper.defaultModulePath())
+                .output(image)
+                .addMods("leaf1")
+                .call().assertFailure("Error: directory already exists: .*failure4.image(\n|\r|.)*");
+    }
+
+    public void testModuleNotFound() {
+        // limit module is not found
+        Path imageFile = helper.createNewImageDir("test");
+        JImageGenerator.getJLinkTask()
+                .output(imageFile)
+                .addMods("leaf1")
+                .limitMods("leaf1")
+                .limitMods("failure5")
+                .modulePath(helper.defaultModulePath())
+                .call().assertFailure("Error: Module failure5 not found");
+    }
+
+    public void testJmodIsDir() throws IOException {
+        Path imageFile = helper.createNewImageDir("test");
+        Path dirJmod = helper.createNewJmodFile("dir");
+        Files.createDirectory(dirJmod);
+        try {
+            JImageGenerator.getJLinkTask()
+                    .output(imageFile)
+                    .addMods("dir")
+                    .modulePath(helper.defaultModulePath())
+                    .call().assertFailure("Error: Module dir not found");
+        } finally {
+            deleteDirectory(dirJmod);
+        }
+    }
+
+    public void testJarIsDir() throws IOException {
+        Path imageFile = helper.createNewImageDir("test");
+        Path dirJar = helper.createNewJarFile("dir");
+        Files.createDirectory(dirJar);
+        try {
+            JImageGenerator.getJLinkTask()
+                    .output(imageFile)
+                    .addMods("dir")
+                    .modulePath(helper.defaultModulePath())
+                    .call().assertFailure("Error: Module dir not found");
+        } finally {
+            deleteDirectory(dirJar);
+        }
+    }
+
+    public void testMalformedJar() throws IOException {
+        Path imageFile = helper.createNewImageDir("test");
+        Path jar = helper.createNewJarFile("not_zip");
+        Files.createFile(jar);
+        try {
+            JImageGenerator.getJLinkTask()
+                    .output(imageFile)
+                    .addMods("not_zip")
+                    .modulePath(helper.defaultModulePath())
+                    .call().assertFailure("Error: java.util.zip.ZipException: zip file is empty");
+        } finally {
+            deleteDirectory(jar);
+        }
+    }
+
+    public void testMalformedJmod() throws IOException {
+        Path imageFile = helper.createNewImageDir("test");
+        Path jmod = helper.createNewJmodFile("not_zip");
+        Files.createFile(jmod);
+        try {
+            JImageGenerator.getJLinkTask()
+                    .output(imageFile)
+                    .addMods("not_zip")
+                    .modulePath(helper.defaultModulePath())
+                    .call().assertFailure("Error: java.util.zip.ZipException: zip file is empty");
+        } finally {
+            deleteDirectory(jmod);
+        }
+    }
+
+    // Temporarily exclude; the jmod tool can no longer be used to create a jmod
+    // with a class in the unnamed package. Find another way, or remove.
+//    public void testAddDefaultPackage() throws IOException {
+//        String moduleName = "hacked1";
+//        Path module = helper.generateModuleCompiledClasses(helper.getJmodSrcDir(), helper.getJmodClassesDir(),
+//                moduleName, Arrays.asList("hacked1.Main", "A", "B"), "leaf1");
+//        JImageGenerator
+//                .getJModTask()
+//                .addClassPath(module)
+//                .jmod(helper.getJmodDir().resolve(moduleName + ".jmod"))
+//                .create().assertSuccess();
+//        Path image = helper.generateDefaultImage(moduleName).assertSuccess();
+//        helper.checkImage(image, moduleName, null, null);
+//    }
+
+    public void testAddSomeTopLevelFiles() throws IOException {
+        String moduleName = "hacked2";
+        Path module = helper.generateModuleCompiledClasses(helper.getJmodSrcDir(), helper.getJmodClassesDir(),
+                moduleName);
+        Files.createFile(module.resolve("top-level-file"));
+        Path jmod = JImageGenerator
+                .getJModTask()
+                .addClassPath(module)
+                .jmod(helper.getJmodDir().resolve(moduleName + ".jmod"))
+                .create().assertSuccess();
+        try {
+            Path image = helper.generateDefaultImage(moduleName).assertSuccess();
+            helper.checkImage(image, moduleName, null, null);
+        } finally {
+            deleteDirectory(jmod);
+        }
+    }
+
+    public void testAddNonStandardSection() throws IOException {
+        String moduleName = "hacked3";
+        Path module = helper.generateDefaultJModule(moduleName).assertSuccess();
+        JImageGenerator.addFiles(module, new InMemoryFile("unknown/A.class", new byte[0]));
+        try {
+            Result result = helper.generateDefaultImage(moduleName);
+            if (result.getExitCode() != 4) {
+                throw new AssertionError("Crash expected");
+            }
+            if (!result.getMessage().contains("java.lang.InternalError: unexpected entry: unknown")) {
+                System.err.println(result.getMessage());
+                throw new AssertionError("InternalError expected");
+            }
+        } finally {
+            deleteDirectory(module);
+        }
+    }
+
+    @Test(enabled = true)
+    public void testSectionsAreFiles() throws IOException {
+        String moduleName = "module";
+        Path jmod = helper.generateDefaultJModule(moduleName).assertSuccess();
+        JImageGenerator.addFiles(jmod,
+                new InMemoryFile("/native", new byte[0]),
+                new InMemoryFile("/conf", new byte[0]),
+                new InMemoryFile("/bin", new byte[0]));
+        try {
+            Result result = helper.generateDefaultImage(moduleName);
+            if (result.getExitCode() != 4) {
+                throw new AssertionError("Crash expected");
+            }
+            if (!result.getMessage().contains("java.lang.InternalError: unexpected entry: ")) {
+                System.err.println(result.getMessage());
+                throw new AssertionError("InternalError expected");
+            }
+        } finally {
+            deleteDirectory(jmod);
+        }
+    }
+
+    public void testDuplicateModule1() throws IOException {
+        String moduleName1 = "dupRes1Jmod1";
+        String moduleName2 = "dupRes1Jmod2";
+        List<String> classNames = Arrays.asList("java.A", "javax.B");
+        Path module1 = helper.generateModuleCompiledClasses(
+                helper.getJmodSrcDir(), helper.getJmodClassesDir(), moduleName1, classNames);
+        Path module2 = helper.generateModuleCompiledClasses(
+                helper.getJmodSrcDir(), helper.getJmodClassesDir(), moduleName2, classNames);
+
+        try (OutputStream out = Files.newOutputStream(module2.resolve("module-info.class"))) {
+            ModuleInfoWriter.write(new ModuleDescriptor.Builder(moduleName1)
+                    .requires("java.base").build(), out);
+        }
+
+        Path jmod1 = JImageGenerator.getJModTask()
+                .addClassPath(module1)
+                .jmod(helper.createNewJmodFile(moduleName1))
+                .create()
+                .assertSuccess();
+        Path jmod2 = JImageGenerator.getJModTask()
+                .addClassPath(module2)
+                .jmod(helper.createNewJmodFile(moduleName2))
+                .create()
+                .assertSuccess();
+        try {
+            helper.generateDefaultImage(moduleName1)
+                    .assertFailure("Error: Two versions of module dupRes1Jmod1 found in");
+        } finally {
+            deleteDirectory(jmod1);
+            deleteDirectory(jmod2);
+        }
+    }
+
+    public void testDuplicateModule2() throws IOException {
+        String moduleName = "dupRes2Jmod";
+        List<String> classNames = Arrays.asList("java.A", "javax.B");
+        Path module1 = helper.generateModuleCompiledClasses(
+                helper.getJmodSrcDir(), helper.getJmodClassesDir(), moduleName, classNames);
+        Path module2 = helper.generateModuleCompiledClasses(
+                helper.getJarSrcDir(), helper.getJarClassesDir(), moduleName, classNames);
+
+        Path jmod = JImageGenerator.getJModTask()
+                .addClassPath(module1)
+                .jmod(helper.createNewJmodFile(moduleName))
+                .create()
+                .assertSuccess();
+        Path jar = JImageGenerator.createJarFile(helper.getJarDir().resolve(moduleName + ".jar"), module2);
+        Path newJar = helper.getJmodDir().resolve(jar.getFileName());
+        Files.move(jar, newJar);
+        try {
+            helper.generateDefaultImage(moduleName)
+                    .assertFailure("Error: Two versions of module dupRes2Jmod found in");
+        } finally {
+            deleteDirectory(jmod);
+            deleteDirectory(newJar);
+        }
+    }
+
+    public void testDuplicateModule3() throws IOException {
+        String moduleName1 = "dupRes3Jar1";
+        String moduleName2 = "dupRes3Jar2";
+        List<String> classNames = Arrays.asList("java.A", "javax.B");
+        Path module1 = helper.generateModuleCompiledClasses(
+                helper.getJarSrcDir(), helper.getJarClassesDir(), moduleName1, classNames);
+        Path module2 = helper.generateModuleCompiledClasses(
+                helper.getJarSrcDir(), helper.getJarClassesDir(), moduleName2, classNames);
+
+        try (OutputStream out = Files.newOutputStream(module2.resolve("module-info.class"))) {
+            ModuleInfoWriter.write(new ModuleDescriptor.Builder(moduleName1)
+                    .requires("java.base").build(), out);
+        }
+
+        Path jar1 = JImageGenerator.createJarFile(helper.getJarDir().resolve(moduleName1 + ".jar"), module1);
+        Path jar2 = JImageGenerator.createJarFile(helper.getJarDir().resolve(moduleName2 + ".jar"), module2);
+        try {
+            helper.generateDefaultImage(moduleName1)
+                    .assertFailure("Error: Two versions of module dupRes3Jar1 found in");
+        } finally {
+            deleteDirectory(jar1);
+            deleteDirectory(jar2);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/JLinkOptimTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,374 @@
+
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Stream;
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.internal.org.objectweb.asm.tree.AbstractInsnNode;
+import jdk.internal.org.objectweb.asm.tree.ClassNode;
+import jdk.internal.org.objectweb.asm.tree.MethodInsnNode;
+import jdk.internal.org.objectweb.asm.tree.MethodNode;
+import jdk.internal.org.objectweb.asm.tree.TryCatchBlockNode;
+import jdk.tools.jlink.internal.PluginRepository;
+import jdk.tools.jlink.internal.PoolImpl;
+import jdk.tools.jlink.internal.plugins.OptimizationPlugin;
+import jdk.tools.jlink.internal.plugins.asm.AsmModulePool;
+import jdk.tools.jlink.internal.plugins.asm.AsmPlugin;
+import jdk.tools.jlink.internal.plugins.asm.AsmPools;
+import jdk.tools.jlink.internal.plugins.optim.ControlFlow;
+import jdk.tools.jlink.internal.plugins.optim.ControlFlow.Block;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Pool.ModuleData;
+
+import tests.Helper;
+import tests.JImageGenerator;
+
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+ /*
+ * @test
+ * @summary Test image creation with class optimization
+ * @author Jean-Francois Denise
+ * @library ../lib
+ * @modules java.base/jdk.internal.jimage
+ *          jdk.jdeps/com.sun.tools.classfile
+ *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jmod
+ *          jdk.jlink/jdk.tools.jimage
+ *          jdk.jlink/jdk.tools.jlink.internal.plugins
+ *          jdk.jlink/jdk.tools.jlink.internal.plugins.asm
+ *          jdk.jlink/jdk.tools.jlink.internal.plugins.optim
+ *          java.base/jdk.internal.org.objectweb.asm
+ *          java.base/jdk.internal.org.objectweb.asm.tree
+ *          java.base/jdk.internal.org.objectweb.asm.util
+ *          jdk.compiler
+ * @build tests.*
+ * @run main JLinkOptimTest
+ */
+public class JLinkOptimTest {
+
+    private static final String EXPECTED = "expected";
+    private static Helper helper;
+
+    public static class ControlFlowPlugin extends AsmPlugin {
+
+        private boolean called;
+        private int numMethods;
+        private int numBlocks;
+
+        private static final String NAME = "test-optim";
+
+        private ControlFlowPlugin() {
+        }
+
+        @Override
+        public void visit(AsmPools pools) {
+            called = true;
+            for (AsmModulePool p : pools.getModulePools()) {
+
+                p.visitClassReaders((reader) -> {
+                    ClassNode cn = new ClassNode();
+                    if ((reader.getAccess() & Opcodes.ACC_INTERFACE) == 0) {
+                        reader.accept(cn, ClassReader.EXPAND_FRAMES);
+                        for (MethodNode m : cn.methods) {
+                            if ((m.access & Opcodes.ACC_ABSTRACT) == 0
+                                    && (m.access & Opcodes.ACC_NATIVE) == 0) {
+                                numMethods += 1;
+                                try {
+                                    ControlFlow f
+                                            = ControlFlow.createControlFlow(cn.name, m);
+                                    for (Block b : f.getBlocks()) {
+                                        numBlocks += 1;
+                                        f.getClosure(b);
+                                    }
+                                } catch (Throwable ex) {
+                                    //ex.printStackTrace();
+                                    throw new RuntimeException("Exception in "
+                                            + cn.name + "." + m.name, ex);
+                                }
+                            }
+                        }
+                    }
+                    return null;
+                });
+            }
+        }
+
+        @Override
+        public String getName() {
+            return NAME;
+        }
+
+        @Override
+        public Set<PluginType> getType() {
+            Set<PluginType> set = new HashSet<>();
+            set.add(CATEGORY.TRANSFORMER);
+            return Collections.unmodifiableSet(set);
+        }
+    }
+
+    private static void testForName() throws Exception {
+        String moduleName = "optimplugin";
+        Path src = Paths.get(System.getProperty("test.src")).resolve(moduleName);
+        Path classes = helper.getJmodClassesDir().resolve(moduleName);
+        JImageGenerator.compile(src, classes);
+
+        FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
+        Path root = fs.getPath("/modules/java.base");
+        // Access module-info.class to be reused as fake module-info.class
+        List<ModuleData> javabaseResources = new ArrayList<>();
+        try (Stream<Path> stream = Files.walk(root)) {
+            for (Iterator<Path> iterator = stream.iterator(); iterator.hasNext();) {
+                Path p = iterator.next();
+                if (Files.isRegularFile(p)) {
+                    try {
+                        javabaseResources.add(Pool.newResource(p.toString().
+                                substring("/modules".length()), Files.readAllBytes(p)));
+                    } catch (Exception ex) {
+                        throw new RuntimeException(ex);
+                    }
+                }
+            }
+        }
+
+        //forName folding
+        PoolImpl pool = new PoolImpl();
+        byte[] content = Files.readAllBytes(classes.
+                resolve("optim").resolve("ForNameTestCase.class"));
+        byte[] content2 = Files.readAllBytes(classes.
+                resolve("optim").resolve("AType.class"));
+        byte[] mcontent = Files.readAllBytes(classes.resolve("module-info.class"));
+
+        pool.add(Pool.newResource("/optimplugin/optim/ForNameTestCase.class", content));
+        pool.add(Pool.newResource("/optimplugin/optim/AType.class", content2));
+        pool.add(Pool.newResource("/optimplugin/module-info.class", mcontent));
+
+        for (ModuleData r : javabaseResources) {
+            pool.add(r);
+        }
+
+        OptimizationPlugin plugin = new OptimizationPlugin();
+        Map<String, String> optional = new HashMap<>();
+        optional.put(OptimizationPlugin.NAME, OptimizationPlugin.FORNAME_REMOVAL);
+        optional.put(OptimizationPlugin.LOG, "forName.log");
+        plugin.configure(optional);
+        Pool out = new PoolImpl();
+        plugin.visit(pool, out);
+
+        ModuleData result = out.getContent().iterator().next();
+
+        ClassReader optimReader = new ClassReader(result.getBytes());
+        ClassNode optimClass = new ClassNode();
+        optimReader.accept(optimClass, ClassReader.EXPAND_FRAMES);
+
+        if (!optimClass.name.equals("optim/ForNameTestCase")) {
+            throw new Exception("Invalid class " + optimClass.name);
+        }
+        if (optimClass.methods.size() < 2) {
+            throw new Exception("Not enough methods in new class");
+        }
+        for (MethodNode mn : optimClass.methods) {
+            if (!mn.name.contains("forName") && !mn.name.contains("<clinit>")) {
+                continue;
+            }
+            if (mn.name.startsWith("negative")) {
+                checkForName(mn);
+            } else {
+                checkNoForName(mn);
+            }
+        }
+        Map<String, byte[]> newClasses = new HashMap<>();
+        newClasses.put("optim.ForNameTestCase", result.getBytes());
+        newClasses.put("optim.AType", content2);
+        MemClassLoader loader = new MemClassLoader(newClasses);
+        Class<?> loaded = loader.loadClass("optim.ForNameTestCase");
+        if (loaded.getDeclaredMethods().length < 2) {
+            throw new Exception("Not enough methods in new class");
+        }
+        for (Method m : loaded.getDeclaredMethods()) {
+            if (m.getName().contains("Exception")) {
+                try {
+                    m.invoke(null);
+                } catch (Exception ex) {
+                    //ex.getCause().printStackTrace();
+                    if (!ex.getCause().getMessage().equals(EXPECTED)) {
+                        throw new Exception("Unexpected exception " + ex);
+                    }
+                }
+            } else if (!m.getName().startsWith("negative")) {
+                Class<?> clazz = (Class<?>) m.invoke(null);
+                if (clazz != String.class && clazz != loader.findClass("optim.AType")) {
+                    throw new Exception("Invalid class " + clazz);
+                }
+            }
+        }
+    }
+
+    private static void checkNoForName(MethodNode m) throws Exception {
+        Iterator<AbstractInsnNode> it = m.instructions.iterator();
+        while (it.hasNext()) {
+            AbstractInsnNode n = it.next();
+            if (n instanceof MethodInsnNode) {
+                MethodInsnNode met = (MethodInsnNode) n;
+                if (met.name.equals("forName")
+                        && met.owner.equals("java/lang/Class")
+                        && met.desc.equals("(Ljava/lang/String;)Ljava/lang/Class;")) {
+                    throw new Exception("forName not removed in " + m.name);
+                }
+            }
+        }
+        for (TryCatchBlockNode tcb : m.tryCatchBlocks) {
+            if (tcb.type.equals(ClassNotFoundException.class.getName().replaceAll("\\.", "/"))) {
+                throw new Exception("ClassNotFoundException Block not removed for " + m.name);
+            }
+        }
+    }
+
+    private static void checkForName(MethodNode m) throws Exception {
+        Iterator<AbstractInsnNode> it = m.instructions.iterator();
+        boolean found = false;
+        while (it.hasNext()) {
+            AbstractInsnNode n = it.next();
+            if (n instanceof MethodInsnNode) {
+                MethodInsnNode met = (MethodInsnNode) n;
+                if (met.name.equals("forName")
+                        && met.owner.equals("java/lang/Class")
+                        && met.desc.equals("(Ljava/lang/String;)Ljava/lang/Class;")) {
+                    found = true;
+                    break;
+                }
+            }
+        }
+        if (!found) {
+            throw new Exception("forName removed but shouldn't have");
+        }
+        found = false;
+        for (TryCatchBlockNode tcb : m.tryCatchBlocks) {
+            if (tcb.type.equals(ClassNotFoundException.class.getName().replaceAll("\\.", "/"))) {
+                found = true;
+                break;
+            }
+        }
+        if (!found) {
+            throw new Exception("tryCatchBlocks removed but shouldn't have");
+        }
+    }
+
+    static class MemClassLoader extends ClassLoader {
+
+        private final Map<String, byte[]> classes;
+        private final Map<String, Class<?>> cache = new HashMap<>();
+
+        MemClassLoader(Map<String, byte[]> classes) {
+            super(null);
+            this.classes = classes;
+        }
+
+        @Override
+        public Class findClass(String name) throws ClassNotFoundException {
+            Class<?> clazz = cache.get(name);
+            if (clazz == null) {
+                byte[] b = classes.get(name);
+                if (b == null) {
+                    return super.findClass(name);
+                } else {
+                    clazz = defineClass(name, b, 0, b.length);
+                    cache.put(name, clazz);
+                }
+            }
+            return clazz;
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        helper = Helper.newHelper();
+        if (helper == null) {
+            System.err.println("Test not run");
+            return;
+        }
+
+        testForName();
+
+        helper.generateDefaultModules();
+        helper.generateDefaultJModule("optim1", "java.se");
+        {
+            String[] userOptions = {"--class-optim=all:log=./class-optim-log.txt"};
+
+            Path imageDir = helper.generateDefaultImage(userOptions, "optim1").assertSuccess();
+            helper.checkImage(imageDir, "optim1", null, null);
+        }
+
+        /*{
+         Path dir = Paths.get("dir.log");
+         Files.createDirectory(dir);
+         String[] userOptions = {"--class-optim=all:log=" + dir.toString()};
+         helper.generateDefaultImage(userOptions, "optim1")
+         .assertFailure("java.io.FileNotFoundException: dir.log (Is a directory)");
+         }*/
+ /*{
+         String[] userOptions = {"--class-optim", "UNKNOWN"};
+         helper.generateDefaultImage(userOptions, "optim1").assertFailure("Unknown optimization");
+         }*/
+        {
+            String[] userOptions = {"--class-optim=forName-folding:log=./class-optim-log.txt"};
+            Path imageDir = helper.generateDefaultImage(userOptions, "optim1").assertSuccess();
+            helper.checkImage(imageDir, "optim1", null, null);
+        }
+
+        {
+            ControlFlowPlugin plugin = new ControlFlowPlugin();
+            PluginRepository.registerPlugin(plugin);
+            String[] userOptions = {"--test-optim"};
+            Path imageDir = helper.generateDefaultImage(userOptions, "optim1").assertSuccess();
+            helper.checkImage(imageDir, "optim1", null, null);
+            //System.out.println("Num methods analyzed " + provider.numMethods
+            //        + "num blocks " + provider.numBlocks);
+            if (!plugin.called) {
+                throw new Exception("Plugin not called");
+            }
+            if (plugin.numMethods < 1000) {
+                throw new Exception("Not enough method called,  should be "
+                        + "around 10000 but is " + plugin.numMethods);
+            }
+            if (plugin.numBlocks < 100000) {
+                throw new Exception("Not enough blocks,  should be "
+                        + "around 640000 but is " + plugin.numMethods);
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/JLinkOptionsTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.internal.PluginRepository;
+import jdk.tools.jlink.plugin.TransformerPlugin;
+
+import tests.Helper;
+
+/*
+ * @test
+ * @summary Test jlink options
+ * @author Jean-Francois Denise
+ * @library ../lib
+ * @modules java.base/jdk.internal.jimage
+ *          jdk.jdeps/com.sun.tools.classfile
+ *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jmod
+ *          jdk.jlink/jdk.tools.jimage
+ *          jdk.compiler
+ * @build tests.*
+ * @run main JLinkOptionsTest
+ */
+public class JLinkOptionsTest {
+
+    private static class TestPlugin implements TransformerPlugin {
+        private final String name;
+        private final String option;
+
+        private TestPlugin(String name, String option) {
+            this.name = name;
+            this.option = option;
+        }
+
+
+        @Override
+        public String getOption() {
+            return option;
+        }
+
+        @Override
+        public void visit(Pool in, Pool out) {
+
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
+
+        @Override
+        public String getDescription() {
+            return name;
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        Helper helper = Helper.newHelper();
+        if (helper == null) {
+            System.err.println("Test not run");
+            return;
+        }
+        helper.generateDefaultModules();
+        {
+            // multiple plugins with same option
+
+            PluginRepository.
+                    registerPlugin(new TestPlugin("test1", "test1"));
+            PluginRepository.
+                    registerPlugin(new TestPlugin("test2", "test1"));
+            helper.generateDefaultImage("composite2").assertFailure("Error: More than one plugin enabled by test1 option");
+            PluginRepository.unregisterPlugin("test1");
+            PluginRepository.unregisterPlugin("test2");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/JLinkPluginsTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collections;
+
+import tests.Helper;
+
+/*
+ * @test
+ * @summary Test image creation
+ * @author Jean-Francois Denise
+ * @library ../lib
+ * @modules java.base/jdk.internal.jimage
+ *          jdk.jdeps/com.sun.tools.classfile
+ *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jmod
+ *          jdk.jlink/jdk.tools.jimage
+ *          jdk.compiler
+ * @build tests.*
+ * @run main/othervm -verbose:gc -Xmx1g JLinkPluginsTest
+ */
+public class JLinkPluginsTest {
+
+    private static String createProperties(String fileName, String content) throws IOException {
+        Path p = Paths.get(fileName);
+        Files.write(p, Collections.singletonList(content));
+        return p.toAbsolutePath().toString();
+    }
+
+    public static void main(String[] args) throws Exception {
+        Helper helper = Helper.newHelper();
+        if (helper == null) {
+            System.err.println("Test not run");
+            return;
+        }
+        helper.generateDefaultModules();
+        {
+            // Skip debug
+            String[] userOptions = {"--strip-debug"};
+            String moduleName = "skipdebugcomposite";
+            helper.generateDefaultJModule(moduleName, "composite2");
+            Path imageDir = helper.generateDefaultImage(userOptions, moduleName).assertSuccess();
+            helper.checkImage(imageDir, moduleName, null, null);
+        }
+        {
+            // Filter out files
+            String[] userOptions = {"--exclude-resources", "*.jcov, */META-INF/*"};
+            String moduleName = "excludecomposite";
+            helper.generateDefaultJModule(moduleName, "composite2");
+            String[] res = {".jcov", "/META-INF/"};
+            Path imageDir = helper.generateDefaultImage(userOptions, moduleName).assertSuccess();
+            helper.checkImage(imageDir, moduleName, res, null);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/JLinkPostProcessingTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import jdk.tools.jlink.internal.PluginRepository;
+import jdk.tools.jlink.plugin.ExecutableImage;
+import jdk.tools.jlink.plugin.PostProcessorPlugin;
+import tests.Helper;
+
+/*
+ * @test
+ * @summary Test post processing
+ * @author Jean-Francois Denise
+ * @library ../lib
+ * @modules java.base/jdk.internal.jimage
+ *          jdk.jdeps/com.sun.tools.classfile
+ *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jmod
+ *          jdk.jlink/jdk.tools.jimage
+ *          jdk.compiler
+ * @build tests.*
+ * @run main/othervm JLinkPostProcessingTest
+ */
+public class JLinkPostProcessingTest {
+
+    private static class PPPlugin implements PostProcessorPlugin {
+
+        private static ExecutableImage called;
+        private static final String NAME = "pp";
+
+        @Override
+        public List<String> process(ExecutableImage image) {
+            called = image;
+            Path gen = image.getHome().resolve("lib").resolve("toto.txt");
+            try {
+                Files.createFile(gen);
+            } catch (IOException ex) {
+                throw new UncheckedIOException(ex);
+            }
+            return null;
+        }
+
+        @Override
+        public String getName() {
+            return NAME;
+        }
+
+        @Override
+        public Set<PluginType> getType() {
+            Set<PluginType> set = new HashSet<>();
+            set.add(CATEGORY.PROCESSOR);
+            return Collections.unmodifiableSet(set);
+        }
+
+        @Override
+        public String getDescription() {
+            return NAME;
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+
+        Helper helper = Helper.newHelper();
+        if (helper == null) {
+            System.err.println("Test not run");
+            return;
+        }
+        helper.generateDefaultModules();
+
+        PluginRepository.registerPlugin(new PPPlugin());
+
+        // Generate an image and post-process in same jlink execution.
+        {
+            String[] userOptions = {"--pp"};
+            String moduleName = "postprocessing1";
+            helper.generateDefaultJModule(moduleName, "composite2");
+            String[] res = {};
+            String[] files = {};
+            Path imageDir = helper.generateDefaultImage(userOptions, moduleName).assertSuccess();
+            helper.checkImage(imageDir, moduleName, res, files);
+
+            test(imageDir);
+        }
+
+        // Generate an image, post-process in 2 jlink executions.
+        {
+            String[] userOptions = {};
+            String moduleName = "postprocessing2";
+            helper.generateDefaultJModule(moduleName, "composite2");
+            String[] res = {};
+            String[] files = {};
+            Path imageDir = helper.generateDefaultImage(userOptions, moduleName).assertSuccess();
+            helper.checkImage(imageDir, moduleName, res, files);
+
+            String[] ppOptions = {"--pp"};
+            helper.postProcessImage(imageDir, ppOptions);
+            test(imageDir);
+        }
+    }
+
+    private static void test(Path imageDir)
+            throws Exception {
+        if (PPPlugin.called == null) {
+            throw new Exception("Post processor not called.");
+        }
+        if (!PPPlugin.called.getHome().equals(imageDir)) {
+            throw new Exception("Not right imageDir " + PPPlugin.called.getHome());
+        }
+        if (PPPlugin.called.getExecutionArgs().isEmpty()) {
+            throw new Exception("No arguments to run java...");
+        }
+        Path gen = imageDir.resolve("lib").resolve("toto.txt");
+        if (!Files.exists(gen)) {
+            throw new Exception("Generated file doesn;t exist");
+        }
+        PPPlugin.called = null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/JLinkTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.Layer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Stream;
+
+import jdk.tools.jlink.plugin.Plugin;
+import jdk.tools.jlink.internal.PluginRepository;
+import tests.Helper;
+import tests.JImageGenerator;
+import tests.JImageGenerator.InMemoryFile;
+
+/*
+ * @test
+ * @summary Test image creation
+ * @author Jean-Francois Denise
+ * @library ../lib
+ * @modules java.base/jdk.internal.jimage
+ *          jdk.jdeps/com.sun.tools.classfile
+ *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jmod
+ *          jdk.jlink/jdk.tools.jimage
+ *          jdk.compiler
+ * @build tests.*
+ * @run main/othervm -verbose:gc -Xmx1g JLinkTest
+ */
+public class JLinkTest {
+
+    public static void main(String[] args) throws Exception {
+
+        Helper helper = Helper.newHelper();
+        if (helper == null) {
+            System.err.println("Test not run");
+            return;
+        }
+        helper.generateDefaultModules();
+        int numPlugins = 12;
+        {
+            // number of built-in plugins
+            List<Plugin> builtInPlugins = new ArrayList<>();
+            builtInPlugins.addAll(PluginRepository.getPlugins(Layer.boot()));
+            for (Plugin p : builtInPlugins) {
+                p.getState();
+                p.getType();
+            }
+            if (builtInPlugins.size() != numPlugins) {
+                throw new AssertionError("Found plugins doesn't match expected number : " +
+                        numPlugins + "\n" + builtInPlugins);
+            }
+        }
+
+        {
+            String moduleName = "bug8134651";
+            JImageGenerator.getJLinkTask()
+                    .modulePath(helper.defaultModulePath())
+                    .output(helper.createNewImageDir(moduleName))
+                    .addMods("leaf1")
+                    .option("")
+                    .call().assertSuccess();
+            JImageGenerator.getJLinkTask()
+                    .modulePath(helper.defaultModulePath())
+                    .addMods("leaf1")
+                    .option("--output")
+                    .option("")
+                    .call().assertFailure("Error: no value given for --output");
+            JImageGenerator.getJLinkTask()
+                    .modulePath("")
+                    .output(helper.createNewImageDir(moduleName))
+                    .addMods("leaf1")
+                    .option("")
+                    .call().assertFailure("Error: no value given for --modulepath");
+        }
+
+        {
+            String moduleName = "filter";
+            Path jmod = helper.generateDefaultJModule(moduleName).assertSuccess();
+            String className = "_A.class";
+            JImageGenerator.addFiles(jmod, new InMemoryFile(className, new byte[0]));
+            Path image = helper.generateDefaultImage(moduleName).assertSuccess();
+            helper.checkImage(image, moduleName, new String[] {"/" + moduleName + "/" + className}, null);
+        }
+
+        {
+            // Help
+            StringWriter writer = new StringWriter();
+            jdk.tools.jlink.internal.Main.run(new String[]{"--help"}, new PrintWriter(writer));
+            String output = writer.toString();
+            if (output.split("\n").length < 10) {
+                System.err.println(output);
+                throw new AssertionError("Help");
+            }
+        }
+
+        {
+            // License files
+            String copied = "LICENSE";
+            String[] arr = copied.split(",");
+            String[] copyFiles = new String[2];
+            copyFiles[0] = "--copy-files";
+            copyFiles[1] = copied;
+            Path imageDir = helper.generateDefaultImage(copyFiles, "composite2").assertSuccess();
+            helper.checkImage(imageDir, "composite2", null, null, arr);
+        }
+
+        {
+            // List plugins
+            StringWriter writer = new StringWriter();
+            jdk.tools.jlink.internal.Main.run(new String[]{"--list-plugins"}, new PrintWriter(writer));
+            String output = writer.toString();
+            long number = Stream.of(output.split("\\R"))
+                    .filter((s) -> s.matches("Plugin Name:.*"))
+                    .count();
+            if (number != numPlugins) {
+                System.err.println(output);
+                throw new AssertionError("Found: " + number + " expected " + numPlugins);
+            }
+        }
+
+        // filter out files and resources + Skip debug + compress
+        {
+            String[] userOptions = {"--compress", "2", "--strip-debug",
+                "--exclude-resources", "*.jcov, */META-INF/*", "--exclude-files",
+                "*" + Helper.getDebugSymbolsExtension()};
+            String moduleName = "excludezipskipdebugcomposite2";
+            helper.generateDefaultJModule(moduleName, "composite2");
+            String[] res = {".jcov", "/META-INF/"};
+            String[] files = {Helper.getDebugSymbolsExtension()};
+            Path imageDir = helper.generateDefaultImage(userOptions, moduleName).assertSuccess();
+            helper.checkImage(imageDir, moduleName, res, files);
+        }
+
+        // filter out + Skip debug + compress with filter + sort resources
+        {
+            String[] userOptions2 = {"--compress=2:compress-filter=^/java.base/*",
+                "--strip-debug", "--exclude-resources",
+                "*.jcov, */META-INF/*", "--sort-resources",
+                "*/module-info.class,/sortcomposite2/*,*/javax/management/*"};
+            String moduleName = "excludezipfilterskipdebugcomposite2";
+            helper.generateDefaultJModule(moduleName, "composite2");
+            String[] res = {".jcov", "/META-INF/"};
+            Path imageDir = helper.generateDefaultImage(userOptions2, moduleName).assertSuccess();
+            helper.checkImage(imageDir, moduleName, res, null);
+        }
+
+        // default compress
+        {
+            testCompress(helper, "compresscmdcomposite2", "--compress", "2");
+        }
+
+        {
+            testCompress(helper, "compressfiltercmdcomposite2",
+                    "--compress=2:filter=^/java.base/java/lang/*");
+        }
+
+        // compress 0
+        {
+            testCompress(helper, "compress0filtercmdcomposite2",
+                    "--compress=0:filter=^/java.base/java/lang/*");
+        }
+
+        // compress 1
+        {
+            testCompress(helper, "compress1filtercmdcomposite2",
+                    "--compress=1:filter=^/java.base/java/lang/*");
+        }
+
+        // compress 2
+        {
+            testCompress(helper, "compress2filtercmdcomposite2",
+                    "--compress=2:filter=^/java.base/java/lang/*");
+        }
+
+        // invalid compress level
+        {
+            String[] userOptions = {"--compress", "invalid"};
+            String moduleName = "invalidCompressLevel";
+            helper.generateDefaultJModule(moduleName, "composite2");
+            helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: Invalid level invalid");
+        }
+
+        // @file
+        {
+            Path path = Paths.get("embedded.properties");
+            Files.write(path, Collections.singletonList("--strip-debug --addmods " +
+                    "toto.unknown --compress UNKNOWN\n"));
+            String[] userOptions = {"@", path.toAbsolutePath().toString()};
+            String moduleName = "configembeddednocompresscomposite2";
+            helper.generateDefaultJModule(moduleName, "composite2");
+            Path imageDir = helper.generateDefaultImage(userOptions, moduleName).assertSuccess();
+            helper.checkImage(imageDir, moduleName, null, null);
+        }
+
+    }
+
+    private static void testCompress(Helper helper, String moduleName, String... userOptions) throws IOException {
+        helper.generateDefaultJModule(moduleName, "composite2");
+        Path imageDir = helper.generateDefaultImage(userOptions, moduleName).assertSuccess();
+        helper.checkImage(imageDir, moduleName, null, null);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/NativeTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Test config, cmd and lib directories of jmod.
+ * @author Andrei Eremeev
+ * @library ../lib
+ * @modules java.base/jdk.internal.jimage
+ *          jdk.jdeps/com.sun.tools.classfile
+ *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jmod
+ *          jdk.jlink/jdk.tools.jimage
+ *          jdk.compiler
+ * @build tests.*
+ * @run main NativeTest
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+
+import tests.Helper;
+import tests.JImageGenerator;
+
+public class NativeTest {
+
+    private final Helper helper;
+
+    public NativeTest(Helper helper) {
+        this.helper = helper;
+    }
+
+    public static void main(String[] args) throws IOException {
+        Helper helper = Helper.newHelper();
+        if (helper == null) {
+            System.err.println("Not run");
+            return;
+        }
+        new NativeTest(helper).test();
+    }
+
+    public void test() throws IOException {
+        String moduleName = "native_library";
+        Path classesDir = helper.generateModuleCompiledClasses(
+                helper.getJmodSrcDir(), helper.getJmodClassesDir(), moduleName);
+        Path libsDir = helper.getJmodDir().resolve("lib").resolve(moduleName);
+        Path configDir = helper.getJmodDir().resolve("config").resolve(moduleName);
+        Path cmdDir = helper.getJmodDir().resolve("cmd").resolve(moduleName);
+
+        Path config = writeFile(configDir.resolve("config.txt"), "AAAA\nBBBB");
+        Path cmd = writeFile(cmdDir.resolve("ls.sh"), "ls");
+        Path lib = writeFile(libsDir.resolve("native.so"), "native library");
+
+        JImageGenerator.getJModTask()
+                .addClassPath(classesDir)
+                .addNativeLibraries(libsDir)
+                .addCmds(cmdDir)
+                .addConfig(configDir)
+                .jmod(helper.createNewJmodFile(moduleName))
+                .create()
+                .assertSuccess();
+
+        String[] expectedFiles = new String[] {
+                "bin" + File.separator + cmd.getFileName(),
+                "conf" + File.separator + config.getFileName(),
+                "lib" + File.separator + lib.getFileName()
+        };
+        Path image = JImageGenerator.getJLinkTask()
+                .modulePath(helper.defaultModulePath())
+                .addMods(moduleName)
+                .output(helper.createNewImageDir(moduleName))
+                .call().assertSuccess();
+        helper.checkImage(image, moduleName, null, null, expectedFiles);
+    }
+
+    private Path writeFile(Path path, String content) throws IOException {
+        if (path.getParent() != null) {
+            Files.createDirectories(path.getParent());
+        }
+        Files.write(path, Arrays.asList(content.split("\n")));
+        return path;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/ResourcePoolTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Test a pool containing jimage resources and classes.
+ * @author Jean-Francois Denise
+ * @modules jdk.jlink/jdk.tools.jlink.internal
+ * @run build ResourcePoolTest
+ * @run main ResourcePoolTest
+ */
+
+import java.io.ByteArrayInputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import jdk.tools.jlink.internal.PoolImpl;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Pool.Module;
+import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.Pool.ModuleDataType;
+import jdk.tools.jlink.plugin.Pool.Visitor;
+
+public class ResourcePoolTest {
+
+    public static void main(String[] args) throws Exception {
+        new ResourcePoolTest().test();
+    }
+
+    public void test() throws Exception {
+        checkResourceAdding();
+        checkResourceVisitor();
+        checkResourcesAfterCompression();
+    }
+
+    private static final String SUFFIX = "END";
+
+    private void checkResourceVisitor() throws Exception {
+        Pool input = new PoolImpl();
+        for (int i = 0; i < 1000; ++i) {
+            String module = "/module" + (i / 10);
+            String resourcePath = module + "/java/package" + i;
+            byte[] bytes = resourcePath.getBytes();
+            input.add(new ModuleData(module, resourcePath,
+                    ModuleDataType.CLASS_OR_RESOURCE,
+                    new ByteArrayInputStream(bytes), bytes.length));
+        }
+        Pool output = new PoolImpl();
+        ResourceVisitor visitor = new ResourceVisitor();
+        input.visit(visitor, output);
+        if (visitor.getAmountBefore() == 0) {
+            throw new AssertionError("Resources not found");
+        }
+        if (visitor.getAmountBefore() != input.getContent().size()) {
+            throw new AssertionError("Number of visited resources. Expected: " +
+                    visitor.getAmountBefore() + ", got: " + input.getContent().size());
+        }
+        if (visitor.getAmountAfter() != output.getContent().size()) {
+            throw new AssertionError("Number of added resources. Expected: " +
+                    visitor.getAmountAfter() + ", got: " + output.getContent().size());
+        }
+        for (ModuleData outResource : output.getContent()) {
+            String path = outResource.getPath().replaceAll(SUFFIX + "$", "");
+            ModuleData inResource = input.get(path);
+            if (inResource == null) {
+                throw new AssertionError("Unknown resource: " + path);
+            }
+        }
+    }
+
+    private static class ResourceVisitor implements Visitor {
+
+        private int amountBefore;
+        private int amountAfter;
+
+        @Override
+        public ModuleData visit(ModuleData resource) {
+            int index = ++amountBefore % 3;
+            switch (index) {
+                case 0:
+                    ++amountAfter;
+                    return new ModuleData(resource.getModule(), resource.getPath() + SUFFIX,
+                            resource.getType(), resource.stream(), resource.getLength());
+                case 1:
+                    ++amountAfter;
+                    return new ModuleData(resource.getModule(), resource.getPath(),
+                            resource.getType(), resource.stream(), resource.getLength());
+            }
+            return null;
+        }
+
+        public int getAmountAfter() {
+            return amountAfter;
+        }
+
+        public int getAmountBefore() {
+            return amountBefore;
+        }
+    }
+
+    private void checkResourceAdding() {
+        List<String> samples = new ArrayList<>();
+        samples.add("java.base");
+        samples.add("java/lang/Object");
+        samples.add("java.base");
+        samples.add("java/lang/String");
+        samples.add("java.management");
+        samples.add("javax/management/ObjectName");
+        test(samples, (resources, module, path) -> {
+            try {
+                resources.add(new ModuleData(module, path,
+                        ModuleDataType.CLASS_OR_RESOURCE,
+                        new ByteArrayInputStream(new byte[0]), 0));
+            } catch (Exception ex) {
+                throw new RuntimeException(ex);
+            }
+        });
+        test(samples, (resources, module, path) -> {
+            try {
+                resources.add(PoolImpl.
+                        newCompressedResource(new ModuleData(module, path,
+                                ModuleDataType.CLASS_OR_RESOURCE,
+                                new ByteArrayInputStream(new byte[0]), 0),
+                                ByteBuffer.allocate(99), "bitcruncher", null,
+                                ((PoolImpl)resources).getStringTable(), ByteOrder.nativeOrder()));
+            } catch (Exception ex) {
+                throw new RuntimeException(ex);
+            }
+        });
+    }
+
+    private void test(List<String> samples, ResourceAdder adder) {
+        if (samples.isEmpty()) {
+            throw new AssertionError("No sample to test");
+        }
+        Pool resources = new PoolImpl();
+        Set<String> modules = new HashSet<>();
+        for (int i = 0; i < samples.size(); i++) {
+            String module = samples.get(i);
+            modules.add(module);
+            i++;
+            String clazz = samples.get(i);
+            String path = "/" + module + "/" + clazz + ".class";
+            adder.add(resources, module, path);
+        }
+        for (int i = 0; i < samples.size(); i++) {
+            String module = samples.get(i);
+            i++;
+            String clazz = samples.get(i);
+            String path = "/" + module + "/" + clazz + ".class";
+            ModuleData res = resources.get(path);
+            checkModule(resources, res);
+            if (res == null) {
+                throw new AssertionError("Resource not found " + path);
+            }
+            ModuleData res2 = resources.get(clazz);
+            if (res2 != null) {
+                throw new AssertionError("Resource found " + clazz);
+            }
+        }
+        if (resources.getContent().size() != samples.size() / 2) {
+            throw new AssertionError("Invalid number of resources");
+        }
+    }
+
+    private void checkModule(Pool resources, ModuleData res) {
+        Module m = resources.getModule(res.getModule());
+        if (m == null) {
+            throw new AssertionError("No module " + res.getModule());
+        }
+        if (!m.getName().equals(res.getModule())) {
+            throw new AssertionError("Not right module name " + res.getModule());
+        }
+        if (m.get(res.getPath()) == null) {
+            throw new AssertionError("resource " + res.getPath()
+                    + " not in module " + m.getName());
+        }
+    }
+
+    private void checkResourcesAfterCompression() throws Exception {
+        PoolImpl resources1 = new PoolImpl();
+        ModuleData res1 = new ModuleData("module1", "/module1/toto1",
+                ModuleDataType.CLASS_OR_RESOURCE,
+                new ByteArrayInputStream(new byte[0]), 0);
+        ModuleData res2 = new ModuleData("module2", "/module2/toto1",
+                ModuleDataType.CLASS_OR_RESOURCE,
+                new ByteArrayInputStream(new byte[0]), 0);
+        resources1.add(res1);
+        resources1.add(res2);
+
+        checkResources(resources1, res1, res2);
+        Pool resources2 = new PoolImpl();
+        ModuleData res3 = new ModuleData("module2", "/module2/toto1",
+                ModuleDataType.CLASS_OR_RESOURCE,
+                new ByteArrayInputStream(new byte[7]), 7);
+        resources2.add(res3);
+        resources2.add(PoolImpl.newCompressedResource(res1,
+                ByteBuffer.allocate(7), "zip", null, resources1.getStringTable(),
+                ByteOrder.nativeOrder()));
+        checkResources(resources2, res1, res2);
+    }
+
+    private void checkResources(Pool resources, ModuleData... expected) {
+        Collection<Module> ms = resources.getModules();
+        List<String> modules = new ArrayList();
+        for(Module m : ms) {
+            modules.add(m.getName());
+        }
+        for (ModuleData res : expected) {
+            if (!resources.contains(res)) {
+                throw new AssertionError("Resource not found: " + res);
+            }
+
+            if (resources.get(res.getPath()) == null) {
+                throw new AssertionError("Resource not found: " + res);
+            }
+
+            if (!modules.contains(res.getModule())) {
+                throw new AssertionError("Module not found: " + res.getModule());
+            }
+
+            if (!resources.getContent().contains(res)) {
+                throw new AssertionError("Resources not found: " + res);
+            }
+
+            try {
+                resources.add(res);
+                throw new AssertionError(res + " already present, but an exception is not thrown");
+            } catch (Exception ex) {
+                // Expected
+            }
+        }
+
+        if (resources.isReadOnly()) {
+            throw new AssertionError("ReadOnly resources");
+        }
+
+        ((PoolImpl) resources).setReadOnly();
+        try {
+            resources.add(new ModuleData("module2",  "/module2/toto1",
+                    ModuleDataType.CLASS_OR_RESOURCE, new ByteArrayInputStream(new byte[0]), 0));
+            throw new AssertionError("Pool is read-only, but an exception is not thrown");
+        } catch (Exception ex) {
+            // Expected
+        }
+    }
+
+    interface ResourceAdder {
+        void add(Pool resources, String module, String path);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/SecurityTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Test JlinkPermission
+ * @author Jean-Francois Denise
+ * @run main SecurityTest
+ */
+
+import java.security.AccessControlException;
+import jdk.tools.jlink.Jlink;
+
+public class SecurityTest {
+
+    public static void main(String[] args) throws Exception {
+        new Jlink();
+        System.setSecurityManager(new SecurityManager());
+        boolean failed = false;
+        try {
+            new Jlink();
+            failed = true;
+        } catch (AccessControlException ex) {
+            //XXX OK.
+        }
+        if (failed) {
+            throw new Exception("Call should have failed");
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/asmplugin/AddForgetResourcesTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,509 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Asm plugin testing.
+ * @test
+ * @summary Test resource transformation.
+ * @author Andrei Eremeev
+ * @modules java.base/jdk.internal.org.objectweb.asm
+ *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jlink.internal.plugins.asm
+ *          jdk.jdeps/com.sun.tools.classfile
+ * @build AsmPluginTestBase
+ * @run main AddForgetResourcesTest
+*/
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.Method;
+import java.io.UncheckedIOException;
+import java.util.Set;
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.ClassVisitor;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.tools.jlink.internal.plugins.asm.AsmGlobalPool;
+import jdk.tools.jlink.internal.plugins.asm.AsmModulePool;
+import jdk.tools.jlink.internal.plugins.asm.AsmPool.ResourceFile;
+import jdk.tools.jlink.internal.plugins.asm.AsmPool.WritableClassPool;
+import jdk.tools.jlink.internal.plugins.asm.AsmPool.WritableResourcePool;
+import jdk.tools.jlink.internal.plugins.asm.AsmPools;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Pool.ModuleData;
+
+public class AddForgetResourcesTest extends AsmPluginTestBase {
+
+    public static void main(String[] args) throws Exception {
+        if (!isImageBuild()) {
+            System.err.println("Test not run. Not image build.");
+            return;
+        }
+        new AddForgetResourcesTest().test();
+    }
+
+    @Override
+    public void test() throws Exception {
+        TestPlugin[] plugins = new TestPlugin[] {
+                new AddClassesPlugin(),
+                new AddResourcesPlugin(),
+                new ReplaceClassesPlugin(),
+                new ReplaceResourcesPlugin(),
+                new ForgetClassesPlugin(),
+                new ForgetResourcesPlugin(),
+                new AddForgetClassesPlugin(),
+                new AddForgetResourcesPlugin(),
+                new ComboPlugin()
+        };
+        for (TestPlugin p : plugins) {
+            Pool out = p.visit(getPool());
+            p.test(getPool(), out);
+        }
+    }
+
+    private static final String SUFFIX = "HELLOWORLD";
+
+    private static class RenameClassVisitor extends ClassVisitor {
+
+        public RenameClassVisitor(ClassWriter cv) {
+            super(Opcodes.ASM5, cv);
+        }
+
+        @Override
+        public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+            super.visit(version, access, name + SUFFIX, signature, superName, interfaces);
+        }
+    }
+
+    private static class AddMethodClassVisitor extends ClassVisitor {
+
+        public AddMethodClassVisitor(ClassWriter cv) {
+            super(Opcodes.ASM5, cv);
+        }
+
+        @Override
+        public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+            this.visitMethod(0, SUFFIX, "()V", null, null);
+            super.visit(version, access, name, signature, superName, interfaces);
+        }
+    }
+
+    private class AddClassesPlugin extends TestPlugin {
+
+        private int expected = 0;
+
+        @Override
+        public void visit() {
+            AsmPools pools = getPools();
+            AsmGlobalPool globalPool = pools.getGlobalPool();
+            WritableClassPool transformedClasses = globalPool.getTransformedClasses();
+            expected = globalPool.getClasses().size();
+            for (ModuleData res : globalPool.getClasses()) {
+                ClassReader reader = globalPool.getClassReader(res);
+                String className = reader.getClassName();
+                if (!className.endsWith("module-info")) {
+                    ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES);
+                    reader.accept(new RenameClassVisitor(writer), ClassReader.EXPAND_FRAMES);
+                    transformedClasses.addClass(writer);
+                    ++expected;
+                }
+            }
+        }
+
+        @Override
+        public void test(Pool inResources, Pool outResources) {
+            Collection<ModuleData> inClasses = extractClasses(inResources);
+            Collection<ModuleData> outClasses = extractClasses(outResources);
+            if (expected != outClasses.size()) {
+                throw new AssertionError("Classes were not added. Expected: " + expected
+                        + ", got: " + outClasses.size());
+            }
+            for (ModuleData in : inClasses) {
+                String path = in.getPath();
+                if (!outClasses.contains(in)) {
+                    throw new AssertionError("Class not found: " + path);
+                }
+                if (path.endsWith("module-info.class")) {
+                    continue;
+                }
+                String modifiedPath = path.replace(".class", SUFFIX + ".class");
+                if (!outClasses.contains(Pool.newResource(modifiedPath, new byte[0]))) {
+                    throw new AssertionError("Class not found: " + modifiedPath);
+                }
+            }
+        }
+    }
+
+    private class AddResourcesPlugin extends TestPlugin {
+
+        @Override
+        public void visit() {
+            AsmPools pools = getPools();
+            AsmGlobalPool globalPool = pools.getGlobalPool();
+            for (ModuleData res : globalPool.getResourceFiles()) {
+                String path = res.getPath();
+                String moduleName = getModule(path);
+                AsmModulePool modulePool = pools.getModulePool(moduleName);
+                WritableResourcePool resourcePool = modulePool.getTransformedResourceFiles();
+                resourcePool.addResourceFile(new ResourceFile(removeModule(res.getPath()) + SUFFIX,
+                        res.getBytes()));
+            }
+        }
+
+        @Override
+        public void test(Pool in, Pool out) throws Exception {
+            Collection<ModuleData> inResources = extractResources(in);
+            Collection<ModuleData> outResources = extractResources(out);
+            if (2 * inResources.size() != outResources.size()) {
+                throw new AssertionError("Classes were not added. Expected: " + (2 * inResources.size())
+                        + ", got: " + outResources.size());
+            }
+            for (ModuleData r : inResources) {
+                String path = r.getPath();
+                if (!outResources.contains(r)) {
+                    throw new AssertionError("Class not found: " + path);
+                }
+                String modifiedPath = path + SUFFIX;
+                if (!outResources.contains(Pool.newResource(modifiedPath, new byte[0]))) {
+                    throw new AssertionError("Class not found: " + modifiedPath);
+                }
+            }
+        }
+    }
+
+    private class ReplaceClassesPlugin extends TestPlugin {
+
+        @Override
+        public void visit() {
+            AsmPools pools = getPools();
+            AsmGlobalPool globalPool = pools.getGlobalPool();
+            WritableClassPool transformedClasses = globalPool.getTransformedClasses();
+            for (ModuleData res : globalPool.getClasses()) {
+                ClassReader reader = globalPool.getClassReader(res);
+                ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES);
+                reader.accept(new AddMethodClassVisitor(writer), ClassReader.EXPAND_FRAMES);
+                transformedClasses.addClass(writer);
+            }
+        }
+
+        @Override
+        public void test(Pool inResources, Pool outResources) throws Exception {
+            Collection<ModuleData> inClasses = extractClasses(inResources);
+            Collection<ModuleData> outClasses = extractClasses(outResources);
+            if (inClasses.size() != outClasses.size()) {
+                throw new AssertionError("Number of classes. Expected: " + (inClasses.size())
+                        + ", got: " + outClasses.size());
+            }
+            for (ModuleData out : outClasses) {
+                String path = out.getPath();
+                if (!inClasses.contains(out)) {
+                    throw new AssertionError("Class not found: " + path);
+                }
+                ClassFile cf = ClassFile.read(new ByteArrayInputStream(out.getBytes()));
+                if (path.endsWith("module-info.class")) {
+                    continue;
+                }
+                boolean failed = true;
+                for (Method m : cf.methods) {
+                    if (m.getName(cf.constant_pool).equals(SUFFIX)) {
+                        failed = false;
+                    }
+                }
+                if (failed) {
+                    throw new AssertionError("Not found method with name " + SUFFIX + " in class " + path);
+                }
+            }
+        }
+    }
+
+    private class ReplaceResourcesPlugin extends TestPlugin {
+
+        @Override
+        public void visit() {
+            AsmPools pools = getPools();
+            AsmGlobalPool globalPool = pools.getGlobalPool();
+            for (ModuleData res : globalPool.getResourceFiles()) {
+                String path = res.getPath();
+                AsmModulePool modulePool = pools.getModulePool(getModule(path));
+                modulePool.getTransformedResourceFiles().addResourceFile(new ResourceFile(removeModule(path),
+                        "HUI".getBytes()));
+            }
+        }
+
+        @Override
+        public void test(Pool in, Pool out) throws Exception {
+            Collection<ModuleData> inResources = extractResources(in);
+            Collection<ModuleData> outResources = extractResources(out);
+            if (inResources.size() != outResources.size()) {
+                throw new AssertionError("Number of resources. Expected: " + inResources.size()
+                        + ", got: " + outResources.size());
+            }
+            for (ModuleData r : outResources) {
+                String path = r.getPath();
+                if (!inResources.contains(r)) {
+                    throw new AssertionError("Resource not found: " + path);
+                }
+                String content = new String(r.getBytes());
+                if (!"HUI".equals(content)) {
+                    throw new AssertionError("Content expected: 'HUI', got: " + content);
+                }
+            }
+        }
+    }
+
+    private class ForgetClassesPlugin extends TestPlugin {
+
+        private int expected = 0;
+
+        @Override
+        public void visit() {
+            AsmPools pools = getPools();
+            AsmGlobalPool globalPool = pools.getGlobalPool();
+            WritableClassPool transformedClasses = globalPool.getTransformedClasses();
+            int i = 0;
+            for (ModuleData res : globalPool.getClasses()) {
+                String path = removeModule(res.getPath());
+                String className = path.replace(".class", "");
+                if ((i & 1) == 0 && !className.endsWith("module-info")) {
+                    transformedClasses.forgetClass(className);
+                } else {
+                    ++expected;
+                }
+                i ^= 1;
+            }
+        }
+
+        @Override
+        public void test(Pool inResources, Pool outResources) throws Exception {
+            Collection<ModuleData> outClasses = extractClasses(outResources);
+            if (expected != outClasses.size()) {
+                throw new AssertionError("Number of classes. Expected: " + expected +
+                        ", got: " + outClasses.size());
+            }
+        }
+    }
+
+    private class ForgetResourcesPlugin extends TestPlugin {
+
+        private int expectedAmount = 0;
+
+        @Override
+        public void visit() {
+            AsmPools pools = getPools();
+            AsmGlobalPool globalPool = pools.getGlobalPool();
+            int i = 0;
+            for (ModuleData res : globalPool.getResourceFiles()) {
+                String path = res.getPath();
+                if (!path.contains("META-INF/services")) {
+                    if ((i & 1) == 0) {
+                        AsmModulePool modulePool = pools.getModulePool(getModule(path));
+                        modulePool.getTransformedResourceFiles().forgetResourceFile(removeModule(res.getPath()));
+                    } else {
+                        ++expectedAmount;
+                    }
+                    i ^= 1;
+                } else {
+                    ++expectedAmount;
+                }
+            }
+        }
+
+        @Override
+        public void test(Pool in, Pool out) throws Exception {
+            Collection<ModuleData> outResources = extractResources(out);
+            if (expectedAmount != outResources.size()) {
+                throw new AssertionError("Number of classes. Expected: " + expectedAmount
+                        + ", got: " + outResources.size());
+            }
+        }
+    }
+
+    private class AddForgetClassesPlugin extends TestPlugin {
+
+        private int expected = 0;
+
+        @Override
+        public void visit() {
+            AsmPools pools = getPools();
+            AsmGlobalPool globalPool = pools.getGlobalPool();
+            WritableClassPool transformedClasses = globalPool.getTransformedClasses();
+            int i = 0;
+            for (ModuleData res : globalPool.getClasses()) {
+                ClassReader reader = globalPool.getClassReader(res);
+                String className = reader.getClassName();
+                ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES);
+                if (!className.endsWith("module-info")) {
+                    reader.accept(new RenameClassVisitor(writer), ClassReader.EXPAND_FRAMES);
+                    transformedClasses.addClass(writer);
+                    ++expected;
+                }
+
+                if ((i & 1) == 0 && !className.endsWith("module-info")) {
+                    transformedClasses.forgetClass(className);
+                } else {
+                    ++expected;
+                }
+                i ^= 1;
+            }
+        }
+
+        @Override
+        public void test(Pool inResources, Pool outResources) throws Exception {
+            Collection<ModuleData> outClasses = extractClasses(outResources);
+            if (expected != outClasses.size()) {
+                throw new AssertionError("Number of classes. Expected: " + expected
+                        + ", got: " + outClasses.size());
+            }
+        }
+    }
+
+    private class AddForgetResourcesPlugin extends TestPlugin {
+
+        private int expectedAmount = 0;
+
+        @Override
+        public void visit() {
+            AsmPools pools = getPools();
+            AsmGlobalPool globalPool = pools.getGlobalPool();
+            int i = 0;
+            for (ModuleData res : globalPool.getResourceFiles()) {
+                String path = res.getPath();
+                String moduleName = getModule(path);
+                if (!path.contains("META-INF")) {
+                    AsmModulePool modulePool = pools.getModulePool(moduleName);
+                    WritableResourcePool transformedResourceFiles = modulePool.getTransformedResourceFiles();
+                    String newPath = removeModule(path) + SUFFIX;
+                    transformedResourceFiles.addResourceFile(new ResourceFile(newPath, res.getBytes()));
+                    if ((i & 1) == 0) {
+                        transformedResourceFiles.forgetResourceFile(newPath);
+                    } else {
+                        ++expectedAmount;
+                    }
+                    i ^= 1;
+                }
+                ++expectedAmount;
+            }
+        }
+
+        @Override
+        public void test(Pool inResources, Pool out) throws Exception {
+            Collection<ModuleData> outResources = extractResources(out);
+            if (expectedAmount != outResources.size()) {
+                throw new AssertionError("Number of classes. Expected: " + expectedAmount
+                        + ", got: " + outResources.size());
+            }
+        }
+    }
+
+    private class ComboPlugin extends TestPlugin {
+
+        private class RenameClassVisitor extends ClassVisitor {
+
+            public RenameClassVisitor(ClassWriter cv) {
+                super(Opcodes.ASM5, cv);
+            }
+
+            @Override
+            public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+                super.visit(version, access, name + SUFFIX, signature, superName, interfaces);
+            }
+        }
+
+        @Override
+        public void visit() {
+            try {
+                renameClasses();
+                renameResources();
+            } catch (IOException ex) {
+                throw new UncheckedIOException(ex);
+            }
+        }
+
+        @Override
+        public void test(Pool inResources, Pool outResources) throws Exception {
+            if (!isVisitCalled()) {
+                throw new AssertionError("Resources not visited");
+            }
+            AsmGlobalPool globalPool = getPools().getGlobalPool();
+            if (globalPool.getTransformedClasses().getClasses().size() != getClasses().size()) {
+                throw new AssertionError("Number of transformed classes not equal to expected");
+            }
+            // Check that only renamed classes and resource files are in the result.
+            for (ModuleData r : outResources.getContent()) {
+                String resourceName = r.getPath();
+                if (resourceName.endsWith(".class") && !resourceName.endsWith("module-info.class")) {
+                    if (!resourceName.endsWith(SUFFIX + ".class")) {
+                        throw new AssertionError("Class not renamed " + resourceName);
+                    }
+                } else if (resourceName.contains("META-INF/services/") && MODULES.containsKey(r.getModule())) {
+                    String newClassName = new String(r.getBytes());
+                    if(!newClassName.endsWith(SUFFIX)) {
+                        throw new AssertionError("Resource file not renamed " + resourceName);
+                    }
+                }
+            }
+        }
+
+        private void renameResources() throws IOException {
+            AsmPools pools = getPools();
+            // Rename the resource Files
+            for (Map.Entry<String, List<String>> mod : MODULES.entrySet()) {
+                String moduleName = mod.getKey();
+                AsmModulePool modulePool = pools.getModulePool(moduleName);
+                for (ModuleData res : modulePool.getResourceFiles()) {
+                    ResourceFile resFile = modulePool.getResourceFile(res);
+                    if (resFile.getPath().startsWith("META-INF/services/")) {
+                        String newContent = new String(resFile.getContent()) + SUFFIX;
+                        ResourceFile newResourceFile = new ResourceFile(resFile.getPath(),
+                                newContent.getBytes());
+                        modulePool.getTransformedResourceFiles().addResourceFile(newResourceFile);
+                    }
+                }
+            }
+        }
+
+        private void renameClasses() throws IOException {
+            AsmPools pools = getPools();
+            AsmGlobalPool globalPool = pools.getGlobalPool();
+            WritableClassPool transformedClasses = globalPool.getTransformedClasses();
+            for (ModuleData res : globalPool.getClasses()) {
+                if (res.getPath().endsWith("module-info.class")) {
+                    continue;
+                }
+                ClassReader reader = globalPool.getClassReader(res);
+                ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES);
+                RenameClassVisitor visitor = new RenameClassVisitor(writer);
+                reader.accept(visitor, ClassReader.EXPAND_FRAMES);
+
+                transformedClasses.forgetClass(reader.getClassName());
+                transformedClasses.addClass(writer);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/asmplugin/AsmPluginTestBase.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import jdk.tools.jlink.internal.PoolImpl;
+import jdk.tools.jlink.internal.StringTable;
+
+import jdk.tools.jlink.internal.plugins.asm.AsmPlugin;
+import jdk.tools.jlink.internal.plugins.asm.AsmPools;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Pool.ModuleData;
+
+public abstract class AsmPluginTestBase {
+
+    protected static final String TEST_MODULE = "jlink.test";
+    protected static final Map<String, List<String>> MODULES;
+
+    private static final Predicate<ModuleData> isClass = r -> r.getPath().endsWith(".class");
+    private final List<String> classes;
+    private final List<String> resources;
+    private final Pool pool;
+
+    static {
+        Map<String, List<String>> map = new HashMap<>();
+        map.put("jdk.localedata", new ArrayList<>());
+        map.put("java.base", new ArrayList<>());
+        map.put(TEST_MODULE, new ArrayList<>());
+        MODULES = Collections.unmodifiableMap(map);
+    }
+
+    public static boolean isImageBuild() {
+        Path javaHome = Paths.get(System.getProperty("test.jdk"));
+        Path jmods = javaHome.resolve("jmods");
+        return Files.exists(jmods);
+    }
+
+    public AsmPluginTestBase() {
+        try {
+            List<String> classes = new ArrayList<>();
+            List<String> resources = new ArrayList<>();
+
+            pool = new PoolImpl();
+
+            FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
+            Path root = fs.getPath("/modules");
+
+            List<byte[]> moduleInfos = new ArrayList<>();
+            try (Stream<Path> stream = Files.walk(root)) {
+                for (Iterator<Path> iterator = stream.iterator(); iterator.hasNext(); ) {
+                    Path p = iterator.next();
+                    if (Files.isRegularFile(p)) {
+                        String module = p.toString().substring("/modules/".length());
+                        module = module.substring(0, module.indexOf("/"));
+                        if (MODULES.keySet().contains(module)) {
+                            try {
+                                boolean isModuleInfo = p.endsWith("module-info.class");
+                                if (isModuleInfo) {
+                                    moduleInfos.add(Files.readAllBytes(p));
+                                }
+                                byte[] content = Files.readAllBytes(p);
+                                if (p.toString().endsWith(".class") && !isModuleInfo) {
+                                    classes.add(toClassName(p));
+                                } else if (!isModuleInfo) {
+                                    MODULES.get(module).add(toResourceFile(p));
+                                }
+                                resources.add(toPath(p.toString()));
+                                ModuleData res = Pool.newResource(toPath(p.toString()), content);
+                                pool.add(res);
+                            } catch (Exception ex) {
+                                throw new RuntimeException(ex);
+                            }
+                        }
+                    }
+                }
+            }
+            // There is more than 10 classes in java.base...
+            if (classes.size() < 10 || pool.getContent().size() < 10) {
+                throw new AssertionError("Not expected resource or class number");
+            }
+
+            //Add a fake resource file
+            String content = "java.lang.Object";
+            String path = "META-INF/services/com.foo.BarProvider";
+            ModuleData resFile = Pool.newResource("/" + TEST_MODULE + "/" +
+                    path, content.getBytes());
+            pool.add(resFile);
+            ModuleData fakeInfoFile = Pool.newResource("/" + TEST_MODULE
+                    + "/module-info.class", moduleInfos.get(0));
+            pool.add(fakeInfoFile);
+            MODULES.get(TEST_MODULE).add(path);
+            for(Map.Entry<String, List<String>> entry : MODULES.entrySet()) {
+                if (entry.getValue().isEmpty()) {
+                    throw new AssertionError("No resource file for " + entry.getKey());
+                }
+            }
+            this.classes = Collections.unmodifiableList(classes);
+            this.resources = Collections.unmodifiableList(resources);
+        } catch (Exception e) {
+            throw new ExceptionInInitializerError(e);
+        }
+    }
+
+    public List<String> getClasses() {
+        return classes;
+    }
+
+    public List<String> getResources() {
+        return resources;
+    }
+
+    public Pool getPool() {
+        return pool;
+    }
+
+    public abstract void test() throws Exception;
+
+    public Collection<ModuleData> extractClasses(Pool pool) {
+        return pool.getContent().stream()
+                .filter(isClass)
+                .collect(Collectors.toSet());
+    }
+
+    public Collection<ModuleData> extractResources(Pool pool) {
+        return pool.getContent().stream()
+                .filter(isClass.negate())
+                .collect(Collectors.toSet());
+    }
+
+    public String getModule(String path) {
+        int index = path.indexOf("/", 1);
+        return path.substring(1, index);
+    }
+
+    public String removeModule(String path) {
+        int index = path.indexOf("/", 1);
+        return path.substring(index + 1);
+    }
+
+    private String toPath(String p) {
+        return p.substring("/modules".length());
+    }
+
+    private String toClassName(Path p) {
+        String path = p.toString();
+        path = path.substring("/modules/".length());
+        // remove module
+        if (!path.endsWith("module-info.class")) {
+            path = path.substring(path.indexOf("/") + 1);
+        }
+        path = path.substring(0, path.length() - ".class".length());
+
+        return path;
+    }
+
+    private String toResourceFile(Path p) {
+        String path = p.toString();
+        path = path.substring("/modules/".length());
+        // remove module
+        path = path.substring(path.indexOf("/") + 1);
+
+        return path;
+    }
+
+    public abstract class TestPlugin extends AsmPlugin {
+
+        private AsmPools pools;
+
+        public AsmPools getPools() {
+            return pools;
+        }
+
+        public boolean isVisitCalled() {
+            return pools != null;
+        }
+
+        public Pool visit(Pool inResources) throws IOException {
+            try {
+                Pool outResources = new PoolImpl(inResources.getByteOrder(), new StringTable() {
+                    @Override
+                    public int addString(String str) {
+                        return -1;
+                    }
+
+                    @Override
+                    public String getString(int id) {
+                        return null;
+                    }
+                });
+                visit(inResources, outResources);
+                return outResources;
+            } catch (Exception e) {
+                throw new IOException(e);
+            }
+        }
+
+        @Override
+        public void visit(AsmPools pools) {
+            if (isVisitCalled()) {
+                throw new AssertionError("Visit was called twice");
+            }
+            this.pools = pools;
+            visit();
+        }
+
+        public abstract void visit();
+        public abstract void test(Pool inResources, Pool outResources) throws Exception;
+
+        @Override
+        public String getName() {
+            return "test-plugin";
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/asmplugin/BasicTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Asm plugin testing.
+ * @test
+ * @summary Test basic functionality.
+ * @author Jean-Francois Denise
+ * @modules java.base/jdk.internal.org.objectweb.asm
+ *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jlink.internal.plugins.asm
+ * @build AsmPluginTestBase
+ * @run main BasicTest
+ */
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.tools.jlink.internal.plugins.asm.AsmModulePool;
+import jdk.tools.jlink.internal.plugins.asm.AsmPool;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Pool.ModuleData;
+
+public class BasicTest extends AsmPluginTestBase {
+
+    public static void main(String[] args) throws Exception {
+        if (!isImageBuild()) {
+            System.err.println("Test not run. Not image build.");
+            return;
+        }
+        new BasicTest().test();
+    }
+
+    @Override
+    public void test() throws Exception {
+        BasicPlugin basicPlugin = new BasicPlugin(getClasses());
+        Pool res = basicPlugin.visit(getPool());
+        basicPlugin.test(getPool(), res);
+    }
+
+    private class BasicPlugin extends TestPlugin {
+
+        private final List<String> classes;
+
+        public BasicPlugin(List<String> classes) {
+            this.classes = classes;
+        }
+
+        @Override
+        public void visit() {
+            for (String m : MODULES.keySet()) {
+                AsmModulePool pool = getPools().getModulePool(m);
+                if (pool == null) {
+                    throw new AssertionError(m + " pool not found");
+                }
+                if(!pool.getModuleName().equals(m)) {
+                    throw new AssertionError("Invalid module name " +
+                            pool.getModuleName() + " should be "+ m);
+                }
+                if (pool.getClasses().size() == 0 && !m.equals(TEST_MODULE)) {
+                    throw new AssertionError("Empty pool " + m);
+                }
+                pool.addPackage("toto");
+                if (!pool.getTransformedClasses().getClasses().isEmpty()) {
+                    throw new AssertionError("Should be empty");
+                }
+                for(String res : MODULES.get(m)) {
+                    AsmPool.ResourceFile resFile = pool.getResourceFile(res);
+                    if(resFile == null) {
+                        throw new AssertionError("No resource file for " + res);
+                    }
+                }
+            }
+            try {
+                testPools();
+                testVisitor();
+            } catch (IOException ex) {
+                throw new UncheckedIOException(ex);
+            }
+        }
+
+        @Override
+        public void test(Pool inResources, Pool outResources) throws Exception {
+            if (!isVisitCalled()) {
+                throw new AssertionError("Resources not visited");
+            }
+            if (inResources.getContent().size() != outResources.getContent().size()) {
+                throw new AssertionError("Input size " + inResources.getContent().size() +
+                        " != to " + outResources.getContent().size());
+            }
+        }
+
+        private void testVisitor() throws IOException {
+            List<String> seen = new ArrayList<>();
+            getPools().getGlobalPool().visitClassReaders((reader) -> {
+                String className = reader.getClassName();
+                // Wrong naming of module-info.class in ASM
+                if (className.endsWith("module-info")) {
+                    return null;
+                }
+                if (!classes.contains(className)) {
+                    throw new AssertionError("Class is not expected " + className);
+                }
+                if (getPools().getGlobalPool().getClassReader(className) == null) {
+                    throw new AssertionError("Class not found in pool " + className);
+                }
+                seen.add(className);
+                return null;
+            });
+
+            if (!seen.equals(classes)) {
+                throw new AssertionError("Expected and seen are not equal");
+            }
+        }
+
+        private void testPools() throws IOException {
+            Set<String> remain = new HashSet<>(classes);
+            for (ModuleData res : getPools().getGlobalPool().getClasses()) {
+                ClassReader reader = getPools().getGlobalPool().getClassReader(res);
+                String className = reader.getClassName();
+                // Wrong naming of module-info.class in ASM
+                if (className.endsWith("module-info")) {
+                    continue;
+                }
+                if (!classes.contains(className)) {
+                    throw new AssertionError("Class is not expected " + className);
+                }
+                if (getPools().getGlobalPool().getClassReader(className) == null) {
+                    throw new AssertionError("Class " + className + " not found in pool ");
+                }
+                // Check the module pool
+                boolean found = false;
+                for(AsmModulePool mp : getPools().getModulePools()) {
+                    if(mp.getClassReader(className) != null) {
+                        found = true;
+                        break;
+                    }
+                }
+                if(!found) {
+                    throw new AssertionError("No modular pool for " +
+                            className);
+                }
+                remain.remove(className);
+            }
+            if (!remain.isEmpty()) {
+                throw new AssertionError("Remaining classes " + remain);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/asmplugin/IdentityPluginTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Asm plugin testing.
+ * @test
+ * @summary Test basic functionality.
+ * @author Jean-Francois Denise
+ * @modules java.base/jdk.internal.org.objectweb.asm
+ *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jlink.internal.plugins.asm
+ * @build AsmPluginTestBase
+ * @run main IdentityPluginTest
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.ClassVisitor;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.tools.jlink.internal.plugins.asm.AsmPool.WritableClassPool;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Pool.ModuleData;
+
+public class IdentityPluginTest extends AsmPluginTestBase {
+
+    public static void main(String[] args) throws Exception {
+        if (!isImageBuild()) {
+            System.err.println("Test not run. Not image build.");
+            return;
+        }
+        new IdentityPluginTest().test();
+    }
+
+    public void test() throws Exception {
+        IdentityPlugin asm = new IdentityPlugin();
+        Pool resourcePool = asm.visit(getPool());
+        asm.test(getPool(), resourcePool);
+    }
+
+    private class IdentityPlugin extends TestPlugin {
+
+        @Override
+        public void visit() {
+            for (ModuleData res : getPools().getGlobalPool().getClasses()) {
+                if (res.getPath().endsWith("module-info.class")) {
+                    continue;
+                }
+                ClassReader reader = getPools().getGlobalPool().getClassReader(res);
+                ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES);
+                IdentityClassVisitor visitor = new IdentityClassVisitor(writer);
+                reader.accept(visitor, ClassReader.EXPAND_FRAMES);
+                getPools().getGlobalPool().getTransformedClasses().addClass(writer);
+            }
+        }
+
+        @Override
+        public void test(Pool inResources, Pool outResources) throws IOException {
+            if (outResources.isEmpty()) {
+                throw new AssertionError("Empty result");
+            }
+            if (!isVisitCalled()) {
+                throw new AssertionError("Resources not visited");
+            }
+            WritableClassPool transformedClasses = getPools().getGlobalPool().getTransformedClasses();
+            if (transformedClasses.getClasses().size() != getClasses().size()) {
+                throw new AssertionError("Number of transformed classes not equal to expected");
+            }
+            for (String className : getClasses()) {
+                if (transformedClasses.getClassReader(className) == null) {
+                    throw new AssertionError("Class not transformed " + className);
+                }
+            }
+            for (ModuleData r : outResources.getContent()) {
+                if (r.getPath().endsWith(".class") && !r.getPath().endsWith("module-info.class")) {
+                    ClassReader reader = new ClassReader(new ByteArrayInputStream(r.getBytes()));
+                    ClassWriter w = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES);
+                    reader.accept(w, ClassReader.EXPAND_FRAMES);
+                }
+            }
+        }
+
+        @Override
+        public String getName() {
+            return "identity-plugin";
+        }
+    }
+
+    private static class IdentityClassVisitor extends ClassVisitor {
+        public IdentityClassVisitor(ClassWriter cv) {
+            super(Opcodes.ASM5, cv);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/asmplugin/NegativeTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Asm plugin testing.
+ * @test
+ * @summary Test basic functionality.
+ * @author Andrei Eremeev
+ * @modules java.base/jdk.internal.org.objectweb.asm
+ *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jlink.internal.plugins.asm
+ * @build AsmPluginTestBase
+ * @run main NegativeTest
+ */
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.ByteOrder;
+import java.util.Map;
+import java.util.Set;
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.ClassVisitor;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.tools.jlink.plugin.Plugin;
+import jdk.tools.jlink.internal.PoolImpl;
+import jdk.tools.jlink.internal.StringTable;
+import jdk.tools.jlink.internal.plugins.asm.AsmGlobalPool;
+import jdk.tools.jlink.internal.plugins.asm.AsmModulePool;
+import jdk.tools.jlink.internal.plugins.asm.AsmPlugin;
+import jdk.tools.jlink.internal.plugins.asm.AsmPool.ResourceFile;
+import jdk.tools.jlink.internal.plugins.asm.AsmPools;
+import jdk.tools.jlink.plugin.PluginException;
+import jdk.tools.jlink.plugin.Pool;
+
+public class NegativeTest extends AsmPluginTestBase {
+    public static void main(String[] args) throws Exception {
+        if (!isImageBuild()) {
+            System.err.println("Test not run. Not image build.");
+            return;
+        }
+        new NegativeTest().test();
+    }
+
+    @Override
+    public void test() throws Exception {
+        testNull();
+        testUnknownPackage();
+    }
+
+    private void testUnknownPackage() throws Exception {
+        AsmPlugin t = new AsmPlugin() {
+            @Override
+            public void visit(AsmPools pools) {
+                try {
+                    AsmGlobalPool globalPool = pools.getGlobalPool();
+                    AsmModulePool javabase = pools.getModulePool("java.base");
+                    ClassReader cr = new ClassReader(NegativeTest.class.getResourceAsStream("NegativeTest.class"));
+                    ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES);
+                    cr.accept(new RenameClassVisitor(cw), ClassReader.EXPAND_FRAMES);
+                    action(() -> globalPool.getTransformedClasses().addClass(cw),
+                            "Unknown package", PluginException.class);
+                    action(() -> javabase.getTransformedClasses().addClass(cw),
+                            "Unknown package", PluginException.class);
+
+                    ResourceFile newResFile = new ResourceFile("java/aaa/file", new byte[0]);
+                    action(() -> globalPool.getTransformedResourceFiles().addResourceFile(newResFile),
+                            "Unknown package", PluginException.class);
+                    action(() -> javabase.getTransformedResourceFiles().addResourceFile(newResFile),
+                            "Unknown package", PluginException.class);
+
+                    action(() -> globalPool.getTransformedClasses().forgetClass("java/aaa/file"),
+                            "Unknown package", PluginException.class);
+                    action(() -> javabase.getTransformedClasses().forgetClass("java/aaa/file"),
+                            "Unknown package", PluginException.class);
+                    action(() -> globalPool.getTransformedResourceFiles().forgetResourceFile("java/aaa/file"),
+                            "Unknown package", PluginException.class);
+                    action(() -> javabase.getTransformedResourceFiles().forgetResourceFile("java/aaa/file"),
+                            "Unknown package", PluginException.class);
+                } catch (IOException ex) {
+                   throw new UncheckedIOException(ex);
+                }
+            }
+        };
+        Pool resources = new PoolImpl(ByteOrder.BIG_ENDIAN, new StringTable() {
+            @Override
+            public int addString(String str) {
+                return -1;
+            }
+
+            @Override
+            public String getString(int id) {
+                throw new UnsupportedOperationException("Not supported yet.");
+            }
+        });
+        t.visit(getPool(), resources);
+    }
+
+    private static class RenameClassVisitor extends ClassVisitor {
+
+        public RenameClassVisitor(ClassWriter cv) {
+            super(Opcodes.ASM5, cv);
+        }
+
+        @Override
+        public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+            super.visit(version, access, "RENAMED", signature, superName, interfaces);
+        }
+    }
+
+    private void testNull() throws Exception {
+        AsmPlugin t = new AsmPlugin() {
+            @Override
+            public void visit(AsmPools pools) {
+                action(() -> pools.getModulePool(null), "Module name is null", NullPointerException.class);
+                action(() -> pools.fillOutputResources(null), "Output resource is null", NullPointerException.class);
+            }
+        };
+        Pool resources = new PoolImpl(ByteOrder.BIG_ENDIAN, new StringTable() {
+            @Override
+            public int addString(String str) {
+                return -1;
+            }
+
+            @Override
+            public String getString(int id) {
+                throw new UnsupportedOperationException("Not supported yet.");
+            }
+        });
+        action(() -> t.visit(null, resources), "Input resource is null", NullPointerException.class);
+        action(() -> t.visit(resources, null), "Output resource is null", NullPointerException.class);
+        t.visit(resources, resources);
+    }
+
+    private void action(Action action, String message, Class<? extends Exception> expected) {
+        try {
+            System.err.println("Testing: " + message);
+            action.call();
+            throw new AssertionError(message + ": should have failed");
+        } catch (Exception e) {
+            if (!expected.isInstance(e)) {
+                throw new RuntimeException(e);
+            } else {
+                System.err.println("Got exception as expected: " + e);
+            }
+        }
+    }
+
+    private interface Action {
+        void call() throws Exception;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/asmplugin/PackageMappingTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Asm plugin testing.
+ * @test
+ * @summary Test plugins
+ * @author Andrei Eremeev
+ * @modules jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jlink.internal.plugins.asm
+ * @run main PackageMappingTest
+ */
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import jdk.tools.jlink.internal.plugins.asm.AsmGlobalPool;
+import jdk.tools.jlink.internal.plugins.asm.AsmModulePool;
+import jdk.tools.jlink.internal.plugins.asm.AsmPool.ResourceFile;
+import jdk.tools.jlink.internal.plugins.asm.AsmPool.WritableResourcePool;
+import jdk.tools.jlink.plugin.PluginException;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Pool.ModuleData;
+
+public class PackageMappingTest extends AsmPluginTestBase {
+
+    private final List<String> newFiles = Arrays.asList(
+            "/java.base/a1/bbb/c",
+            "/" + TEST_MODULE + "/a2/bbb/d"
+    );
+
+    public static void main(String[] args) throws Exception {
+        if (!isImageBuild()) {
+            System.err.println("Test not run. Not image build.");
+            return;
+        }
+        new PackageMappingTest().test();
+    }
+
+    public void test() throws Exception {
+        TestPlugin[] plugins = new TestPlugin[]{
+            new PackageMappingPlugin(newFiles, false),
+            new PackageMappingPlugin(newFiles, true)
+        };
+        for (TestPlugin p : plugins) {
+            Pool pool = p.visit(getPool());
+            p.test(getPool(), pool);
+        }
+    }
+
+    public class PackageMappingPlugin extends TestPlugin {
+
+        private final Map<String, List<ResourceFile>> newFiles;
+        private final boolean testGlobal;
+
+        private String getModuleName(String res) {
+            return res.substring(1, res.indexOf("/", 1));
+        }
+
+        private PackageMappingPlugin(List<String> files, boolean testGlobal) {
+            this.newFiles = new HashMap<>();
+            this.testGlobal = testGlobal;
+            for (String file : files) {
+                String moduleName = getModuleName(file);
+                String path = file.substring(1 + moduleName.length() + 1);
+                newFiles.computeIfAbsent(moduleName, $ -> new ArrayList<>()).add(
+                        new ResourceFile(path, new byte[0]));
+            }
+        }
+
+        @Override
+        public void visit() {
+            testMapToUnknownModule();
+            testMapPackageTwice();
+            testPackageMapping();
+        }
+
+        @Override
+        public void test(Pool inResources, Pool outResources) {
+            Set<String> in = getPools().getGlobalPool().getResourceFiles().stream()
+                    .map(ModuleData::getPath)
+                    .collect(Collectors.toSet());
+            Set<String> out = extractResources(outResources).stream()
+                    .map(ModuleData::getPath)
+                    .collect(Collectors.toSet());
+            in.addAll(PackageMappingTest.this.newFiles);
+            if (!Objects.equals(in, out)) {
+                throw new AssertionError("Expected: " + in + ", got: " + outResources);
+            }
+        }
+
+        private void testPackageMapping() {
+            AsmGlobalPool globalPool = getPools().getGlobalPool();
+            try {
+                Map<String, Set<String>> mappedPackages = new HashMap<>();
+                Function<String, Set<String>> produceSet = $ -> new HashSet<>();
+                for (Map.Entry<String, List<ResourceFile>> entry : newFiles.entrySet()) {
+                    String moduleName = entry.getKey();
+                    Set<String> module = mappedPackages.computeIfAbsent(moduleName, produceSet);
+                    AsmModulePool modulePool = getPools().getModulePool(moduleName);
+                    for (ResourceFile r : entry.getValue()) {
+                        String name = r.getPath();
+                        String packageName = name.substring(0, name.lastIndexOf('/'));
+                        if (module.add(packageName)) {
+                            globalPool.addPackageModuleMapping(packageName, moduleName);
+                        }
+                        WritableResourcePool transformedResourceFiles = testGlobal
+                                ? globalPool.getTransformedResourceFiles()
+                                : modulePool.getTransformedResourceFiles();
+                        transformedResourceFiles.addResourceFile(r);
+                    }
+                    try {
+                        modulePool.getTransformedResourceFiles().addResourceFile(
+                                new ResourceFile("a3/bbb", new byte[0]));
+                        throw new AssertionError("Exception expected");
+                    } catch (Exception ex) {
+                        // expected
+                    }
+                }
+                try {
+                    globalPool.getTransformedResourceFiles().addResourceFile(
+                            new ResourceFile("a3/bbb", new byte[0]));
+                    throw new AssertionError("Exception expected");
+                } catch (Exception ex) {
+                    // expected
+                }
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        private void testMapPackageTwice() {
+            try {
+                AsmGlobalPool globalPool = getPools().getGlobalPool();
+                globalPool.addPackageModuleMapping("a/p1", TEST_MODULE);
+                globalPool.addPackageModuleMapping("a/p1", TEST_MODULE);
+                throw new AssertionError("Exception expected after mapping a package twice to the same module");
+            } catch (Exception e) {
+                if (e instanceof PluginException) {
+                    // expected
+                    String message = e.getMessage();
+                    if (!(TEST_MODULE + " module already contains package a.p1").equals(message)) {
+                        throw new AssertionError(e);
+                    }
+                } else {
+                    throw new AssertionError(e);
+                }
+            }
+        }
+
+        private void testMapToUnknownModule() {
+            AsmModulePool unknownModule = getPools().getModulePool("UNKNOWN");
+            if (unknownModule != null) {
+                throw new AssertionError("getModulePool returned not null value: " + unknownModule.getModuleName());
+            }
+            try {
+                AsmGlobalPool globalPool = getPools().getGlobalPool();
+                globalPool.addPackageModuleMapping("a/b", "UNKNOWN");
+                throw new AssertionError("Exception expected after mapping a package to unknown module");
+            } catch (Exception e) {
+                String message = e.getMessage();
+                if (message == null || !message.startsWith("Unknown module UNKNOWN")) {
+                    throw new AssertionError(e);
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/asmplugin/SortingTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Asm plugin testing.
+ * @test
+ * @summary Test resource sorting.
+ * @author Jean-Francois Denise
+ * @modules jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jlink.internal.plugins.asm
+ * @build AsmPluginTestBase
+ * @run main SortingTest
+ */
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import jdk.tools.jlink.internal.plugins.asm.AsmModulePool;
+import jdk.tools.jlink.plugin.PluginException;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Pool.ModuleData;
+
+public class SortingTest extends AsmPluginTestBase {
+
+    public static void main(String[] args) throws Exception {
+        if (!isImageBuild()) {
+            System.err.println("Test not run. Not image build.");
+            return;
+        }
+        new SortingTest().test();
+    }
+
+    @Override
+    public void test() {
+        try {
+            classSorting();
+            moduleSorting();
+        } catch (Exception ex) {
+            throw new PluginException(ex);
+        }
+    }
+
+    private void classSorting() throws Exception {
+        List<String> sorted = new ArrayList<>(getResources());
+        sorted.sort(null);
+        ClassSorterPlugin sorterPlugin = new ClassSorterPlugin(sorted);
+        Pool resourcePool = sorterPlugin.visit(getPool());
+        sorterPlugin.test(getPool(), resourcePool);
+    }
+
+    private String getModuleName(String p) {
+        return p.substring(1, p.indexOf('/', 1));
+    }
+
+    private void moduleSorting() throws Exception {
+        List<String> sorted = new ArrayList<>(getResources());
+        sorted.sort((s1, s2) -> -getModuleName(s1).compareTo(getModuleName(s2)));
+        ModuleSorterPlugin sorterPlugin = new ModuleSorterPlugin();
+        Pool resourcePool = sorterPlugin.visit(getPool());
+        sorterPlugin.test(getPool(), resourcePool);
+    }
+
+    private class ModuleSorterPlugin extends TestPlugin {
+
+        @Override
+        public void visit() {
+            for (AsmModulePool modulePool : getPools().getModulePools()) {
+                modulePool.setSorter(resources -> {
+                    List<String> sort = resources.getContent().stream()
+                            .map(ModuleData::getPath)
+                            .collect(Collectors.toList());
+                    sort.sort(null);
+                    return sort;
+                });
+            }
+            getPools().setModuleSorter(modules -> {
+                modules.sort((s1, s2) -> -s1.compareTo(s2));
+                return modules;
+            });
+        }
+
+        @Override
+        public void test(Pool inResources, Pool outResources) throws Exception {
+            if (!isVisitCalled()) {
+                throw new AssertionError("Resources not visited");
+            }
+            List<String> sortedResourcePaths = outResources.getContent().stream()
+                    .map(ModuleData::getPath)
+                    .collect(Collectors.toList());
+
+            List<String> defaultResourceOrder = new ArrayList<>();
+            for (ModuleData r : inResources.getContent()) {
+                if (!inResources.getContent().contains(r)) {
+                    throw new AssertionError("Resource " + r.getPath() + " not in result pool");
+                }
+                defaultResourceOrder.add(r.getPath());
+            }
+            // Check that default sorting is not equal to sorted one
+            if (defaultResourceOrder.equals(sortedResourcePaths)) {
+                throw new AssertionError("Sorting not applied, default ordering");
+            }
+            // Check module order.
+            for (int i = 0; i < sortedResourcePaths.size() - 1; ++i) {
+                String first = sortedResourcePaths.get(i);
+                String p1 = getModuleName(first);
+                String second = sortedResourcePaths.get(i + 1);
+                String p2 = getModuleName(second);
+                if (p1.compareTo(p2) < 0 || p1.compareTo(p2) == 0 &&
+                        removeModule(first).compareTo(removeModule(second)) >= 0) {
+                    throw new AssertionError("Modules are not sorted properly: resources: " + first + " " + second);
+                }
+            }
+        }
+    }
+
+    private class ClassSorterPlugin extends TestPlugin {
+
+        private final List<String> expectedClassesOrder;
+
+        private ClassSorterPlugin(List<String> expectedClassesOrder) {
+            this.expectedClassesOrder = expectedClassesOrder;
+        }
+
+        @Override
+        public void visit() {
+            getPools().getGlobalPool().setSorter(
+                    (resources) -> expectedClassesOrder.stream()
+                            .map(resources::get)
+                            .map(ModuleData::getPath)
+                            .collect(Collectors.toList()));
+        }
+
+        @Override
+        public void test(Pool inResources, Pool outResources) throws Exception {
+            if (!isVisitCalled()) {
+                throw new AssertionError("Resources not visited");
+            }
+            List<String> sortedResourcePaths = outResources.getContent().stream()
+                    .map(ModuleData::getPath)
+                    .collect(Collectors.toList());
+
+            List<String> defaultResourceOrder = new ArrayList<>();
+            for (ModuleData r : getPool().getContent()) {
+                if (!getPool().getContent().contains(r)) {
+                    throw new AssertionError("Resource " + r.getPath() + " not in result pool");
+                }
+                defaultResourceOrder.add(r.getPath());
+            }
+            // Check that default sorting is not equal to sorted one
+            if (defaultResourceOrder.equals(sortedResourcePaths)) {
+                throw new AssertionError("Sorting not applied, default ordering");
+            }
+            // Check that sorted is equal to result.
+            if (!expectedClassesOrder.equals(sortedResourcePaths)) {
+                throw new AssertionError("Sorting not properly applied");
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/asmplugin/VisitorTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Asm plugin testing.
+ * @test
+ * @summary Test visitors.
+ * @author Andrei Eremeev
+ * @modules java.base/jdk.internal.org.objectweb.asm
+ *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jlink.internal.plugins.asm
+ * @build AsmPluginTestBase
+ * @run main VisitorTest
+ */
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.function.Function;
+
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.ClassVisitor;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.tools.jlink.internal.plugins.asm.AsmPool;
+import jdk.tools.jlink.internal.plugins.asm.AsmPool.ClassReaderVisitor;
+import jdk.tools.jlink.internal.plugins.asm.AsmPool.ResourceFile;
+import jdk.tools.jlink.internal.plugins.asm.AsmPool.ResourceFileVisitor;
+import jdk.tools.jlink.internal.plugins.asm.AsmPools;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Pool.ModuleData;
+
+public class VisitorTest extends AsmPluginTestBase {
+
+    public static void main(String[] args) throws Exception {
+        if (!isImageBuild()) {
+            System.err.println("Test not run. Not image build.");
+            return;
+        }
+        new VisitorTest().test();
+    }
+
+    @Override
+    public void test() throws Exception {
+        TestPlugin[] plugins = new TestPlugin[] {
+                new ClassVisitorPlugin("Class-global-pool", AsmPools::getGlobalPool),
+                new ClassVisitorPlugin("Class-module-pool", pools -> pools.getModulePool("java.base")),
+                new ResourceVisitorPlugin("Resource-global-pool", AsmPools::getGlobalPool),
+                new ResourceVisitorPlugin("Resource-module-pool", pools -> pools.getModulePool("java.base"))
+        };
+        for (TestPlugin p : plugins) {
+            System.err.println("Testing: " + p.getName());
+            Pool out = p.visit(getPool());
+            p.test(getPool(), out);
+        }
+    }
+
+    private static class CustomClassReaderVisitor implements ClassReaderVisitor {
+        private int amount = 0;
+        private int changed = 0;
+
+        @Override
+        public ClassWriter visit(ClassReader reader) {
+            if ((amount++ % 2) == 0) {
+                String className = reader.getClassName();
+                if (className.endsWith("module-info")) {
+                    return null;
+                }
+                ClassWriter cw = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES);
+                reader.accept(new ClassVisitor(Opcodes.ASM5, cw) {
+                    @Override
+                    public void visit(int i, int i1, String s, String s1, String s2, String[] strings) {
+                        super.visit(i, i1, s + "Changed", s1, s2, strings);
+                    }
+                }, ClassReader.EXPAND_FRAMES);
+                ++changed;
+                return cw;
+            } else {
+                return null;
+            }
+        }
+
+        public int getAmount() {
+            return amount;
+        }
+
+        public int getNumberOfChanged() {
+            return changed;
+        }
+    }
+
+    private static class CustomResourceFileVisitor implements ResourceFileVisitor {
+        private int amount = 0;
+        private int changed = 0;
+
+        @Override
+        public ResourceFile visit(ResourceFile resourceFile) {
+            if ((amount++ % 2) == 0) {
+                ++changed;
+                return new ResourceFile(resourceFile.getPath() + "Changed", resourceFile.getContent());
+            } else {
+                return null;
+            }
+        }
+
+        public int getAmount() {
+            return amount;
+        }
+
+        public int getNumberOfChanged() {
+            return changed;
+        }
+    }
+
+    public class ClassVisitorPlugin extends TestPlugin {
+
+        private final String name;
+        private final Function<AsmPools, AsmPool> getPool;
+        private final CustomClassReaderVisitor classReaderVisitor = new CustomClassReaderVisitor();
+
+        public ClassVisitorPlugin(String name, Function<AsmPools, AsmPool> getPool) {
+            this.name = name;
+            this.getPool = getPool;
+        }
+
+        @Override
+        public void visit() {
+            AsmPool pool = getPool.apply(getPools());
+            pool.visitClassReaders(classReaderVisitor);
+        }
+
+        @Override
+        public void test(Pool in, Pool out) throws Exception {
+            Collection<ModuleData> inClasses = getPool.apply(getPools()).getClasses();
+            if (inClasses.size() != classReaderVisitor.getAmount()) {
+                throw new AssertionError("Testing " + name + ". Number of visited classes. Expected: " +
+                        inClasses.size() + ", got: " + classReaderVisitor.getAmount());
+            }
+            Collection<ModuleData> outClasses = extractClasses(out);
+            int changedClasses = 0;
+            for (ModuleData r : outClasses) {
+                if (r.getPath().endsWith("Changed.class")) {
+                    ++changedClasses;
+                }
+            }
+            if (changedClasses != classReaderVisitor.getNumberOfChanged()) {
+                throw new AssertionError("Testing " + name + ". Changed classes. Expected: " + changedClasses +
+                        ", got: " + classReaderVisitor.getNumberOfChanged());
+            }
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
+    }
+
+    public class ResourceVisitorPlugin extends TestPlugin {
+
+        private final String name;
+        private final Function<AsmPools, AsmPool> getPool;
+        private final CustomResourceFileVisitor resourceFileVisitor = new CustomResourceFileVisitor();
+
+        public ResourceVisitorPlugin(String name, Function<AsmPools, AsmPool> getPool) {
+            this.name = name;
+            this.getPool = getPool;
+        }
+
+        @Override
+        public void visit() {
+            AsmPool pool = getPool.apply(getPools());
+            pool.visitResourceFiles(resourceFileVisitor);
+        }
+
+        @Override
+        public void test(Pool in, Pool out) throws Exception {
+            Collection<ModuleData> inResources = getPool.apply(getPools()).getResourceFiles();
+            if (inResources.size() != resourceFileVisitor.getAmount()) {
+                throw new AssertionError("Testing " + name + ". Number of visited resources. Expected: " +
+                        inResources.size() + ", got: " + resourceFileVisitor.getAmount());
+            }
+            Collection<ModuleData> outResources = extractResources(out);
+            int changedClasses = 0;
+            for (ModuleData r : outResources) {
+                if (r.getPath().endsWith("Changed")) {
+                    ++changedClasses;
+                }
+            }
+            if (changedClasses != resourceFileVisitor.getNumberOfChanged()) {
+                throw new AssertionError("Testing " + name + ". Changed classes. Expected: " + changedClasses +
+                        ", got: " + resourceFileVisitor.getNumberOfChanged());
+            }
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/basic/BasicTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,131 @@
+/**
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Basic test of jlink to create jmods and images
+ * @author Andrei Eremeev
+ * @library /lib/testlibrary
+ * @modules java.base/jdk.internal.module
+ *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jmod
+ *          jdk.compiler
+ * @build jdk.testlibrary.ProcessTools
+ *        jdk.testlibrary.OutputAnalyzer
+ *        JarUtils CompilerUtils
+ * @run main BasicTest
+ */
+
+import java.io.File;
+import java.io.PrintWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import jdk.testlibrary.OutputAnalyzer;
+import jdk.testlibrary.ProcessTools;
+
+public class BasicTest {
+
+    private final Path jdkHome = Paths.get(System.getProperty("test.jdk"));
+    private final Path jdkMods = jdkHome.resolve("jmods");
+    private final Path testSrc = Paths.get(System.getProperty("test.src"));
+    private final Path src = testSrc.resolve("src");
+    private final Path classes = Paths.get("classes");
+    private final Path jmods = Paths.get("jmods");
+    private final Path jars = Paths.get("jars");
+
+    public static void main(String[] args) throws Throwable {
+        new BasicTest().run();
+    }
+
+    public void run() throws Throwable {
+        if (Files.notExists(jdkMods)) {
+            return;
+        }
+
+        if (!CompilerUtils.compile(src, classes)) {
+            throw new AssertionError("Compilation failure. See log.");
+        }
+
+        String modName = "test";
+        Files.createDirectories(jmods);
+        Files.createDirectories(jars);
+        Path jarfile = jars.resolve("test.jar");
+        JarUtils.createJarFile(jarfile, classes);
+
+        Path image = Paths.get("mysmallimage");
+        runJmod(jarfile.toString(), modName);
+        runJlink(image, modName, "--compress", "2");
+        execute(image, modName);
+
+        Files.delete(jmods.resolve(modName + ".jmod"));
+
+        image = Paths.get("myimage");
+        runJmod(classes.toString(), modName);
+        runJlink(image, modName);
+        execute(image, modName);
+    }
+
+    private void execute(Path image, String moduleName) throws Throwable {
+        String cmd = image.resolve("bin").resolve(moduleName).toString();
+        OutputAnalyzer analyzer;
+        if (System.getProperty("os.name").startsWith("Windows")) {
+            analyzer = ProcessTools.executeProcess("sh.exe", cmd, "1", "2", "3");
+        } else {
+            analyzer = ProcessTools.executeProcess(cmd, "1", "2", "3");
+        }
+        if (analyzer.getExitValue() != 0) {
+            throw new AssertionError("Image invocation failed: rc=" + analyzer.getExitValue());
+        }
+    }
+
+    private void runJlink(Path image, String modName, String... options) {
+        List<String> args = new ArrayList<>();
+        Collections.addAll(args,
+                "--modulepath", jdkMods + File.pathSeparator + jmods,
+                "--addmods", modName,
+                "--output", image.toString());
+        Collections.addAll(args, options);
+        int rc = jdk.tools.jlink.internal.Main.run(args.toArray(new String[args.size()]), new PrintWriter(System.out));
+        if (rc != 0) {
+            throw new AssertionError("Jlink failed: rc = " + rc);
+        }
+    }
+
+    private void runJmod(String cp, String modName) {
+        int rc = jdk.tools.jmod.Main.run(new String[] {
+                "create",
+                "--class-path", cp,
+                "--module-version", "1.0",
+                "--main-class", "jdk.test.Test",
+                jmods.resolve(modName + ".jmod").toString(),
+        }, System.out);
+        if (rc != 0) {
+            throw new AssertionError("Jmod failed: rc = " + rc);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/basic/src/test/jdk/test/Test.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test;
+
+import java.lang.reflect.Module;
+import java.lang.reflect.Layer;
+
+public class Test {
+    public static void main(String[] args) {
+        System.out.println(Test.class + " ...");
+        for (String arg: args) {
+            System.out.println(arg);
+        }
+
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+        ClassLoader cl1 = Test.class.getClassLoader();
+        Module testModule = Test.class.getModule();
+        ClassLoader cl2 = Layer.boot().findLoader(testModule.getName());
+
+        if (cl1 != scl)
+            throw new RuntimeException("Not loaded by system class loader");
+        if (cl2 != scl)
+            throw new RuntimeException("Not associated with system class loader");
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/basic/src/test/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module test {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/customplugin/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module customplugin {
+    requires jdk.jlink;
+    provides jdk.tools.jlink.plugin.TransformerPlugin with plugin.HelloPlugin;
+    provides jdk.tools.jlink.plugin.TransformerPlugin with plugin.CustomPlugin;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/customplugin/plugin/CustomPlugin.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package plugin;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.TransformerPlugin;
+
+public class CustomPlugin implements TransformerPlugin {
+
+    private final static String NAME = "custom-plugin";
+
+    public CustomPlugin() {
+    }
+
+    @Override
+    public void visit(Pool in, Pool out) {
+        in.visit(new Pool.Visitor() {
+            @Override
+            public Pool.ModuleData visit(Pool.ModuleData content) {
+                return content;
+            }
+        }, out);
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    @Override
+    public String getDescription() {
+        return NAME + "-description";
+    }
+
+    @Override
+    public void configure(Map<String, String> config) {
+    }
+
+    @Override
+    public Set<PluginType> getType() {
+        Set<PluginType> set = new HashSet<>();
+        set.add(CATEGORY.PROCESSOR);
+        return Collections.unmodifiableSet(set);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/customplugin/plugin/HelloPlugin.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package plugin;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.TransformerPlugin;
+
+/**
+ * Custom plugin
+ */
+public final class HelloPlugin implements TransformerPlugin {
+
+    private static final String OUTPUT_FILE = "customplugin.txt";
+    public static final String NAME = "hello";
+
+    public static boolean called;
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    @Override
+    public void visit(Pool inResources, Pool outResources) {
+        try {
+            System.out.println("Hello!!!!!!!!!!");
+            File f = new File(OUTPUT_FILE);
+            f.createNewFile();
+            for (ModuleData res : inResources.getContent()) {
+                outResources.add(res);
+            }
+        } catch (IOException ex) {
+            throw new UncheckedIOException(ex);
+        }
+    }
+
+    @Override
+    public Set<PluginType> getType() {
+        Set<PluginType> set = new HashSet<>();
+        set.add(CATEGORY.TRANSFORMER);
+        return Collections.unmodifiableSet(set);
+    }
+
+    @Override
+    public String getDescription() {
+        return NAME + "-description";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/hashes/HashesTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,160 @@
+/**
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Test the recording and checking of dependency hashes
+ * @author Andrei Eremeev
+ * @library /lib/testlibrary
+ * @modules java.base/jdk.internal.module
+ *          jdk.jlink/jdk.tools.jlink
+ *          jdk.jlink/jdk.tools.jmod
+ *          jdk.compiler
+ * @ignore
+ * @build jdk.testlibrary.ProcessTools jdk.testlibrary.OutputAnalyzer CompilerUtils
+ * @run main HashesTest
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import jdk.testlibrary.OutputAnalyzer;
+import jdk.testlibrary.ProcessTools;
+
+public class HashesTest {
+
+    private final Path jdkHome = Paths.get(System.getProperty("test.jdk"));
+    private final Path stdJmods = jdkHome.resolve("jmods");
+    private final Path testSrc = Paths.get(System.getProperty("test.src"));
+    private final Path modSrc = testSrc.resolve("src");
+    private final Path newModSrc = testSrc.resolve("newsrc");
+    private final Path classes = Paths.get("classes");
+    private final Path jmods = Paths.get("jmods");
+
+    public static void main(String[] args) throws Exception {
+        new HashesTest().run();
+    }
+
+    private void run() throws Exception {
+        if (!Files.exists(stdJmods)) {
+            return;
+        }
+        Files.createDirectories(jmods);
+        Path m1Classes = classes.resolve("m1");
+        Path m2Classes = classes.resolve("m2");
+        Path m3Classes = classes.resolve("not_matched");
+        // build the second module
+        compileClasses(modSrc, m2Classes);
+        runJmod(m2Classes.toString(), m2Classes.getFileName().toString());
+
+        // build the third module
+        compileClasses(modSrc, m3Classes);
+        runJmod(m3Classes.toString(), m3Classes.getFileName().toString());
+
+        compileClasses(modSrc, m1Classes, "-mp", jmods.toString());
+        runJmod(m1Classes.toString(), m1Classes.getFileName().toString(),
+                "--modulepath", jmods.toString(), "--hash-dependencies", "m2");
+        runJava(0, "-mp", jmods.toString(), "-m", "m1/org.m1.Main");
+
+        deleteDirectory(m3Classes);
+        Files.delete(jmods.resolve("not_matched.jmod"));
+
+        // build the new third module
+        compileClasses(newModSrc, m3Classes);
+        runJmod(m3Classes.toString(), m3Classes.getFileName().toString());
+        runJava(0, "-mp", jmods.toString(), "-m", "m1/org.m1.Main");
+
+        deleteDirectory(m2Classes);
+        Files.delete(jmods.resolve("m2.jmod"));
+
+        compileClasses(newModSrc, m2Classes);
+        runJmod(m2Classes.toString(), m2Classes.getFileName().toString());
+
+        runJava(1, "-mp", jmods.toString(), "-m", "m1/org.m1.Main");
+
+        if (jdk.tools.jlink.internal.Main.run(new String[]{
+                "--modulepath", stdJmods.toString() + File.pathSeparator + jmods.toString(),
+                "--addmods", "m1", "--output", "myimage"}, new PrintWriter(System.out)) == 0) {
+            throw new AssertionError("Expected failure. rc = 0");
+        }
+    }
+
+    private void deleteDirectory(Path dir) throws IOException {
+        Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
+            @Override
+            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+                Files.delete(file);
+                return FileVisitResult.CONTINUE;
+            }
+
+            @Override
+            public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
+                Files.delete(dir);
+                return FileVisitResult.CONTINUE;
+            }
+        });
+    }
+
+    private void runJava(int expectedExitCode, String... args) throws Exception {
+        OutputAnalyzer analyzer = ProcessTools.executeTestJava(args);
+        if (analyzer.getExitValue() != expectedExitCode) {
+            throw new AssertionError("Expected exit code: " + expectedExitCode +
+                    ", got: " + analyzer.getExitValue());
+        }
+    }
+
+    private void compileClasses(Path src, Path output, String... options) throws IOException {
+        List<String> args = new ArrayList<>();
+        Collections.addAll(args, options);
+        Collections.addAll(args, "-d", output.toString());
+        args.add(src.toString());
+        System.out.println("javac options: " + args.stream().collect(Collectors.joining(" ")));
+        if (!CompilerUtils.compile(src.resolve(output.getFileName()), output, options)) {
+            throw new AssertionError("Compilation failure. See log.");
+        }
+    }
+
+    private void runJmod(String cp, String modName, String... options) {
+        List<String> args = new ArrayList<>();
+        args.add("create");
+        Collections.addAll(args, options);
+        Collections.addAll(args, "--class-path", cp,
+                jmods + File.separator + modName + ".jmod");
+        int rc = jdk.tools.jmod.Main.run(args.toArray(new String[args.size()]), System.out);
+        System.out.println("jmod options: " + args.stream().collect(Collectors.joining(" ")));
+        if (rc != 0) {
+            throw new AssertionError("Jmod failed: rc = " + rc);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/hashes/newsrc/m2/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m2 {
+    exports org.m2;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/hashes/newsrc/m2/org/m2/Util.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.m2;
+
+public class Util {
+    private Util() { }
+
+    public static String timeOfDay() {
+        return "Time for a beer";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/hashes/newsrc/not_matched/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module not_matched {
+    exports org.not_matched;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/hashes/newsrc/not_matched/org/not_matched/Name.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.not_matched;
+
+public class Name {
+    private Name() { }
+
+    public static String name() {
+        return "new_module";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/hashes/src/m1/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m1 {
+    requires m2;
+    requires not_matched;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/hashes/src/m1/org/m1/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.m1;
+
+import org.m2.Util;
+import org.not_matched.Name;
+
+public class Main {
+    public static void main(String[] args) {
+        System.out.println(Util.timeOfDay());
+        System.out.println(Name.name());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/hashes/src/m2/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m2 {
+    exports org.m2;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/hashes/src/m2/org/m2/Util.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.m2;
+
+public class Util {
+    private Util() { }
+
+    public static String timeOfDay() {
+        return "Time for lunch";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/hashes/src/not_matched/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module not_matched {
+    exports org.not_matched;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/hashes/src/not_matched/org/not_matched/Name.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.not_matched;
+
+public class Name {
+    private Name() { }
+
+    public static String name() {
+        return "old_module";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/optimplugin/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module optimplugin {
+    exports optim;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/optimplugin/optim/AType.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package optim;
+
+//package class
+class AType {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/optimplugin/optim/ForNameTestCase.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package optim;
+
+public class ForNameTestCase {
+    private static final String EXPECTED = "expected";
+    public static Class<?> forName() {
+        try {
+            Class<?> cl = Class.forName("java.lang.String");
+            return cl;
+        } catch (ClassNotFoundException |
+                IllegalArgumentException |
+                ClassCastException x) {
+            throw new InternalError(x);
+        }
+    }
+
+    public static Class<?> forName0() throws ClassNotFoundException {
+        return Class.forName("java.lang.String");
+    }
+
+    public static Class<?> forName1() throws Exception {
+        Class<?> clazz = null;
+        try {
+            clazz = Class.forName("java.lang.String");
+        } catch (ClassNotFoundException e) {
+            return null;
+        }
+        return clazz;
+    }
+
+    public static void forNameException() throws Exception {
+        try {
+            Class.forName("java.lang.String");
+            throw new Exception(EXPECTED);
+        } catch (ClassNotFoundException e) {
+            return;
+        } catch (RuntimeException e) {
+            return;
+        }
+    }
+
+    public static Class<?> forName2() throws Exception {
+        Class<?> clazz = null;
+        try {
+            clazz = Class.forName("java.lang.String");
+            try {
+                throw new Exception("das");
+            } catch (Exception ex) {
+            }
+        } catch (ClassNotFoundException e) {
+            return null;
+        }
+        return clazz;
+    }
+
+    public static Class<?> forName3() throws Exception {
+        Class<?> clazz = null;
+        try {
+            return clazz = Class.forName("java.lang.String");
+        } catch (ClassNotFoundException e) {
+            return null;
+        }
+    }
+
+    public static Class<?> forName4() throws Exception {
+        Class<?> clazz = null;
+        try {
+            clazz = Class.forName("java.lang.String");
+        } catch (ClassNotFoundException e) {
+            return null;
+        } catch (RuntimeException e) {
+            return null;
+        }
+        return clazz;
+    }
+
+    public static Class<?> forName5() {
+        Class<?> clazz = null;
+        try {
+            clazz = Class.forName("java.lang.String");
+        } catch (ClassNotFoundException e) {
+        }
+        int i;
+        try {
+            i = 0;
+        } catch (Exception e) {
+        }
+        return clazz;
+    }
+
+    public static Class<?> forName6() {
+        Class<?> clazz = null;
+        try {
+            return Class.forName("java.lang.String");
+        } catch (ClassNotFoundException e) {
+        }
+
+        try {
+                // This one is removed because no more reachable when
+            // Class.forName is removed
+            int k = 0;
+        } catch (RuntimeException e) {
+        }
+
+        int i;
+        try {
+                // This one is removed because no more reachable when
+            // Class.forName is removed
+            return Class.forName("TOTO");
+        } catch (ClassNotFoundException e) {
+        }
+        try {
+                // This one is removed because no more reachable when
+            // Class.forName is removed
+            return Class.forName("TOTO");
+        } catch (ClassNotFoundException e) {
+        }
+        try {
+                // This one is removed because no more reachable when
+            // Class.forName is removed
+            return Class.forName("TOTO");
+        } catch (ClassNotFoundException e) {
+        }
+        try {
+                // This one is removed because no more reachable when
+            // Class.forName is removed
+            return Class.forName("TOTO");
+        } catch (ClassNotFoundException e) {
+        }
+        return clazz;
+    }
+
+    public static Class<?> forName7() {
+        Class<?> clazz = null;
+        try {
+            clazz = Class.forName("optim.AType");
+        } catch (ClassNotFoundException e) {
+        }
+        return clazz;
+    }
+
+    public static Class<?> negativeforName() {
+        Class<?> clazz = null;
+        try {
+            clazz = Class.forName("jdk.internal.jimage.BasicImageReader");
+        } catch (ClassNotFoundException e) {
+        }
+        return clazz;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/plugins/CompressIndexesTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Test CompressIndexes
+ * @author Jean-Francois Denise
+ * @modules java.base/jdk.internal.jimage.decompressor
+ * @run main CompressIndexesTest
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.internal.jimage.decompressor.CompressIndexes;
+
+public class CompressIndexesTest {
+
+    public static void main(String[] args) throws IOException {
+        new CompressIndexesTest().test();
+    }
+
+    public void test() throws IOException {
+        int[] data = {
+                // compressed length 1
+                0x00000000,
+                0x00000001,
+                0x0000000F,
+                0x0000001F,
+                // compressed length 2
+                0x0000002F,
+                0x00000100,
+                0x00001FFF,
+                // compressed length 3
+                0x00002FFF,
+                0x00010000,
+                0x001FFFFF,
+                // compressed length 4
+                0x00200000,
+                0x01000000,
+                Integer.MAX_VALUE
+        };
+        int[] intervals = {4, 7, 10, data.length};
+        List<byte[]> arrays = new ArrayList<>();
+        int length = 0;
+        int begin = 0;
+        for (int interval : intervals) {
+            ++length;
+            for (int j = begin; j < interval; ++j) {
+                arrays.add(check(data[j], length));
+            }
+            begin = interval;
+        }
+
+        int totalLength = arrays.stream().mapToInt(b -> b.length).sum();
+        ByteBuffer all = ByteBuffer.allocate(totalLength);
+        arrays.forEach(all::put);
+        byte[] flow = all.array();
+        check(flow, arrays);
+        System.err.println(arrays.size() * 4 + " compressed in " + flow.length
+                + " gain of " + (100 - ((flow.length * 100) / (arrays.size() * 4))) + "%");
+        try (DataInputStream is = new DataInputStream(new ByteArrayInputStream(flow))) {
+            int index = 0;
+            while (is.available() > 0) {
+                int d = CompressIndexes.readInt(is);
+                if (data[index] != d) {
+                    throw new AssertionError("Expected: " + data[index] + ", got: " + d);
+                }
+                ++index;
+            }
+        }
+    }
+
+    private void check(byte[] flow, List<byte[]> arrays) {
+        List<Integer> d = CompressIndexes.decompressFlow(flow);
+        List<Integer> dd = new ArrayList<>();
+        for (byte[] b : arrays) {
+            int i = CompressIndexes.decompress(b, 0);
+            dd.add(i);
+        }
+        if (!d.equals(dd)) {
+            System.err.println(dd);
+            System.err.println(d);
+            throw new AssertionError("Invalid flow " + d);
+        } else {
+            System.err.println("OK for flow");
+        }
+    }
+
+    private byte[] check(int val, int size) {
+        byte[] c = CompressIndexes.compress(val);
+        if (c.length != size) {
+            throw new AssertionError("Invalid compression size " + c.length);
+        }
+        int d = CompressIndexes.decompress(c, 0);
+        if (val != d) {
+            throw new AssertionError("Invalid " + d);
+        } else {
+            System.err.println("Ok for " + val);
+        }
+        return c;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/plugins/CompressorPluginTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,356 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Test zip compressor
+ * @author Jean-Francois Denise
+ * @modules java.base/jdk.internal.jimage.decompressor
+ *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jlink.internal.plugins
+ * @run main CompressorPluginTest
+ */
+import java.net.URI;
+import java.nio.ByteOrder;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystemNotFoundException;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.ProviderNotFoundException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import jdk.internal.jimage.decompressor.CompressedResourceHeader;
+import jdk.internal.jimage.decompressor.ResourceDecompressor;
+import jdk.internal.jimage.decompressor.ResourceDecompressorFactory;
+import jdk.internal.jimage.decompressor.StringSharingDecompressorFactory;
+import jdk.internal.jimage.decompressor.ZipDecompressorFactory;
+import jdk.tools.jlink.internal.PoolImpl;
+import jdk.tools.jlink.internal.StringTable;
+import jdk.tools.jlink.internal.plugins.DefaultCompressPlugin;
+import jdk.tools.jlink.internal.plugins.StringSharingPlugin;
+import jdk.tools.jlink.internal.plugins.ZipPlugin;
+import jdk.tools.jlink.plugin.Plugin;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.TransformerPlugin;
+
+public class CompressorPluginTest {
+
+    private static int strID = 1;
+
+    public static void main(String[] args) throws Exception {
+        new CompressorPluginTest().test();
+    }
+
+    public void test() throws Exception {
+        FileSystem fs;
+        try {
+            fs = FileSystems.getFileSystem(URI.create("jrt:/"));
+        } catch (ProviderNotFoundException | FileSystemNotFoundException e) {
+            System.err.println("Not an image build, test skipped.");
+            return;
+        }
+        Path javabase = fs.getPath("/modules/java.base");
+
+        checkCompress(gatherResources(javabase), new ZipPlugin(), null,
+                new ResourceDecompressorFactory[]{
+                    new ZipDecompressorFactory()
+                });
+
+        Pool classes = gatherClasses(javabase);
+        // compress = String sharing
+        checkCompress(classes, new StringSharingPlugin(), null,
+                new ResourceDecompressorFactory[]{
+                    new StringSharingDecompressorFactory()});
+
+        // compress == ZIP + String sharing
+        Properties options = new Properties();
+        options.setProperty(ZipPlugin.NAME, "");
+        checkCompress(classes, new DefaultCompressPlugin(), options,
+                new ResourceDecompressorFactory[]{
+                    new ZipDecompressorFactory(),
+                    new StringSharingDecompressorFactory()
+                });
+
+        // compress == ZIP + String sharing + filter
+        options.setProperty(DefaultCompressPlugin.FILTER,
+                "*Exception.class,^*IOException.class");
+        checkCompress(classes, new DefaultCompressPlugin(), options,
+                new ResourceDecompressorFactory[]{
+                    new ZipDecompressorFactory(),
+                    new StringSharingDecompressorFactory()
+                }, Collections.singletonList(".*Exception.class"),
+                Collections.singletonList(".*IOException.class"));
+
+        // compress level 1 == ZIP
+        Properties options1 = new Properties();
+        options1.setProperty(DefaultCompressPlugin.NAME,
+                "1");
+        checkCompress(classes, new DefaultCompressPlugin(),
+                options1,
+                new ResourceDecompressorFactory[]{
+                    new ZipDecompressorFactory()
+                });
+
+        // compress level 1 == ZIP
+        options1.setProperty(DefaultCompressPlugin.FILTER,
+                "*Exception.class,^*IOException.class");
+        checkCompress(classes, new DefaultCompressPlugin(),
+                options1,
+                new ResourceDecompressorFactory[]{
+                    new ZipDecompressorFactory()
+                }, Collections.singletonList(".*Exception.class"),
+                Collections.singletonList(".*IOException.class"));
+
+        // compress level 2 == ZIP + String sharing
+        Properties options2 = new Properties();
+        options2.setProperty(DefaultCompressPlugin.NAME,
+                "2");
+        checkCompress(classes, new DefaultCompressPlugin(),
+                options2,
+                new ResourceDecompressorFactory[]{
+                    new ZipDecompressorFactory(),
+                    new StringSharingDecompressorFactory()
+                });
+
+        // compress level 2 == ZIP + String sharing + filter
+        options2.setProperty(DefaultCompressPlugin.FILTER,
+                "*Exception.class,^*IOException.class");
+        checkCompress(classes, new DefaultCompressPlugin(),
+                options2,
+                new ResourceDecompressorFactory[]{
+                    new ZipDecompressorFactory(),
+                    new StringSharingDecompressorFactory()
+                }, Collections.singletonList(".*Exception.class"),
+                Collections.singletonList(".*IOException.class"));
+
+        // compress level 0 == String sharing
+        Properties options0 = new Properties();
+        options0.setProperty(DefaultCompressPlugin.NAME, "0");
+        checkCompress(classes, new DefaultCompressPlugin(),
+                options0,
+                new ResourceDecompressorFactory[]{
+                    new StringSharingDecompressorFactory()
+                });
+
+        // compress level 0 == String sharing + filter
+        options0.setProperty(DefaultCompressPlugin.FILTER,
+                "*Exception.class,^*IOException.class");
+        checkCompress(classes, new DefaultCompressPlugin(),
+                options0,
+                new ResourceDecompressorFactory[]{
+                    new StringSharingDecompressorFactory()
+                }, Collections.singletonList(".*Exception.class"),
+                Collections.singletonList(".*IOException.class"));
+    }
+
+    private Pool gatherResources(Path module) throws Exception {
+        Pool pool = new PoolImpl(ByteOrder.nativeOrder(), new StringTable() {
+
+            @Override
+            public int addString(String str) {
+                return -1;
+            }
+
+            @Override
+            public String getString(int id) {
+                return null;
+            }
+        });
+        try (Stream<Path> stream = Files.walk(module)) {
+            for (Iterator<Path> iterator = stream.iterator(); iterator.hasNext();) {
+                Path p = iterator.next();
+                if (Files.isRegularFile(p)) {
+                    byte[] content = Files.readAllBytes(p);
+                    pool.add(Pool.newResource(p.toString(), content));
+                }
+            }
+        }
+        return pool;
+    }
+
+    private Pool gatherClasses(Path module) throws Exception {
+        Pool pool = new PoolImpl(ByteOrder.nativeOrder(), new StringTable() {
+
+            @Override
+            public int addString(String str) {
+                return -1;
+            }
+
+            @Override
+            public String getString(int id) {
+                return null;
+            }
+        });
+        try (Stream<Path> stream = Files.walk(module)) {
+            for (Iterator<Path> iterator = stream.iterator(); iterator.hasNext();) {
+                Path p = iterator.next();
+                if (Files.isRegularFile(p) && p.toString().endsWith(".class")) {
+                    byte[] content = Files.readAllBytes(p);
+                    pool.add(Pool.newResource(p.toString(), content));
+                }
+            }
+        }
+        return pool;
+    }
+
+    private void checkCompress(Pool resources, Plugin prov,
+            Properties config,
+            ResourceDecompressorFactory[] factories) throws Exception {
+        checkCompress(resources, prov, config, factories, Collections.emptyList(), Collections.emptyList());
+    }
+
+    private void checkCompress(Pool resources, Plugin prov,
+            Properties config,
+            ResourceDecompressorFactory[] factories,
+            List<String> includes,
+            List<String> excludes) throws Exception {
+        long original = 0;
+        long compressed = 0;
+        for (ModuleData resource : resources.getContent()) {
+            List<Pattern> includesPatterns = includes.stream()
+                    .map(Pattern::compile)
+                    .collect(Collectors.toList());
+            List<Pattern> excludesPatterns = excludes.stream()
+                    .map(Pattern::compile)
+                    .collect(Collectors.toList());
+
+            Map<String, String> props = new HashMap<>();
+            if (config != null) {
+                for (String p : config.stringPropertyNames()) {
+                    props.put(p, config.getProperty(p));
+                }
+            }
+            prov.configure(props);
+            final Map<Integer, String> strings = new HashMap<>();
+            PoolImpl inputResources = new PoolImpl(ByteOrder.nativeOrder(), new StringTable() {
+                @Override
+                public int addString(String str) {
+                    int id = strID;
+                    strID += 1;
+                    strings.put(id, str);
+                    return id;
+                }
+
+                @Override
+                public String getString(int id) {
+                    return strings.get(id);
+                }
+            });
+            inputResources.add(resource);
+            Pool compressedResources = applyCompressor(prov, inputResources, resource, includesPatterns, excludesPatterns);
+            original += resource.getLength();
+            compressed += compressedResources.get(resource.getPath()).getLength();
+            applyDecompressors(factories, inputResources, compressedResources, strings, includesPatterns, excludesPatterns);
+        }
+        String compressors = Stream.of(factories)
+                .map(Object::getClass)
+                .map(Class::getSimpleName)
+                .collect(Collectors.joining(", "));
+        String size = "Compressed size: " + compressed + ", original size: " + original;
+        System.out.println("Used " + compressors + ". " + size);
+        if (original <= compressed) {
+            throw new AssertionError("java.base not compressed.");
+        }
+    }
+
+    private Pool applyCompressor(Plugin plugin,
+            PoolImpl inputResources,
+            ModuleData res,
+            List<Pattern> includesPatterns,
+            List<Pattern> excludesPatterns) throws Exception {
+        TransformerPlugin compressor = (TransformerPlugin) plugin;
+        Pool compressedPool = new PoolImpl(ByteOrder.nativeOrder(), inputResources.getStringTable());
+        compressor.visit(inputResources, compressedPool);
+        String path = res.getPath();
+        ModuleData compressed = compressedPool.get(path);
+        CompressedResourceHeader header
+                = CompressedResourceHeader.readFromResource(ByteOrder.nativeOrder(), compressed.getBytes());
+        if (isIncluded(includesPatterns, excludesPatterns, path)) {
+            if (header == null) {
+                throw new AssertionError("Path should be compressed: " + path);
+            }
+            if (header.getDecompressorNameOffset() == 0) {
+                throw new AssertionError("Invalid plugin offset "
+                        + header.getDecompressorNameOffset());
+            }
+            if (header.getResourceSize() <= 0) {
+                throw new AssertionError("Invalid compressed size "
+                        + header.getResourceSize());
+            }
+        } else if (header != null) {
+            throw new AssertionError("Path should not be compressed: " + path);
+        }
+        return compressedPool;
+    }
+
+    private void applyDecompressors(ResourceDecompressorFactory[] decompressors,
+            Pool inputResources,
+            Pool compressedResources,
+            Map<Integer, String> strings,
+            List<Pattern> includesPatterns,
+            List<Pattern> excludesPatterns) throws Exception {
+        for (ModuleData compressed : compressedResources.getContent()) {
+            CompressedResourceHeader header = CompressedResourceHeader.readFromResource(
+                    ByteOrder.nativeOrder(), compressed.getBytes());
+            String path = compressed.getPath();
+            ModuleData orig = inputResources.get(path);
+            if (!isIncluded(includesPatterns, excludesPatterns, path)) {
+                continue;
+            }
+            byte[] decompressed = compressed.getBytes();
+            for (ResourceDecompressorFactory factory : decompressors) {
+                ResourceDecompressor decompressor = factory.newDecompressor(new Properties());
+                decompressed = decompressor.decompress(
+                        strings::get, decompressed,
+                        CompressedResourceHeader.getSize(), header.getUncompressedSize());
+            }
+
+            if (decompressed.length != orig.getLength()) {
+                throw new AssertionError("Invalid uncompressed size "
+                        + header.getUncompressedSize());
+            }
+            byte[] origContent = orig.getBytes();
+            for (int i = 0; i < decompressed.length; i++) {
+                if (decompressed[i] != origContent[i]) {
+                    throw new AssertionError("Decompressed and original differ at index " + i);
+                }
+            }
+        }
+    }
+
+    private boolean isIncluded(List<Pattern> includesPatterns, List<Pattern> excludesPatterns, String path) {
+        return !excludesPatterns.stream().anyMatch((pattern) -> pattern.matcher(path).matches())
+                && (includesPatterns.isEmpty()
+                || includesPatterns.stream().anyMatch((pattern) -> pattern.matcher(path).matches()));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/plugins/ExcludeFilesPluginTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Test exclude files plugin
+ * @author Jean-Francois Denise
+ * @modules jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jlink.internal.plugins
+ * @run main ExcludeFilesPluginTest
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.nio.file.Files;
+import java.util.HashMap;
+import java.util.Map;
+import jdk.tools.jlink.internal.PoolImpl;
+
+import jdk.tools.jlink.internal.plugins.ExcludeFilesPlugin;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.Pool.ModuleDataType;
+import jdk.tools.jlink.plugin.TransformerPlugin;
+
+public class ExcludeFilesPluginTest {
+    public static void main(String[] args) throws Exception {
+        new ExcludeFilesPluginTest().test();
+    }
+
+    public void test() throws Exception {
+        checkFiles("*.jcov", "num/toto.jcov", "", true);
+        checkFiles("*.jcov", "/toto.jcov", "", true);
+        checkFiles("*.jcov", "toto.jcov/tutu/tata", "", false);
+        checkFiles("/java.base/*.jcov", "toto.jcov", "java.base", true);
+        checkFiles("/java.base/toto.jcov", "iti.jcov", "t/java.base", false);
+        checkFiles("/java.base/*/toto.jcov", "toto.jcov", "java.base", false);
+        checkFiles("/java.base/*/toto.jcov", "tutu/toto.jcov", "java.base", true);
+        checkFiles("*/java.base/*/toto.jcov", "java.base/tutu/toto.jcov", "/tutu", true);
+
+        checkFiles("/*$*.properties", "tutu/Toto$Titi.properties", "java.base", true);
+        checkFiles("*$*.properties", "tutu/Toto$Titi.properties", "java.base", true);
+
+        // Excluded files list in a file
+        File order = new File("files.exc");
+        order.createNewFile();
+        Files.write(order.toPath(), "*.jcov".getBytes());
+        checkFiles(order.getAbsolutePath(), "/num/toto.jcov", "", true);
+    }
+
+    public void checkFiles(String s, String sample, String module, boolean exclude) throws Exception {
+        Map<String, String> prop = new HashMap<>();
+        prop.put(ExcludeFilesPlugin.NAME, s);
+        ExcludeFilesPlugin fplug = new ExcludeFilesPlugin();
+        fplug.configure(prop);
+        PoolImpl files = new PoolImpl();
+        PoolImpl fresult = new PoolImpl();
+        ModuleData f = Pool.newImageFile(module, "/" + module + "/" + sample,
+                ModuleDataType.CONFIG, new ByteArrayInputStream(new byte[0]), 0);
+        files.add(f);
+
+        fplug.visit(files, fresult);
+
+        if (exclude) {
+            if (fresult.getContent().contains(f)) {
+                throw new Exception(sample + " should be excluded by " + s);
+            }
+        } else {
+            if (!fresult.getContent().contains(f)) {
+                throw new Exception(sample + " shouldn't be excluded by " + s);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/plugins/ExcludePluginTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Test exclude plugin
+ * @author Jean-Francois Denise
+ * @modules jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jlink.internal.plugins
+ * @run main ExcludePluginTest
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import java.util.HashMap;
+import java.util.Map;
+import jdk.tools.jlink.internal.PoolImpl;
+
+import jdk.tools.jlink.internal.plugins.ExcludePlugin;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Pool.ModuleData;
+
+public class ExcludePluginTest {
+
+    public static void main(String[] args) throws Exception {
+        new ExcludePluginTest().test();
+    }
+
+    public void test() throws Exception {
+        check("*.jcov", "/num/toto.jcov", true);
+        check("*.jcov", "//toto.jcov", true);
+        check("*.jcov", "/toto.jcov/tutu/tata", false);
+        check("/java.base/*.jcov", "/java.base/toto.jcov", true);
+        check("/java.base/toto.jcov", "t/java.base/iti.jcov", false);
+        check("/java.base/*/toto.jcov", "/java.base/toto.jcov", false);
+        check("/java.base/*/toto.jcov", "/java.base/tutu/toto.jcov", true);
+        check("*/java.base/*/toto.jcov", "/tutu/java.base/tutu/toto.jcov", true);
+        check("*/META-INF/*", "/META-INF/services/  MyProvider ", false);
+        check("*/META-INF/*", "/META-INF/services/MyProvider", false);
+        check("*/META-INF", " /META-INF/services/MyProvider", false);
+        check("*/META-INF/*", "/java.base//META-INF/services/MyProvider", true);
+        check("/java.base/*/Toto$Titi.class", "/java.base/tutu/Toto$Titi.class", true);
+        check("/*$*.class", "/java.base/tutu/Toto$Titi.class", true);
+        check("*$*.class", "/java.base/tutu/Toto$Titi.class", true);
+
+        // Excluded resource list in a file
+        File order = new File("resources.exc");
+        order.createNewFile();
+        Files.write(order.toPath(), "*.jcov".getBytes());
+        check(order.getAbsolutePath(), "/num/toto.jcov", true);
+    }
+
+    public void check(String s, String sample, boolean exclude) throws Exception {
+        Map<String, String> prop = new HashMap<>();
+        prop.put(ExcludePlugin.NAME, s);
+        ExcludePlugin excludePlugin = new ExcludePlugin();
+        excludePlugin.configure(prop);
+        Pool resources = new PoolImpl();
+        ModuleData resource = Pool.newResource(sample, new byte[0]);
+        resources.add(resource);
+        Pool result = new PoolImpl();
+        excludePlugin.visit(resources, result);
+        if (exclude) {
+            if (result.getContent().contains(resource)) {
+                throw new AssertionError(sample + " should be excluded by " + s);
+            }
+        } else {
+            if (!result.getContent().contains(resource)) {
+                throw new AssertionError(sample + " shouldn't be excluded by " + s);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/plugins/ExcludeVMPluginTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+ /*
+ * @test
+ * @summary Test exclude VM plugin
+ * @author Jean-Francois Denise
+ * @modules jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jlink.internal.plugins
+ * @run main ExcludeVMPluginTest
+ */
+import java.io.ByteArrayInputStream;
+import java.util.HashMap;
+import java.util.Map;
+import jdk.tools.jlink.internal.PoolImpl;
+
+import jdk.tools.jlink.internal.plugins.ExcludeVMPlugin;
+import jdk.tools.jlink.plugin.Plugin;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.Pool.ModuleDataType;
+import jdk.tools.jlink.plugin.TransformerPlugin;
+
+public class ExcludeVMPluginTest {
+
+    private static final String TAG = "# orig in test\n";
+
+    private static final String[] ARCHITECTURES = {"/", "/amd64/", "/i386/", "/arm/",
+        "/aarch64/", "/toto/"};
+
+    private static final String[] CLIENT = {"client/" + jvmlib(),};
+    private static final String[] SERVER = {"server/" + jvmlib()};
+    private static final String[] MINIMAL = {"minimal/" + jvmlib()};
+    private static final String[] ALL = {CLIENT[0], SERVER[0], MINIMAL[0]};
+    private static final String JVM_CFG_ALL = TAG + "-server KNOWN\n-client KNOWN\n-minimal KNOWN\n";
+    private static final String JVM_CFG_CLIENT = TAG + "-client KNOWN\n";
+    private static final String JVM_CFG_SERVER = TAG + "-server KNOWN\n";
+    private static final String JVM_CFG_SERVER_ALIAS_OTHERS = TAG + "-server KNOWN\n-client ALIASED_TO -server\n-minimal ALIASED_TO -server\n";
+    private static final String JVM_CFG_CLIENT_ALIAS_OTHERS = TAG + "-client KNOWN\n-server ALIASED_TO -client\n-minimal ALIASED_TO -client\n";
+    private static final String JVM_CFG_MINIMAL_ALIAS_OTHERS = TAG + "-minimal KNOWN\n-server ALIASED_TO -minimal\n-client ALIASED_TO -minimal\n";
+    private static final String JVM_CFG_MINIMAL = TAG + "-minimal KNOWN\n";
+
+    public static void main(String[] args) throws Exception {
+        new ExcludeVMPluginTest().test();
+    }
+
+    public void test() throws Exception {
+        boolean failed = false;
+
+        try {
+            checkVM("toto", ALL, JVM_CFG_ALL, ALL, JVM_CFG_ALL);
+            failed = true;
+            throw new Exception("Should have failed");
+        } catch (Exception ex) {
+            if (failed) {
+                throw ex;
+            }
+        }
+
+        checkVM("all", ALL, JVM_CFG_ALL, ALL, JVM_CFG_ALL);
+        checkVM("all", CLIENT, JVM_CFG_CLIENT, CLIENT, JVM_CFG_CLIENT);
+        checkVM("all", SERVER, JVM_CFG_SERVER, SERVER, JVM_CFG_SERVER);
+        checkVM("all", MINIMAL, JVM_CFG_MINIMAL, MINIMAL, JVM_CFG_MINIMAL);
+
+        checkVM("server", ALL, JVM_CFG_ALL, SERVER, JVM_CFG_SERVER_ALIAS_OTHERS);
+        checkVM("server", SERVER, JVM_CFG_SERVER, SERVER, JVM_CFG_SERVER);
+        try {
+            checkVM("server", CLIENT, JVM_CFG_CLIENT, SERVER, JVM_CFG_SERVER);
+            failed = true;
+            throw new Exception("Should have failed");
+        } catch (Exception ex) {
+            if (failed) {
+                throw ex;
+            }
+        }
+        try {
+            checkVM("server", MINIMAL, JVM_CFG_MINIMAL, SERVER, JVM_CFG_SERVER);
+            failed = true;
+            throw new Exception("Should have failed");
+        } catch (Exception ex) {
+            if (failed) {
+                throw ex;
+            }
+        }
+
+        checkVM("client", ALL, JVM_CFG_ALL, CLIENT, JVM_CFG_CLIENT_ALIAS_OTHERS);
+        checkVM("client", CLIENT, JVM_CFG_CLIENT, CLIENT, JVM_CFG_CLIENT);
+        try {
+            checkVM("client", SERVER, JVM_CFG_SERVER, CLIENT, JVM_CFG_CLIENT);
+            failed = true;
+            throw new Exception("Should have failed");
+        } catch (Exception ex) {
+            if (failed) {
+                throw ex;
+            }
+        }
+        try {
+            checkVM("client", MINIMAL, JVM_CFG_MINIMAL, CLIENT, JVM_CFG_CLIENT);
+            failed = true;
+            throw new Exception("Should have failed");
+        } catch (Exception ex) {
+            if (failed) {
+                throw ex;
+            }
+        }
+
+        checkVM("minimal", ALL, JVM_CFG_ALL, MINIMAL, JVM_CFG_MINIMAL_ALIAS_OTHERS);
+        checkVM("minimal", MINIMAL, JVM_CFG_MINIMAL, MINIMAL, JVM_CFG_MINIMAL);
+        try {
+            checkVM("minimal", SERVER, JVM_CFG_SERVER, MINIMAL, JVM_CFG_MINIMAL);
+            failed = true;
+            throw new Exception("Should have failed");
+        } catch (Exception ex) {
+            if (failed) {
+                throw ex;
+            }
+        }
+        try {
+            checkVM("minimal", CLIENT, JVM_CFG_CLIENT, MINIMAL, JVM_CFG_MINIMAL);
+            failed = true;
+            throw new Exception("Should have failed");
+        } catch (Exception ex) {
+            if (failed) {
+                throw ex;
+            }
+        }
+
+    }
+
+    public void checkVM(String vm, String[] input, String jvmcfg, String[] expectedOutput, String expectdJvmCfg) throws Exception {
+
+        for (String arch : ARCHITECTURES) {
+            String[] winput = new String[input.length];
+            String[] woutput = new String[expectedOutput.length];
+            for (int i = 0; i < input.length; i++) {
+                winput[i] = "/java.base/native" + arch + input[i];
+            }
+            for (int i = 0; i < expectedOutput.length; i++) {
+                woutput[i] = "/java.base/native" + arch + expectedOutput[i];
+            }
+            doCheckVM(vm, winput, jvmcfg, woutput, expectdJvmCfg);
+        }
+    }
+
+    private void doCheckVM(String vm, String[] input, String jvmcfg, String[] expectedOutput, String expectdJvmCfg) throws Exception {
+        // Create a pool with jvm.cfg and the input paths.
+        byte[] jvmcfgContent = jvmcfg.getBytes();
+        Pool pool = new PoolImpl();
+        pool.add(Pool.newImageFile("java.base", "/java.base/native/jvm.cfg",
+                ModuleDataType.NATIVE_LIB, new ByteArrayInputStream(jvmcfgContent), jvmcfgContent.length));
+        for (String in : input) {
+            pool.add(Pool.newImageFile("java.base", in,
+                    ModuleDataType.NATIVE_LIB, new ByteArrayInputStream(new byte[0]), 0));
+        }
+        Pool out = new PoolImpl();
+
+        TransformerPlugin p = new ExcludeVMPlugin();
+        Map<String, String> config = new HashMap<>();
+        if (vm != null) {
+            config.put(ExcludeVMPlugin.NAME, vm);
+        }
+        p.configure(config);
+        p.visit(pool, out);
+
+        String newContent = new String(out.get("/java.base/native/jvm.cfg").stream().readAllBytes());
+
+        if (!expectdJvmCfg.equals(newContent)) {
+            throw new Exception("Got content " + newContent + " expected " + expectdJvmCfg);
+        }
+
+        if (out.getContent().size() != (expectedOutput.length + 1)) {
+            for (ModuleData m : out.getContent()) {
+                System.err.println(m.getPath());
+            }
+            throw new Exception("Invalid output size " + out.getContent().size() + " expected " + (expectedOutput.length + 1));
+        }
+
+        for (ModuleData md : out.getContent()) {
+            if (md.getPath().equals("/java.base/native/jvm.cfg")) {
+                continue;
+            }
+            boolean contained = false;
+            for (String o : expectedOutput) {
+                if (md.getPath().equals(o)) {
+                    contained = true;
+                    break;
+                }
+            }
+            if (!contained) {
+                throw new Exception(md.getPath() + " not expected");
+            }
+        }
+
+    }
+
+    private static boolean isWindows() {
+        return System.getProperty("os.name").startsWith("Windows");
+    }
+
+    private static boolean isMac() {
+        return System.getProperty("os.name").startsWith("Mac OS");
+    }
+
+    private static String jvmlib() {
+        String lib = "libjvm.so";
+        if (isWindows()) {
+            lib = "jvm.dll";
+        } else if (isMac()) {
+            lib = "libjvm.dylib";
+        }
+        return lib;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/plugins/FileCopierPluginTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Test files copy plugin
+ * @author Jean-Francois Denise
+ * @modules jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jlink.internal.plugins
+ * @run main FileCopierPluginTest
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import jdk.tools.jlink.internal.PoolImpl;
+import jdk.tools.jlink.builder.DefaultImageBuilder;
+
+import jdk.tools.jlink.internal.plugins.FileCopierPlugin;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.Pool.ModuleDataType;
+
+public class FileCopierPluginTest {
+
+    public static void main(String[] args) throws Exception {
+        new FileCopierPluginTest().test();
+    }
+
+    /**
+     * 3 cases - Absolute, no target ==> copy in image root dir - Absolute and
+     * target ==> copy in image root dir/target - Relative ==> copy from JDK
+     * home dir.
+     *
+     * @throws Exception
+     */
+    public void test() throws Exception {
+        FileCopierPlugin plug = new FileCopierPlugin();
+        String content = "You \n should \n be \bthere.\n";
+        String name = "sample.txt";
+        File src = new File("src");
+        src.mkdir();
+        // Need a fake bin
+        File bin = new File("bin");
+        bin.mkdir();
+
+        File txt = new File(src, name);
+        txt.createNewFile();
+
+        String target = "target" + File.separator + name;
+        Files.write(txt.toPath(), content.getBytes());
+        File lic = new File(System.getProperty("java.home"), "LICENSE");
+        StringBuilder builder = new StringBuilder();
+        int expected = lic.exists() ? 4 : 3;
+        if (lic.exists()) {
+            builder.append("LICENSE,");
+        }
+        builder.append(txt.getAbsolutePath()+",");
+        builder.append(txt.getAbsolutePath() + "=" + target+",");
+        builder.append(src.getAbsolutePath() + "=src2");
+
+        Map<String, String> conf = new HashMap<>();
+        conf.put(FileCopierPlugin.NAME, builder.toString());
+        plug.configure(conf);
+        Pool pool = new PoolImpl();
+        plug.visit(new PoolImpl(), pool);
+        if (pool.getContent().size() != expected) {
+            throw new AssertionError("Wrong number of added files");
+        }
+        for (ModuleData f : pool.getContent()) {
+            if (!f.getType().equals(ModuleDataType.OTHER)) {
+                throw new AssertionError("Invalid type " + f.getType()
+                        + " for file " + f.getPath());
+            }
+            if (f.stream() == null) {
+                throw new AssertionError("Null stream for file " + f.getPath());
+            }
+
+        }
+        Path root = new File(".").toPath();
+        DefaultImageBuilder imgbuilder = new DefaultImageBuilder(false,
+                root);
+        imgbuilder.storeFiles(pool, "");
+
+        if (lic.exists()) {
+            File license = new File(root.toFile(), "LICENSE");
+            if (!license.exists() || license.length() == 0) {
+                throw new AssertionError("Invalide license file "
+                        + license.getAbsoluteFile());
+            }
+        }
+
+        File sample1 = new File(root.toFile(), txt.getName());
+        if (!sample1.exists() || sample1.length() == 0) {
+            throw new AssertionError("Invalide sample1 file "
+                    + sample1.getAbsoluteFile());
+        }
+        if (!new String(Files.readAllBytes(sample1.toPath())).equals(content)) {
+            throw new AssertionError("Invalid Content in sample1");
+        }
+
+        File sample2 = new File(root.toFile(), target);
+        if (!sample2.exists() || sample2.length() == 0) {
+            throw new AssertionError("Invalide sample2 file "
+                    + sample2.getAbsoluteFile());
+        }
+        if (!new String(Files.readAllBytes(sample2.toPath())).equals(content)) {
+            throw new AssertionError("Invalid Content in sample2");
+        }
+
+        File src2 = new File(root.toFile(), "src2");
+        if (!src2.exists() || src2.list().length != 1) {
+            throw new AssertionError("Invalide src2 dir "
+                    + src2.getAbsoluteFile());
+        }
+        File f = src2.listFiles()[0];
+        if (!f.getName().equals(txt.getName())) {
+            throw new AssertionError("Invalide file name in src2 dir "
+                    + f.getAbsoluteFile());
+        }
+        if (!new String(Files.readAllBytes(f.toPath())).equals(content)) {
+            throw new AssertionError("Invalid Content in src2 dir");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/plugins/GetAvailableLocales.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.util.Arrays;
+import java.util.Locale;
+import java.util.stream.Collectors;
+
+class GetAvailableLocales {
+
+    public static void main(String[] args) {
+        String availableLocales = Arrays.stream(Locale.getAvailableLocales())
+            .map(l -> l.toString())
+            .sorted()
+            .collect(Collectors.joining(" "));
+
+        if (!availableLocales.equals(args[0])) {
+            throw new RuntimeException("Available locales are not equal to the expected ones.\n" +
+                "Expected: " + args[0] + "\n" +
+                "Actual:   " + availableLocales);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/plugins/IncludeLocalesPluginTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.Layer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Stream;
+
+import jdk.tools.jlink.plugin.Plugin;
+import jdk.tools.jlink.internal.PluginRepository;
+import tests.Helper;
+import tests.JImageGenerator;
+import tests.JImageValidator;
+
+/*
+ * @test
+ * @summary IncludeLocalesPlugin tests
+ * @author Naoto Sato
+ * @library ../../lib
+ * @modules java.base/jdk.internal.jimage
+ *          jdk.jdeps/com.sun.tools.classfile
+ *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jmod
+ *          jdk.jlink/jdk.tools.jimage
+ *          jdk.compiler
+ * @build tests.*
+ * @build tools.jlink.plugins.GetAvailableLocales
+ * @run main/othervm -verbose:gc -Xmx1g IncludeLocalesPluginTest
+ */
+public class IncludeLocalesPluginTest {
+
+    private final static String moduleName = "IncludeLocalesTest";
+    private static Helper helper;
+    private final static int INCLUDE_LOCALES_OPTION = 0;
+    private final static int EXPECTED_LOCATIONS     = 1;
+    private final static int UNEXPECTED_PATHS       = 2;
+    private final static int AVAILABLE_LOCALES      = 3;
+
+    private final static Object[][] testData = {
+        // without --include-locales option: should include all locales
+        {
+            "",
+            List.of(
+                "/jdk.localedata/sun/text/resources/ext/FormatData_en_GB.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_ja.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_th.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_zh.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_en_001.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_ja.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_th.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_zh.class"),
+            List.of(),
+            " af af_NA af_ZA agq agq_CM ak ak_GH am am_ET ar ar_001 ar_AE ar_BH " +
+            "ar_DJ ar_DZ ar_EG ar_EH ar_ER ar_IL ar_IQ ar_JO ar_KM ar_KW ar_LB " +
+            "ar_LY ar_MA ar_MR ar_OM ar_PS ar_QA ar_SA ar_SD ar_SO ar_SS ar_SY " +
+            "ar_TD ar_TN ar_YE as as_IN asa asa_TZ ast ast_ES az az_AZ_#Cyrl " +
+            "az_AZ_#Latn az__#Cyrl az__#Latn bas bas_CM be be_BY bem bem_ZM bez " +
+            "bez_TZ bg bg_BG bm bm_ML_#Latn bm__#Latn bn bn_BD bn_IN bo bo_CN " +
+            "bo_IN br br_FR brx brx_IN bs bs_BA_#Cyrl bs_BA_#Latn bs__#Cyrl " +
+            "bs__#Latn ca ca_AD ca_ES ca_ES_VALENCIA ca_FR ca_IT cgg cgg_UG chr " +
+            "chr_US cs cs_CZ cy cy_GB da da_DK da_GL dav dav_KE de de_AT de_BE " +
+            "de_CH de_DE de_GR de_LI de_LU dje dje_NE dsb dsb_DE dua dua_CM dyo " +
+            "dyo_SN dz dz_BT ebu ebu_KE ee ee_GH ee_TG el el_CY el_GR en en_001 " +
+            "en_150 en_AG en_AI en_AS en_AU en_BB en_BE en_BM en_BS en_BW en_BZ " +
+            "en_CA en_CC en_CK en_CM en_CX en_DG en_DM en_ER en_FJ en_FK en_FM " +
+            "en_GB en_GD en_GG en_GH en_GI en_GM en_GU en_GY en_HK en_IE en_IM " +
+            "en_IN en_IO en_JE en_JM en_KE en_KI en_KN en_KY en_LC en_LR en_LS " +
+            "en_MG en_MH en_MO en_MP en_MS en_MT en_MU en_MW en_MY en_NA en_NF " +
+            "en_NG en_NR en_NU en_NZ en_PG en_PH en_PK en_PN en_PR en_PW en_RW " +
+            "en_SB en_SC en_SD en_SG en_SH en_SL en_SS en_SX en_SZ en_TC en_TK " +
+            "en_TO en_TT en_TV en_TZ en_UG en_UM en_US en_US_POSIX en_VC en_VG " +
+            "en_VI en_VU en_WS en_ZA en_ZM en_ZW eo eo_001 es es_419 es_AR es_BO " +
+            "es_CL es_CO es_CR es_CU es_DO es_EA es_EC es_ES es_GQ es_GT es_HN " +
+            "es_IC es_MX es_NI es_PA es_PE es_PH es_PR es_PY es_SV es_US es_UY " +
+            "es_VE et et_EE eu eu_ES ewo ewo_CM fa fa_AF fa_IR ff ff_CM ff_GN " +
+            "ff_MR ff_SN fi fi_FI fil fil_PH fo fo_FO fr fr_BE fr_BF fr_BI fr_BJ " +
+            "fr_BL fr_CA fr_CD fr_CF fr_CG fr_CH fr_CI fr_CM fr_DJ fr_DZ fr_FR " +
+            "fr_GA fr_GF fr_GN fr_GP fr_GQ fr_HT fr_KM fr_LU fr_MA fr_MC fr_MF " +
+            "fr_MG fr_ML fr_MQ fr_MR fr_MU fr_NC fr_NE fr_PF fr_PM fr_RE fr_RW " +
+            "fr_SC fr_SN fr_SY fr_TD fr_TG fr_TN fr_VU fr_WF fr_YT fur fur_IT fy " +
+            "fy_NL ga ga_IE gd gd_GB gl gl_ES gsw gsw_CH gsw_FR gsw_LI gu gu_IN " +
+            "guz guz_KE gv gv_IM ha ha_GH_#Latn ha_NE_#Latn ha_NG_#Latn ha__#Latn " +
+            "haw haw_US hi hi_IN hr hr_BA hr_HR hsb hsb_DE hu hu_HU hy hy_AM ig " +
+            "ig_NG ii ii_CN in in_ID is is_IS it it_CH it_IT it_SM iw iw_IL ja " +
+            "ja_JP ja_JP_JP_#u-ca-japanese jgo jgo_CM ji ji_001 jmc jmc_TZ ka " +
+            "ka_GE kab kab_DZ kam kam_KE kde kde_TZ kea kea_CV khq khq_ML ki " +
+            "ki_KE kk kk_KZ_#Cyrl kk__#Cyrl kkj kkj_CM kl kl_GL kln kln_KE km " +
+            "km_KH kn kn_IN ko ko_KP ko_KR kok kok_IN ks ks_IN_#Arab ks__#Arab " +
+            "ksb ksb_TZ ksf ksf_CM ksh ksh_DE kw kw_GB ky ky_KG_#Cyrl ky__#Cyrl " +
+            "lag lag_TZ lb lb_LU lg lg_UG lkt lkt_US ln ln_AO ln_CD ln_CF ln_CG " +
+            "lo lo_LA lt lt_LT lu lu_CD luo luo_KE luy luy_KE lv lv_LV mas " +
+            "mas_KE mas_TZ mer mer_KE mfe mfe_MU mg mg_MG mgh mgh_MZ mgo mgo_CM " +
+            "mk mk_MK ml ml_IN mn mn_MN_#Cyrl mn__#Cyrl mr mr_IN ms ms_BN_#Latn " +
+            "ms_MY ms_MY_#Latn ms_SG_#Latn ms__#Latn mt mt_MT mua mua_CM my " +
+            "my_MM naq naq_NA nb nb_NO nb_SJ nd nd_ZW ne ne_IN ne_NP nl nl_AW " +
+            "nl_BE nl_BQ nl_CW nl_NL nl_SR nl_SX nmg nmg_CM nn nn_NO nnh nnh_CM " +
+            "no no_NO no_NO_NY nus nus_SD nyn nyn_UG om om_ET om_KE or or_IN os " +
+            "os_GE os_RU pa pa_IN_#Guru pa_PK_#Arab pa__#Arab pa__#Guru pl pl_PL " +
+            "ps ps_AF pt pt_AO pt_BR pt_CV pt_GW pt_MO pt_MZ pt_PT pt_ST pt_TL qu " +
+            "qu_BO qu_EC qu_PE rm rm_CH rn rn_BI ro ro_MD ro_RO rof rof_TZ ru " +
+            "ru_BY ru_KG ru_KZ ru_MD ru_RU ru_UA rw rw_RW rwk rwk_TZ sah sah_RU " +
+            "saq saq_KE sbp sbp_TZ se se_FI se_NO se_SE seh seh_MZ ses ses_ML sg " +
+            "sg_CF shi shi_MA_#Latn shi_MA_#Tfng shi__#Latn shi__#Tfng si si_LK " +
+            "sk sk_SK sl sl_SI smn smn_FI sn sn_ZW so so_DJ so_ET so_KE so_SO sq " +
+            "sq_AL sq_MK sq_XK sr sr_BA sr_BA_#Cyrl sr_BA_#Latn sr_CS sr_ME " +
+            "sr_ME_#Cyrl sr_ME_#Latn sr_RS sr_RS_#Cyrl sr_RS_#Latn sr_XK_#Cyrl " +
+            "sr_XK_#Latn sr__#Cyrl sr__#Latn sv sv_AX sv_FI sv_SE sw sw_CD sw_KE " +
+            "sw_TZ sw_UG ta ta_IN ta_LK ta_MY ta_SG te te_IN teo teo_KE teo_UG " +
+            "th th_TH th_TH_TH_#u-nu-thai ti ti_ER ti_ET to to_TO tr tr_CY tr_TR " +
+            "twq twq_NE tzm tzm_MA_#Latn tzm__#Latn ug ug_CN_#Arab ug__#Arab uk " +
+            "uk_UA ur ur_IN ur_PK uz uz_AF_#Arab uz_UZ_#Cyrl uz_UZ_#Latn " +
+            "uz__#Arab uz__#Cyrl uz__#Latn vai vai_LR_#Latn vai_LR_#Vaii " +
+            "vai__#Latn vai__#Vaii vi vi_VN vun vun_TZ wae wae_CH xog xog_UG yav " +
+            "yav_CM yo yo_BJ yo_NG zgh zgh_MA zh zh_CN zh_CN_#Hans zh_HK " +
+            "zh_HK_#Hans zh_HK_#Hant zh_MO_#Hans zh_MO_#Hant zh_SG zh_SG_#Hans " +
+            "zh_TW zh_TW_#Hant zh__#Hans zh__#Hant zu zu_ZA",
+        },
+
+        // All English/Japanese locales
+        {
+            "--include-locales=en,ja",
+            List.of(
+                "/jdk.localedata/sun/text/resources/ext/FormatData_en_GB.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_ja.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_en_001.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_ja.class"),
+            List.of(
+                "/jdk.localedata/sun/text/resources/LineBreakIteratorData_th",
+                "/jdk.localedata/sun/text/resources/thai_dict",
+                "/jdk.localedata/sun/text/resources/WordBreakIteratorData_th",
+                "/jdk.localedata/sun/text/resources/ext/BreakIteratorInfo_th.class",
+                "/jdk.localedata/sun/text/resources/ext/BreakIteratorRules_th.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_th.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_zh.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_th.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_zh.class"),
+            " en en_001 en_150 en_AG en_AI en_AS en_AU en_BB en_BE en_BM en_BS " +
+            "en_BW en_BZ en_CA en_CC en_CK en_CM en_CX en_DG en_DM en_ER en_FJ " +
+            "en_FK en_FM en_GB en_GD en_GG en_GH en_GI en_GM en_GU en_GY en_HK " +
+            "en_IE en_IM en_IN en_IO en_JE en_JM en_KE en_KI en_KN en_KY en_LC " +
+            "en_LR en_LS en_MG en_MH en_MO en_MP en_MS en_MT en_MU en_MW en_MY " +
+            "en_NA en_NF en_NG en_NR en_NU en_NZ en_PG en_PH en_PK en_PN en_PR " +
+            "en_PW en_RW en_SB en_SC en_SD en_SG en_SH en_SL en_SS en_SX en_SZ " +
+            "en_TC en_TK en_TO en_TT en_TV en_TZ en_UG en_UM en_US en_US_POSIX " +
+            "en_VC en_VG en_VI en_VU en_WS en_ZA en_ZM en_ZW ja ja_JP ja_JP_JP_#u-ca-japanese",
+        },
+
+        // All locales in India
+        {
+            "--include-locales=*-IN",
+            List.of(
+                "/jdk.localedata/sun/text/resources/ext/FormatData_en_IN.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_hi_IN.class",
+                "/jdk.localedata/sun/util/resources/cldr/ext/CalendarData_as_IN.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_en_001.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_en_IN.class",
+                "/jdk.localedata/sun/util/resources/cldr/ext/CalendarData_kok_IN.class",
+                "/jdk.localedata/sun/util/resources/cldr/ext/CalendarData_ks_Arab_IN.class"),
+            List.of(
+                "/jdk.localedata/sun/text/resources/LineBreakIteratorData_th",
+                "/jdk.localedata/sun/text/resources/thai_dict",
+                "/jdk.localedata/sun/text/resources/WordBreakIteratorData_th",
+                "/jdk.localedata/sun/text/resources/ext/BreakIteratorInfo_th.class",
+                "/jdk.localedata/sun/text/resources/ext/BreakIteratorRules_th.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_en_GB.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_ja.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_th.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_zh.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_ja.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_th.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_zh.class"),
+            " as_IN bn_IN bo_IN brx_IN en en_IN en_US en_US_POSIX gu_IN hi_IN kn_IN " +
+            "kok_IN ks_IN_#Arab ml_IN mr_IN ne_IN or_IN pa_IN_#Guru ta_IN te_IN ur_IN",
+        },
+
+        // Thai
+        {"--include-locales=th",
+            List.of(
+                "/jdk.localedata/sun/text/resources/LineBreakIteratorData_th",
+                "/jdk.localedata/sun/text/resources/thai_dict",
+                "/jdk.localedata/sun/text/resources/WordBreakIteratorData_th",
+                "/jdk.localedata/sun/text/resources/ext/BreakIteratorInfo_th.class",
+                "/jdk.localedata/sun/text/resources/ext/BreakIteratorRules_th.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_th.class"),
+            List.of(
+                "/jdk.localedata/sun/text/resources/ext/FormatData_en_GB.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_ja.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_zh.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_en_001.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_ja.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_zh.class"),
+            " en en_US en_US_POSIX th th_TH th_TH_TH_#u-nu-thai",
+        },
+
+        // Hong Kong
+        {"--include-locales=zh-HK",
+            List.of(
+                "/jdk.localedata/sun/text/resources/ext/FormatData_zh.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_zh_HK.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_zh_TW.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_zh.class"),
+            List.of(
+                "/jdk.localedata/sun/text/resources/LineBreakIteratorData_th",
+                "/jdk.localedata/sun/text/resources/thai_dict",
+                "/jdk.localedata/sun/text/resources/WordBreakIteratorData_th",
+                "/jdk.localedata/sun/text/resources/ext/BreakIteratorInfo_th.class",
+                "/jdk.localedata/sun/text/resources/ext/BreakIteratorRules_th.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_en_GB.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_ja.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_th.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_en_001.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_ja.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_th.class"),
+            " en en_US en_US_POSIX zh_HK zh_HK_#Hans zh_HK_#Hant",
+        },
+
+        // Norwegian
+        {"--include-locales=nb,nn,no",
+            List.of(
+                "/jdk.localedata/sun/text/resources/ext/FormatData_no.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_no_NO.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_no_NO_NY.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_nb.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_nn.class"),
+            List.of(
+                "/jdk.localedata/sun/text/resources/LineBreakIteratorData_th",
+                "/jdk.localedata/sun/text/resources/thai_dict",
+                "/jdk.localedata/sun/text/resources/WordBreakIteratorData_th",
+                "/jdk.localedata/sun/text/resources/ext/BreakIteratorInfo_th.class",
+                "/jdk.localedata/sun/text/resources/ext/BreakIteratorRules_th.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_en_GB.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_ja.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_th.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_en_001.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_ja.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_th.class"),
+            " en en_US en_US_POSIX nb nb_NO nb_SJ nn nn_NO no no_NO no_NO_NY",
+        },
+
+        // Hebrew/Indonesian/Yiddish
+        {"--include-locales=he,id,yi",
+            List.of(
+                "/jdk.localedata/sun/text/resources/ext/FormatData_in.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_in_ID.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_iw.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_iw_IL.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_in.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_iw.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_ji.class"),
+            List.of(
+                "/jdk.localedata/sun/text/resources/LineBreakIteratorData_th",
+                "/jdk.localedata/sun/text/resources/thai_dict",
+                "/jdk.localedata/sun/text/resources/WordBreakIteratorData_th",
+                "/jdk.localedata/sun/text/resources/ext/BreakIteratorInfo_th.class",
+                "/jdk.localedata/sun/text/resources/ext/BreakIteratorRules_th.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_en_GB.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_ja.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_th.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_en_001.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_ja.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_th.class"),
+            " en en_US en_US_POSIX in in_ID iw iw_IL ji ji_001",
+        },
+    };
+
+    public static void main(String[] args) throws Exception {
+        helper = Helper.newHelper();
+        if (helper == null) {
+            System.err.println("Test not run");
+            return;
+        }
+
+        helper.generateDefaultModules();
+
+        for (Object[] data : testData) {
+            // create image for each test data
+            Path image = JImageGenerator.getJLinkTask()
+                    .modulePath(helper.defaultModulePath())
+                    .output(helper.createNewImageDir(moduleName))
+                    .addMods("jdk.localedata")
+                    .option((String)data[INCLUDE_LOCALES_OPTION])
+                    .call().assertSuccess();
+
+            // test locale data entries
+            testLocaleDataEntries(image,
+                (List<String>)data[EXPECTED_LOCATIONS],
+                (List<String>)data[UNEXPECTED_PATHS]);
+
+            // test available locales
+            testAvailableLocales(image, (String)data[AVAILABLE_LOCALES]);
+        }
+    }
+
+    private static void testLocaleDataEntries(Path image, List<String> expectedLocations,
+                        List<String> unexpectedPaths) throws Exception {
+        JImageValidator.validate(
+            image.resolve("lib").resolve("modules"),
+            expectedLocations, unexpectedPaths);
+    }
+
+    private static void testAvailableLocales(Path image, String availableLocales) throws Exception {
+        Path launcher = image.resolve("bin/java" +
+            (System.getProperty("os.name").startsWith("Windows") ? ".exe" : ""));
+        System.out.print(launcher);
+        ProcessBuilder pb = new ProcessBuilder(launcher.toString(),
+            "GetAvailableLocales", availableLocales);
+        int ret = pb.start().waitFor();
+        System.out.println(" Return code: " + ret);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/plugins/InstalledModuleDescriptors/InstalledModulesTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Requires.Modifier;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReference;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Map;
+import java.util.Set;
+
+import jdk.internal.misc.JavaLangModuleAccess;
+import jdk.internal.misc.SharedSecrets;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/**
+ * @test
+ * @modules java.base/jdk.internal.misc
+ * @run testng InstalledModulesTest
+ * @summary Verify the properties of ModuleDescriptor created
+ *          by InstalledModules
+ */
+
+public class InstalledModulesTest {
+    private static final JavaLangModuleAccess jlma = SharedSecrets.getJavaLangModuleAccess();
+
+    /**
+     * Verify ModuleDescriptor contains unmodifiable sets
+     */
+    @Test
+    public void testUnmodifableDescriptors() throws Exception {
+        ModuleFinder.ofSystem().findAll()
+                    .stream()
+                    .map(ModuleReference::descriptor)
+                    .forEach(this::testModuleDescriptor);
+    }
+
+    private void testModuleDescriptor(ModuleDescriptor md) {
+        assertUnmodifiable(md.conceals(), "conceal");
+        assertUnmodifiable(md.packages(), "package");
+        assertUnmodifiable(md.requires(),
+                           jlma.newRequires(EnumSet.allOf(Modifier.class), "require"));
+        assertUnmodifiable(md.exports(), jlma.newExports("export"));
+        assertUnmodifiable(md.uses(), "use");
+        assertUnmodifiable(md.provides(), "provide",
+                           jlma.newProvides("provide", Collections.singleton("provide")));
+
+    }
+
+    private <T> void assertUnmodifiable(Set<T> set, T dummy) {
+        try {
+            set.add(dummy);
+            fail("Should throw UnsupportedOperationException");
+        } catch (UnsupportedOperationException e) {
+            // pass
+        } catch (Exception e) {
+            fail("Should throw UnsupportedOperationException");
+        }
+    }
+
+    private <T, V> void assertUnmodifiable(Map<T, V> set, T dummyKey, V dummyValue) {
+        try {
+            set.put(dummyKey, dummyValue);
+            fail("Should throw UnsupportedOperationException");
+        } catch (UnsupportedOperationException e) {
+            // pass
+        } catch (Exception e) {
+            fail("Should throw UnsupportedOperationException");
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/plugins/InstalledModuleDescriptors/UserModuleTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.stream.Collectors;
+
+import jdk.testlibrary.FileUtils;
+import static jdk.testlibrary.ProcessTools.*;
+
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/**
+ * @test
+ * @library /lib/testlibrary
+ * @modules jdk.compiler
+ * @build UserModuleTest CompilerUtils jdk.testlibrary.FileUtils jdk.testlibrary.ProcessTools
+ * @run testng UserModuleTest
+ */
+
+public class UserModuleTest {
+    private static final String JAVA_HOME = System.getProperty("java.home");
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path MODS_DIR = Paths.get("mods");
+    private static final Path IMAGE = Paths.get("image");
+    private static final Path JMODS = Paths.get(JAVA_HOME, "jmods");
+
+    // the names of the modules in this test
+    private static String[] modules = new String[] {"m1", "m2", "m3"};
+
+    private static boolean hasJmods() {
+        if (!Files.exists(JMODS)) {
+            System.err.println("Test skipped. NO jmods directory");
+            return false;
+        }
+        return true;
+    }
+
+    /*
+     * Compiles all modules used by the test
+     */
+    @BeforeTest
+    public void compileAll() throws Throwable {
+        if (!hasJmods()) return;
+
+        for (String mn : modules) {
+            Path msrc = SRC_DIR.resolve(mn);
+            assertTrue(CompilerUtils.compile(msrc, MODS_DIR, "-modulesourcepath", SRC_DIR.toString()));
+        }
+
+        if (Files.exists(IMAGE)) {
+            FileUtils.deleteFileTreeUnchecked(IMAGE);
+        }
+
+        createImage(IMAGE, "java.base", "m1");
+    }
+
+    private void createImage(Path outputDir, String... modules) throws Throwable {
+        Path jlink = Paths.get(JAVA_HOME, "bin", "jlink");
+        String mp = JMODS.toString() + File.pathSeparator + MODS_DIR.toString();
+        assertTrue(executeProcess(jlink.toString(), "--output", outputDir.toString(),
+                        "--addmods", Arrays.stream(modules).collect(Collectors.joining(",")),
+                        "--modulepath", mp)
+                        .outputTo(System.out)
+                        .errorTo(System.out)
+                        .getExitValue() == 0);
+    }
+
+    /*
+     * Test the image created when linking with a module with
+     * no ConcealedPackages attribute
+     */
+    @Test
+    public void test() throws Throwable {
+        if (!hasJmods()) return;
+
+        Path java = IMAGE.resolve("bin").resolve("java");
+        assertTrue(executeProcess(java.toString(), "-m", "m1/p1.Main")
+                        .outputTo(System.out)
+                        .errorTo(System.out)
+                        .getExitValue() == 0);
+    }
+
+    /*
+     * Disable the fast loading of installed modules.
+     * Parsing module-info.class
+     */
+    @Test
+    public void disableInstalledModules() throws Throwable {
+        if (!hasJmods()) return;
+
+        Path java = IMAGE.resolve("bin").resolve("java");
+        assertTrue(executeProcess(java.toString(),
+                                  "-Djdk.installed.modules.disable",
+                                  "-m", "m1/p1.Main")
+                        .outputTo(System.out)
+                        .errorTo(System.out)
+                        .getExitValue() == 0);
+    }
+
+    /*
+     * Test the optimization that deduplicates Set<String> on targets of exports,
+     * uses, provides.
+     */
+    @Test
+    public void testDedupSet() throws Throwable {
+        if (!hasJmods()) return;
+
+        Path dir = Paths.get("newImage");
+        createImage(dir, "java.base", "m1", "m2", "m3");
+        Path java = dir.resolve("bin").resolve("java");
+        assertTrue(executeProcess(java.toString(), "-m", "m1/p1.Main")
+                        .outputTo(System.out)
+                        .errorTo(System.out)
+                        .getExitValue() == 0);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m1/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m1 {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m1/p1/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p1;
+
+import java.lang.module.ModuleDescriptor;
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Set;
+
+public class Main {
+    public static void main(String... args) throws Exception {
+        // load another package
+        p2.T.test();
+
+        // check the module descriptor of an installed module
+        validate(Main.class.getModule().getDescriptor());
+
+        // read m1/module-info.class
+        FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"), null);
+        Path path = fs.getPath("/", "modules", "m1", "module-info.class");
+        validate(ModuleDescriptor.read(Files.newInputStream(path)));
+    }
+
+    static void validate(ModuleDescriptor md) {
+        checkPackages(md.conceals(), "p1", "p2");
+        checkPackages(md.packages(), "p1", "p2");
+    }
+
+    static void checkPackages(Set<String> pkgs, String... expected) {
+        for (String pn : expected) {
+            if (!pkgs.contains(pn)) {
+                throw new RuntimeException(pn + " missing in " + pkgs);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m1/p2/T.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p2;
+
+public class T {
+    public static void test() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m2/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m2 {
+    uses q.S1;
+    uses q.S2;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m2/q/S1.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package q;
+
+public interface S1 {
+    public String name();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m2/q/S2.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package q;
+
+public interface S2 {
+    public String name();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m3/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m3 {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/plugins/LastSorterTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Test last sorter property
+ * @author Jean-Francois Denise
+ * @modules jdk.jlink/jdk.tools.jlink.internal
+ * @run main/othervm LastSorterTest
+ */
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import jdk.tools.jlink.internal.ImagePluginConfiguration;
+import jdk.tools.jlink.internal.PluginRepository;
+import jdk.tools.jlink.internal.ImagePluginStack;
+import jdk.tools.jlink.internal.PoolImpl;
+import jdk.tools.jlink.Jlink;
+import jdk.tools.jlink.Jlink.PluginsConfiguration;
+import jdk.tools.jlink.plugin.Plugin;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.TransformerPlugin;
+
+public class LastSorterTest {
+
+    public LastSorterTest() {
+        for (int i = 1; i <= 6; i++) {
+            PluginRepository.registerPlugin(new SorterPlugin("sorterplugin" + i));
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        new LastSorterTest().test();
+    }
+
+    public void test() throws Exception {
+        checkUnknownPlugin();
+
+        checkOrderAfterLastSorter();
+
+        checkPositiveCase();
+
+        checkTwoLastSorters();
+    }
+
+    private void checkTwoLastSorters() throws Exception {
+        List<Plugin> plugins = new ArrayList<>();
+        plugins.add(createPlugin("sorterplugin5", "/a"));
+        plugins.add(createPlugin("sorterplugin6", "/a"));
+        PluginsConfiguration config = new Jlink.PluginsConfiguration(plugins,
+                null, "sorterplugin5");
+
+        ImagePluginStack stack = ImagePluginConfiguration.parseConfiguration(config);
+
+        // check order
+        PoolImpl res = fillOutResourcePool();
+
+        try {
+            stack.visitResources(res);
+            throw new AssertionError("Exception expected: Order of resources is already frozen." +
+                    "Plugin sorterplugin6 is badly located");
+        } catch (Exception e) {
+            // expected
+        }
+    }
+
+    private PoolImpl fillOutResourcePool() throws Exception {
+        PoolImpl res = new PoolImpl();
+        res.add(Pool.newResource("/eee/bbb/res1.class", new byte[90]));
+        res.add(Pool.newResource("/aaaa/bbb/res2.class", new byte[90]));
+        res.add(Pool.newResource("/bbb/aa/res1.class", new byte[90]));
+        res.add(Pool.newResource("/aaaa/bbb/res3.class", new byte[90]));
+        res.add(Pool.newResource("/bbb/aa/res2.class", new byte[90]));
+        res.add(Pool.newResource("/fff/bbb/res1.class", new byte[90]));
+        res.add(Pool.newResource("/aaaa/bbb/res1.class", new byte[90]));
+        res.add(Pool.newResource("/bbb/aa/res3.class", new byte[90]));
+        res.add(Pool.newResource("/ccc/bbb/res1.class", new byte[90]));
+        res.add(Pool.newResource("/ddd/bbb/res1.class", new byte[90]));
+        return res;
+    }
+
+    private static Plugin createPlugin(String name, String arg) {
+        Map<String, String> conf = new HashMap<>();
+        conf.put(name, arg);
+        return Jlink.newPlugin(name, conf, null);
+    }
+
+    private void checkPositiveCase() throws Exception {
+        List<Plugin> plugins = new ArrayList<>();
+        plugins.add(createPlugin("sorterplugin1", "/c"));
+        plugins.add(createPlugin("sorterplugin2", "/b"));
+        plugins.add(createPlugin("sorterplugin3", "/a"));
+
+        PluginsConfiguration config = new Jlink.PluginsConfiguration(plugins,
+                null, "sorterplugin3");
+
+        ImagePluginStack stack = ImagePluginConfiguration.parseConfiguration(config);
+
+        // check order
+        PoolImpl res = fillOutResourcePool();
+
+        stack.visitResources(res);
+    }
+
+    private void checkUnknownPlugin() {
+        List<Plugin> plugins = new ArrayList<>();
+        plugins.add(createPlugin("sorterplugin1", "/1"));
+        plugins.add(createPlugin("sorterplugin2", "/1"));
+        plugins.add(createPlugin("sorterplugin3", "/1"));
+        plugins.add(createPlugin("sorterplugin4", "/1"));
+
+        PluginsConfiguration config = new Jlink.PluginsConfiguration(plugins,
+                null, "sorterplugin5");
+        try {
+            ImagePluginConfiguration.parseConfiguration(config);
+            throw new AssertionError("Unknown plugin should have failed.");
+        } catch (Exception ex) {
+            // XXX OK expected
+        }
+    }
+
+    private void checkOrderAfterLastSorter() throws Exception {
+        List<Plugin> plugins = new ArrayList<>();
+        plugins.add(createPlugin("sorterplugin1", "/c"));
+        plugins.add(createPlugin("sorterplugin2", "/b"));
+        plugins.add(createPlugin("sorterplugin3", "/a"));
+        plugins.add(createPlugin("sorterplugin4", "/d"));
+
+        PluginsConfiguration config = new Jlink.PluginsConfiguration(plugins,
+                null, "sorterplugin3");
+
+        ImagePluginStack stack = ImagePluginConfiguration.parseConfiguration(config);
+
+        // check order
+        PoolImpl res = fillOutResourcePool();
+        try {
+            stack.visitResources(res);
+            throw new AssertionError("Order was changed after the last sorter, but no exception occurred");
+        } catch (Exception ex) {
+            // XXX OK expected
+        }
+    }
+
+    public static class SorterPlugin implements TransformerPlugin {
+
+        private final String name;
+        private String starts;
+
+        private SorterPlugin(String name) {
+            this.name = name;
+        }
+
+        @Override
+        public void visit(Pool resources, Pool output) {
+            List<ModuleData> paths = new ArrayList<>();
+            for (ModuleData res : resources.getContent()) {
+                if (res.getPath().startsWith(starts)) {
+                    paths.add(0, res);
+                } else {
+                    paths.add(res);
+                }
+            }
+
+            for (ModuleData r : paths) {
+                output.add(r);
+            }
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
+
+        @Override
+        public Set<PluginType> getType() {
+            Set<PluginType> set = new HashSet<>();
+            set.add(CATEGORY.TRANSFORMER);
+            return Collections.unmodifiableSet(set);
+        }
+
+        @Override
+        public void configure(Map<String, String> config) {
+            String arguments = config.get(name);
+            this.starts = arguments;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/plugins/PluginOrderTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+ /*
+ * @test
+ * @summary Test order of plugins
+ * @author Jean-Francois Denise
+ * @library ../../lib
+ * @modules java.base/jdk.internal.jimage
+ *          jdk.jdeps/com.sun.tools.classfile
+ *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jmod
+ *          jdk.jlink/jdk.tools.jimage
+ *          jdk.compiler
+ * @build tests.*
+ * @run main/othervm PluginOrderTest
+ */
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import jdk.tools.jlink.internal.PluginOrderingGraph;
+import jdk.tools.jlink.plugin.Plugin;
+import jdk.tools.jlink.plugin.Plugin.CATEGORY;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.TransformerPlugin;
+
+public class PluginOrderTest {
+
+    public static void main(String[] args) throws Exception {
+
+        validGraph0();
+        validGraph1();
+
+        boolean failed = false;
+
+        try {
+            withCycles0();
+            failed = true;
+        } catch (Exception ex) {
+            //ok
+            System.err.println(ex.getMessage());
+        }
+        if (failed) {
+            throw new Exception("Should have failed");
+        }
+
+        try {
+            withCycles1();
+            failed = true;
+        } catch (Exception ex) {
+            //ok
+            System.err.println(ex.getMessage());
+        }
+        if (failed) {
+            throw new Exception("Should have failed");
+        }
+
+        try {
+            withCycles2();
+            failed = true;
+        } catch (Exception ex) {
+            //ok
+            System.err.println(ex.getMessage());
+        }
+        if (failed) {
+            throw new Exception("Should have failed");
+        }
+    }
+
+    private static void validGraph0() throws Exception {
+        Set<String> set = new HashSet<>();
+        set.add("plug2");
+        List<Plugin> plugins = new ArrayList<>();
+        plugins.add(new Plug("plug2", Collections.emptySet(), Collections.emptySet(),
+                CATEGORY.TRANSFORMER));
+        plugins.add(new Plug("plug1", set, Collections.emptySet(), CATEGORY.TRANSFORMER));
+        List<Plugin> ordered = PluginOrderingGraph.sort(plugins);
+        if (ordered.get(0) != plugins.get(1) || ordered.get(1) != plugins.get(0)) {
+            throw new Exception("Invalid sorting");
+        }
+    }
+
+    private static void validGraph1() {
+        Set<String> lst1 = new HashSet<>();
+        lst1.add("plug2");
+        lst1.add("plug3");
+        Plugin p1 = new Plug("plug1", lst1, Collections.emptySet(), CATEGORY.TRANSFORMER);
+
+        Plugin p2 = new Plug("plug2", Collections.emptySet(), Collections.emptySet(), CATEGORY.TRANSFORMER);
+
+        Set<String> lst3 = new HashSet<>();
+        lst3.add("plug4");
+        lst3.add("plug6");
+        Plugin p3 = new Plug("plug3", lst3, Collections.emptySet(), CATEGORY.TRANSFORMER);
+
+        Plugin p4 = new Plug("plug4", Collections.emptySet(), Collections.emptySet(), CATEGORY.TRANSFORMER);
+
+        Set<String> lst5 = new HashSet<>();
+        lst5.add("plug3");
+        lst5.add("plug1");
+        lst5.add("plug2");
+        lst5.add("plug6");
+        Plugin p5 = new Plug("plug5", lst5, Collections.emptySet(), CATEGORY.TRANSFORMER);
+
+        Set<String> lst6 = new HashSet<>();
+        lst6.add("plug4");
+        lst6.add("plug2");
+        Plugin p6 = new Plug("plug6", lst6, Collections.emptySet(), CATEGORY.TRANSFORMER);
+
+        Plugin p7 = new Plug("plug7", Collections.emptySet(), Collections.emptySet(), CATEGORY.TRANSFORMER);
+
+        Plugin p8 = new Plug("plug8", Collections.emptySet(), Collections.emptySet(), CATEGORY.TRANSFORMER);
+
+        List<Plugin> plugins = new ArrayList<>();
+        plugins.add(p1);
+        plugins.add(p2);
+        plugins.add(p3);
+        plugins.add(p4);
+        plugins.add(p5);
+        plugins.add(p6);
+        plugins.add(p7);
+        plugins.add(p8);
+
+        PluginOrderingGraph.sort(plugins);
+    }
+
+    private static void withCycles0() throws Exception {
+        Set<String> set2 = new HashSet<>();
+        set2.add("plug1");
+        List<Plugin> plugins = new ArrayList<>();
+        plugins.add(new Plug("plug2", set2, Collections.emptySet(),
+                CATEGORY.TRANSFORMER));
+
+        Set<String> set1 = new HashSet<>();
+        set1.add("plug2");
+        plugins.add(new Plug("plug1", set1, Collections.emptySet(), CATEGORY.TRANSFORMER));
+        PluginOrderingGraph.sort(plugins);
+
+    }
+
+    private static void withCycles2() {
+        Set<String> lst1 = new HashSet<>();
+        lst1.add("plug2");
+        lst1.add("plug3");
+        Plugin p1 = new Plug("plug1", lst1, Collections.emptySet(), CATEGORY.TRANSFORMER);
+
+        Plugin p2 = new Plug("plug2", Collections.emptySet(), Collections.emptySet(), CATEGORY.TRANSFORMER);
+
+        Set<String> lst3 = new HashSet<>();
+        lst3.add("plug4");
+        lst3.add("plug6");
+        Plugin p3 = new Plug("plug3", lst3, Collections.emptySet(), CATEGORY.TRANSFORMER);
+
+        Plugin p4 = new Plug("plug4", Collections.emptySet(), Collections.emptySet(), CATEGORY.TRANSFORMER);
+
+        Set<String> lst5 = new HashSet<>();
+        lst5.add("plug3");
+        lst5.add("plug1");
+        lst5.add("plug2");
+        Plugin p5 = new Plug("plug5", lst5, Collections.emptySet(), CATEGORY.TRANSFORMER);
+
+        Set<String> lst6 = new HashSet<>();
+        lst6.add("plug4");
+        lst6.add("plug1");
+        Plugin p6 = new Plug("plug6", lst6, Collections.emptySet(), CATEGORY.TRANSFORMER);
+
+        Plugin p7 = new Plug("plug7", Collections.emptySet(), Collections.emptySet(), CATEGORY.TRANSFORMER);
+
+        Plugin p8 = new Plug("plug8", Collections.emptySet(), Collections.emptySet(), CATEGORY.TRANSFORMER);
+
+        List<Plugin> plugins = new ArrayList<>();
+        plugins.add(p1);
+        plugins.add(p2);
+        plugins.add(p3);
+        plugins.add(p4);
+        plugins.add(p5);
+        plugins.add(p6);
+        plugins.add(p7);
+        plugins.add(p8);
+        PluginOrderingGraph.sort(plugins);
+    }
+
+    private static void withCycles1() {
+        Set<String> lst1 = new HashSet<>();
+        lst1.add("plug2");
+        lst1.add("plug3");
+        Plugin p = new Plug("plug1", lst1, Collections.emptySet(), CATEGORY.TRANSFORMER);
+        Plugin p2 = new Plug("plug2", Collections.emptySet(), Collections.emptySet(), CATEGORY.TRANSFORMER);
+
+        Set<String> lst3 = new HashSet<>();
+        lst3.add("plug2");
+
+        Set<String> lst4 = new HashSet<>();
+        lst4.add("plug1");
+
+        Plugin p3 = new Plug("plug3", lst4, lst3, CATEGORY.TRANSFORMER);
+        List<Plugin> plugins = new ArrayList<>();
+        plugins.add(p);
+        plugins.add(p2);
+        plugins.add(p3);
+        PluginOrderingGraph.sort(plugins);
+    }
+
+    private static class Plug implements TransformerPlugin {
+
+        private final Set<String> isBefore;
+        private final Set<String> isAfter;
+        private final CATEGORY category;
+        private final String name;
+
+        private Plug(String name, Set<String> isBefore, Set<String> isAfter, CATEGORY category) {
+            this.name = name;
+            this.isBefore = isBefore;
+            this.isAfter = isAfter;
+            this.category = category;
+        }
+
+        @Override
+        public Set<String> isAfter() {
+            return isAfter;
+        }
+
+        @Override
+        public Set<String> isBefore() {
+            return isBefore;
+        }
+
+        @Override
+        public String toString() {
+            return name;
+        }
+
+        @Override
+        public void visit(Pool in, Pool out) {
+
+        }
+
+        @Override
+        public Set<PluginType> getType() {
+            return Collections.singleton(category);
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/plugins/PluginsNegativeTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+ /*
+ * @test
+ * @summary Negative test for ImagePluginStack.
+ * @author Andrei Eremeev
+ * @modules jdk.jlink/jdk.tools.jlink.internal
+ * @run main/othervm PluginsNegativeTest
+ */
+import java.lang.reflect.Layer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import jdk.tools.jlink.internal.ImagePluginConfiguration;
+import jdk.tools.jlink.internal.PluginRepository;
+import jdk.tools.jlink.internal.ImagePluginStack;
+import jdk.tools.jlink.internal.PoolImpl;
+import jdk.tools.jlink.Jlink;
+import jdk.tools.jlink.Jlink.PluginsConfiguration;
+import jdk.tools.jlink.plugin.Plugin;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.TransformerPlugin;
+
+public class PluginsNegativeTest {
+
+    public static void main(String[] args) throws Exception {
+        new PluginsNegativeTest().test();
+    }
+
+    public void test() throws Exception {
+        testDuplicateBuiltInProviders();
+        testUnknownProvider();
+        PluginRepository.registerPlugin(new CustomPlugin("plugin"));
+        testEmptyInputResource();
+        testEmptyOutputResource();
+    }
+
+    private void testDuplicateBuiltInProviders() {
+        List<Plugin> javaPlugins = new ArrayList<>();
+        javaPlugins.addAll(PluginRepository.getPlugins(Layer.boot()));
+        for (Plugin javaPlugin : javaPlugins) {
+            System.out.println("Registered plugin: " + javaPlugin.getName());
+        }
+        for (Plugin javaPlugin : javaPlugins) {
+            String pluginName = javaPlugin.getName();
+            try {
+                PluginRepository.registerPlugin(new CustomPlugin(pluginName));
+                try {
+                    PluginRepository.getPlugin(pluginName, Layer.boot());
+                    throw new AssertionError("Exception is not thrown for duplicate plugin: " + pluginName);
+                } catch (Exception ignored) {
+                }
+            } finally {
+                PluginRepository.unregisterPlugin(pluginName);
+            }
+        }
+    }
+
+    private void testUnknownProvider() {
+        if (PluginRepository.getPlugin("unknown", Layer.boot()) != null) {
+            throw new AssertionError("Exception expected for unknown plugin name");
+        }
+    }
+
+    private static Plugin createPlugin(String name) {
+        return Jlink.newPlugin(name, Collections.emptyMap(), null);
+    }
+
+    private void testEmptyOutputResource() throws Exception {
+        List<Plugin> plugins = new ArrayList<>();
+        plugins.add(createPlugin("plugin"));
+        ImagePluginStack stack = ImagePluginConfiguration.parseConfiguration(new PluginsConfiguration(plugins,
+                null, null));
+        PoolImpl inResources = new PoolImpl();
+        inResources.add(Pool.newResource("/aaa/bbb/A", new byte[10]));
+        try {
+            stack.visitResources(inResources);
+            throw new AssertionError("Exception expected when output resource is empty");
+        } catch (Exception ignored) {
+        }
+    }
+
+    private void testEmptyInputResource() throws Exception {
+        List<Plugin> plugins = new ArrayList<>();
+        plugins.add(createPlugin("plugin"));
+        ImagePluginStack stack = ImagePluginConfiguration.parseConfiguration(new PluginsConfiguration(plugins,
+                null, null));
+        PoolImpl inResources = new PoolImpl();
+        PoolImpl outResources = (PoolImpl) stack.visitResources(inResources);
+        if (!outResources.isEmpty()) {
+            throw new AssertionError("Output resource is not empty");
+        }
+    }
+
+    public static class CustomPlugin implements TransformerPlugin {
+
+        private final String name;
+
+        CustomPlugin(String name) {
+            this.name = name;
+        }
+
+        @Override
+        public void visit(Pool inResources, Pool outResources) {
+            // do nothing
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
+
+        @Override
+        public Set<PluginType> getType() {
+            Set<PluginType> set = new HashSet<>();
+            set.add(CATEGORY.TRANSFORMER);
+            return Collections.unmodifiableSet(set);
+        }
+
+        @Override
+        public String getDescription() {
+            return null;
+        }
+
+        @Override
+        public void configure(Map<String, String> config) {
+
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/plugins/PrevisitorTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+ /*
+ * @test
+ * @summary Test previsitor
+ * @author Andrei Eremeev
+ * @modules jdk.jlink/jdk.tools.jlink.internal
+ * @run main/othervm PrevisitorTest
+ */
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import jdk.tools.jlink.internal.ImagePluginConfiguration;
+import jdk.tools.jlink.internal.PluginRepository;
+import jdk.tools.jlink.internal.ImagePluginStack;
+import jdk.tools.jlink.internal.PoolImpl;
+import jdk.tools.jlink.internal.ResourcePrevisitor;
+import jdk.tools.jlink.internal.StringTable;
+import jdk.tools.jlink.Jlink;
+import jdk.tools.jlink.plugin.Plugin;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.TransformerPlugin;
+
+public class PrevisitorTest {
+
+    public static void main(String[] args) throws Exception {
+        new PrevisitorTest().test();
+    }
+
+    private static Plugin createPlugin(String name) {
+        return Jlink.newPlugin(name, Collections.emptyMap(), null);
+    }
+
+    public void test() throws Exception {
+        CustomPlugin plugin = new CustomPlugin();
+        PluginRepository.registerPlugin(plugin);
+        List<Plugin> plugins = new ArrayList<>();
+        plugins.add(createPlugin(CustomPlugin.NAME));
+        ImagePluginStack stack = ImagePluginConfiguration.parseConfiguration(new Jlink.PluginsConfiguration(plugins,
+                null, null));
+        PoolImpl inResources = new PoolImpl(ByteOrder.nativeOrder(), new CustomStringTable());
+        inResources.add(Pool.newResource("/aaa/bbb/res1.class", new byte[90]));
+        inResources.add(Pool.newResource("/aaa/bbb/res2.class", new byte[90]));
+        inResources.add(Pool.newResource("/aaa/bbb/res3.class", new byte[90]));
+        inResources.add(Pool.newResource("/aaa/ddd/res1.class", new byte[90]));
+        inResources.add(Pool.newResource("/aaa/res1.class", new byte[90]));
+        Pool outResources = stack.visitResources(inResources);
+        Collection<String> input = inResources.getContent().stream()
+                .map(Object::toString)
+                .collect(Collectors.toList());
+        Collection<String> output = outResources.getContent().stream()
+                .map(Object::toString)
+                .collect(Collectors.toList());
+        if (!input.equals(output)) {
+            throw new AssertionError("Input and output resources differ: input: "
+                    + input + ", output: " + output);
+        }
+    }
+
+    private static class CustomStringTable implements StringTable {
+
+        private final List<String> strings = new ArrayList<>();
+
+        @Override
+        public int addString(String str) {
+            strings.add(str);
+            return strings.size() - 1;
+        }
+
+        @Override
+        public String getString(int id) {
+            return strings.get(id);
+        }
+
+        public int size() {
+            return strings.size();
+        }
+    }
+
+    private static class CustomPlugin implements TransformerPlugin, ResourcePrevisitor {
+
+        private static String NAME = "plugin";
+
+        private boolean isPrevisitCalled = false;
+
+        @Override
+        public void visit(Pool inResources, Pool outResources) {
+            if (!isPrevisitCalled) {
+                throw new AssertionError("Previsit was not called");
+            }
+            CustomStringTable table = (CustomStringTable)
+                    ((PoolImpl) inResources).getStringTable();
+            if (table.size() == 0) {
+                throw new AssertionError("Table is empty");
+            }
+            Map<String, Integer> count = new HashMap<>();
+            for (int i = 0; i < table.size(); ++i) {
+                String s = table.getString(i);
+                if (inResources.get(s) != null) {
+                    throw new AssertionError();
+                }
+                count.compute(s, (k, c) -> 1 + (c == null ? 0 : c));
+            }
+            count.forEach((k, v) -> {
+                if (v != 1) {
+                    throw new AssertionError("Expected one entry in the table, got: " + v + " for " + k);
+                }
+            });
+            for (ModuleData r : inResources.getContent()) {
+                outResources.add(r);
+            }
+        }
+
+        @Override
+        public String getName() {
+            return NAME;
+        }
+
+        @Override
+        public void previsit(Pool resources, StringTable strings) {
+            isPrevisitCalled = true;
+            for (ModuleData r : resources.getContent()) {
+                String s = r.getPath();
+                int lastIndexOf = s.lastIndexOf('/');
+                if (lastIndexOf >= 0) {
+                    strings.addString(s.substring(0, lastIndexOf));
+                }
+            }
+        }
+
+        @Override
+        public Set<PluginType> getType() {
+            Set<PluginType> set = new HashSet<>();
+            set.add(CATEGORY.TRANSFORMER);
+            return Collections.unmodifiableSet(set);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/plugins/ResourceFilterTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Test ResourceFilter class
+ * @author Jean-Francois Denise
+ * @modules jdk.jlink/jdk.tools.jlink.internal.plugins
+ * @run main ResourceFilterTest
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import jdk.tools.jlink.internal.plugins.ResourceFilter;
+
+public class ResourceFilterTest {
+
+    public static void main(String[] args) throws Exception {
+        new ResourceFilterTest().test();
+    }
+
+    public void test() throws Exception {
+        String[] samples = {"toto.jcov", "/module/META-INF/services/MyProvider"};
+        String[] patterns = {"*.jcov", "*/META-INF/*"};
+        ResourceFilter rf = new ResourceFilter(patterns);
+        for (String s : samples) {
+            if (!rf.test(s)) {
+                throw new Exception("Sample " + s + "not accepted");
+            }
+        }
+        ResourceFilter rf2 = new ResourceFilter(patterns, true);
+        for (String s : samples) {
+            if (rf2.test(s)) {
+                throw new Exception("Sample " + s + " accepted");
+            }
+        }
+
+        // Excluded resource list in a file
+        File resources = new File("resources.exc");
+        resources.createNewFile();
+        StringBuilder builder = new StringBuilder();
+        for (String p : patterns) {
+            builder.append(p).append("\n");
+        }
+        Files.write(resources.toPath(), builder.toString().getBytes());
+
+        String[] input = {resources.getAbsolutePath()};
+        ResourceFilter rf3 = new ResourceFilter(input);
+        for (String s : samples) {
+            if (!rf3.test(s)) {
+                throw new Exception("Sample " + s + "not accepted");
+            }
+        }
+        ResourceFilter rf4 = new ResourceFilter(input, true);
+        for (String s : samples) {
+            if (rf4.test(s)) {
+                throw new Exception("Sample " + s + " accepted");
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/plugins/SignatureParserTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Test SignatureParser
+ * @author Jean-Francois Denise
+ * @modules java.base/jdk.internal.jimage.decompressor
+ * @run main SignatureParserTest
+ */
+
+import java.util.Arrays;
+import java.util.Objects;
+
+import jdk.internal.jimage.decompressor.SignatureParser;
+
+public class SignatureParserTest {
+
+    private int passed = 0;
+    private int failed = 0;
+
+    public static void main(String[] args) {
+        new SignatureParserTest().test();
+    }
+
+    private void test() {
+        test("[Ljava/lang/String;", "[L;", "java/lang/String");
+        test("[[[[[[[[[[Ljava/lang/String;", "[[[[[[[[[[L;", "java/lang/String");
+        test("<T:Ljava/lang/Object;:Ljava/lang/Comparable<-TT;>;>" +
+                        "(Ljava/lang/String;Ljava/lang/Class<TT;>;TT;Ljava/lang/Comparable<-TT;>;" +
+                        "Ljava/lang/Comparable<-TT;>;ZZ)V",
+                "<T:L;:L<-TT;>;>(L;L<TT;>;TT;L<-TT;>;L<-TT;>;ZZ)V",
+                "java/lang/Object", "java/lang/Comparable", "java/lang/String",
+                "java/lang/Class", "java/lang/Comparable", "java/lang/Comparable");
+        test("(Ljava/lang/String;ZLjava/util/EventListener;TTK;)V",
+                "(L;ZL;TTK;)V",
+                "java/lang/String", "java/util/EventListener");
+        test("<Y:Ljava/lang/String;>", "<Y:L;>", "java/lang/String");
+        test("<Y:Ljava/lang/String;Z::Ljava/util/EventListener;>",
+                "<Y:L;Z::L;>", "java/lang/String",
+                "java/util/EventListener");
+        test("<Y:Ljava/lang/String;Z::Ljava/util/EventListener;O::Ljava/lang/Comparable<Ljava/lang/String;>;>",
+                "<Y:L;Z::L;O::L<L;>;>",
+                "java/lang/String", "java/util/EventListener", "java/lang/Comparable", "java/lang/String");
+        test("<Y:Ljava/lang/String;O::Ljava/lang/Comparable<Ljava/lang/String;Ljava/lang/Float;>;>",
+                "<Y:L;O::L<L;L;>;>",
+                "java/lang/String", "java/lang/Comparable", "java/lang/String", "java/lang/Float");
+        test("<Y:Ljava/lang/String;O::Ljava/lang/Comparable<Ljava/lang/String;Ljava/lang/Float<Ljava/lang/Object;>;>;>",
+                "<Y:L;O::L<L;L<L;>;>;>",
+                "java/lang/String", "java/lang/Comparable", "java/lang/String", "java/lang/Float", "java/lang/Object");
+        test("Ljava/util/Set;", "L;", "java/util/Set");
+        test("Ljavaapplication20/Titi<[Ljava/lang/String;Ljava/lang/Integer;>;", "L<[L;L;>;",
+                "javaapplication20/Titi",
+                "java/lang/String", "java/lang/Integer");
+        test("Ljava/lang/Comparable<TK;>;", "L<TK;>;", "java/lang/Comparable");
+        test("Ljava/io/Serializable;Ljava/lang/Comparable<TK;>;", "L;L<TK;>;",
+                "java/io/Serializable", "java/lang/Comparable");
+        test("<Y:Ljava/lang/String;Z::Ljava/util/EventListener;K::Ljava/util/EventListener;O::"
+                + "Ljava/lang/Comparable<Ljava/lang/String;>;>"
+                + "Ljavaapplication20/Titi<[Ljava/lang/String;Ljava/lang/Integer;TZ;>;"
+                + "Ljava/io/Serializable;Ljava/lang/Comparable<TK;>;",
+                "<Y:L;Z::L;K::L;O::L<L;>;>L<[L;L;TZ;>;L;L<TK;>;",
+                "java/lang/String", "java/util/EventListener", "java/util/EventListener", "java/lang/Comparable",
+                "java/lang/String", "javaapplication20/Titi", "java/lang/String", "java/lang/Integer",
+                "java/io/Serializable", "java/lang/Comparable");
+        test("<PO:Ljava/lang/Object;>(Ljava/lang/Integer;TPO;)Ljava/lang/Integer;",
+                "<PO:L;>(L;TPO;)L;",
+                "java/lang/Object", "java/lang/Integer", "java/lang/Integer");
+        test("<PO:Ljava/lang/Object;>(Ljava/lang/Integer;TPO;)TPO;", "<PO:L;>(L;TPO;)TPO;",
+                "java/lang/Object", "java/lang/Integer");
+        test("<T::Ljava/util/EventListener;>(Ljava/lang/Class<TT;>;)[TT;",
+                "<T::L;>(L<TT;>;)[TT;",
+                "java/util/EventListener", "java/lang/Class");
+        test("<PO:LTiti;>(Ljava/lang/Integer;ITPO;)Z", "<PO:L;>(L;ITPO;)Z",
+                "Titi", "java/lang/Integer");
+        test("<K:Ljava/lang/Object;V:Ljava/lang/Object;>Ljava/lang/Object;",
+                "<K:L;V:L;>L;",
+                "java/lang/Object", "java/lang/Object", "java/lang/Object");
+        test("Ljava/util/LinkedHashMap<TK;TV;>.LinkedHashIterator;Ljava/util/Iterator<TV;>;",
+                "L<TK;TV;>.L;L<TV;>;",
+                "java/util/LinkedHashMap",
+                "inkedHashIterator",
+                "java/util/Iterator");
+        test("LToto<Ljava/lang/String;>;", "L<L;>;", "Toto",
+                "java/lang/String");
+        test("Ljavaapplication20/Titi<[Ljava/lang/String;Ljava/lang/Integer<LToto;>;TZ;>;",
+                "L<[L;L<L;>;TZ;>;",
+                "javaapplication20/Titi", "java/lang/String", "java/lang/Integer", "Toto");
+        test("LX<[LQ;LW<LToto;>;TZ;>;", "L<[L;L<L;>;TZ;>;",
+                "X", "Q", "W", "Toto");
+        test("Ljava/lang/String<*>;", "L<*>;", "java/lang/String");
+        test("Ljava/util/List<[B>;", "L<[B>;", "java/util/List");
+        test("<T:Ljava/lang/Object;T_NODE::Ljava/util/stream/Node<TT;>;>Ljava/lang/Object;Ljava/util/stream/Node<TT;>;",
+                "<T:L;T_NODE::L<TT;>;>L;L<TT;>;",
+                "java/lang/Object", "java/util/stream/Node", "java/lang/Object", "java/util/stream/Node");
+        test("Ljavaapplication20/Titi<[Ljava/lang/String;>;", "L<[L;>;",
+                "javaapplication20/Titi", "java/lang/String");
+        test("<A::Ljava/lang/annotation/Annotation;"
+                        + "W::Lcom/sun/codemodel/internal/JAnnotationWriter<TA;>;>"
+                        + "Ljava/lang/Object;Ljava/lang/reflect/InvocationHandler;"
+                        + "Lcom/sun/codemodel/internal/JAnnotationWriter<TA;>;",
+                "<A::L;W::L<TA;>;>L;L;L<TA;>;",
+                "java/lang/annotation/Annotation", "com/sun/codemodel/internal/JAnnotationWriter",
+                "java/lang/Object", "java/lang/reflect/InvocationHandler", "com/sun/codemodel/internal/JAnnotationWriter");
+        test("<W::Lcom/sun/codemodel/internal/JAnnotationWriter<*>;>(Ljava/lang/Class<TW;>;" +
+                "Lcom/sun/codemodel/internal/JAnnotatable;)TW;",
+                "<W::L<*>;>(L<TW;>;L;)TW;",
+                "com/sun/codemodel/internal/JAnnotationWriter", "java/lang/Class", "com/sun/codemodel/internal/JAnnotatable");
+        test("Ljava/util/Set<Lcom/sun/tools/jdeps/JdepsTask$DotGraph<TT;>.Edge;>;",
+                "L<L<TT;>.Edge;>;",
+                "java/util/Set",
+                "com/sun/tools/jdeps/JdepsTask$DotGraph");
+        test("<E::Lcom/sun/xml/internal/rngom/ast/om/ParsedElementAnnotation;" +
+                "L::Lcom/sun/xml/internal/rngom/ast/om/Location;" +
+                "CL::Lcom/sun/xml/internal/rngom/ast/builder/CommentList<TL;>;>Ljava/lang/Object;",
+                "<E::L;L::L;CL::L<TL;>;>L;",
+                "com/sun/xml/internal/rngom/ast/om/ParsedElementAnnotation",
+                "",
+                "com/sun/xml/internal/rngom/ast/om/Location",
+                "",
+                "com/sun/xml/internal/rngom/ast/builder/CommentList",
+                "",
+                "java/lang/Object");
+        test("(Ljava/util/List<Lcom/sun/xml/internal/rngom/nc/NameClass;>;TL;TA;)" +
+                "Lcom/sun/xml/internal/rngom/nc/NameClass;",
+                "(L<L;>;TL;TA;)L;",
+                "java/util/List",
+                "com/sun/xml/internal/rngom/nc/NameClass",
+                "",
+                "com/sun/xml/internal/rngom/nc/NameClass");
+        test("[Ljava/util/List;", "[L;", "java/util/List");
+        test("[Ljava/util/List<+Lcom/sun/jdi/request/EventRequest;>;",
+                "[L<+L;>;",
+                "java/util/List", "com/sun/jdi/request/EventRequest");
+        test("Lcom/sun/xml/internal/bind/v2/util/QNameMap<TV;>.HashIterator" +
+                "<Lcom/sun/xml/internal/bind/v2/util/QNameMap$Entry<TV;>;>;",
+                "L<TV;>.HashIterator<L<TV;>;>;",
+                "com/sun/xml/internal/bind/v2/util/QNameMap", "com/sun/xml/internal/bind/v2/util/QNameMap$Entry");
+        test("[Ljava/lang/String;", "[L;", "java/lang/String");
+        test("[Ljava/lang/String<Ljava/lang/Toto<Ljava/lang/Titi;>;>;",
+                "[L<L<L;>;>;",
+                "java/lang/String", "java/lang/Toto", "java/lang/Titi");
+        test("<T::Ljava/util/EventListener;K:Ljava/util/BOO;>(ZCLjava/lang/Class<TT;>;IJS)[TT;",
+                "<T::L;K:L;>(ZCL<TT;>;IJS)[TT;",
+                "java/util/EventListener", "java/util/BOO", "java/lang/Class");
+        test("<T:Ljava/lang/Object;>(TT;ILjava/lang/Long;)TT;",
+                "<T:L;>(TT;IL;)TT;", "java/lang/Object", "java/lang/Long");
+        test("<T:Ljava/lang/Object;>(TT;ILjava/lang/Long;)TT;^TT;",
+                "<T:L;>(TT;IL;)TT;^TT;", "java/lang/Object", "java/lang/Long");
+        test("<T:Ljava/lang/Object;>(TT;ILjava/lang/Long;)TT;^TT;^Ljava/lang/Exception;",
+                "<T:L;>(TT;IL;)TT;^TT;^L;",
+                "java/lang/Object", "java/lang/Long", "java/lang/Exception");
+        if (passed + failed == 0) {
+            throw new AssertionError("No tests were run");
+        }
+        String message = String.format("Passed: %d, failed: %d, total: %d", passed, failed, passed + failed);
+        if (failed > 0) {
+            throw new AssertionError("Test failed: " + message);
+        } else {
+            System.err.println(message);
+        }
+    }
+
+    private void test(String type, String formatted, String...classNames) {
+        try {
+            SignatureParser.ParseResult result = SignatureParser.parseSignatureDescriptor(type);
+            String[] parsedNames = parse(classNames);
+            assertEquals(result.formatted, formatted, "Input: '" + type + "', checking 'formatted'");
+            assertEquals(result.types.size(), 2 * classNames.length,
+                    "Input: '" + type + "', checking the length of 'types':" +
+                            "\nexpected: " + Arrays.toString(parsedNames) +
+                            "\n     got: " + result.types);
+            for (int i = 0; i < result.types.size(); ++i) {
+                assertEquals(result.types.get(i), parsedNames[i],
+                        "Input: '" + type + "', checking 'packageName' at index " + i / 2);
+                ++i;
+                assertEquals(result.types.get(i), parsedNames[i],
+                        "Input: '" + type + "', checking 'simpleName' at index " + i / 2);
+            }
+            String reconstructed = SignatureParser.reconstruct(result.formatted, result.types);
+            assertEquals(reconstructed, type, "Input: '" + type + "', checking reconstruction from: "
+                    + result.formatted + " " + result.types);
+            ++passed;
+        } catch (Exception | AssertionError e) {
+            e.printStackTrace();
+            ++failed;
+        }
+    }
+
+    private void assertEquals(Object actual, Object expected, String message) {
+        if (!Objects.equals(actual, expected)) {
+            throw new AssertionError(message + ": expected: " + expected + ", actual: " + actual);
+        }
+    }
+
+    private String[] parse(String[] classNames) {
+        String[] result = new String[2 * classNames.length];
+        for (int i = 0; i < classNames.length; ++i) {
+            int index = classNames[i].lastIndexOf("/");
+            result[2 * i] = index == -1 ? "" : classNames[i].substring(0, index);
+            result[2 *i + 1] = classNames[i].substring(index + 1);
+        }
+        return result;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/plugins/SorterPluginTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Test sorter plugin
+ * @author Jean-Francois Denise
+ * @modules jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jlink.internal.plugins
+ * @run main SorterPluginTest
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import jdk.tools.jlink.internal.PoolImpl;
+
+import jdk.tools.jlink.internal.plugins.SortResourcesPlugin;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.TransformerPlugin;
+
+public class SorterPluginTest {
+
+    public static void main(String[] args) throws Exception {
+        new SorterPluginTest().test();
+    }
+
+    public void test() throws Exception {
+        ModuleData[] array = {
+                Pool.newResource("/module1/toto1", new byte[0]),
+                Pool.newResource("/module2/toto1", new byte[0]),
+                Pool.newResource("/module3/toto1", new byte[0]),
+                Pool.newResource("/module3/toto1/module-info.class", new byte[0]),
+                Pool.newResource("/zazou/toto1", new byte[0]),
+                Pool.newResource("/module4/zazou", new byte[0]),
+                Pool.newResource("/module5/toto1", new byte[0]),
+                Pool.newResource("/module6/toto1/module-info.class", new byte[0])
+        };
+
+        ModuleData[] sorted = {
+                Pool.newResource("/zazou/toto1", new byte[0]),
+                Pool.newResource("/module3/toto1/module-info.class", new byte[0]),
+                Pool.newResource("/module6/toto1/module-info.class", new byte[0]),
+                Pool.newResource("/module1/toto1", new byte[0]),
+                Pool.newResource("/module2/toto1", new byte[0]),
+                Pool.newResource("/module3/toto1", new byte[0]),
+                Pool.newResource("/module4/zazou", new byte[0]),
+                Pool.newResource("/module5/toto1", new byte[0]),
+};
+
+        ModuleData[] sorted2 = {
+            Pool.newResource("/module5/toto1", new byte[0]),
+            Pool.newResource("/module6/toto1/module-info.class", new byte[0]),
+            Pool.newResource("/module4/zazou", new byte[0]),
+            Pool.newResource("/module3/toto1", new byte[0]),
+            Pool.newResource("/module3/toto1/module-info.class", new byte[0]),
+            Pool.newResource("/module1/toto1", new byte[0]),
+            Pool.newResource("/module2/toto1", new byte[0]),
+            Pool.newResource("/zazou/toto1", new byte[0]),};
+
+        Pool resources = new PoolImpl();
+        for (ModuleData r : array) {
+            resources.add(r);
+        }
+
+        {
+            Pool out = new PoolImpl();
+            Map<String, String> config = new HashMap<>();
+            config.put(SortResourcesPlugin.NAME, "/zazou/*,*/module-info.class");
+            TransformerPlugin p = new SortResourcesPlugin();
+            p.configure(config);
+            p.visit(resources, out);
+            check(out.getContent(), sorted);
+        }
+
+        {
+            // Order of resources in the file, then un-ordered resources.
+            File order = new File("resources.order");
+            order.createNewFile();
+            StringBuilder builder = new StringBuilder();
+            // 5 first resources come from file
+            for (int i = 0; i < 5; i++) {
+                builder.append(sorted2[i].getPath()).append("\n");
+            }
+            Files.write(order.toPath(), builder.toString().getBytes());
+
+            Pool out = new PoolImpl();
+            Map<String, String> config = new HashMap<>();
+            config.put(SortResourcesPlugin.NAME, order.getAbsolutePath());
+            TransformerPlugin p = new SortResourcesPlugin();
+            p.configure(config);
+            p.visit(resources, out);
+            check(out.getContent(), sorted2);
+
+        }
+    }
+
+    private void check(Collection<ModuleData> outResources,
+            ModuleData[] sorted) {
+        if (outResources.size() != sorted.length) {
+            throw new AssertionError("Wrong number of resources:\n"
+                    + "expected: " + Arrays.toString(sorted) + ",\n"
+                    + "     got: " + outResources);
+        }
+        int i = 0;
+        for (ModuleData r : outResources) {
+            System.err.println("Resource: " + r);
+            if (!sorted[i].getPath().equals(r.getPath())) {
+                throw new AssertionError("Resource not properly sorted, difference at: " + i + "\n"
+                        + "expected: " + Arrays.toString(sorted) + ",\n"
+                        + "     got: " + outResources);
+            }
+            i++;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/plugins/StringSharingPluginTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Test StringSharingPluginTest
+ * @author Jean-Francois Denise
+ * @library ../../lib
+ * @modules java.base/jdk.internal.jimage
+ *          java.base/jdk.internal.jimage.decompressor
+ *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jlink.internal.plugins
+ *          jdk.jlink/jdk.tools.jmod
+ *          jdk.jlink/jdk.tools.jimage
+ *          jdk.jdeps/com.sun.tools.classfile
+ *          jdk.compiler
+ * @run build tests.*
+ * @run main StringSharingPluginTest
+ */
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
+
+import jdk.internal.jimage.decompressor.CompressedResourceHeader;
+import jdk.internal.jimage.decompressor.StringSharingDecompressor;
+import jdk.tools.jlink.internal.PoolImpl;
+import jdk.tools.jlink.internal.StringTable;
+import jdk.tools.jlink.internal.plugins.StringSharingPlugin;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.TransformerPlugin;
+import tests.Helper;
+import tests.JImageValidator;
+
+public class StringSharingPluginTest {
+
+    private static int strID = 1;
+
+    public static void main(String[] args) throws Exception {
+        // JPRT not yet ready for jmods
+        Helper helper = Helper.newHelper();
+        if (helper == null) {
+            System.err.println("Test not run, NO jmods directory");
+            return;
+        }
+
+        List<String> classes = Arrays.asList("toto.Main", "toto.com.foo.bar.X");
+        Path compiledClasses = helper.generateModuleCompiledClasses(
+                helper.getJmodSrcDir(), helper.getJmodClassesDir(), "composite2", classes);
+
+        Map<String, Integer> map = new HashMap<>();
+        Map<Integer, String> reversedMap = new HashMap<>();
+
+        PoolImpl resources = new PoolImpl(ByteOrder.nativeOrder(), new StringTable() {
+            @Override
+            public int addString(String str) {
+                Integer id = map.get(str);
+                if (id == null) {
+                    id = strID;
+                    map.put(str, id);
+                    reversedMap.put(id, str);
+                    strID += 1;
+                }
+                return id;
+            }
+
+            @Override
+            public String getString(int id) {
+                throw new UnsupportedOperationException("Not supported yet.");
+            }
+        });
+        Consumer<Path> c = (p) -> {
+            // take only the .class resources.
+            if (Files.isRegularFile(p) && p.toString().endsWith(".class")
+                    && !p.toString().endsWith("module-info.class")) {
+                try {
+                    byte[] content = Files.readAllBytes(p);
+                    String path = p.toString().replace('\\', '/');
+                    path = path.substring("/modules".length());
+                    ModuleData res = Pool.newResource(path, content);
+                    resources.add(res);
+                } catch (Exception ex) {
+                    throw new RuntimeException(ex);
+                }
+            }
+        };
+        try (java.util.stream.Stream<Path> stream = Files.walk(compiledClasses)) {
+            stream.forEach(c);
+        }
+        TransformerPlugin plugin = new StringSharingPlugin();
+        PoolImpl result = new PoolImpl(resources.getByteOrder(), resources.getStringTable());
+        plugin.visit(resources, result);
+
+        if (result.isEmpty()) {
+            throw new AssertionError("No result");
+        }
+
+        for (ModuleData res : result.getContent()) {
+            if (res.getPath().endsWith(".class")) {
+                byte[] uncompacted = StringSharingDecompressor.normalize(reversedMap::get, res.getBytes(),
+                        CompressedResourceHeader.getSize());
+                JImageValidator.readClass(uncompacted);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/plugins/StripDebugPluginTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Test StripDebugPlugin
+ * @author Jean-Francois Denise
+ * @library ../../lib
+ * @build tests.*
+ * @modules java.base/jdk.internal.jimage
+ *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jlink.internal.plugins
+ *          jdk.jlink/jdk.tools.jimage
+ *          jdk.jlink/jdk.tools.jmod
+ *          jdk.jdeps/com.sun.tools.classfile
+ *          jdk.compiler
+ * @run main StripDebugPluginTest
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.stream.Stream;
+
+import com.sun.tools.classfile.Attribute;
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.Code_attribute;
+import com.sun.tools.classfile.ConstantPoolException;
+import com.sun.tools.classfile.Method;
+import java.util.HashMap;
+import java.util.Map;
+import jdk.tools.jlink.internal.PoolImpl;
+import jdk.tools.jlink.internal.plugins.StripDebugPlugin;
+import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.TransformerPlugin;
+import tests.Helper;
+
+public class StripDebugPluginTest {
+    public static void main(String[] args) throws Exception {
+        new StripDebugPluginTest().test();
+    }
+
+    public void test() throws Exception {
+        // JPRT not yet ready for jmods
+        Helper helper = Helper.newHelper();
+        if (helper == null) {
+            System.err.println("Test not run, NO jmods directory");
+            return;
+        }
+
+        List<String> classes = Arrays.asList("toto.Main", "toto.com.foo.bar.X");
+        Path moduleFile = helper.generateModuleCompiledClasses(
+                helper.getJmodSrcDir(), helper.getJmodClassesDir(), "leaf1", classes);
+        Path moduleInfo = moduleFile.resolve("module-info.class");
+
+        // Classes have been compiled in debug.
+        List<Path> covered = new ArrayList<>();
+        byte[] infoContent = Files.readAllBytes(moduleInfo);
+        try (Stream<Path> stream = Files.walk(moduleFile)) {
+            for (Iterator<Path> iterator = stream.iterator(); iterator.hasNext(); ) {
+                Path p = iterator.next();
+                if (Files.isRegularFile(p) && p.toString().endsWith(".class")) {
+                    byte[] content = Files.readAllBytes(p);
+                    String path = "/" + helper.getJmodClassesDir().relativize(p).toString();
+                    String moduleInfoPath = path + "/module-info.class";
+                    check(path, content, moduleInfoPath, infoContent);
+                    covered.add(p);
+                }
+            }
+        }
+        if (covered.isEmpty()) {
+            throw new AssertionError("No class to compress");
+        } else {
+            System.err.println("removed debug attributes from "
+                    + covered.size() + " classes");
+        }
+    }
+
+    private void check(String path, byte[] content, String infoPath, byte[] moduleInfo) throws Exception {
+        path = path.replace('\\', '/');
+        StripDebugPlugin debug = new StripDebugPlugin();
+        debug.configure(new HashMap<>());
+        ModuleData result1 = stripDebug(debug, Pool.newResource(path,content), path, infoPath, moduleInfo);
+
+        if (!path.endsWith("module-info.class")) {
+            if (result1.getLength() >= content.length) {
+                throw new AssertionError("Class size not reduced, debug info not "
+                        + "removed for " + path);
+            }
+            checkDebugAttributes(result1.getBytes());
+        }
+
+        ModuleData result2 = stripDebug(debug, result1, path, infoPath, moduleInfo);
+        if (result1.getLength() != result2.getLength()) {
+            throw new AssertionError("removing debug info twice reduces class size of "
+                    + path);
+        }
+        checkDebugAttributes(result1.getBytes());
+    }
+
+    private ModuleData stripDebug(TransformerPlugin debug, ModuleData classResource,
+            String path, String infoPath, byte[] moduleInfo) throws Exception {
+        Pool resources = new PoolImpl();
+        resources.add(classResource);
+        if (!path.endsWith("module-info.class")) {
+            ModuleData res2 = Pool.newResource(infoPath, moduleInfo);
+            resources.add(res2);
+        }
+        Pool results = new PoolImpl();
+        debug.visit(resources, results);
+        System.out.println(classResource.getPath());
+        return results.get(classResource.getPath());
+    }
+
+    private void checkDebugAttributes(byte[] strippedClassFile) throws IOException, ConstantPoolException {
+        ClassFile classFile = ClassFile.read(new ByteArrayInputStream(strippedClassFile));
+        String[] debugAttributes = new String[]{
+                Attribute.LineNumberTable,
+                Attribute.LocalVariableTable,
+                Attribute.LocalVariableTypeTable
+        };
+        for (Method method : classFile.methods) {
+            String methodName = method.getName(classFile.constant_pool);
+            Code_attribute code = (Code_attribute) method.attributes.get(Attribute.Code);
+            for (String attr : debugAttributes) {
+                if (code.attributes.get(attr) != null) {
+                    throw new AssertionError("Debug attribute was not removed: " + attr +
+                            " from method " + classFile.getName() + "#" + methodName);
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jmod/JmodNegativeTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,552 @@
+/**
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @modules jdk.jlink/jdk.tools.jmod
+ *          jdk.compiler
+ * @build jdk.testlibrary.FileUtils CompilerUtils
+ * @run testng JmodNegativeTest
+ * @summary Negative tests for jmod
+ */
+
+import java.io.*;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+import java.util.zip.ZipOutputStream;
+import jdk.testlibrary.FileUtils;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import static java.io.File.pathSeparator;
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.testng.Assert.assertTrue;
+
+public class JmodNegativeTest {
+
+    static final String TEST_SRC = System.getProperty("test.src", ".");
+    static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    static final Path EXPLODED_DIR = Paths.get("build");
+    static final Path MODS_DIR = Paths.get("jmods");
+
+    @BeforeTest
+    public void buildExplodedModules() throws IOException {
+        if (Files.exists(EXPLODED_DIR))
+            FileUtils.deleteFileTreeWithRetry(EXPLODED_DIR);
+
+        for (String name : new String[] { "foo"/*, "bar", "baz"*/ } ) {
+            Path dir = EXPLODED_DIR.resolve(name);
+            assertTrue(compileModule(name, dir.resolve("classes")));
+        }
+
+        if (Files.exists(MODS_DIR))
+            FileUtils.deleteFileTreeWithRetry(MODS_DIR);
+        Files.createDirectories(MODS_DIR);
+    }
+
+    @Test
+    public void testNoArgs() {
+        jmod()
+            .assertFailure()
+            .resultChecker(r ->
+                assertContains(r.output, "Error: one of create, list, or describe must be specified")
+            );
+    }
+
+    @Test
+    public void testBadAction() {
+        jmod("badAction")
+            .assertFailure()
+            .resultChecker(r ->
+                assertContains(r.output, "Error: mode must be one of create, list, or describe")
+            );
+
+        jmod("--badOption")
+            .assertFailure()
+            .resultChecker(r ->
+                assertContains(r.output, "Error: 'badOption' is not a recognized option")
+            );
+    }
+
+    @Test
+    public void testTooManyArgs() throws IOException {
+        Path jmod = MODS_DIR.resolve("doesNotExist.jmod");
+        FileUtils.deleteFileIfExistsWithRetry(jmod);
+
+        jmod("create",
+             jmod.toString(),
+             "AAA")
+            .assertFailure()
+            .resultChecker(r ->
+                assertContains(r.output, "Error: unknown option(s): [AAA]")
+            );
+    }
+
+    @Test
+    public void testCreateNoArgs() {
+        jmod("create")
+            .assertFailure()
+            .resultChecker(r ->
+                assertContains(r.output, "Error: jmod-file must be specified")
+            );
+    }
+
+    @Test
+    public void testListNoArgs() {
+        jmod("list")
+            .assertFailure()
+            .resultChecker(r ->
+                assertContains(r.output, "Error: jmod-file must be specified")
+            );
+    }
+
+    @Test
+    public void testListFileDoesNotExist() throws IOException {
+        Path jmod = MODS_DIR.resolve("doesNotExist.jmod");
+        FileUtils.deleteFileIfExistsWithRetry(jmod);
+
+        jmod("list",
+             jmod.toString())
+            .assertFailure()
+            .resultChecker(r ->
+                assertContains(r.output, "Error: no jmod file found: "
+                        + jmod.toString())
+            );
+    }
+
+    @Test
+    public void testListJmodIsDir() throws IOException {
+        Path jmod = MODS_DIR.resolve("testListJmodIsDir.jmod");
+        if (Files.notExists(jmod))
+            Files.createDirectory(jmod);
+
+        jmod("list",
+             jmod.toString())
+            .assertFailure()
+            .resultChecker(r ->
+                assertContains(r.output, "Error: error opening jmod file")
+            );
+    }
+
+    @Test
+    public void testlistJmodMalformed() throws IOException {
+        Path jmod = MODS_DIR.resolve("testlistJmodMalformed.jmod");
+        if (Files.notExists(jmod))
+            Files.createFile(jmod);
+
+        jmod("list",
+             jmod.toString())
+            .assertFailure()
+            .resultChecker(r ->
+                assertContains(r.output, "Error: error opening jmod file")
+            );
+    }
+
+    @Test
+    public void testHashDependenciesModulePathNotSpecified() {
+        jmod("create",
+             "--hash-dependencies", "anyPattern.*",
+             "output.jmod")
+            .assertFailure()
+            .resultChecker(r ->
+                assertContains(r.output, "Error: --module-path must be "
+                        +"specified when hashing dependencies")
+            );
+    }
+
+    @Test
+    public void testCreateJmodAlreadyExists() throws IOException {
+        Path jmod = MODS_DIR.resolve("testCreateJmodAlreadyExists.jmod");
+        if (Files.notExists(jmod))
+            Files.createFile(jmod);
+
+        jmod("create",
+             "--class-path", Paths.get(".").toString(), // anything that exists
+             jmod.toString())
+            .assertFailure()
+            .resultChecker(r ->
+                assertContains(r.output, "Error: file already exists: " + jmod.toString())
+            );
+    }
+
+    @Test
+    public void testCreateJmodIsDir() throws IOException {
+        Path jmod = MODS_DIR.resolve("testCreateJmodAlreadyExists");
+        if (Files.notExists(jmod))
+            Files.createDirectory(jmod);
+
+        jmod("create",
+             "--class-path", Paths.get(".").toString(), // anything that exists
+             jmod.toString())
+            .assertFailure()
+            .resultChecker(r ->
+                assertContains(r.output, "Error: file already exists: " + jmod.toString())
+            );
+    }
+
+    @Test
+    public void testInvalidModuleVersion() throws IOException {
+        Path jmod = MODS_DIR.resolve("testEmptyModuleVersion.jmod");
+        FileUtils.deleteFileIfExistsWithRetry(jmod);
+        String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString();
+
+        for (String version : new String[] { "", "NOT_A_VALID_VERSION" }) {
+            jmod("create",
+                 "--class-path", cp,
+                 "--module-version", version,
+                 jmod.toString())
+                .assertFailure()
+                .resultChecker(r ->
+                    assertContains(r.output, "Error: invalid module version")
+                );
+        }
+    }
+
+    @Test(enabled = false)  // TODO: jmod should check for duplicates before creating.
+    public void testDuplicates() throws IOException {
+        Path jmod = MODS_DIR.resolve("testDuplicates.jmod");
+        FileUtils.deleteFileIfExistsWithRetry(jmod);
+        String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString();
+
+        jmod("create",
+             "--class-path", cp + pathSeparator + cp,
+             jmod.toString())
+            .assertFailure()
+            .resultChecker(r ->
+                assertContains(r.output, "Error: duplicate resource found, etc..")
+            );
+    }
+
+    @Test
+    public void testEmptyFileInClasspath() throws IOException {
+        Path jmod = MODS_DIR.resolve("testEmptyFileInClasspath.jmod");
+        FileUtils.deleteFileIfExistsWithRetry(jmod);
+        Path jar = MODS_DIR.resolve("NotARealJar_Empty.jar");
+        FileUtils.deleteFileIfExistsWithRetry(jar);
+        Files.createFile(jar);
+
+        jmod("create",
+             "--class-path", jar.toString(),
+             jmod.toString())
+            .assertFailure()
+            .resultChecker(r ->
+                assertContains(r.output, "Error: module-info.class not found")
+            );
+    }
+
+    @Test
+    public void testEmptyJarInClasspath() throws IOException {
+        Path jmod = MODS_DIR.resolve("testEmptyJarInClasspath.jmod");
+        FileUtils.deleteFileIfExistsWithRetry(jmod);
+        Path jar = MODS_DIR.resolve("empty.jar");
+        FileUtils.deleteFileIfExistsWithRetry(jar);
+        try (FileOutputStream fos = new FileOutputStream(jar.toFile());
+             ZipOutputStream zos = new ZipOutputStream(fos)) {
+            // empty
+        }
+
+        jmod("create",
+             "--class-path", jar.toString(),
+             jmod.toString())
+            .assertFailure()
+            .resultChecker(r ->
+                assertContains(r.output, "Error: module-info.class not found")
+            );
+    }
+
+    @Test
+    public void testModuleInfoNotFound() throws IOException {
+        Path jmod = MODS_DIR.resolve("output.jmod");
+        FileUtils.deleteFileIfExistsWithRetry(jmod);
+        Path jar = MODS_DIR.resolve("empty");
+        FileUtils.deleteFileIfExistsWithRetry(jar);
+        Files.createDirectory(jar);
+
+        jmod("create",
+             "--class-path", jar.toString(),
+             jmod.toString())
+            .assertFailure()
+            .resultChecker(r ->
+                assertContains(r.output, "Error: module-info.class not found")
+            );
+    }
+
+    @Test
+    public void testModuleInfoIsDir() throws IOException {
+        Path jmod = MODS_DIR.resolve("output.jmod");
+        FileUtils.deleteFileIfExistsWithRetry(jmod);
+        Path cp = MODS_DIR.resolve("module-info.class");
+        FileUtils.deleteFileIfExistsWithRetry(cp);
+        Files.createDirectory(cp);
+        Files.createFile(cp.resolve("nada.txt"));
+
+        jmod("create",
+             "--class-path", cp.toString(),
+             jmod.toString())
+            .assertFailure()
+            .resultChecker(r ->
+                assertContains(r.output, "Error: module-info.class not found")
+            );
+    }
+
+    @Test
+    public void testDependencyNotFound() throws IOException {
+        Path jmod = MODS_DIR.resolve("output.jmod");
+        FileUtils.deleteFileIfExistsWithRetry(jmod);
+        Path emptyDir = Paths.get("empty");
+        if (Files.exists(emptyDir))
+            FileUtils.deleteFileTreeWithRetry(emptyDir);
+        Files.createDirectory(emptyDir);
+        String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString();
+
+        jmod("create",
+             "--class-path", cp,
+             "--hash-dependencies", ".*",
+             "--modulepath", emptyDir.toString(),
+            jmod.toString())
+            .assertFailure()
+            .resultChecker(r ->
+                assertContains(r.output, "Hashing module foo dependencies, "
+                        + "unable to find module java.base on module path")
+            );
+    }
+
+    @Test
+    public void testEmptyFileInModulePath() throws IOException {
+        Path jmod = MODS_DIR.resolve("output.jmod");
+        FileUtils.deleteFileIfExistsWithRetry(jmod);
+        Path empty = MODS_DIR.resolve("emptyFile.jmod");
+        FileUtils.deleteFileIfExistsWithRetry(empty);
+        Files.createFile(empty);
+        try {
+            String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString();
+
+            jmod("create",
+                 "--class-path", cp,
+                 "--hash-dependencies", ".*",
+                 "--modulepath", MODS_DIR.toString(),
+                 jmod.toString())
+                .assertFailure()
+                .resultChecker(r ->
+                    assertContains(r.output, "Error: error reading module path")
+                );
+        } finally {
+            FileUtils.deleteFileWithRetry(empty);
+        }
+    }
+
+    @Test
+    public void testFileInModulePath() throws IOException {
+        Path jmod = MODS_DIR.resolve("output.jmod");
+        FileUtils.deleteFileIfExistsWithRetry(jmod);
+        Path file = MODS_DIR.resolve("testFileInModulePath.txt");
+        FileUtils.deleteFileIfExistsWithRetry(file);
+        Files.createFile(file);
+
+        jmod("create",
+             "--hash-dependencies", ".*",
+             "--modulepath", file.toString(),
+             jmod.toString())
+            .assertFailure()
+            .resultChecker(r ->
+                assertContains(r.output, "Error: path must be a directory")
+            );
+    }
+
+    @DataProvider(name = "pathDoesNotExist")
+    public Object[][] pathDoesNotExist() throws IOException {
+        Path jmod = MODS_DIR.resolve("output.jmod");
+        FileUtils.deleteFileIfExistsWithRetry(jmod);
+        FileUtils.deleteFileIfExistsWithRetry(Paths.get("doesNotExist"));
+
+        List<Supplier<JmodResult>> tasks = Arrays.asList(
+                () -> jmod("create",
+                           "--hash-dependencies", "anyPattern",
+                           "--modulepath", "doesNotExist",
+                           "output.jmod"),
+                () -> jmod("create",
+                           "--class-path", "doesNotExist",
+                           "output.jmod"),
+                () -> jmod("create",
+                           "--class-path", "doesNotExist.jar",
+                           "output.jmod"),
+                () -> jmod("create",
+                           "--cmds", "doesNotExist",
+                           "output.jmod"),
+                () -> jmod("create",
+                           "--config", "doesNotExist",
+                           "output.jmod"),
+                () -> jmod("create",
+                           "--libs", "doesNotExist",
+                           "output.jmod") );
+
+        String errMsg = "Error: path not found: doesNotExist";
+        return tasks.stream().map(t -> new Object[] {t, errMsg} )
+                             .toArray(Object[][]::new);
+    }
+
+    @Test(dataProvider = "pathDoesNotExist")
+    public void testPathDoesNotExist(Supplier<JmodResult> supplier,
+                                     String errMsg)
+    {
+        supplier.get()
+                .assertFailure()
+                .resultChecker(r -> {
+                    assertContains(r.output, errMsg);
+                });
+    }
+
+    @DataProvider(name = "partOfPathDoesNotExist")
+    public Object[][] partOfPathDoesNotExist() throws IOException {
+        Path jmod = MODS_DIR.resolve("output.jmod");
+        FileUtils.deleteFileIfExistsWithRetry(jmod);
+        FileUtils.deleteFileIfExistsWithRetry(Paths.get("doesNotExist"));
+
+        Path emptyDir = Paths.get("empty");
+        if (Files.exists(emptyDir))
+            FileUtils.deleteFileTreeWithRetry(emptyDir);
+        Files.createDirectory(emptyDir);
+
+        List<Supplier<JmodResult>> tasks = Arrays.asList(
+            () -> jmod("create",
+                       "--hash-dependencies", "anyPattern",
+                       "--modulepath","empty" + pathSeparator + "doesNotExist",
+                       "output.jmod"),
+            () -> jmod("create",
+                       "--class-path", "empty" + pathSeparator + "doesNotExist",
+                       "output.jmod"),
+            () -> jmod("create",
+                       "--class-path", "empty" + pathSeparator + "doesNotExist.jar",
+                       "output.jmod"),
+            () -> jmod("create",
+                       "--cmds", "empty" + pathSeparator + "doesNotExist",
+                       "output.jmod"),
+            () -> jmod("create",
+                       "--config", "empty" + pathSeparator + "doesNotExist",
+                       "output.jmod"),
+            () -> jmod("create",
+                       "--libs", "empty" + pathSeparator + "doesNotExist",
+                       "output.jmod") );
+
+        String errMsg = "Error: path not found: doesNotExist";
+        return tasks.stream().map(t -> new Object[] {t, errMsg} )
+                             .toArray(Object[][]::new);
+    }
+
+    @Test(dataProvider = "partOfPathDoesNotExist")
+    public void testPartOfPathNotExist(Supplier<JmodResult> supplier,
+                                       String errMsg)
+    {
+        supplier.get()
+                .assertFailure()
+                .resultChecker(r -> {
+                    assertContains(r.output, errMsg);
+                });
+    }
+
+    @DataProvider(name = "pathIsFile")
+    public Object[][] pathIsFile() throws IOException {
+        Path jmod = MODS_DIR.resolve("output.jmod");
+        FileUtils.deleteFileIfExistsWithRetry(jmod);
+        Path aFile = Paths.get("aFile.txt");
+        if (Files.exists(aFile) && !Files.isRegularFile(aFile))
+            throw new InternalError("Unexpected file:" + aFile);
+        else
+            Files.createFile(aFile);
+
+        List<Supplier<JmodResult>> tasks = Arrays.asList(
+                () -> jmod("create",
+                           "--class-path", "aFile.txt",
+                           "output.jmod"),
+                () -> jmod("create",
+                           "--modulepath", "aFile.txt",
+                           "output.jmod"),
+                () -> jmod("create",
+                           "--cmds", "aFile.txt",
+                           "output.jmod"),
+                () -> jmod("create",
+                           "--config", "aFile.txt",
+                           "output.jmod"),
+                () -> jmod("create",
+                           "--libs", "aFile.txt",
+                           "output.jmod") );
+
+        String errMsg = "Error: path must be a directory: aFile.txt";
+        Object[][] a = tasks.stream().map(t -> new Object[] {t, errMsg} )
+                                     .toArray(Object[][]::new);
+        a[0][1] = "invalid class path entry: aFile.txt";  // class path err msg
+        return a;
+    }
+
+    @Test(dataProvider = "pathIsFile")
+    public void testPathIsFile(Supplier<JmodResult> supplier,
+                               String errMsg)
+    {
+        supplier.get()
+                .assertFailure()
+                .resultChecker(r -> {
+                    assertContains(r.output, errMsg);
+                });
+    }
+
+    // ---
+
+    static boolean compileModule(String name, Path dest) throws IOException {
+        return CompilerUtils.compile(SRC_DIR.resolve(name), dest);
+    }
+
+    static void assertContains(String output, String subString) {
+        if (output.contains(subString))
+            assertTrue(true);
+        else
+            assertTrue(false,"Expected to find [" + subString + "], in output ["
+                             + output + "]");
+    }
+
+    static JmodResult jmod(String... args) {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        PrintStream ps = new PrintStream(baos);
+        System.out.println("jmod " + Arrays.asList(args));
+        int ec = jdk.tools.jmod.Main.run(args, ps);
+        return new JmodResult(ec, new String(baos.toByteArray(), UTF_8));
+    }
+
+    static class JmodResult {
+        final int exitCode;
+        final String output;
+
+        JmodResult(int exitValue, String output) {
+            this.exitCode = exitValue;
+            this.output = output;
+        }
+        JmodResult assertFailure() { assertTrue(exitCode != 0, output); return this; }
+        JmodResult resultChecker(Consumer<JmodResult> r) { r.accept(this); return this; }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jmod/JmodTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,485 @@
+/**
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @modules jdk.jlink/jdk.tools.jmod
+ *          jdk.compiler
+ * @build jdk.testlibrary.FileUtils CompilerUtils
+ * @run testng JmodTest
+ * @summary Basic test for jmod
+ */
+
+import java.io.*;
+import java.lang.module.ModuleDescriptor;
+import java.lang.reflect.Method;
+import java.nio.file.*;
+import java.util.*;
+import java.util.function.Consumer;
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
+import jdk.testlibrary.FileUtils;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+import static java.lang.module.ModuleDescriptor.Version;
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.util.stream.Collectors.toSet;
+import static org.testng.Assert.*;
+
+public class JmodTest {
+
+    static final String TEST_SRC = System.getProperty("test.src", ".");
+    static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    static final Path EXPLODED_DIR = Paths.get("build");
+    static final Path MODS_DIR = Paths.get("jmods");
+
+    static final String CLASSES_PREFIX = "classes/";
+    static final String CMDS_PREFIX = "bin/";
+    static final String LIBS_PREFIX = "native/";
+    static final String CONFIGS_PREFIX = "conf/";
+
+    @BeforeTest
+    public void buildExplodedModules() throws IOException {
+        if (Files.exists(EXPLODED_DIR))
+            FileUtils.deleteFileTreeWithRetry(EXPLODED_DIR);
+
+        for (String name : new String[] { "foo"/*, "bar", "baz"*/ } ) {
+            Path dir = EXPLODED_DIR.resolve(name);
+            assertTrue(compileModule(name, dir.resolve("classes")));
+            createCmds(dir.resolve("bin"));
+            createLibs(dir.resolve("lib"));
+            createConfigs(dir.resolve("conf"));
+        }
+
+        if (Files.exists(MODS_DIR))
+            FileUtils.deleteFileTreeWithRetry(MODS_DIR);
+        Files.createDirectories(MODS_DIR);
+    }
+
+    @Test
+    public void testList() throws IOException {
+        String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString();
+        jmod("create",
+             "--class-path", cp,
+             MODS_DIR.resolve("foo.jmod").toString())
+            .assertSuccess();
+
+        jmod("list",
+             MODS_DIR.resolve("foo.jmod").toString())
+            .assertSuccess()
+            .resultChecker(r -> {
+                // asserts dependent on the exact contents of foo
+                assertContains(r.output, CLASSES_PREFIX + "module-info.class");
+                assertContains(r.output, CLASSES_PREFIX + "jdk/test/foo/Foo.class");
+                assertContains(r.output, CLASSES_PREFIX + "jdk/test/foo/internal/Message.class");
+            });
+    }
+
+    @Test
+    public void testMainClass() throws IOException {
+        Path jmod = MODS_DIR.resolve("fooMainClass.jmod");
+        FileUtils.deleteFileIfExistsWithRetry(jmod);
+        String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString();
+
+        jmod("create",
+             "--class-path", cp,
+             "--main-class", "jdk.test.foo.Foo",
+             jmod.toString())
+            .assertSuccess()
+            .resultChecker(r -> {
+                Optional<String> omc = getModuleDescriptor(jmod).mainClass();
+                assertTrue(omc.isPresent());
+                assertEquals(omc.get(), "jdk.test.foo.Foo");
+            });
+    }
+
+    @Test
+    public void testModuleVersion() throws IOException {
+        Path jmod = MODS_DIR.resolve("fooVersion.jmod");
+        FileUtils.deleteFileIfExistsWithRetry(jmod);
+        String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString();
+
+        jmod("create",
+             "--class-path", cp,
+             "--module-version", "5.4.3",
+             jmod.toString())
+            .assertSuccess()
+            .resultChecker(r -> {
+                Optional<Version> ov = getModuleDescriptor(jmod).version();
+                assertTrue(ov.isPresent());
+                assertEquals(ov.get().toString(), "5.4.3");
+            });
+    }
+
+    @Test
+    public void testConfig() throws IOException {
+        Path jmod = MODS_DIR.resolve("fooConfig.jmod");
+        FileUtils.deleteFileIfExistsWithRetry(jmod);
+        Path cp = EXPLODED_DIR.resolve("foo").resolve("classes");
+        Path cf = EXPLODED_DIR.resolve("foo").resolve("conf");
+
+        jmod("create",
+             "--class-path", cp.toString(),
+             "--config", cf.toString(),
+             jmod.toString())
+            .assertSuccess()
+            .resultChecker(r -> {
+                try (Stream<String> s1 = findFiles(cf).map(p -> CONFIGS_PREFIX + p);
+                     Stream<String> s2 = findFiles(cp).map(p -> CLASSES_PREFIX + p)) {
+                    Set<String> expectedFilenames = Stream.concat(s1, s2)
+                                                          .collect(toSet());
+                    assertJmodContent(jmod, expectedFilenames);
+                }
+            });
+    }
+
+    @Test
+    public void testCmds() throws IOException {
+        Path jmod = MODS_DIR.resolve("fooCmds.jmod");
+        FileUtils.deleteFileIfExistsWithRetry(jmod);
+        Path cp = EXPLODED_DIR.resolve("foo").resolve("classes");
+        Path bp = EXPLODED_DIR.resolve("foo").resolve("bin");
+
+        jmod("create",
+             "--cmds", bp.toString(),
+             "--class-path", cp.toString(),
+             jmod.toString())
+            .assertSuccess()
+            .resultChecker(r -> {
+                try (Stream<String> s1 = findFiles(bp).map(p -> CMDS_PREFIX + p);
+                     Stream<String> s2 = findFiles(cp).map(p -> CLASSES_PREFIX + p)) {
+                    Set<String> expectedFilenames = Stream.concat(s1,s2)
+                                                          .collect(toSet());
+                    assertJmodContent(jmod, expectedFilenames);
+                }
+            });
+    }
+
+    @Test
+    public void testLibs() throws IOException {
+        Path jmod = MODS_DIR.resolve("fooLibs.jmod");
+        FileUtils.deleteFileIfExistsWithRetry(jmod);
+        Path cp = EXPLODED_DIR.resolve("foo").resolve("classes");
+        Path lp = EXPLODED_DIR.resolve("foo").resolve("lib");
+
+        jmod("create",
+             "--libs=", lp.toString(),
+             "--class-path", cp.toString(),
+             jmod.toString())
+            .assertSuccess()
+            .resultChecker(r -> {
+                try (Stream<String> s1 = findFiles(lp).map(p -> LIBS_PREFIX + p);
+                     Stream<String> s2 = findFiles(cp).map(p -> CLASSES_PREFIX + p)) {
+                    Set<String> expectedFilenames = Stream.concat(s1,s2)
+                                                          .collect(toSet());
+                    assertJmodContent(jmod, expectedFilenames);
+                }
+            });
+    }
+
+    @Test
+    public void testAll() throws IOException {
+        Path jmod = MODS_DIR.resolve("fooAll.jmod");
+        FileUtils.deleteFileIfExistsWithRetry(jmod);
+        Path cp = EXPLODED_DIR.resolve("foo").resolve("classes");
+        Path bp = EXPLODED_DIR.resolve("foo").resolve("bin");
+        Path lp = EXPLODED_DIR.resolve("foo").resolve("lib");
+        Path cf = EXPLODED_DIR.resolve("foo").resolve("conf");
+
+        jmod("create",
+             "--conf", cf.toString(),
+             "--cmds=", bp.toString(),
+             "--libs=", lp.toString(),
+             "--class-path", cp.toString(),
+             jmod.toString())
+            .assertSuccess()
+            .resultChecker(r -> {
+                try (Stream<String> s1 = findFiles(lp).map(p -> LIBS_PREFIX + p);
+                     Stream<String> s2 = findFiles(cp).map(p -> CLASSES_PREFIX + p);
+                     Stream<String> s3 = findFiles(bp).map(p -> CMDS_PREFIX + p);
+                     Stream<String> s4 = findFiles(cf).map(p -> CONFIGS_PREFIX + p)) {
+                    Set<String> expectedFilenames = Stream.concat(Stream.concat(s1,s2),
+                                                                  Stream.concat(s3, s4))
+                                                          .collect(toSet());
+                    assertJmodContent(jmod, expectedFilenames);
+                }
+            });
+    }
+
+    @Test
+    public void testExcludes() throws IOException {
+        Path jmod = MODS_DIR.resolve("fooLibs.jmod");
+        FileUtils.deleteFileIfExistsWithRetry(jmod);
+        Path cp = EXPLODED_DIR.resolve("foo").resolve("classes");
+        Path lp = EXPLODED_DIR.resolve("foo").resolve("lib");
+
+        jmod("create",
+             "--libs=", lp.toString(),
+             "--class-path", cp.toString(),
+             "--exclude", "**internal**",
+             "--exclude", "first.so",
+             jmod.toString())
+             .assertSuccess()
+             .resultChecker(r -> {
+                 Set<String> expectedFilenames = new HashSet<>();
+                 expectedFilenames.add(CLASSES_PREFIX + "module-info.class");
+                 expectedFilenames.add(CLASSES_PREFIX + "jdk/test/foo/Foo.class");
+                 expectedFilenames.add(LIBS_PREFIX + "second.so");
+                 expectedFilenames.add(LIBS_PREFIX + "third/third.so");
+                 assertJmodContent(jmod, expectedFilenames);
+
+                 Set<String> unexpectedFilenames = new HashSet<>();
+                 unexpectedFilenames.add(CLASSES_PREFIX + "jdk/test/foo/internal/Message.class");
+                 unexpectedFilenames.add(LIBS_PREFIX + "first.so");
+                 assertJmodDoesNotContain(jmod, unexpectedFilenames);
+             });
+    }
+
+    @Test
+    public void describe() throws IOException {
+        String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString();
+        jmod("create",
+             "--class-path", cp,
+              MODS_DIR.resolve("describeFoo.jmod").toString())
+             .assertSuccess();
+
+        jmod("describe",
+             MODS_DIR.resolve("describeFoo.jmod").toString())
+             .assertSuccess()
+             .resultChecker(r -> {
+                 // Expect similar output: "foo,  requires mandated java.base
+                 // exports jdk.test.foo,  conceals jdk.test.foo.internal"
+                 Pattern p = Pattern.compile("\\s+foo\\s+requires\\s+mandated\\s+java.base");
+                 assertTrue(p.matcher(r.output).find(),
+                           "Expecting to find \"foo, requires java.base\"" +
+                                "in output, but did not: [" + r.output + "]");
+                 p = Pattern.compile(
+                        "exports\\s+jdk.test.foo\\s+conceals\\s+jdk.test.foo.internal");
+                 assertTrue(p.matcher(r.output).find(),
+                           "Expecting to find \"exports ..., conceals ...\"" +
+                                "in output, but did not: [" + r.output + "]");
+             });
+    }
+
+    @Test
+    public void testVersion() {
+        jmod("--version")
+            .assertSuccess()
+            .resultChecker(r -> {
+                assertContains(r.output, System.getProperty("java.version"));
+            });
+    }
+
+    @Test
+    public void testHelp() {
+        jmod("--help")
+            .assertSuccess()
+            .resultChecker(r ->
+                assertTrue(r.output.startsWith("Usage: jmod"), "Help not printed")
+            );
+    }
+
+    @Test
+    public void testTmpFileAlreadyExists() throws IOException {
+        // Implementation detail: jmod tool creates <jmod-file>.tmp
+        // Ensure that there are no problems if existing
+
+        Path jmod = MODS_DIR.resolve("testTmpFileAlreadyExists.jmod");
+        Path tmp = MODS_DIR.resolve("testTmpFileAlreadyExists.jmod.tmp");
+        FileUtils.deleteFileIfExistsWithRetry(jmod);
+        FileUtils.deleteFileIfExistsWithRetry(tmp);
+        Files.createFile(tmp);
+        String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString();
+
+        jmod("create",
+             "--class-path", cp,
+             jmod.toString())
+            .assertSuccess()
+            .resultChecker(r ->
+                assertTrue(Files.notExists(tmp), "Unexpected tmp file:" + tmp)
+            );
+    }
+
+    @Test
+    public void testTmpFileRemoved() throws IOException {
+        // Implementation detail: jmod tool creates <jmod-file>.tmp
+        // Ensure that it is removed in the event of a failure.
+        // The failure in this case is a class in the unnamed package.
+
+        Path jmod = MODS_DIR.resolve("testTmpFileRemoved.jmod");
+        Path tmp = MODS_DIR.resolve("testTmpFileRemoved.jmod.tmp");
+        FileUtils.deleteFileIfExistsWithRetry(jmod);
+        FileUtils.deleteFileIfExistsWithRetry(tmp);
+        String cp = EXPLODED_DIR.resolve("foo").resolve("classes") + File.pathSeparator +
+                    EXPLODED_DIR.resolve("foo").resolve("classes")
+                                .resolve("jdk").resolve("test").resolve("foo").toString();
+
+        jmod("create",
+             "--class-path", cp,
+             jmod.toString())
+             .assertFailure()
+             .resultChecker(r -> {
+                 assertContains(r.output, "unnamed package");
+                 assertTrue(Files.notExists(tmp), "Unexpected tmp file:" + tmp);
+             });
+    }
+
+    // ---
+
+    static boolean compileModule(String name, Path dest) throws IOException {
+        return CompilerUtils.compile(SRC_DIR.resolve(name), dest);
+    }
+
+    static void assertContains(String output, String subString) {
+        if (output.contains(subString))
+            assertTrue(true);
+        else
+            assertTrue(false,"Expected to find [" + subString + "], in output ["
+                           + output + "]" + "\n");
+    }
+
+    static ModuleDescriptor getModuleDescriptor(Path jmod) {
+        ClassLoader cl = ClassLoader.getSystemClassLoader();
+        try (FileSystem fs = FileSystems.newFileSystem(jmod, cl)) {
+            String p = "/classes/module-info.class";
+            try (InputStream is = Files.newInputStream(fs.getPath(p))) {
+                return ModuleDescriptor.read(is);
+            }
+        } catch (IOException ioe) {
+            throw new UncheckedIOException(ioe);
+        }
+    }
+
+    static Stream<String> findFiles(Path dir) {
+        try {
+            return Files.find(dir, Integer.MAX_VALUE, (p, a) -> a.isRegularFile())
+                        .map(dir::relativize)
+                        .map(Path::toString)
+                        .map(p -> p.replace(File.separator, "/"));
+        } catch (IOException x) {
+            throw new UncheckedIOException(x);
+        }
+    }
+
+    static Set<String> getJmodContent(Path jmod) {
+        JmodResult r = jmod("list", jmod.toString()).assertSuccess();
+        return Stream.of(r.output.split("\r?\n")).collect(toSet());
+    }
+
+    static void assertJmodContent(Path jmod, Set<String> expected) {
+        Set<String> actual = getJmodContent(jmod);
+        if (!Objects.equals(actual, expected)) {
+            Set<String> unexpected = new HashSet<>(actual);
+            unexpected.removeAll(expected);
+            Set<String> notFound = new HashSet<>(expected);
+            notFound.removeAll(actual);
+            StringBuilder sb = new StringBuilder();
+            sb.append("Unexpected but found:\n");
+            unexpected.forEach(s -> sb.append("\t" + s + "\n"));
+            sb.append("Expected but not found:\n");
+            notFound.forEach(s -> sb.append("\t" + s + "\n"));
+            assertTrue(false, "Jmod content check failed.\n" + sb.toString());
+        }
+    }
+
+    static void assertJmodDoesNotContain(Path jmod, Set<String> unexpectedNames) {
+        Set<String> actual = getJmodContent(jmod);
+        Set<String> unexpected = new HashSet<>();
+        for (String name : unexpectedNames) {
+            if (actual.contains(name))
+                unexpected.add(name);
+        }
+        if (!unexpected.isEmpty()) {
+            StringBuilder sb = new StringBuilder();
+            for (String s : unexpected)
+                sb.append("Unexpected but found: " + s + "\n");
+            sb.append("In :");
+            for (String s : actual)
+                sb.append("\t" + s + "\n");
+            assertTrue(false, "Jmod content check failed.\n" + sb.toString());
+        }
+    }
+
+    static JmodResult jmod(String... args) {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        PrintStream ps = new PrintStream(baos);
+        System.out.println("jmod " + Arrays.asList(args));
+        int ec = jdk.tools.jmod.Main.run(args, ps);
+        return new JmodResult(ec, new String(baos.toByteArray(), UTF_8));
+    }
+
+    static class JmodResult {
+        final int exitCode;
+        final String output;
+
+        JmodResult(int exitValue, String output) {
+            this.exitCode = exitValue;
+            this.output = output;
+        }
+        JmodResult assertSuccess() { assertTrue(exitCode == 0, output); return this; }
+        JmodResult assertFailure() { assertTrue(exitCode != 0, output); return this; }
+        JmodResult resultChecker(Consumer<JmodResult> r) { r.accept(this); return this; }
+    }
+
+    static void createCmds(Path dir) throws IOException {
+        List<String> files = Arrays.asList(
+                "first", "second", "third" + File.separator + "third");
+        createFiles(dir, files);
+    }
+
+    static void createLibs(Path dir) throws IOException {
+        List<String> files = Arrays.asList(
+                "first.so", "second.so", "third" + File.separator + "third.so");
+        createFiles(dir, files);
+    }
+
+    static void createConfigs(Path dir) throws IOException {
+        List<String> files = Arrays.asList(
+                "first.cfg", "second.cfg", "third" + File.separator + "third.cfg");
+        createFiles(dir, files);
+    }
+
+    static void createFiles(Path dir, List<String> filenames) throws IOException {
+        for (String name : filenames) {
+            Path file = dir.resolve(name);
+            Files.createDirectories(file.getParent());
+            Files.createFile(file);
+            try (OutputStream os  = Files.newOutputStream(file)) {
+                os.write("blahblahblah".getBytes(UTF_8));
+            }
+        }
+    }
+
+    // Standalone entry point.
+    public static void main(String[] args) throws Throwable {
+        JmodTest test = new JmodTest();
+        test.buildExplodedModules();
+        for (Method m : JmodTest.class.getDeclaredMethods()) {
+            if (m.getAnnotation(Test.class) != null) {
+                System.out.println("Invoking " + m.getName());
+                m.invoke(test);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jmod/src/foo/jdk/test/foo/Foo.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.foo;
+
+public class Foo { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jmod/src/foo/jdk/test/foo/internal/Message.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.foo.internal;
+
+public class Message  {
+    public static String get() {
+        return "Hello World!!!";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jmod/src/foo/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module foo {
+    exports jdk.test.foo;
+}
--- a/test/tools/launcher/MiscTests.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/tools/launcher/MiscTests.java	Thu Mar 17 19:04:16 2016 +0000
@@ -31,29 +31,71 @@
 
 
 import java.io.File;
-import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
 
 public class MiscTests extends TestHelper {
 
-    // 6856415: Checks to ensure that proper exceptions are thrown by java
-    static void test6856415() {
-        StringBuilder sb = new StringBuilder();
-        sb.append("public static void main(String... args) {\n");
-        sb.append("java.security.Provider p = new sun.security.pkcs11.SunPKCS11();\n");
-        sb.append("java.security.Security.insertProviderAt(p, 1);\n");
-        sb.append("}");
+    /**
+     * Test with class path set on the command line via -Djava.class.path
+     */
+    static void testWithClassPathSetViaProperty() throws IOException {
+        final String mainClass = "Foo";
+
+        File source = new File(mainClass + ".java");
+
+        List<String> scratch = new ArrayList<>();
+        scratch.add("public class Foo {");
+        scratch.add("public static void main(String... args) {");
+        scratch.add("}");
+        scratch.add("}");
+        createFile(source, scratch);
+
+        compile(mainClass + ".java");
+
+        String dir = new File(mainClass + ".class").getAbsoluteFile().getParent();
+        TestResult tr = doExec(javaCmd, "-Djava.class.path=" + dir, mainClass);
+        for (String s : tr.testOutput) {
+            System.out.println(s);
+        }
+    }
+
+    /**
+     * 6856415: Checks to ensure that proper exceptions are thrown by java
+     */
+    static void test6856415() throws IOException {
+
+        final String mainClass = "Foo6856415";
+        final String exportOpts
+            = "-XaddExports:jdk.crypto.pkcs11/sun.security.pkcs11=ALL-UNNAMED";
+
+        List<String> scratch = new ArrayList<>();
+        scratch.add("public class Foo6856415 {");
+        scratch.add("public static void main(String... args) {");
+        scratch.add("java.security.Provider p = new sun.security.pkcs11.SunPKCS11();");
+        scratch.add("java.security.Security.insertProviderAt(p, 1);");
+        scratch.add("}");
+        scratch.add("}");
+        createFile(new File(mainClass + ".java"), scratch);
+
+        compile(mainClass + ".java", exportOpts);
+
         File testJar = new File("Foo.jar");
         testJar.delete();
-        try {
-            createJar(testJar, sb.toString());
-        } catch (FileNotFoundException fnfe) {
-            throw new RuntimeException(fnfe);
-        }
+        String jarArgs[] = {
+            (debug) ? "cvfe" : "cfe",
+            testJar.getAbsolutePath(),
+            mainClass,
+            mainClass + ".class"
+        };
+        createJar(jarArgs);
+
         TestResult tr = doExec(javaCmd,
                 "-Djava.security.manager", "-jar", testJar.getName(), "foo.bak");
         for (String s : tr.testOutput) {
             System.out.println(s);
-    }
+        }
         if (!tr.contains("java.security.AccessControlException:" +
                 " access denied (\"java.lang.RuntimePermission\"" +
                 " \"accessClassInPackage.sun.security.pkcs11\")")) {
@@ -61,7 +103,8 @@
         }
     }
 
-    public static void main(String... args) {
+    public static void main(String... args) throws IOException {
+        testWithClassPathSetViaProperty();
         test6856415();
         if (testExitValue != 0) {
             throw new Error(testExitValue + " tests failed");
--- a/test/tools/launcher/ToolsOpts.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/tools/launcher/ToolsOpts.java	Thu Mar 17 19:04:16 2016 +0000
@@ -38,8 +38,6 @@
 import java.util.List;
 
 public class ToolsOpts extends TestHelper {
-    static final String JBCP_PREPEND = "-J-Xbootclasspath/p:";
-    private static File testJar = null;
     static String[][] optionPatterns = {
         {"-J-Xmx128m"},
         {"-J-version"},
@@ -75,14 +73,10 @@
         {"option1", "-J-version", "-J-XshowSettings:vm", "option2"},};
 
     static void init() throws IOException {
-        if (testJar != null) {
-            return;
-        }
 
         // A tool which simulates com.sun.tools.javac.Main argument processing,
         // intercepts options passed via the javac launcher.
         final String mainJava = "Main" + JAVA_FILE_EXT;
-        testJar = new File("test" + JAR_FILE_EXT);
         List<String> contents = new ArrayList<>();
         contents.add("package com.sun.tools.javac;");
         contents.add("public class Main {");
@@ -95,10 +89,10 @@
         contents.add("}\n");
         createFile(new File(mainJava), contents);
 
-        // compile and jar Main.java into test.jar
-        compile("-d", ".", mainJava);
-            createJar("cvf", testJar.getAbsolutePath(), "com");
-        }
+        // compile Main.java into directory to override classes in jdk.compiler
+        new File("jdk.compiler").mkdir();
+        compile("-Xmodule:jdk.compiler", "-d", "jdk.compiler", mainJava);
+    }
 
     static void pass(String msg) {
         System.out.println("pass: " + msg);
@@ -156,30 +150,29 @@
     static void runTestOptions() throws IOException {
         init();
         TestResult tr = null;
-        String sTestJar = testJar.getAbsolutePath();
         int jpos = -1;
         for (String arg[] : optionPatterns) {
             jpos = indexOfJoption(arg);
             //Build a cmd string for output in results reporting.
-            String cmdString = javacCmd + " " + JBCP_PREPEND + sTestJar;
+            String cmdString = javacCmd + " -J-Xpatch:.";
             for (String opt : arg) {
                 cmdString = cmdString.concat(" " + opt);
             }
             switch (arg.length) {
                 case 1:
-                    tr = doExec(javacCmd, JBCP_PREPEND + sTestJar,
+                    tr = doExec(javacCmd, "-J-Xpatch:.",
                             arg[0]);
                     break;
                 case 2:
-                    tr = doExec(javacCmd, JBCP_PREPEND + sTestJar,
+                    tr = doExec(javacCmd, "-J-Xpatch:.",
                             arg[0], arg[1]);
                     break;
                 case 3:
-                    tr = doExec(javacCmd, JBCP_PREPEND + sTestJar,
+                    tr = doExec(javacCmd, "-J-Xpatch:.",
                             arg[0], arg[1], arg[2]);
                     break;
                 case 4:
-                    tr = doExec(javacCmd, JBCP_PREPEND + sTestJar,
+                    tr = doExec(javacCmd, "-J-Xpatch:.",
                             arg[0], arg[1], arg[2], arg[3]);
                     break;
                 default:
--- a/test/tools/launcher/VersionCheck.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/tools/launcher/VersionCheck.java	Thu Mar 17 19:04:16 2016 +0000
@@ -85,7 +85,9 @@
         "jdeps",
         "jimage",
         "jinfo",
+        "jlink",
         "jmap",
+        "jmod",
         "jmc",
         "jmc.ini",
         "jps",
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/addexports/AddExportsTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @library /lib/testlibrary
+ * @modules jdk.compiler
+ * @build AddExportsTest CompilerUtils jdk.testlibrary.*
+ * @run testng AddExportsTest
+ * @summary Basic tests for java -XaddExports
+ */
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import static jdk.testlibrary.ProcessTools.*;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+
+@Test
+public class AddExportsTest {
+
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path MODS_DIR = Paths.get("mods");
+    private static final Path UPGRADE_MODS_DIRS = Paths.get("upgrademods");
+
+    // test module m1 that uses Unsafe
+    private static final String TEST1_MODULE = "m1";
+    private static final String TEST1_MAIN_CLASS = "jdk.test1.Main";
+
+    // test module m2 uses java.transaction internals
+    private static final String TEST2_MODULE = "m2";
+    private static final String TEST2_MAIN_CLASS = "jdk.test2.Main";
+
+    // test module m3 uses m4 internals
+    private static final String TEST3_MODULE = "m3";
+    private static final String TEST3_MAIN_CLASS = "jdk.test3.Main";
+    private static final String TEST4_MODULE = "m4";
+
+
+    @BeforeTest
+    public void compileTestModules() throws Exception {
+
+        // javac -d mods/m1 src/m1/**
+        boolean compiled = CompilerUtils.compile(
+                SRC_DIR.resolve(TEST1_MODULE),
+                MODS_DIR.resolve(TEST1_MODULE),
+                "-XaddExports:java.base/sun.misc=m1");
+        assertTrue(compiled, "module " + TEST1_MODULE + " did not compile");
+
+        // javac -d upgrademods/java.transaction src/java.transaction/**
+        compiled = CompilerUtils.compile(
+                SRC_DIR.resolve("java.transaction"),
+                UPGRADE_MODS_DIRS.resolve("java.transaction"));
+        assertTrue(compiled, "module java.transaction did not compile");
+
+        // javac -upgrademodulepath upgrademods -d mods/m2 src/m2/**
+        compiled = CompilerUtils.compile(
+                SRC_DIR.resolve(TEST2_MODULE),
+                MODS_DIR.resolve(TEST2_MODULE),
+                "-upgrademodulepath", UPGRADE_MODS_DIRS.toString(),
+                "-XaddExports:java.transaction/javax.transaction.internal=m2");
+        assertTrue(compiled, "module " + TEST2_MODULE + " did not compile");
+
+        // javac -d mods/m3 src/m3/**
+        compiled = CompilerUtils.compile(
+                SRC_DIR.resolve(TEST3_MODULE),
+                MODS_DIR.resolve(TEST3_MODULE));
+        assertTrue(compiled, "module " + TEST3_MODULE + " did not compile");
+
+        // javac -d mods/m4 src/m4/**
+        compiled = CompilerUtils.compile(
+                SRC_DIR.resolve(TEST4_MODULE),
+                MODS_DIR.resolve(TEST4_MODULE));
+        assertTrue(compiled, "module " + TEST4_MODULE + " did not compile");
+    }
+
+    /**
+     * Sanity check with -version
+     */
+    public void testSanity() throws Exception {
+
+        int exitValue
+            =  executeTestJava("-XaddExports:java.base/sun.reflect=ALL-UNNAMED",
+                               "-version")
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
+
+        assertTrue(exitValue == 0);
+    }
+
+
+    /**
+     * Run class path application that uses sun.misc.Unsafe
+     */
+    public void testUnnamedModule() throws Exception {
+
+        // java -XaddExports:java.base/sun.misc=ALL-UNNAMED \
+        //      -cp mods/$TESTMODULE jdk.test.UsesUnsafe
+
+        String classpath = MODS_DIR.resolve(TEST1_MODULE).toString();
+        int exitValue
+            = executeTestJava("-XaddExports:java.base/sun.misc=ALL-UNNAMED",
+                              "-cp", classpath,
+                              TEST1_MAIN_CLASS)
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
+
+        assertTrue(exitValue == 0);
+    }
+
+
+    /**
+     * Run named module that uses sun.misc.Unsafe
+     */
+    public void testNamedModule() throws Exception {
+
+        //  java -XaddExports:java.base/sun.misc=test \
+        //       -mp mods -m $TESTMODULE/$MAIN_CLASS
+
+        String mid = TEST1_MODULE + "/" + TEST1_MAIN_CLASS;
+        int exitValue =
+            executeTestJava("-XaddExports:java.base/sun.misc=" + TEST1_MODULE,
+                            "-mp", MODS_DIR.toString(),
+                            "-m", mid)
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
+
+        assertTrue(exitValue == 0);
+    }
+
+
+    /**
+     * Test -XaddExports with upgraded module
+     */
+    public void testWithUpgradedModule() throws Exception {
+
+        // java -XaddExports:java.transaction/javax.transaction.internal=m2
+        //      -upgrademodulepath upgrademods -mp mods -m ...
+        String mid = TEST2_MODULE + "/" + TEST2_MAIN_CLASS;
+        int exitValue = executeTestJava(
+                "-XaddExports:java.transaction/javax.transaction.internal=m2",
+                "-upgrademodulepath", UPGRADE_MODS_DIRS.toString(),
+                "-mp", MODS_DIR.toString(),
+                "-m", mid)
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
+
+        assertTrue(exitValue == 0);
+    }
+
+
+    /**
+     * Test -XaddExports with module that is added to the set of root modules
+     * with -addmods.
+     */
+    public void testWithAddMods() throws Exception {
+
+        // java -XaddExports:m4/jdk.test4=m3 -mp mods -m ...
+        String mid = TEST3_MODULE + "/" + TEST3_MAIN_CLASS;
+        int exitValue = executeTestJava(
+                "-XaddExports:m4/jdk.test4=m3",
+                "-mp", MODS_DIR.toString(),
+                "-addmods", TEST4_MODULE,
+                "-m", mid)
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
+
+        assertTrue(exitValue == 0);
+    }
+
+
+    /**
+     * -XaddExports can only be specified once
+     */
+    public void testWithDuplicateOption() throws Exception {
+
+        int exitValue
+            =  executeTestJava("-XaddExports:java.base/sun.reflect=ALL-UNNAMED",
+                               "-XaddExports:java.base/sun.reflect=ALL-UNNAMED",
+                               "-version")
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .shouldContain("specified more than once")
+                .getExitValue();
+
+        assertTrue(exitValue != 0);
+    }
+
+
+    /**
+     * Exercise -XaddExports with bad values
+     */
+    @Test(dataProvider = "badvalues")
+    public void testWithBadValue(String value, String ignore) throws Exception {
+
+        //  -XaddExports:$VALUE -version
+        int exitValue =
+            executeTestJava("-XaddExports:" + value,
+                            "-version")
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
+
+        assertTrue(exitValue != 0);
+    }
+
+    @DataProvider(name = "badvalues")
+    public Object[][] badValues() {
+        return new Object[][]{
+
+            { "java.base/sun.misc",                  null }, // missing target
+            { "java.base/sun.misc=sun.monkey",       null }, // unknown target
+            { "java.monkey/sun.monkey=ALL-UNNAMED",  null }, // unknown module
+            { "java.base/sun.monkey=ALL-UNNAMED",    null }, // unknown package
+            { "java.monkey/sun.monkey=ALL-UNNAMED",  null }, // unknown module/package
+            { "java.base=ALL-UNNAMED",               null }, // missing package
+            { "java.base/=ALL-UNNAMED",              null }  // missing package
+
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/addexports/src/java.transaction/javax/transaction/Transaction.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.transaction;
+
+public class Transaction {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/addexports/src/java.transaction/javax/transaction/internal/Helper.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.transaction.internal;
+
+public class Helper {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/addexports/src/java.transaction/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module java.transaction {
+    exports javax.transaction;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/addexports/src/m1/jdk/test1/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,35 @@
+/**
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test1;
+
+import java.lang.reflect.Field;
+import sun.misc.Unsafe;
+
+public class Main {
+    public static void main(String[] args) throws Exception {
+        Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
+        theUnsafe.setAccessible(true);
+        Unsafe unsafe = (Unsafe) theUnsafe.get(null);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/addexports/src/m1/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m1 {
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/addexports/src/m2/jdk/test2/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test2;
+
+import javax.transaction.internal.Helper;
+
+public class Main {
+    public static void main(String[] args) {
+        Helper h = new Helper();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/addexports/src/m2/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m2 {
+    requires java.transaction;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/addexports/src/m3/jdk/test3/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test3;
+
+public class Main {
+    public static void main(String[] args) throws Exception {
+        Class<?> c = Class.forName("jdk.test4.Type");
+        Main.class.getModule().addReads(c.getModule());
+        Object o = c.newInstance();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/addexports/src/m3/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m3 {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/addexports/src/m4/jdk/test4/Type.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test4;
+
+public class Type {
+    public Type() { }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/addexports/src/m4/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m4 {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/addmods/AddModsTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @library /lib/testlibrary
+ * @modules jdk.jlink/jdk.tools.jmod
+ *          jdk.compiler
+ * @build AddModsTest CompilerUtils jdk.testlibrary.*
+ * @run testng AddModsTest
+ * @summary Basic test for java -addmods
+ */
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import static jdk.testlibrary.ProcessTools.*;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+
+@Test
+public class AddModsTest {
+
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path MODS_DIR = Paths.get("mods");
+
+    // the module name of the library module
+    private static final String LIB_MODULE = "lib";
+
+    // application source directory
+    private static final String APP_SRC = "app";
+
+    // application is compiled to classes
+    private static final Path CLASSES_DIR = Paths.get("classes");
+
+    // application main class
+    private static final String MAIN_CLASS = "app.Main";
+
+
+    @BeforeTest
+    public void compile() throws Exception {
+
+        // javac -d mods/$LIB_MODULE src/$LIB_MODULE/**
+        boolean compiled = CompilerUtils.compile(
+            SRC_DIR.resolve(LIB_MODULE),
+            MODS_DIR.resolve(LIB_MODULE)
+        );
+        assertTrue(compiled, "library module did not compile");
+
+        // javac -d classes -mp mods src/$APP_DIR/**
+        compiled = CompilerUtils.compile(
+            SRC_DIR.resolve(APP_SRC),
+            CLASSES_DIR,
+            "-mp", MODS_DIR.toString(),
+            "-addmods", LIB_MODULE
+        );
+        assertTrue(compiled, "app did not compile");
+    }
+
+
+    /**
+     * Basic test of -addmods ALL-SYSTEM, using the output of -listmods to
+     * check that the a sample of the system modules are resolved.
+     */
+    public void testAddSystemModules() throws Exception {
+
+        executeTestJava("-addmods", "ALL-SYSTEM",
+                        "-listmods",
+                        "-m", "java.base")
+            .outputTo(System.out)
+            .errorTo(System.out)
+            .shouldContain("java.sql")
+            .shouldContain("java.corba");
+
+        // no exit value to check as -m java.base will likely fail
+    }
+
+
+    /**
+     * Run application on class path that makes use of module on the
+     * application module path. Uses {@code -addmods lib}
+     */
+    public void testRunWithAddMods() throws Exception {
+
+        // java -mp mods -addmods lib -cp classes app.Main
+        int exitValue
+            = executeTestJava("-mp", MODS_DIR.toString(),
+                              "-addmods", LIB_MODULE,
+                              "-cp", CLASSES_DIR.toString(),
+                              MAIN_CLASS)
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
+
+        assertTrue(exitValue == 0);
+
+    }
+
+    /**
+     * Run application on class path that makes use of module on the
+     * application module path. Uses {@code -addmods ALL-MODULE-PATH}.
+     */
+    public void testAddAllModulePath() throws Exception {
+
+        // java -mp mods -addmods lib -cp classes app.Main
+        int exitValue
+            = executeTestJava("-mp", MODS_DIR.toString(),
+                              "-addmods", "ALL-MODULE-PATH",
+                              "-cp", CLASSES_DIR.toString(),
+                              MAIN_CLASS)
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
+
+        assertTrue(exitValue == 0);
+
+    }
+
+
+    /**
+     * Run application on class path that makes use of module on the
+     * application module path. Does not use -addmods and so will
+     * fail at run-time.
+     */
+    public void testRunMissingAddMods() throws Exception {
+
+        // java -mp mods -cp classes app.Main
+        int exitValue
+            = executeTestJava("-mp", MODS_DIR.toString(),
+                              "-cp", CLASSES_DIR.toString(),
+                              MAIN_CLASS)
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
+
+        // CNFE or other error/exception
+        assertTrue(exitValue != 0);
+
+    }
+
+
+    /**
+     * Attempt to run with a bad module name specified to -addmods
+     */
+    public void testRunWithBadAddMods() throws Exception {
+
+        // java -mp mods -addmods,DoesNotExist lib -cp classes app.Main
+        int exitValue
+            = executeTestJava("-mp", MODS_DIR.toString(),
+                              "-addmods", LIB_MODULE + ",DoesNotExist",
+                              "-cp", CLASSES_DIR.toString(),
+                              MAIN_CLASS)
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
+
+        assertTrue(exitValue != 0);
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/addmods/src/app/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package app;
+
+import jdk.lib.Util;
+
+public class Main {
+    public static void main(String[] args) {
+        Object obj = Util.makeObject();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/addmods/src/lib/jdk/lib/Util.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.lib;
+
+public class Util {
+    private Util() { }
+
+    public static Object makeObject() {
+        return new Object();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/addmods/src/lib/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module lib {
+    exports jdk.lib;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/addreads/AddReadsTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @library /lib/testlibrary
+ * @modules jdk.compiler
+ * @build AddReadsTest CompilerUtils jdk.testlibrary.*
+ * @run testng AddReadsTest
+ * @summary Basic tests for java -XaddReads
+ */
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import jdk.testlibrary.OutputAnalyzer;
+import static jdk.testlibrary.ProcessTools.*;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/**
+ * The tests consists of two modules: m1 and junit.
+ * Code in module m1 calls into code in module junit but the module-info.java
+ * does not have a 'requires'. Instead a read edge is added via the command
+ * line option -XaddReads.
+ */
+
+@Test
+public class AddReadsTest {
+
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path CLASSES_DIR = Paths.get("classes");
+    private static final Path MODS_DIR = Paths.get("mods");
+
+    private static final String MAIN = "m1/p.Main";
+
+
+    @BeforeTest
+    public void setup() throws Exception {
+
+        // javac -d classes src/junit/**
+        assertTrue(CompilerUtils
+            .compile(SRC_DIR.resolve("junit"), CLASSES_DIR));
+
+        // javac -d mods/m1 -cp classes/ src/m1/**
+        assertTrue(CompilerUtils
+            .compile(SRC_DIR.resolve("m1"),
+                    MODS_DIR.resolve("m1"),
+                    "-cp", CLASSES_DIR.toString(),
+                    "-XaddReads:m1=ALL-UNNAMED"));
+
+        // jar cf mods/junit.jar -C classes .
+        JarUtils.createJarFile(MODS_DIR.resolve("junit.jar"), CLASSES_DIR);
+
+    }
+
+    private OutputAnalyzer run(String... options) throws Exception {
+        return executeTestJava(options)
+            .outputTo(System.out)
+            .errorTo(System.out);
+    }
+
+
+    /**
+     * Run with junit as a module on the module path.
+     */
+    public void testJUnitOnModulePath() throws Exception {
+
+        // java -mp mods -addmods junit -XaddReads:m1=junit -m ..
+        int exitValue
+            = run("-mp", MODS_DIR.toString(),
+                  "-addmods", "junit",
+                  "-XaddReads:m1=junit",
+                  "-m", MAIN)
+                .getExitValue();
+
+        assertTrue(exitValue == 0);
+    }
+
+
+    /**
+     * Exercise -XaddReads:m1=ALL-UNNAMED by running with junit on the
+     * class path.
+     */
+    public void testJUnitOnClassPath() throws Exception {
+
+        // java -mp mods -cp mods/junit.jar -XaddReads:m1=ALL-UNNAMED -m ..
+        String cp = MODS_DIR.resolve("junit.jar").toString();
+        int exitValue
+            = run("-mp", MODS_DIR.toString(),
+                  "-cp", cp,
+                  "-XaddReads:m1=ALL-UNNAMED",
+                  "-m", MAIN)
+                .getExitValue();
+
+        assertTrue(exitValue == 0);
+    }
+
+
+    /**
+     * Run with junit as a module on the module path but without -XaddReads.
+     */
+    public void testJUnitOnModulePathMissingAddReads() throws Exception {
+        // java -mp mods -addmods junit -m ..
+        int exitValue
+            = run("-mp", MODS_DIR.toString(),
+                  "-addmods", "junit",
+                  "-m", MAIN)
+                .shouldContain("IllegalAccessError")
+                .getExitValue();
+
+        assertTrue(exitValue != 0);
+    }
+
+
+    /**
+     * Run with junit on the class path but without -XaddReads.
+     */
+    public void testJUnitOnClassPathMissingAddReads() throws Exception {
+        // java -mp mods -cp mods/junit.jar -m ..
+        String cp = MODS_DIR.resolve("junit.jar").toString();
+        int exitValue
+            = run("-mp", MODS_DIR.toString(),
+                  "-cp", cp,
+                  "-m", MAIN)
+                .shouldContain("IllegalAccessError")
+                .getExitValue();
+
+        assertTrue(exitValue != 0);
+    }
+
+
+    /**
+     * Exercise -XaddReads with a more than one source module.
+     */
+    public void testJUnitWithMultiValueOption() throws Exception {
+
+        int exitValue
+            = run("-mp", MODS_DIR.toString(),
+                  "-addmods", "java.xml,junit",
+                  "-XaddReads:m1=java.xml,junit",
+                  "-m", MAIN)
+                .getExitValue();
+
+        assertTrue(exitValue == 0);
+    }
+
+
+    /**
+     * Exercise -XaddReads where the target module is specified more than once
+     */
+    public void testWithTargetSpecifiedManyTimes() throws Exception {
+
+        int exitValue
+            = run("-mp", MODS_DIR.toString(),
+                "-addmods", "java.xml,junit",
+                "-XaddReads:m1=java.xml",
+                "-XaddReads:m1=junit",
+                "-m", MAIN)
+                .shouldContain("specified more than once")
+                .getExitValue();
+
+        assertTrue(exitValue != 0);
+    }
+
+
+    /**
+     * Exercise -XaddReads with bad values
+     */
+    @Test(dataProvider = "badvalues")
+    public void testWithBadValue(String value, String ignore) throws Exception {
+
+        //  -XaddExports:$VALUE -version
+        assertTrue(run("-XaddReads:" + value, "-version").getExitValue() != 0);
+    }
+
+    @DataProvider(name = "badvalues")
+    public Object[][] badValues() {
+        return new Object[][]{
+
+            { "java.base",                  null }, // missing source
+            { "java.monkey=java.base",      null }, // unknown module
+            { "java.base=sun.monkey",       null }, // unknown source
+
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/addreads/src/junit/org/junit/Assert.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.junit;
+
+public class Assert {
+    public static void assertEquals(Object o1, Object o2) {
+        if (!o1.equals(o2)) throw new RuntimeException();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/addreads/src/m1/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m1 { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/addreads/src/m1/p/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p;
+
+import static org.junit.Assert.assertEquals;
+
+public class Main {
+    public static void main(String[] args) {
+        Object o = new Object();
+        assertEquals(o, o);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/basic/BasicTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @library /lib/testlibrary
+ * @modules jdk.jartool/sun.tools.jar
+ *          jdk.jlink/jdk.tools.jmod
+ *          jdk.compiler
+ * @build BasicTest CompilerUtils jdk.testlibrary.*
+ * @run testng BasicTest
+ * @summary Basic test of starting an application as a module
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import static jdk.testlibrary.ProcessTools.*;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+
+@Test
+public class BasicTest {
+
+    private static final Path USER_DIR = Paths.get(System.getProperty("user.dir"));
+
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path MODS_DIR = Paths.get("mods");
+
+    // the module name of the test module
+    private static final String TEST_MODULE = "test";
+
+    // the module main class
+    private static final String MAIN_CLASS = "jdk.test.Main";
+
+
+    @BeforeTest
+    public void compileTestModule() throws Exception {
+
+        // javac -d mods/$TESTMODULE src/$TESTMODULE/**
+        boolean compiled
+            = CompilerUtils.compile(SRC_DIR.resolve(TEST_MODULE),
+                                    MODS_DIR.resolve(TEST_MODULE));
+
+        assertTrue(compiled, "test module did not compile");
+    }
+
+
+    /**
+     * The initial module is loaded from an exploded module
+     */
+    public void testRunWithExplodedModule() throws Exception {
+        String dir = MODS_DIR.toString();
+        String subdir = MODS_DIR.resolve(TEST_MODULE).toString();
+        String mid = TEST_MODULE + "/" + MAIN_CLASS;
+
+        // java -mp mods -m $TESTMODULE/$MAINCLASS
+        int exitValue
+            = executeTestJava("-mp", dir, "-m", mid)
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
+        assertTrue(exitValue == 0);
+
+        // java -mp mods/$TESTMODULE -m $TESTMODULE/$MAINCLASS
+        exitValue
+            = executeTestJava("-mp", subdir, "-m", mid)
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
+        assertTrue(exitValue == 0);
+    }
+
+
+    /**
+     * The initial module is loaded from a modular JAR file
+     */
+    public void testRunWithModularJar() throws Exception {
+        Path dir = Files.createTempDirectory(USER_DIR, "mlib");
+        Path jar = dir.resolve("m.jar");
+
+        // jar --create ...
+        String classes = MODS_DIR.resolve(TEST_MODULE).toString();
+        String[] args = {
+            "--create",
+            "--file=" + jar,
+            "--main-class=" + MAIN_CLASS,
+            "-C", classes, "."
+        };
+        boolean success
+            = new sun.tools.jar.Main(System.out, System.out, "jar")
+                .run(args);
+        assertTrue(success);
+
+        // java -mp mlib -m $TESTMODULE
+        int exitValue
+            = executeTestJava("-mp", dir.toString(),
+                              "-m", TEST_MODULE)
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
+        assertTrue(exitValue == 0);
+
+        // java -mp mlib/m.jar -m $TESTMODULE
+        exitValue
+            = executeTestJava("-mp", jar.toString(),
+                              "-m", TEST_MODULE)
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
+        assertTrue(exitValue == 0);
+    }
+
+
+    /**
+     * Attempt to run with the initial module packaged as a JMOD file.
+     */
+    public void testTryRunWithJMod() throws Exception {
+        Path dir = Files.createTempDirectory(USER_DIR, "mlib");
+
+        // jmod create ...
+        String cp = MODS_DIR.resolve(TEST_MODULE).toString();
+        String jmod = dir.resolve("m.jmod").toString();
+        String[] args = {
+            "create",
+            "--class-path", cp,
+            "--main-class", MAIN_CLASS,
+            jmod
+        };
+        jdk.tools.jmod.JmodTask task = new jdk.tools.jmod.JmodTask();
+        assertEquals(task.run(args), 0);
+
+        // java -mp mods -m $TESTMODULE
+        int exitValue
+            = executeTestJava("-mp", dir.toString(),
+                "-m", TEST_MODULE)
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
+
+        assertTrue(exitValue != 0);
+    }
+
+
+    /**
+     * Run the test with a non-existent file on the application module path.
+     * It should be silently ignored.
+     */
+    public void testRunWithNonExistentEntry() throws Exception {
+        String mp = "DoesNotExist" + File.pathSeparator + MODS_DIR.toString();
+        String mid = TEST_MODULE + "/" + MAIN_CLASS;
+
+        // java -mp mods -m $TESTMODULE/$MAINCLASS
+        int exitValue
+            = executeTestJava("-mp", mp,
+                              "-m", mid)
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
+
+        assertTrue(exitValue == 0);
+    }
+
+
+    /**
+     * Attempt to run an unknown initial module
+     */
+    public void testTryRunWithBadModule() throws Exception {
+        String modulepath = MODS_DIR.toString();
+
+        // java -mp mods -m $TESTMODULE
+        int exitValue
+            = executeTestJava("-mp", modulepath,
+                              "-m", "rhubarb")
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .shouldContain("not found")
+                .getExitValue();
+
+        assertTrue(exitValue != 0);
+    }
+
+
+    /**
+     * Attempt to run with -m specifying a main class that does not
+     * exist.
+     */
+    public void testTryRunWithBadMainClass() throws Exception {
+        String modulepath = MODS_DIR.toString();
+        String mid = TEST_MODULE + "/p.rhubarb";
+
+        // java -mp mods -m $TESTMODULE/$MAINCLASS
+        int exitValue
+            = executeTestJava("-mp", modulepath,
+                              "-m", mid)
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
+
+        assertTrue(exitValue != 0);
+    }
+
+
+    /**
+     * Attempt to run with -m specifying a modular JAR that does not have
+     * a MainClass attribute
+     */
+    public void testTryRunWithMissingMainClass() throws Exception {
+        Path dir = Files.createTempDirectory(USER_DIR, "mlib");
+
+        // jar --create ...
+        String classes = MODS_DIR.resolve(TEST_MODULE).toString();
+        String jar = dir.resolve("m.jar").toString();
+        String[] args = {
+            "--create",
+            "--file=" + jar,
+            "-C", classes, "."
+        };
+        boolean success
+            = new sun.tools.jar.Main(System.out, System.out, "jar")
+                .run(args);
+        assertTrue(success);
+
+        // java -mp mods -m $TESTMODULE
+        int exitValue
+            = executeTestJava("-mp", dir.toString(),
+                              "-m", TEST_MODULE)
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .shouldContain("does not have a MainClass attribute")
+                .getExitValue();
+
+        assertTrue(exitValue != 0);
+    }
+
+
+    /**
+     * Attempt to run with -m specifying a main class that is a different
+     * module to that specified to -m
+     */
+    public void testTryRunWithMainClassInWrongModule() throws Exception {
+        String modulepath = MODS_DIR.toString();
+        String mid = "java.base/" + MAIN_CLASS;
+
+        // java -mp mods -m $TESTMODULE/$MAINCLASS
+        int exitValue
+            = executeTestJava("-mp", modulepath,
+                              "-m", mid)
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
+
+        assertTrue(exitValue != 0);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/basic/src/test/jdk/test/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test;
+
+public class Main {
+    public static void main(String[] args) {
+        System.out.println("Hello world");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/basic/src/test/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module test {
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/limitmods/LimitModsTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @library /lib/testlibrary
+ * @modules java.desktop java.compact1 jdk.compiler
+ * @build LimitModsTest CompilerUtils jdk.testlibrary.*
+ * @run testng LimitModsTest
+ * @summary Basic tests for java -limitmods
+ */
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import static jdk.testlibrary.ProcessTools.*;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+
+@Test
+public class LimitModsTest {
+
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path MODS_DIR = Paths.get("mods");
+
+    // the module name / main class of the test module
+    private static final String TEST_MODULE = "test";
+    private static final String MAIN_CLASS = "jdk.test.UseAWT";
+
+
+    @BeforeTest
+    public void compileTestModule() throws Exception {
+
+        // javac -d mods/$TESTMODULE src/$TESTMODULE/**
+        boolean compiled
+            = CompilerUtils.compile(SRC_DIR.resolve(TEST_MODULE),
+                MODS_DIR.resolve(TEST_MODULE));
+
+        assertTrue(compiled, "test module did not compile");
+    }
+
+
+    /**
+     * Basic test of -limitmods to limit which platform modules are observable.
+     */
+    public void testLimitingPlatformModules() throws Exception {
+        int exitValue;
+
+        // java -limitmods java.base -listmods
+        exitValue = executeTestJava("-limitmods", "java.base", "-listmods")
+            .outputTo(System.out)
+            .errorTo(System.out)
+            .shouldContain("java.base")
+            .shouldNotContain("java.logging")
+            .shouldNotContain("java.xml")
+            .getExitValue();
+
+        assertTrue(exitValue == 0);
+
+
+        // java -limitmods java.compact1 -listmods
+        exitValue = executeTestJava("-limitmods", "java.compact1", "-listmods")
+            .outputTo(System.out)
+            .errorTo(System.out)
+            .shouldContain("java.base")
+            .shouldContain("java.logging")
+            .shouldContain("java.compact1")
+            .shouldNotContain("java.xml")
+            .getExitValue();
+
+        assertTrue(exitValue == 0);
+    }
+
+
+    /**
+     * Test -limitmods with -addmods
+     */
+    public void testWithAddMods() throws Exception {
+        int exitValue;
+
+        // java -limitmods java.base -addmods java.logging -listmods
+        exitValue = executeTestJava("-limitmods", "java.base",
+                                    "-addmods", "java.logging",
+                                    "-listmods")
+            .outputTo(System.out)
+            .errorTo(System.out)
+            .shouldContain("java.base")
+            .shouldContain("java.logging")
+            .shouldNotContain("java.xml")
+            .getExitValue();
+
+        assertTrue(exitValue == 0);
+
+
+        // java -limitmods java.base -addmods java.sql -listmods
+        // This should fail because java.sql has dependences beyond java.base
+        exitValue = executeTestJava("-limitmods", "java.base",
+                                    "-addmods", "java.sql",
+                                    "-listmods")
+            .outputTo(System.out)
+            .errorTo(System.out)
+            .getExitValue();
+
+        assertTrue(exitValue != 0);
+    }
+
+
+    /**
+     * Run class path application with -limitmods
+     */
+    public void testUnnamedModule() throws Exception {
+        String classpath = MODS_DIR.resolve(TEST_MODULE).toString();
+
+        // java -limitmods java.base -cp mods/$TESTMODULE ...
+        int exitValue1
+            = executeTestJava("-limitmods", "java.base",
+                              "-cp", classpath,
+                              MAIN_CLASS)
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .shouldContain("NoClassDefFoundError")
+                .getExitValue();
+
+        assertTrue(exitValue1 != 0);
+
+
+        // java -limitmods java.base -cp mods/$TESTMODULE ...
+        int exitValue2
+            = executeTestJava("-limitmods", "java.desktop",
+                              "-cp", classpath,
+                             MAIN_CLASS)
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
+
+        assertTrue(exitValue2 == 0);
+    }
+
+
+    /**
+     * Run named module with -limitmods
+     */
+    public void testNamedModule() throws Exception {
+
+        String modulepath = MODS_DIR.toString();
+        String mid = TEST_MODULE + "/" + MAIN_CLASS;
+
+        // java -limitmods java.base -mp mods -m $TESTMODULE/$MAINCLASS
+        int exitValue = executeTestJava("-limitmods", "java.base",
+                                        "-mp", modulepath,
+                                        "-m", mid)
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
+
+        assertTrue(exitValue != 0);
+
+        // java -limitmods java.desktop -mp mods -m $TESTMODULE/$MAINCLASS
+        exitValue = executeTestJava("-limitmods", "java.desktop",
+                                    "-mp", modulepath,
+                                    "-m", mid)
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
+
+        assertTrue(exitValue == 0);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/limitmods/src/test/jdk/test/UseAWT.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test;
+
+import java.awt.Component;
+
+public class UseAWT {
+    public static void main(String[] args) {
+        System.out.println(java.awt.Component.class);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/limitmods/src/test/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module test {
+    requires java.desktop;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/listmods/ListModsTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @library /lib/testlibrary
+ * @modules java.se
+ * @build ListModsTest CompilerUtils jdk.testlibrary.*
+ * @run testng ListModsTest
+ * @summary Basic test for java -listmods
+ */
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import static jdk.testlibrary.ProcessTools.*;
+import jdk.testlibrary.OutputAnalyzer;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/**
+ * Basic tests for java -listmods
+ */
+
+public class ListModsTest {
+
+    private static final String TEST_SRC = System.getProperty("test.src");
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path MODS_DIR = Paths.get("mods");
+    private static final Path UPGRADEMODS_DIR = Paths.get("upgrademods");
+
+    @BeforeTest
+    public void setup() throws Exception {
+        boolean compiled;
+
+        // javac -d mods/m1 -mp mods src/m1/**
+        compiled = CompilerUtils.compile(
+                SRC_DIR.resolve("m1"),
+                MODS_DIR.resolve("m1"));
+        assertTrue(compiled);
+
+        // javac -d upgrademods/java.transaction -mp mods src/java.transaction/**
+        compiled = CompilerUtils.compile(
+                SRC_DIR.resolve("java.transaction"),
+                UPGRADEMODS_DIR.resolve("java.transaction"));
+        assertTrue(compiled);
+
+    }
+
+
+    @Test
+    public void testListAll() throws Exception {
+        OutputAnalyzer output
+            = executeTestJava("-listmods")
+                .outputTo(System.out)
+                .errorTo(System.out);
+        output.shouldContain("java.base");
+        output.shouldContain("java.xml");
+        assertTrue(output.getExitValue() == 0);
+    }
+
+
+    @Test
+    public void testListOneModule() throws Exception {
+        OutputAnalyzer output
+            = executeTestJava("-listmods:java.base")
+                .outputTo(System.out)
+                .errorTo(System.out);
+        output.shouldContain("java.base");
+        output.shouldContain("exports java.lang");
+        assertTrue(output.getExitValue() == 0);
+    }
+
+
+    @Test
+    public void testListTwoModules() throws Exception {
+        OutputAnalyzer output
+            = executeTestJava("-listmods:java.base,java.xml")
+                .outputTo(System.out)
+                .errorTo(System.out);
+        output.shouldContain("java.base");
+        output.shouldContain("exports java.lang");
+        output.shouldContain("java.xml");
+        output.shouldContain("exports javax.xml");
+        assertTrue(output.getExitValue() == 0);
+    }
+
+
+    @Test
+    public void testListUnknownModule() throws Exception {
+        OutputAnalyzer output
+            = executeTestJava("-listmods:java.rhubarb")
+                .outputTo(System.out)
+                .errorTo(System.out);
+        output.shouldNotContain("java.base");
+        output.shouldNotContain("java.rhubarb");
+        assertTrue(output.getExitValue() == 0);
+    }
+
+
+    @Test
+    public void testListWithModulePath() throws Exception {
+        OutputAnalyzer output
+            = executeTestJava("-mp", MODS_DIR.toString(), "-listmods")
+                .outputTo(System.out)
+                .errorTo(System.out);
+        output.shouldContain("java.base");
+        output.shouldContain("m1");
+        assertTrue(output.getExitValue() == 0);
+    }
+
+
+    @Test
+    public void testListWithUpgradeModulePath() throws Exception {
+        OutputAnalyzer output
+            = executeTestJava("-upgrademodulepath", UPGRADEMODS_DIR.toString(),
+                              "-listmods:java.transaction")
+                .outputTo(System.out)
+                .errorTo(System.out);
+        output.shouldContain("exports javax.transaction.atomic");
+        assertTrue(output.getExitValue() == 0);
+    }
+
+
+    @Test
+    public void testListWithLimitMods1() throws Exception {
+        OutputAnalyzer output
+            = executeTestJava("-limitmods", "java.compact1", "-listmods")
+                .outputTo(System.out)
+                .errorTo(System.out);
+        output.shouldContain("java.compact1");
+        output.shouldContain("java.base");
+        output.shouldNotContain("java.xml");
+        assertTrue(output.getExitValue() == 0);
+    }
+
+
+    @Test
+    public void testListWithLimitMods2() throws Exception {
+        OutputAnalyzer output
+            = executeTestJava("-mp", MODS_DIR.toString(),
+                              "-limitmods", "java.compact1",
+                              "-listmods")
+                .outputTo(System.out)
+                .errorTo(System.out);
+        output.shouldContain("java.base");
+        output.shouldNotContain("m1");
+        assertTrue(output.getExitValue() == 0);
+    }
+
+
+    /**
+     * java -version -listmods => should print version and exit
+     */
+    @Test
+    public void testListWithPrintVersion1() throws Exception {
+        OutputAnalyzer output
+            = executeTestJava("-version", "-listmods")
+                .outputTo(System.out)
+                .errorTo(System.out);
+        output.shouldNotContain("java.base");
+        output.shouldContain("Runtime Environment");
+        assertTrue(output.getExitValue() == 0);
+    }
+
+
+    /**
+     * java -listmods -version => should list modules and exit
+     */
+    @Test
+    public void testListWithPrintVersion2() throws Exception {
+        OutputAnalyzer output
+            = executeTestJava("-listmods", "-version")
+                .outputTo(System.out)
+                .errorTo(System.out);
+        output.shouldContain("java.base");
+        output.shouldNotContain("Runtime Environment");
+        assertTrue(output.getExitValue() == 0);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/listmods/src/java.transaction/javax/transaction/Transaction.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.transaction;
+
+public class Transaction {
+
+    public Transaction() { }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/listmods/src/java.transaction/javax/transaction/atomic/Atomic.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.transaction.atomic;
+
+public interface Atomic {
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/listmods/src/java.transaction/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module java.transaction {
+    exports javax.transaction;
+    exports javax.transaction.atomic;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/listmods/src/m1/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m1 {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/patch/PatchTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @library /lib/testlibrary
+ * @modules jdk.compiler
+ * @build PatchTest CompilerUtils jdk.testlibrary.*
+ * @run testng PatchTest
+ * @summary Basic test for -Xpatch
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static jdk.testlibrary.ProcessTools.*;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+
+/**
+ * Compiles and launches a test that uses -Xpatch with two directories of
+ * classes to override existing and add new classes to modules in the
+ * boot layer.
+ *
+ * The classes overridden or added via -Xpatch all define a public no-arg
+ * constructor and override toString to return "hi". This allows the launched
+ * test to check that the overridden classes are loaded.
+ */
+
+@Test
+public class PatchTest {
+
+    // top-level source directory
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    // source/destination tree for the test module
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path MODS_DIR = Paths.get("mods");
+
+    // source/destination tree for patch tree 1
+    private static final Path SRC1_DIR = Paths.get(TEST_SRC, "src1");
+    private static final Path PATCHES1_DIR = Paths.get("patches1");
+
+    // source/destination tree for patch tree 2
+    private static final Path SRC2_DIR = Paths.get(TEST_SRC, "src2");
+    private static final Path PATCHES2_DIR = Paths.get("patches2");
+
+
+    // the classes overridden or added with -Xpatch
+    private static final String[] CLASSES = {
+
+        // java.base = boot loader
+        "java.base/java.text.Annotation",           // override class
+        "java.base/java.text.AnnotationBuddy",      // add class to package
+        "java.base/java.lang2.Object",              // new package
+
+        // jdk.naming.dns = platform class loader
+        "jdk.naming.dns/com.sun.jndi.dns.DnsClient",
+        "jdk.naming.dns/com.sun.jndi.dns.DnsClientBuddy",
+        "jdk.naming.dns/com.sun.jndi.dns2.Zone",
+
+        // jdk.compiler = application class loaded
+        "jdk.compiler/com.sun.tools.javac.Main",
+        "jdk.compiler/com.sun.tools.javac.MainBuddy",
+        "jdk.compiler/com.sun.tools.javac2.Main",
+
+    };
+
+
+    @BeforeTest
+    public void compile() throws Exception {
+
+        // javac -d mods/test src/test/**
+        boolean compiled= CompilerUtils.compile(SRC_DIR.resolve("test"),
+                                                MODS_DIR.resolve("test"));
+        assertTrue(compiled, "classes did not compile");
+
+        // javac -Xmodule:$MODULE -d patches1/$MODULE patches1/$MODULE/**
+        for (Path src : Files.newDirectoryStream(SRC1_DIR)) {
+            Path output = PATCHES1_DIR.resolve(src.getFileName());
+            String mn = src.getFileName().toString();
+            compiled  = CompilerUtils.compile(src, output, "-Xmodule:" + mn);
+            assertTrue(compiled, "classes did not compile");
+        }
+
+        // javac -Xmodule:$MODULE -d patches2/$MODULE patches2/$MODULE/**
+        for (Path src : Files.newDirectoryStream(SRC2_DIR)) {
+            Path output = PATCHES2_DIR.resolve(src.getFileName());
+            String mn = src.getFileName().toString();
+            compiled  = CompilerUtils.compile(src, output, "-Xmodule:" + mn);
+            assertTrue(compiled, "classes did not compile");
+        }
+
+    }
+
+    /**
+     * Run the test with -Xpatch
+     */
+    public void testRunWithXPatch() throws Exception {
+
+        // value for -Xpatch
+        String patchPath = PATCHES1_DIR + File.pathSeparator + PATCHES2_DIR;
+
+        // value for -XaddExports
+        String addExportsValue = "java.base/java.lang2=test"
+                + ",jdk.naming.dns/com.sun.jndi.dns=test"
+                + ",jdk.naming.dns/com.sun.jndi.dns2=test"
+                + ",jdk.compiler/com.sun.tools.javac2=test";
+
+        // the argument to the test is the list of classes overridden or added
+        String arg = Stream.of(CLASSES).collect(Collectors.joining(","));
+
+        int exitValue
+            =  executeTestJava("-Xpatch:" + patchPath,
+                               "-XaddExports:" + addExportsValue,
+                               "-addmods", "jdk.naming.dns,jdk.compiler",
+                               "-mp", MODS_DIR.toString(),
+                               "-m", "test/jdk.test.Main", arg)
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
+
+        assertTrue(exitValue == 0);
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/patch/src/test/jdk/test/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,74 @@
+/**
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Used with -Xpatch to exercise the replacement or addition of classes
+ * in modules that are linked into the runtime image.
+ */
+
+package jdk.test;
+
+import java.lang.reflect.Module;
+
+public class Main {
+
+    public static void main(String[] args) throws Exception {
+
+        for (String moduleAndClass : args[0].split(",")) {
+            String mn = moduleAndClass.split("/")[0];
+            String cn = moduleAndClass.split("/")[1];
+
+            // load class
+            Class<?> c = Class.forName(cn);
+
+            // check in expected module
+            Module m = c.getModule();
+            assertEquals(m.getName(), mn);
+
+            // instantiate object
+            Main.class.getModule().addReads(m);
+            Object obj = c.newInstance();
+
+            // check that the expected version of the class is loaded
+            System.out.print(moduleAndClass);
+            String s = obj.toString();
+            System.out.println(" says " + s);
+            assertEquals(s, "hi");
+
+            // check Module getResourceAsStream
+            String rn = cn.replace('.', '/') + ".class";
+            assertNotNull(m.getResourceAsStream(rn));
+        }
+    }
+
+
+    static void assertEquals(Object o1, Object o2) {
+        if (!o1.equals(o2))
+            throw new RuntimeException("assertion failed");
+    }
+
+    static void assertNotNull(Object o) {
+        if (o == null)
+            throw new RuntimeException("unexpected null");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/patch/src/test/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module test {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/patch/src1/java.base/java/text/Annotation.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.text;
+
+public class Annotation {
+    public String toString() { return "hi"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/patch/src1/java.base/java/text/AnnotationBuddy.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.text;
+
+public class AnnotationBuddy {
+    public String toString() { return "hi"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/patch/src1/jdk.compiler/com/sun/tools/javac/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.javac;
+
+public class Main {
+    public String toString() { return "hi"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/patch/src1/jdk.compiler/com/sun/tools/javac/MainBuddy.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.javac;
+
+public class MainBuddy {
+    public String toString() { return "hi"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/patch/src1/jdk.naming.dns/com/sun/jndi/dns/DnsClient.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.jndi.dns;
+
+public class DnsClient {
+    public String toString() { return "hi"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/patch/src1/jdk.naming.dns/com/sun/jndi/dns/DnsClientBuddy.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.jndi.dns;
+
+public class DnsClientBuddy {
+    public String toString() { return "hi"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/patch/src2/java.base/java/lang2/Object.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang2;
+
+public class Object {
+    public String toString() { return "hi"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/patch/src2/jdk.compiler/com/sun/tools/javac2/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.javac2;
+
+public class Main {
+    public String toString() { return "hi"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/patch/src2/jdk.naming.dns/com/sun/jndi/dns2/Zone.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.jndi.dns2;
+
+public class Zone {
+    public String toString() { return "hi"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/upgrademodulepath/UpgradeModulePathTest.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @library /lib/testlibrary
+ * @modules jdk.compiler
+ * @build UpgradeModulePathTest CompilerUtils jdk.testlibrary.*
+ * @run testng UpgradeModulePathTest
+ * @summary Basic test for java -upgrademodulepath
+ */
+
+import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import static jdk.testlibrary.ProcessTools.executeTestJava;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/**
+ * This test upgrades module java.transaction. The upgraded module has a
+ * dependency on module java.enterprise that is deployed on the application
+ * modue path.
+ */
+
+
+@Test
+public class UpgradeModulePathTest {
+
+    private static final String TEST_SRC = System.getProperty("test.src");
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path MODS_DIR = Paths.get("mods");
+    private static final Path UPGRADEDMODS_DIR = Paths.get("upgradedmods");
+
+
+    @BeforeTest
+    public void setup() throws Exception {
+
+        // javac -d mods/java.enterprise src/java.enterprise/**
+        boolean compiled = CompilerUtils.compile(
+                SRC_DIR.resolve("java.enterprise"),
+                MODS_DIR.resolve("java.enterprise"));
+        assertTrue(compiled);
+
+        // javac -d upgrademods/java.transaction -mp mods src/java.transaction/**
+        compiled = CompilerUtils.compile(
+                SRC_DIR.resolve("java.transaction"),
+                UPGRADEDMODS_DIR.resolve("java.transaction"),
+                "-mp", MODS_DIR.toString());
+        assertTrue(compiled);
+
+        // javac -d mods -upgrademodulepath upgrademods -mp mods src/test/**
+        compiled = CompilerUtils.compile(
+                SRC_DIR.resolve("test"),
+                MODS_DIR.resolve("test"),
+                "-upgrademodulepath", UPGRADEDMODS_DIR.toString(),
+                "-mp", MODS_DIR.toString());
+        assertTrue(compiled);
+
+    }
+
+
+    /**
+     * Run the test with an upgraded java.transaction module.
+     */
+    public void testWithUpgradedModule() throws Exception {
+
+        String mid = "test/jdk.test.Main";
+
+        int exitValue
+            = executeTestJava(
+                "-upgrademodulepath", UPGRADEDMODS_DIR.toString(),
+                "-mp", MODS_DIR.toString(),
+                "-m", mid)
+            .outputTo(System.out)
+            .errorTo(System.out)
+            .getExitValue();
+
+        assertTrue(exitValue == 0);
+
+    }
+
+
+    /**
+     * Run the test with a non-existent file on the upgrade module path.
+     * It should be silently ignored.
+     */
+    public void testRunWithNonExistentEntry() throws Exception {
+
+        String upgrademodulepath
+            = "DoesNotExit" + File.pathSeparator + UPGRADEDMODS_DIR.toString();
+        String mid = "test/jdk.test.Main";
+
+        int exitValue
+            = executeTestJava(
+                "-upgrademodulepath", upgrademodulepath,
+                "-mp", MODS_DIR.toString(),
+                "-m", mid)
+            .outputTo(System.out)
+            .errorTo(System.out)
+            .getExitValue();
+
+        assertTrue(exitValue == 0);
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/upgrademodulepath/src/java.enterprise/javax/enterprise/context/Scope.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.enterprise.context;
+
+public class Scope {
+    public Scope() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/upgrademodulepath/src/java.enterprise/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module java.enterprise {
+    exports javax.enterprise.context;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/upgrademodulepath/src/java.transaction/javax/transaction/Transaction.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.transaction;
+
+import javax.enterprise.context.Scope;
+
+public class Transaction {
+
+    public Transaction() { }
+
+    public Scope getScope() {
+        return new Scope();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/upgrademodulepath/src/java.transaction/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module java.transaction {
+    requires public java.enterprise;
+    exports javax.transaction;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/upgrademodulepath/src/test/jdk/test/Main.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test;
+
+import javax.transaction.Transaction;
+import javax.enterprise.context.Scope;
+
+/**
+ * Uses an upgraded version of module java.transaction.
+ */
+
+public class Main {
+
+    public static void main(String[] args) {
+
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+        ClassLoader pcl = ClassLoader.getPlatformClassLoader();
+        assertTrue(pcl.getParent() == null);
+
+        Transaction transaction = new Transaction();
+        Scope scope = transaction.getScope();
+
+        // javax.transaction.Transaction should be in module java.transaction
+        // and defined by the platform class loader
+        assertTrue(Transaction.class.getModule().getName().equals("java.transaction"));
+        assertTrue(Transaction.class.getClassLoader() == pcl);
+
+        // javax.enterprise.context.Scope should be in module java.enterprise
+        // and defined by the application class loader
+        assertTrue(Scope.class.getModule().getName().equals("java.enterprise"));
+        assertTrue(Scope.class.getClassLoader() == scl);
+    }
+
+    static void assertTrue(boolean e) {
+        if (!e) throw new RuntimeException();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/upgrademodulepath/src/test/module-info.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module test {
+    requires java.transaction;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/lib/tests/Helper.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,405 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package tests;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import tests.JImageGenerator.JLinkTask;
+import tests.JImageGenerator.JModTask;
+
+/**
+ * JLink tests helper.
+ */
+public class Helper {
+
+    private final Path explodedmodssrc;
+    private final Path jmodssrc;
+    private final Path jarssrc;
+    private final Path explodedmodsclasses;
+    private final Path jmodsclasses;
+    private final Path jarsclasses;
+    private final Path jmods;
+    private final Path jars;
+    private final Path images;
+    private final Path explodedmods;
+    private final Path stdjmods;
+    private final Path extracted;
+    private final Path recreated;
+
+    private final Map<String, List<String>> moduleClassDependencies = new HashMap<>();
+    private final Map<String, List<String>> moduleDependencies = new HashMap<>();
+    private final List<String> bootClasses;
+    private final FileSystem fs;
+
+    public static Helper newHelper() throws IOException {
+        Path jdkHome = Paths.get(System.getProperty("test.jdk"));
+        // JPRT not yet ready for jmods
+        if (!Files.exists(jdkHome.resolve("jmods"))) {
+            System.err.println("Test not run, NO jmods directory");
+            return null;
+        }
+        return new Helper(jdkHome);
+    }
+
+    private Helper(Path jdkHome) throws IOException {
+        this.stdjmods = jdkHome.resolve("jmods").normalize();
+        if (!Files.exists(stdjmods)) {
+            throw new IOException("Standard jMods do not exist.");
+        }
+        this.fs = FileSystems.getFileSystem(URI.create("jrt:/"));
+
+        Path javabase = fs.getPath("/modules/java.base");
+        this.bootClasses = Files.find(javabase, Integer.MAX_VALUE,
+                (file, attrs) -> file.toString().endsWith(".class"))
+                .map(Object::toString)
+                .map(s -> s.substring("/modules".length()))
+                .collect(Collectors.toList());
+
+        if (bootClasses.isEmpty()) {
+            throw new AssertionError("No boot class to check against");
+        }
+
+        this.jmods = Paths.get("jmods").toAbsolutePath();
+        Files.createDirectories(jmods);
+        this.jars = Paths.get("jars").toAbsolutePath();
+        Files.createDirectories(jars);
+        this.explodedmods = Paths.get("explodedmods").toAbsolutePath();
+        Files.createDirectories(explodedmods);
+        this.explodedmodssrc = explodedmods.resolve("src");
+        Files.createDirectories(explodedmodssrc);
+        this.jarssrc = jars.resolve("src");
+        Files.createDirectories(jarssrc);
+        this.jmodssrc = jmods.resolve("src");
+        Files.createDirectories(jmodssrc);
+        this.explodedmodsclasses = explodedmods.resolve("classes");
+        Files.createDirectories(explodedmodsclasses);
+        this.jmodsclasses = jmods.resolve("classes");
+        Files.createDirectories(jmodsclasses);
+        this.jarsclasses = jars.resolve("classes");
+        Files.createDirectories(jarsclasses);
+        this.images = Paths.get("images").toAbsolutePath();
+        Files.createDirectories(images);
+        this.extracted = Paths.get("extracted").toAbsolutePath();
+        Files.createDirectories(extracted);
+        this.recreated = Paths.get("recreated").toAbsolutePath();
+        Files.createDirectories(recreated);
+    }
+
+    public void generateDefaultModules() throws IOException {
+        generateDefaultJModule("leaf1");
+        generateDefaultJModule("leaf2");
+        generateDefaultJModule("leaf3");
+
+        generateDefaultJarModule("leaf4");
+        generateDefaultJarModule("leaf5");
+
+        generateDefaultExplodedModule("leaf6");
+        generateDefaultExplodedModule("leaf7");
+
+        generateDefaultJarModule("composite1", "leaf1", "leaf2", "leaf4", "leaf6");
+        generateDefaultJModule("composite2", "composite1", "leaf3", "leaf5", "leaf7",
+                "java.management");
+    }
+
+    public String defaultModulePath() {
+        return stdjmods.toAbsolutePath().toString() + File.pathSeparator
+                + jmods.toAbsolutePath().toString() + File.pathSeparator
+                + jars.toAbsolutePath().toString() + File.pathSeparator
+                + explodedmodsclasses.toAbsolutePath().toString();
+    }
+
+    public Path generateModuleCompiledClasses(
+            Path src, Path classes, String moduleName, String... dependencies) throws IOException {
+        return generateModuleCompiledClasses(src, classes, moduleName, getDefaultClasses(moduleName), dependencies);
+    }
+
+    public Path generateModuleCompiledClasses(
+            Path src, Path classes, String moduleName,
+            List<String> classNames, String... dependencies) throws IOException {
+        if (classNames == null) {
+            classNames = getDefaultClasses(moduleName);
+        }
+        putAppClasses(moduleName, classNames);
+        moduleDependencies.put(moduleName, Arrays.asList(dependencies));
+        String modulePath = defaultModulePath();
+        JImageGenerator.generateSourcesFromTemplate(src, moduleName, classNames.toArray(new String[classNames.size()]));
+        List<String> packages = classNames.stream()
+                .map(JImageGenerator::getPackageName)
+                .distinct()
+                .collect(Collectors.toList());
+        Path srcMod = src.resolve(moduleName);
+        JImageGenerator.generateModuleInfo(srcMod, packages, dependencies);
+        Path destination = classes.resolve(moduleName);
+        if (!JImageGenerator.compile(srcMod, destination, "-modulepath", modulePath, "-g")) {
+            throw new AssertionError("Compilation failure");
+        }
+        return destination;
+    }
+
+    public Result generateDefaultJModule(String moduleName, String... dependencies) throws IOException {
+        return generateDefaultJModule(moduleName, getDefaultClasses(moduleName), dependencies);
+    }
+
+    public Result generateDefaultJModule(String moduleName, List<String> classNames,
+                                             String... dependencies) throws IOException {
+        generateModuleCompiledClasses(jmodssrc, jmodsclasses, moduleName, classNames, dependencies);
+        generateGarbage(jmodsclasses.resolve(moduleName));
+
+        Path jmodFile = jmods.resolve(moduleName + ".jmod");
+        JModTask task = JImageGenerator.getJModTask()
+                .jmod(jmodFile)
+                .addJmods(stdjmods)
+                .addJmods(jmods.toAbsolutePath())
+                .addJars(jars.toAbsolutePath())
+                .addClassPath(jmodsclasses.resolve(moduleName));
+        if (!classNames.isEmpty()) {
+            task.mainClass(classNames.get(0));
+        }
+        return task.create();
+    }
+
+    public Result generateDefaultJarModule(String moduleName, String... dependencies) throws IOException {
+        return generateDefaultJarModule(moduleName, getDefaultClasses(moduleName), dependencies);
+    }
+
+    public Result generateDefaultJarModule(String moduleName, List<String> classNames,
+                                         String... dependencies) throws IOException {
+        generateModuleCompiledClasses(jarssrc, jarsclasses, moduleName, classNames, dependencies);
+        generateGarbage(jarsclasses.resolve(moduleName));
+
+        Path jarFile = jars.resolve(moduleName + ".jar");
+        JImageGenerator.createJarFile(jarFile, jarsclasses.resolve(moduleName));
+        return new Result(0, "", jarFile);
+    }
+
+    public Result generateDefaultExplodedModule(String moduleName, String... dependencies) throws IOException {
+        return generateDefaultExplodedModule(moduleName, getDefaultClasses(moduleName), dependencies);
+    }
+
+    public Result generateDefaultExplodedModule(String moduleName, List<String> classNames,
+            String... dependencies) throws IOException {
+        generateModuleCompiledClasses(explodedmodssrc, explodedmodsclasses,
+                moduleName, classNames, dependencies);
+
+        Path dir = explodedmods.resolve(moduleName);
+        return new Result(0, "", dir);
+    }
+
+    private void generateGarbage(Path compiled) throws IOException {
+        Path metaInf = compiled.resolve("META-INF").resolve("services");
+        Files.createDirectories(metaInf);
+        Path provider = metaInf.resolve("MyProvider");
+        Files.createFile(provider);
+        Files.createFile(compiled.resolve("toto.jcov"));
+    }
+
+    public static Path createNewFile(Path root, String pathName, String extension) {
+        Path out = root.resolve(pathName + extension);
+        int i = 1;
+        while (Files.exists(out)) {
+            out = root.resolve(pathName + "-" + (++i) + extension);
+        }
+        return out;
+    }
+
+    public Result generateDefaultImage(String module) {
+        return generateDefaultImage(new String[0], module);
+    }
+
+    public Result generateDefaultImage(String[] options, String module) {
+        Path output = createNewFile(images, module, ".image");
+        JLinkTask jLinkTask = JImageGenerator.getJLinkTask()
+                .modulePath(defaultModulePath())
+                .output(output)
+                .addMods(module)
+                .limitMods(module);
+        for (String option : options) {
+            jLinkTask.option(option);
+        }
+        return jLinkTask.call();
+    }
+
+    public Result postProcessImage(Path root, String[] options) {
+        JLinkTask jLinkTask = JImageGenerator.getJLinkTask()
+                .existing(root);
+        for (String option : options) {
+            jLinkTask.option(option);
+        }
+        return jLinkTask.callPostProcess();
+    }
+
+    private List<String> getDefaultClasses(String module) {
+        return Arrays.asList(module + ".Main", module + ".com.foo.bar.X");
+    }
+
+    private void putAppClasses(String module, List<String> classes) {
+        List<String> appClasses = toLocation(module, classes).stream().collect(Collectors.toList());
+        appClasses.add(toLocation(module, "module-info"));
+        moduleClassDependencies.put(module, appClasses);
+    }
+
+    private static String toLocation(String module, String className) {
+        return "/" + module + "/" + className.replaceAll("\\.", "/") + ".class";
+    }
+
+    public static List<String> toLocation(String module, List<String> classNames) {
+        return classNames.stream()
+                .map(clazz -> toLocation(module, clazz))
+                .collect(Collectors.toList());
+    }
+
+    public void checkImage(Path imageDir, String module, String[] paths, String[] files) throws IOException {
+        checkImage(imageDir, module, paths, files, null);
+    }
+
+    public void checkImage(Path imageDir, String module, String[] paths, String[] files, String[] expectedFiles) throws IOException {
+        List<String> unexpectedPaths = new ArrayList<>();
+        if (paths != null) {
+            Collections.addAll(unexpectedPaths, paths);
+        }
+        List<String> unexpectedFiles = new ArrayList<>();
+        if (files != null) {
+            Collections.addAll(unexpectedFiles, files);
+        }
+
+        JImageValidator validator = new JImageValidator(module, gatherExpectedLocations(module),
+                imageDir.toFile(),
+                unexpectedPaths,
+                unexpectedFiles,
+                expectedFiles);
+        System.out.println("*** Validate Image " + module);
+        validator.validate();
+        long moduleExecutionTime = validator.getModuleLauncherExecutionTime();
+        if (moduleExecutionTime != 0) {
+            System.out.println("Module launcher execution time " + moduleExecutionTime);
+        }
+        System.out.println("Java launcher execution time "
+                + validator.getJavaLauncherExecutionTime());
+        System.out.println("***");
+    }
+
+    private List<String> gatherExpectedLocations(String module) throws IOException {
+        List<String> expectedLocations = new ArrayList<>();
+        expectedLocations.addAll(bootClasses);
+        List<String> modules = moduleDependencies.get(module);
+        for (String dep : modules) {
+            Path path = fs.getPath("/modules/" + dep);
+            if (Files.exists(path)) {
+                List<String> locations = Files.find(path, Integer.MAX_VALUE,
+                        (p, attrs) -> Files.isRegularFile(p) && p.toString().endsWith(".class")
+                                && !p.toString().endsWith("module-info.class"))
+                        .map(p -> p.toString().substring("/modules".length()))
+                        .collect(Collectors.toList());
+                expectedLocations.addAll(locations);
+            }
+        }
+
+        List<String> appClasses = moduleClassDependencies.get(module);
+        if (appClasses != null) {
+            expectedLocations.addAll(appClasses);
+        }
+        return expectedLocations;
+    }
+
+    public static String getDebugSymbolsExtension() {
+        return ".diz";
+    }
+
+    public Path createNewImageDir(String moduleName) {
+        return createNewFile(getImageDir(), moduleName, ".image");
+    }
+
+    public Path createNewExtractedDir(String name) {
+        return createNewFile(getExtractedDir(), name, ".extracted");
+    }
+
+    public Path createNewRecreatedDir(String name) {
+        return createNewFile(getRecreatedDir(), name, ".jimage");
+    }
+
+    public Path createNewJmodFile(String moduleName) {
+        return createNewFile(getJmodDir(), moduleName, ".jmod");
+    }
+
+    public Path createNewJarFile(String moduleName) {
+        return createNewFile(getJarDir(), moduleName, ".jar");
+    }
+
+    public Path getJmodSrcDir() {
+        return jmodssrc;
+    }
+
+    public Path getJarSrcDir() {
+        return jarssrc;
+    }
+
+    public Path getJmodClassesDir() {
+        return jmodsclasses;
+    }
+
+    public Path getJarClassesDir() {
+        return jarsclasses;
+    }
+
+    public Path getJmodDir() {
+        return jmods;
+    }
+
+    public Path getExplodedModsDir() {
+        return explodedmods;
+    }
+
+    public Path getJarDir() {
+        return jars;
+    }
+
+    public Path getImageDir() {
+        return images;
+    }
+
+    public Path getStdJmodsDir() {
+        return stdjmods;
+    }
+
+    public Path getExtractedDir() {
+        return extracted;
+    }
+
+    public Path getRecreatedDir() {
+        return recreated;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/lib/tests/JImageGenerator.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,735 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package tests;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+import java.util.jar.JarOutputStream;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.zip.ZipEntry;
+
+import javax.tools.JavaCompiler;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.StandardLocation;
+import javax.tools.ToolProvider;
+
+/**
+ *
+ * A generator for jmods, jars and images.
+ */
+public class JImageGenerator {
+
+    public static final String LOAD_ALL_CLASSES_TEMPLATE = "package PACKAGE;\n"
+            + "\n"
+            + "import java.net.URI;\n"
+            + "import java.nio.file.FileSystems;\n"
+            + "import java.nio.file.Files;\n"
+            + "import java.nio.file.Path;\n"
+            + "import java.util.function.Function;\n"
+            + "\n"
+            + "public class CLASS {\n"
+            + "    private static long total_time;\n"
+            + "    private static long num_classes;\n"
+            + "    public static void main(String[] args) throws Exception {\n"
+            + "        Function<Path, String> formatter = (path) -> {\n"
+            + "            String clazz = path.toString().substring(\"modules/\".length()+1, path.toString().lastIndexOf(\".\"));\n"
+            + "            clazz = clazz.substring(clazz.indexOf(\"/\") + 1);\n"
+            + "            return clazz.replaceAll(\"/\", \"\\\\.\");\n"
+            + "        };\n"
+            + "        Files.walk(FileSystems.getFileSystem(URI.create(\"jrt:/\")).getPath(\"/modules/\")).\n"
+            + "                filter((p) -> {\n"
+            + "                    return Files.isRegularFile(p) && p.toString().endsWith(\".class\")\n"
+            + "                    && !p.toString().endsWith(\"module-info.class\");\n"
+            + "                }).\n"
+            + "                map(formatter).forEach((clazz) -> {\n"
+            + "                    try {\n"
+            + "                        long t = System.currentTimeMillis();\n"
+            + "                        Class.forName(clazz, false, Thread.currentThread().getContextClassLoader());\n"
+            + "                        total_time+= System.currentTimeMillis()-t;\n"
+            + "                        num_classes+=1;\n"
+            + "                    } catch (IllegalAccessError ex) {\n"
+            + "                        // Security exceptions can occur, this is not what we are testing\n"
+            + "                        System.err.println(\"Access error, OK \" + clazz);\n"
+            + "                    } catch (Exception ex) {\n"
+            + "                        System.err.println(\"ERROR \" + clazz);\n"
+            + "                        throw new RuntimeException(ex);\n"
+            + "                    }\n"
+            + "                });\n"
+            + "    double res = (double) total_time / num_classes;\n"
+            + "    // System.out.println(\"Total time \" + total_time + \" num classes \" + num_classes + \" average \" + res);\n"
+            + "    }\n"
+            + "}\n";
+
+    private static final String OUTPUT_OPTION = "--output";
+    private static final String POST_PROCESS_OPTION = "--post-process-path";
+    private static final String MAIN_CLASS_OPTION = "--main-class";
+    private static final String CLASS_PATH_OPTION = "--class-path";
+    private static final String MODULE_PATH_OPTION = "--modulepath";
+    private static final String ADD_MODS_OPTION = "--addmods";
+    private static final String LIMIT_MODS_OPTION = "--limitmods";
+    private static final String PLUGINS_MODULE_PATH = "--plugin-module-path";
+
+    private static final String CMDS_OPTION = "--cmds";
+    private static final String CONFIG_OPTION = "--config";
+    private static final String HASH_DEPENDENCIES_OPTION = "--hash-dependencies";
+    private static final String LIBS_OPTION = "--libs";
+    private static final String MODULE_VERSION_OPTION = "--module-version";
+
+    private JImageGenerator() {}
+
+    private static String optionsPrettyPrint(String... args) {
+        return Stream.of(args).collect(Collectors.joining(" "));
+    }
+
+    public static File getJModsDir(File jdkHome) {
+        File jdkjmods = new File(jdkHome, "jmods");
+        if (!jdkjmods.exists()) {
+            return null;
+        }
+        return jdkjmods;
+    }
+
+    public static Path addFiles(Path module, InMemoryFile... resources) throws IOException {
+        Path tempFile = Files.createTempFile("jlink-test", "");
+        try (JarInputStream in = new JarInputStream(Files.newInputStream(module));
+             JarOutputStream out = new JarOutputStream(new FileOutputStream(tempFile.toFile()))) {
+            ZipEntry entry;
+            while ((entry = in.getNextEntry()) != null) {
+                String name = entry.getName();
+                out.putNextEntry(new ZipEntry(name));
+                copy(in, out);
+                out.closeEntry();
+            }
+            for (InMemoryFile r : resources) {
+                addFile(r, out);
+            }
+        }
+        Files.move(tempFile, module, StandardCopyOption.REPLACE_EXISTING);
+        return module;
+    }
+
+    private static void copy(InputStream in, OutputStream out) throws IOException {
+        int len;
+        byte[] buf = new byte[4096];
+        while ((len = in.read(buf)) > 0) {
+            out.write(buf, 0, len);
+        }
+    }
+
+    public static JModTask getJModTask() {
+        return new JModTask();
+    }
+
+    public static JLinkTask getJLinkTask() {
+        return new JLinkTask();
+    }
+
+    public static JImageTask getJImageTask() {
+        return new JImageTask();
+    }
+
+    private static void addFile(InMemoryFile resource, JarOutputStream target) throws IOException {
+        String fileName = resource.getPath();
+        fileName = fileName.replace("\\", "/");
+        String[] ss = fileName.split("/");
+        Path p = Paths.get("");
+        for (int i = 0; i < ss.length; ++i) {
+            if (i < ss.length - 1) {
+                if (!ss[i].isEmpty()) {
+                    p = p.resolve(ss[i]);
+                    JarEntry entry = new JarEntry(p.toString() + "/");
+                    target.putNextEntry(entry);
+                    target.closeEntry();
+                }
+            } else {
+                p = p.resolve(ss[i]);
+                JarEntry entry = new JarEntry(p.toString());
+                target.putNextEntry(entry);
+                copy(resource.getBytes(), target);
+                target.closeEntry();
+            }
+        }
+    }
+
+    public static Path createNewFile(Path root, String pathName, String extension) {
+        Path out = root.resolve(pathName + extension);
+        int i = 1;
+        while (Files.exists(out)) {
+            out = root.resolve(pathName + "-" + (++i) + extension);
+        }
+        return out;
+    }
+
+    public static Path generateSources(Path output, String moduleName, List<InMemorySourceFile> sources) throws IOException {
+        Path moduleDir = output.resolve(moduleName);
+        Files.createDirectory(moduleDir);
+        for (InMemorySourceFile source : sources) {
+            Path fileDir = moduleDir;
+            if (!source.packageName.isEmpty()) {
+                String dir = source.packageName.replace('.', File.separatorChar);
+                fileDir = moduleDir.resolve(dir);
+                Files.createDirectories(fileDir);
+            }
+            Files.write(fileDir.resolve(source.className + ".java"), source.source.getBytes());
+        }
+        return moduleDir;
+    }
+
+    public static Path generateSourcesFromTemplate(Path output, String moduleName, String... classNames) throws IOException {
+        List<InMemorySourceFile> sources = new ArrayList<>();
+        for (String className : classNames) {
+            String packageName = getPackageName(className);
+            String simpleName = getSimpleName(className);
+            String content = LOAD_ALL_CLASSES_TEMPLATE
+                    .replace("CLASS", simpleName);
+            if (packageName.isEmpty()) {
+                content = content.replace("package PACKAGE;", packageName);
+            } else {
+                content = content.replace("PACKAGE", packageName);
+            }
+            sources.add(new InMemorySourceFile(packageName, simpleName, content));
+        }
+        return generateSources(output, moduleName, sources);
+    }
+
+    public static void generateModuleInfo(Path moduleDir, List<String> packages, String... dependencies) throws IOException {
+        StringBuilder moduleInfoBuilder = new StringBuilder();
+        Path file = moduleDir.resolve("module-info.java");
+        String moduleName = moduleDir.getFileName().toString();
+        moduleInfoBuilder.append("module ").append(moduleName).append("{\n");
+        for (String dep : dependencies) {
+            moduleInfoBuilder.append("requires ").append(dep).append(";\n");
+        }
+        for (String pkg : packages) {
+            if (!pkg.trim().isEmpty()) {
+                moduleInfoBuilder.append("exports ").append(pkg).append(";\n");
+            }
+        }
+        moduleInfoBuilder.append("}");
+        Files.write(file, moduleInfoBuilder.toString().getBytes());
+    }
+
+    public static void compileSuccess(Path source, Path destination, String... options) throws IOException {
+        if (!compile(source, destination, options)) {
+            throw new AssertionError("Compilation failed.");
+        }
+    }
+
+    public static boolean compile(Path source, Path destination, String... options) throws IOException {
+        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+        try (StandardJavaFileManager jfm = compiler.getStandardFileManager(null, null, null)) {
+            List<Path> sources
+                    = Files.find(source, Integer.MAX_VALUE,
+                    (file, attrs) -> file.toString().endsWith(".java"))
+                    .collect(Collectors.toList());
+
+            Files.createDirectories(destination);
+            jfm.setLocationFromPaths(StandardLocation.CLASS_OUTPUT, Collections.singleton(destination));
+
+            List<String> opts = Arrays.asList(options);
+            JavaCompiler.CompilationTask task
+                    = compiler.getTask(null, jfm, null, opts, null,
+                    jfm.getJavaFileObjectsFromPaths(sources));
+            List<String> list = new ArrayList<>(opts);
+            list.addAll(sources.stream()
+                    .map(Path::toString)
+                    .collect(Collectors.toList()));
+            System.err.println("javac options: " + optionsPrettyPrint(list.toArray(new String[list.size()])));
+            return task.call();
+        }
+    }
+
+    public static Path createJarFile(Path jarfile, Path dir) throws IOException {
+        return createJarFile(jarfile, dir, Paths.get("."));
+    }
+
+    public static Path createJarFile(Path jarfile, Path dir, Path file) throws IOException {
+        // create the target directory
+        Path parent = jarfile.getParent();
+        if (parent != null)
+            Files.createDirectories(parent);
+
+        List<Path> entries = Files.find(dir.resolve(file), Integer.MAX_VALUE,
+                (p, attrs) -> attrs.isRegularFile())
+                .map(dir::relativize)
+                .collect(Collectors.toList());
+
+        try (OutputStream out = Files.newOutputStream(jarfile);
+             JarOutputStream jos = new JarOutputStream(out)) {
+            for (Path entry : entries) {
+                // map the file path to a name in the JAR file
+                Path normalized = entry.normalize();
+                String name = normalized
+                        .subpath(0, normalized.getNameCount())  // drop root
+                        .toString()
+                        .replace(File.separatorChar, '/');
+
+                jos.putNextEntry(new JarEntry(name));
+                Files.copy(dir.resolve(entry), jos);
+            }
+        }
+        return jarfile;
+    }
+
+    public static Set<String> getModuleContent(Path module) {
+        Result result = JImageGenerator.getJModTask()
+                .jmod(module)
+                .list();
+        result.assertSuccess();
+        return Stream.of(result.getMessage().split("\r?\n"))
+                .collect(Collectors.toSet());
+    }
+
+    public static void checkModule(Path module, Set<String> expected) throws IOException {
+        Set<String> actual = getModuleContent(module);
+        if (!Objects.equals(actual, expected)) {
+            Set<String> unexpected = new HashSet<>(actual);
+            unexpected.removeAll(expected);
+            Set<String> notFound = new HashSet<>(expected);
+            notFound.removeAll(actual);
+            System.err.println("Unexpected files:");
+            unexpected.forEach(s -> System.err.println("\t" + s));
+            System.err.println("Not found files:");
+            notFound.forEach(s -> System.err.println("\t" + s));
+            throw new AssertionError("Module check failed.");
+        }
+    }
+
+    public static class JModTask {
+
+        private final List<Path> classpath = new ArrayList<>();
+        private final List<Path> libs = new ArrayList<>();
+        private final List<Path> cmds = new ArrayList<>();
+        private final List<Path> config = new ArrayList<>();
+        private final List<Path> jars = new ArrayList<>();
+        private final List<Path> jmods = new ArrayList<>();
+        private final List<String> options = new ArrayList<>();
+        private Path output;
+        private String hashDependencies;
+        private String mainClass;
+        private String moduleVersion;
+
+        public JModTask addNativeLibraries(Path cp) {
+            this.libs.add(cp);
+            return this;
+        }
+
+        public JModTask hashDependencies(String hash) {
+            this.hashDependencies = hash;
+            return this;
+        }
+
+        public JModTask addCmds(Path cp) {
+            this.cmds.add(cp);
+            return this;
+        }
+
+        public JModTask addClassPath(Path cp) {
+            this.classpath.add(cp);
+            return this;
+        }
+
+        public JModTask addConfig(Path cp) {
+            this.config.add(cp);
+            return this;
+        }
+
+        public JModTask addJars(Path jars) {
+            this.jars.add(jars);
+            return this;
+        }
+
+        public JModTask addJmods(Path jmods) {
+            this.jmods.add(jmods);
+            return this;
+        }
+
+        public JModTask jmod(Path output) {
+            this.output = output;
+            return this;
+        }
+
+        public JModTask moduleVersion(String moduleVersion) {
+            this.moduleVersion = moduleVersion;
+            return this;
+        }
+
+        public JModTask mainClass(String mainClass) {
+            this.mainClass = mainClass;
+            return this;
+        }
+
+        public JModTask option(String o) {
+            this.options.add(o);
+            return this;
+        }
+
+        private String modulePath() {
+            // This is expect FIRST jmods THEN jars, if you change this, some tests could fail
+            String jmods = toPath(this.jmods);
+            String jars = toPath(this.jars);
+            return jmods + File.pathSeparator + jars;
+        }
+
+        private String toPath(List<Path> paths) {
+            return paths.stream()
+                    .map(Path::toString)
+                    .collect(Collectors.joining(File.pathSeparator));
+        }
+
+        private String[] optionsJMod(String cmd) {
+            List<String> options = new ArrayList<>();
+            options.add(cmd);
+            if (!cmds.isEmpty()) {
+                options.add(CMDS_OPTION);
+                options.add(toPath(cmds));
+            }
+            if (!config.isEmpty()) {
+                options.add(CONFIG_OPTION);
+                options.add(toPath(config));
+            }
+            if (hashDependencies != null) {
+                options.add(HASH_DEPENDENCIES_OPTION);
+                options.add(hashDependencies);
+            }
+            if (mainClass != null) {
+                options.add(MAIN_CLASS_OPTION);
+                options.add(mainClass);
+            }
+            if (!libs.isEmpty()) {
+                options.add(LIBS_OPTION);
+                options.add(toPath(libs));
+            }
+            if (!classpath.isEmpty()) {
+                options.add(CLASS_PATH_OPTION);
+                options.add(toPath(classpath));
+            }
+            if (!jars.isEmpty() || !jmods.isEmpty()) {
+                options.add(MODULE_PATH_OPTION);
+                options.add(modulePath());
+            }
+            if (moduleVersion != null) {
+                options.add(MODULE_VERSION_OPTION);
+                options.add(moduleVersion);
+            }
+            options.addAll(this.options);
+            if (output != null) {
+                options.add(output.toString());
+            }
+            return options.toArray(new String[options.size()]);
+        }
+
+        public Result create() {
+            return cmd("create");
+        }
+
+        public Result list() {
+            return cmd("list");
+        }
+
+        public Result call() {
+            return cmd("");
+        }
+
+        private Result cmd(String cmd) {
+            String[] args = optionsJMod(cmd);
+            System.err.println("jmod options: " + optionsPrettyPrint(args));
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            int exitCode = jdk.tools.jmod.Main.run(args, new PrintStream(baos));
+            String msg = new String(baos.toByteArray());
+            return new Result(exitCode, msg, output);
+        }
+    }
+
+    public static String getPackageName(String canonicalName) {
+        int index = canonicalName.lastIndexOf('.');
+        return index > 0 ? canonicalName.substring(0, index) : "";
+    }
+
+    public static String getSimpleName(String canonicalName) {
+        int index = canonicalName.lastIndexOf('.');
+        return canonicalName.substring(index + 1);
+    }
+
+    public static class JImageTask {
+
+        private final List<Path> pluginModulePath = new ArrayList<>();
+        private final List<String> options = new ArrayList<>();
+        private Path dir;
+        private Path image;
+
+        public JImageTask pluginModulePath(Path p) {
+            this.pluginModulePath.add(p);
+            return this;
+        }
+
+        public JImageTask image(Path image) {
+            this.image = image;
+            return this;
+        }
+
+        public JImageTask dir(Path dir) {
+            this.dir = dir;
+            return this;
+        }
+
+        public JImageTask option(String o) {
+            this.options.add(o);
+            return this;
+        }
+
+        private String toPath(List<Path> paths) {
+            return paths.stream()
+                    .map(Path::toString)
+                    .collect(Collectors.joining(File.pathSeparator));
+        }
+
+        private String[] optionsJImage(String cmd) {
+            List<String> options = new ArrayList<>();
+            options.add(cmd);
+            if (dir != null) {
+                options.add("--dir");
+                options.add(dir.toString());
+            }
+            if (!pluginModulePath.isEmpty()) {
+                options.add(PLUGINS_MODULE_PATH);
+                options.add(toPath(pluginModulePath));
+            }
+            options.addAll(this.options);
+            options.add(image.toString());
+            return options.toArray(new String[options.size()]);
+        }
+
+        private Result cmd(String cmd, Path returnPath) {
+            String[] args = optionsJImage(cmd);
+            System.err.println("jimage options: " + optionsPrettyPrint(args));
+            StringWriter writer = new StringWriter();
+            int exitCode = jdk.tools.jimage.Main.run(args, new PrintWriter(writer));
+            return new Result(exitCode, writer.toString(), returnPath);
+        }
+
+        public Result extract() {
+            return cmd("extract", dir);
+        }
+
+        public Result recreate() {
+            return cmd("recreate", image);
+        }
+    }
+
+    public static class JLinkTask {
+
+        private final List<Path> jars = new ArrayList<>();
+        private final List<Path> jmods = new ArrayList<>();
+        private final List<Path> pluginModulePath = new ArrayList<>();
+        private final List<String> addMods = new ArrayList<>();
+        private final List<String> limitMods = new ArrayList<>();
+        private final List<String> options = new ArrayList<>();
+        private String modulePath;
+        private Path output;
+        private Path existing;
+
+        public JLinkTask modulePath(String modulePath) {
+            this.modulePath = modulePath;
+            return this;
+        }
+
+        public JLinkTask addJars(Path jars) {
+            this.jars.add(jars);
+            return this;
+        }
+
+        public JLinkTask addJmods(Path jmods) {
+            this.jmods.add(jmods);
+            return this;
+        }
+
+        public JLinkTask pluginModulePath(Path p) {
+            this.pluginModulePath.add(p);
+            return this;
+        }
+
+        public JLinkTask addMods(String moduleName) {
+            this.addMods.add(moduleName);
+            return this;
+        }
+
+        public JLinkTask limitMods(String moduleName) {
+            this.limitMods.add(moduleName);
+            return this;
+        }
+
+        public JLinkTask output(Path output) {
+            this.output = output;
+            return this;
+        }
+
+        public JLinkTask existing(Path existing) {
+            this.existing = existing;
+            return this;
+        }
+
+        public JLinkTask option(String o) {
+            this.options.add(o);
+            return this;
+        }
+
+        private String modulePath() {
+            // This is expect FIRST jmods THEN jars, if you change this, some tests could fail
+            String jmods = toPath(this.jmods);
+            String jars = toPath(this.jars);
+            return jmods + File.pathSeparator + jars;
+        }
+
+        private String toPath(List<Path> paths) {
+            return paths.stream()
+                    .map(Path::toString)
+                    .collect(Collectors.joining(File.pathSeparator));
+        }
+
+        private String[] optionsJLink() {
+            List<String> options = new ArrayList<>();
+            if (output != null) {
+                options.add(OUTPUT_OPTION);
+                options.add(output.toString());
+            }
+            if (!addMods.isEmpty()) {
+                options.add(ADD_MODS_OPTION);
+                options.add(addMods.stream().collect(Collectors.joining(",")));
+            }
+            if (!limitMods.isEmpty()) {
+                options.add(LIMIT_MODS_OPTION);
+                options.add(limitMods.stream().collect(Collectors.joining(",")));
+            }
+            if (!jars.isEmpty() || !jmods.isEmpty()) {
+                options.add(MODULE_PATH_OPTION);
+                options.add(modulePath());
+            }
+            if (modulePath != null) {
+                options.add(MODULE_PATH_OPTION);
+                options.add(modulePath);
+            }
+            if (!pluginModulePath.isEmpty()) {
+                options.add(PLUGINS_MODULE_PATH);
+                options.add(toPath(pluginModulePath));
+            }
+            options.addAll(this.options);
+            return options.toArray(new String[options.size()]);
+        }
+
+        private String[] optionsPostProcessJLink() {
+            List<String> options = new ArrayList<>();
+            if (existing != null) {
+                options.add(POST_PROCESS_OPTION);
+                options.add(existing.toString());
+            }
+            options.addAll(this.options);
+            return options.toArray(new String[options.size()]);
+        }
+
+        public Result call() {
+            String[] args = optionsJLink();
+            System.err.println("jlink options: " + optionsPrettyPrint(args));
+            StringWriter writer = new StringWriter();
+            int exitCode = jdk.tools.jlink.internal.Main.run(args, new PrintWriter(writer));
+            return new Result(exitCode, writer.toString(), output);
+        }
+
+        public Result callPostProcess() {
+            String[] args = optionsPostProcessJLink();
+            System.err.println("jlink options: " + optionsPrettyPrint(args));
+            StringWriter writer = new StringWriter();
+            int exitCode = jdk.tools.jlink.internal.Main.run(args, new PrintWriter(writer));
+            return new Result(exitCode, writer.toString(), output);
+        }
+    }
+
+    public static class InMemorySourceFile {
+        public final String packageName;
+        public final String className;
+        public final String source;
+
+        public InMemorySourceFile(String packageName, String simpleName, String source) {
+            this.packageName = packageName;
+            this.className = simpleName;
+            this.source = source;
+        }
+    }
+
+    public static class InMemoryFile {
+        private final String path;
+        private final byte[] bytes;
+
+        public String getPath() {
+            return path;
+        }
+
+        public InputStream getBytes() {
+            return new ByteArrayInputStream(bytes);
+        }
+
+        public InMemoryFile(String path, byte[] bytes) {
+            this.path = path;
+            this.bytes = bytes;
+        }
+
+        public InMemoryFile(String path, InputStream is) throws IOException {
+            this(path, readAllBytes(is));
+        }
+    }
+
+    public static byte[] readAllBytes(InputStream is) throws IOException {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        byte[] buf = new byte[1024];
+        while (true) {
+            int n = is.read(buf);
+            if (n < 0) {
+                break;
+            }
+            baos.write(buf, 0, n);
+        }
+        return baos.toByteArray();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/lib/tests/JImageValidator.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package tests;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.ConstantPoolException;
+import jdk.internal.jimage.BasicImageReader;
+import jdk.internal.jimage.ImageLocation;
+
+/**
+ *
+ * JDK Modular image validator
+ */
+public class JImageValidator {
+
+    private static final String[] dirs = {"bin", "lib"};
+
+    private final File rootDir;
+    private final List<String> expectedLocations;
+    private final String module;
+    private long moduleExecutionTime;
+    private long javaExecutionTime;
+    private final List<String> unexpectedPaths;
+    private final List<String> unexpectedFiles;
+    private final String[] expectedFiles;
+
+    public JImageValidator(String module, List<String> expectedLocations,
+            File rootDir,
+            List<String> unexpectedPaths,
+            List<String> unexpectedFiles) throws Exception {
+        this(module, expectedLocations, rootDir, unexpectedPaths, unexpectedFiles, null);
+    }
+
+    public JImageValidator(String module, List<String> expectedLocations,
+            File rootDir,
+            List<String> unexpectedPaths,
+            List<String> unexpectedFiles,
+            String[] expectedFiles) throws IOException {
+        if (!rootDir.exists()) {
+            throw new IOException("Image root dir not found " +
+                    rootDir.getAbsolutePath());
+        }
+        this.expectedLocations = expectedLocations;
+        this.rootDir = rootDir;
+        this.module = module;
+        this.unexpectedPaths = unexpectedPaths;
+        this.unexpectedFiles = unexpectedFiles;
+        this.expectedFiles = expectedFiles == null ? new String[0] : expectedFiles;
+    }
+
+    public void validate() throws IOException {
+        for (String d : dirs) {
+            File dir = new File(rootDir, d);
+            if (!dir.isDirectory()) {
+                throw new IOException("Invalid directory " + d);
+            }
+        }
+
+        //check jimage file
+        Path path = rootDir.toPath().resolve("lib").resolve("modules");
+        if (!Files.isRegularFile(path)) {
+            throw new IOException(path + " No jimage file generated");
+        }
+
+        // Check binary file
+        File launcher = new File(rootDir, "bin" + File.separator + module);
+        if (launcher.exists()) {
+            ProcessBuilder builder = new ProcessBuilder("sh", launcher.getAbsolutePath());
+            long t = System.currentTimeMillis();
+            Process process = builder.inheritIO().start();
+            int ret = waitFor(process);
+            moduleExecutionTime += System.currentTimeMillis() - t;
+            if (ret != 0) {
+                throw new IOException("Image " + module + " execution failed, check logs.");
+            }
+        }
+
+        for (String f : expectedFiles) {
+            File dd = new File(rootDir, f);
+            if (!dd.exists()) {
+                throw new IOException("Expected File " + f + " not found");
+            }
+        }
+
+        //Walk and check that unexpected files are not there
+        try (java.util.stream.Stream<Path> stream = Files.walk(rootDir.toPath())) {
+            stream.forEach((p) -> {
+                for (String u : unexpectedFiles) {
+                    if (p.toString().equals(u)) {
+                        throw new RuntimeException("Seen unexpected path " + p);
+                    }
+                }
+            });
+        }
+
+        File javaLauncher = new File(rootDir, "bin" + File.separator +
+                (isWindows() ? "java.exe" : "java"));
+        if (javaLauncher.exists()) {
+            ProcessBuilder builder = new ProcessBuilder(javaLauncher.getAbsolutePath(),
+                    "-version");
+            long t = System.currentTimeMillis();
+            Process process = builder.start();
+            int ret = waitFor(process);
+            javaExecutionTime += System.currentTimeMillis() - t;
+            if (ret != 0) {
+                throw new RuntimeException("java launcher execution failed, check logs.");
+            }
+        } else {
+            throw new IOException("java launcher not found.");
+        }
+
+        // Check release file
+        File release = new File(rootDir, "release");
+        if (!release.exists()) {
+            throw new IOException("Release file not generated");
+        } else {
+            Properties props = new Properties();
+            try (FileInputStream fs = new FileInputStream(release)) {
+                props.load(fs);
+                String s = props.getProperty("MODULES");
+                if (s == null) {
+                    throw new IOException("No MODULES property in release");
+                }
+                if (!s.contains(module)) {
+                    throw new IOException("Module not found in release file " + s);
+                }
+            }
+        }
+
+    }
+
+    private int waitFor(Process process) {
+        try {
+            return process.waitFor();
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static boolean isWindows() {
+        return System.getProperty("os.name").startsWith("Windows");
+    }
+
+    public static void validate(Path jimage, List<String> expectedLocations,
+            List<String> unexpectedPaths) throws IOException {
+        BasicImageReader reader = BasicImageReader.open(jimage);
+        // Validate expected locations
+        List<String> seenLocations = new ArrayList<>();
+        for (String loc : expectedLocations) {
+            ImageLocation il = reader.findLocation(loc);
+            if (il == null) {
+                throw new IOException("Location " + loc + " not present in " + jimage);
+            }
+        }
+        seenLocations.addAll(expectedLocations);
+
+        for (String s : reader.getEntryNames()) {
+            if (s.endsWith(".class") && !s.endsWith("module-info.class")) {
+                ImageLocation il = reader.findLocation(s);
+                try {
+                    byte[] r = reader.getResource(il);
+                    if(r == null) {
+                        System.out.println("IL, compressed " +
+                                il.getCompressedSize() + " uncompressed " +
+                                il.getUncompressedSize());
+                        throw new IOException("NULL RESOURCE " + s);
+                    }
+                    readClass(r);
+                } catch (IOException ex) {
+                    System.err.println(s + " ERROR " + ex);
+                    throw ex;
+                }
+            }
+            if (seenLocations.contains(s)) {
+                seenLocations.remove(s);
+            }
+            for(String p : unexpectedPaths) {
+                if (s.equals(p)) {
+                    throw new IOException("Seen unexpected path " + s);
+                }
+            }
+        }
+        if (!seenLocations.isEmpty()) {
+            throw new IOException("ImageReader did not return " + seenLocations);
+        }
+    }
+
+    public long getJavaLauncherExecutionTime() {
+        return javaExecutionTime;
+    }
+
+    public long getModuleLauncherExecutionTime() {
+        return moduleExecutionTime;
+    }
+
+    public static void readClass(byte[] clazz) throws IOException {
+        try (InputStream stream = new ByteArrayInputStream(clazz)) {
+            ClassFile.read(stream);
+        } catch (ConstantPoolException e) {
+            throw new IOException(e);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/lib/tests/Result.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package tests;
+
+import java.nio.file.Path;
+
+public class Result {
+    private final int exitCode;
+    private final String message;
+    private final Path imageFile;
+
+    public Result(int exitCode, String message, Path imageFile) {
+        this.exitCode = exitCode;
+        this.message = message;
+        this.imageFile = imageFile;
+    }
+
+    public int getExitCode() {
+        return exitCode;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public Path getFile() {
+        return imageFile;
+    }
+
+    public void assertFailure() {
+        assertFailure(null);
+    }
+
+    public void assertFailure(String expected) {
+        if (getExitCode() == 0) {
+            System.err.println(getMessage());
+            throw new AssertionError("Failure expected: " + getFile());
+        }
+        if (getExitCode() != 1 && getExitCode() != 2) {
+            System.err.println(getMessage());
+            throw new AssertionError("Abnormal exit: " + getFile());
+        }
+        if (expected != null) {
+            if (expected.isEmpty()) {
+                throw new AssertionError("Expected error is empty");
+            }
+            if (!getMessage().matches(expected) && !getMessage().contains(expected)) {
+                System.err.println(getMessage());
+                throw new AssertionError("Output does not fit regexp: " + expected);
+            }
+        }
+        System.err.println("Failed as expected. " + (expected != null ? expected : ""));
+        System.err.println(getMessage());
+    }
+
+    public Path assertSuccess() {
+        if (getExitCode() != 0) {
+            System.err.println(getMessage());
+            throw new AssertionError("Unexpected failure: " + getExitCode());
+        }
+        return getFile();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/pack200/ModuleAttributes.java	Thu Mar 17 19:04:16 2016 +0000
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+/*
+ * @test
+ * @bug 8048100
+ * @summary test the new Module attributes
+ * @compile -XDignore.symbol.file Utils.java ModuleAttributes.java
+ * @run main ModuleAttributes
+ */
+public class ModuleAttributes {
+
+    public static void main(String... args) throws Exception {
+        new ModuleAttributes().run();
+    }
+
+    public void run() throws Exception {
+        File file = createModuleJar();
+        Utils.testWithRepack(file,
+                "--effort=1",
+                "--unknown-attribute=error");
+    }
+
+    File createModuleJar() throws IOException {
+        File libDir = new File(Utils.JavaHome, "lib");
+        File modules = new File(libDir, "modules");
+        File outDir = new File("out");
+
+        List<String> cmdList = new ArrayList<>();
+        cmdList.add(Utils.getJimageCmd());
+        cmdList.add("extract");
+        cmdList.add(modules.getAbsolutePath());
+        cmdList.add("--dir");
+        cmdList.add(outDir.getName());
+        Utils.runExec(cmdList);
+
+        FileFilter filter = (File file) -> file.getName().equals("module-info.class");
+        List<File> mfiles = Utils.findFiles(outDir, filter);
+
+        List<String> contents = new ArrayList<>(mfiles.size());
+        mfiles.stream().forEach((f) -> {
+            contents.add(f.getAbsolutePath());
+        });
+
+        File listFile = new File("mfiles.list");
+        Utils.createFile(listFile, contents);
+        File testFile = new File("test.jar");
+        Utils.jar("cvf", testFile.getName(), "@" + listFile.getName());
+        Utils.recursiveDelete(outDir);
+        return testFile;
+    }
+}
--- a/test/tools/pack200/Utils.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/tools/pack200/Utils.java	Thu Mar 17 19:04:16 2016 +0000
@@ -101,6 +101,7 @@
 
         compiler("-d",
                 XCLASSES.getName(),
+                "-XaddExports:jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED",
                 "@" + tmpFile.getAbsolutePath());
 
         jar("cvfe",
@@ -137,6 +138,7 @@
         init();
         List<String> cmds = new ArrayList<String>();
         cmds.add(getJavaCmd());
+        cmds.add("-XaddExports:jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED");
         cmds.add("-cp");
         cmds.add(VerifierJar.getName());
         cmds.add("sun.tools.pack.verify.Main");
@@ -561,13 +563,12 @@
     }
 
     static File createRtJar() throws IOException {
-        File LibDir = new File(JavaHome, "lib");
-        File ModuleDir = new File(LibDir, "modules");
-        File BootModules = new File(ModuleDir, "bootmodules.jimage");
+        File libDir = new File(JavaHome, "lib");
+        File modules = new File(libDir, "modules");
         List<String> cmdList = new ArrayList<>();
         cmdList.add(getJimageCmd());
         cmdList.add("extract");
-        cmdList.add(BootModules.getAbsolutePath());
+        cmdList.add(modules.getAbsolutePath());
         cmdList.add("--dir");
         cmdList.add("out");
         runExec(cmdList);
--- a/test/tools/pack200/pack200-verifier/make/build.xml	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/tools/pack200/pack200-verifier/make/build.xml	Thu Mar 17 19:04:16 2016 +0000
@@ -1,4 +1,4 @@
-<project name="PackageVerify" default="dist" basedir="..">
+<project name="PackageVerify" default="jar-file" basedir="..">
   <!-- Requires ant 1.6.1+ and JDK 1.7+-->
 
   <!-- set global properties for this build -->
@@ -21,30 +21,35 @@
 
   <target name="compile" depends="init">
     <!-- Compile the java code from ${src} into ${build} -->
-    <javac 
-	source="1.7"
-	srcdir="${src}"
-	destdir="${build}/classes"
-	verbose="no"
-	debug="on"
-    />
+     <javac 
+	   source="1.8"
+	   srcdir="${src}"
+	   destdir="${build}/classes"
+	   verbose="no"
+	   debug="on">
+       <compilerarg value="-XaddExports:jdk.jdeps/com.sun.tools.classfile"/>
+     </javac>
   </target>
 
   <target name="doc" depends="init, compile">
       <javadoc
-        source="1.7"
+        source="1.8"
         sourcepath="${src}"
         destdir="${api}"
       />
   </target>
-  <target name="dist" depends="compile, doc">
-    <!-- Put everything in jar file -->
+  
+  <target name="jar-file" depends="compile">
+  <!-- Put everything in jar file -->
     <jar destfile="${dist}/pack200-verifier.jar">
-	<manifest>
-	   <attribute name="Main-Class" value="sun.tools.pack.verify.Main"/>
-	</manifest>
-	<fileset dir="${classes}"/>
+      <manifest>
+        <attribute name="Main-Class" value="sun.tools.pack.verify.Main"/>
+      </manifest>
+      <fileset dir="${classes}"/>
     </jar>
+</target>
+  
+  <target name="all" depends="jar-file">
     <zip destfile="dist/pack200-verifier-doc.zip">
         <fileset dir="${api}"/>
     </zip>
--- a/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,7 +26,11 @@
 
 import com.sun.tools.classfile.AccessFlags;
 import com.sun.tools.classfile.Annotation;
-import com.sun.tools.classfile.Annotation.*;
+import com.sun.tools.classfile.Annotation.Annotation_element_value;
+import com.sun.tools.classfile.Annotation.Array_element_value;
+import com.sun.tools.classfile.Annotation.Class_element_value;
+import com.sun.tools.classfile.Annotation.Enum_element_value;
+import com.sun.tools.classfile.Annotation.Primitive_element_value;
 import com.sun.tools.classfile.AnnotationDefault_attribute;
 import com.sun.tools.classfile.Attribute;
 import com.sun.tools.classfile.Attributes;
@@ -35,8 +39,24 @@
 import com.sun.tools.classfile.ClassFile;
 import com.sun.tools.classfile.Code_attribute;
 import com.sun.tools.classfile.CompilationID_attribute;
+import com.sun.tools.classfile.ConcealedPackages_attribute;
 import com.sun.tools.classfile.ConstantPool;
-import com.sun.tools.classfile.ConstantPool.*;
+import com.sun.tools.classfile.ConstantPool.CONSTANT_Class_info;
+import com.sun.tools.classfile.ConstantPool.CONSTANT_Double_info;
+import com.sun.tools.classfile.ConstantPool.CONSTANT_Fieldref_info;
+import com.sun.tools.classfile.ConstantPool.CONSTANT_Float_info;
+import com.sun.tools.classfile.ConstantPool.CONSTANT_Integer_info;
+import com.sun.tools.classfile.ConstantPool.CONSTANT_InterfaceMethodref_info;
+import com.sun.tools.classfile.ConstantPool.CONSTANT_InvokeDynamic_info;
+import com.sun.tools.classfile.ConstantPool.CONSTANT_Long_info;
+import com.sun.tools.classfile.ConstantPool.CONSTANT_MethodHandle_info;
+import com.sun.tools.classfile.ConstantPool.CONSTANT_MethodType_info;
+import com.sun.tools.classfile.ConstantPool.CONSTANT_Methodref_info;
+import com.sun.tools.classfile.ConstantPool.CONSTANT_NameAndType_info;
+import com.sun.tools.classfile.ConstantPool.CONSTANT_String_info;
+import com.sun.tools.classfile.ConstantPool.CONSTANT_Utf8_info;
+import com.sun.tools.classfile.ConstantPool.CPInfo;
+import com.sun.tools.classfile.ConstantPool.InvalidIndex;
 import com.sun.tools.classfile.ConstantPoolException;
 import com.sun.tools.classfile.ConstantValue_attribute;
 import com.sun.tools.classfile.DefaultAttribute;
@@ -45,6 +65,8 @@
 import com.sun.tools.classfile.EnclosingMethod_attribute;
 import com.sun.tools.classfile.Exceptions_attribute;
 import com.sun.tools.classfile.Field;
+import com.sun.tools.classfile.Hashes_attribute;
+import com.sun.tools.classfile.Hashes_attribute.Entry;
 import com.sun.tools.classfile.InnerClasses_attribute;
 import com.sun.tools.classfile.InnerClasses_attribute.Info;
 import com.sun.tools.classfile.Instruction;
@@ -52,8 +74,13 @@
 import com.sun.tools.classfile.LineNumberTable_attribute;
 import com.sun.tools.classfile.LocalVariableTable_attribute;
 import com.sun.tools.classfile.LocalVariableTypeTable_attribute;
+import com.sun.tools.classfile.MainClass_attribute;
 import com.sun.tools.classfile.Method;
 import com.sun.tools.classfile.MethodParameters_attribute;
+import com.sun.tools.classfile.Module_attribute;
+import com.sun.tools.classfile.Module_attribute.ExportsEntry;
+import com.sun.tools.classfile.Module_attribute.ProvidesEntry;
+import com.sun.tools.classfile.Module_attribute.RequiresEntry;
 import com.sun.tools.classfile.Opcode;
 import com.sun.tools.classfile.RuntimeInvisibleAnnotations_attribute;
 import com.sun.tools.classfile.RuntimeInvisibleParameterAnnotations_attribute;
@@ -66,14 +93,22 @@
 import com.sun.tools.classfile.SourceFile_attribute;
 import com.sun.tools.classfile.SourceID_attribute;
 import com.sun.tools.classfile.StackMapTable_attribute;
-import com.sun.tools.classfile.StackMapTable_attribute.*;
+import com.sun.tools.classfile.StackMapTable_attribute.append_frame;
+import com.sun.tools.classfile.StackMapTable_attribute.chop_frame;
+import com.sun.tools.classfile.StackMapTable_attribute.full_frame;
+import com.sun.tools.classfile.StackMapTable_attribute.same_frame;
+import com.sun.tools.classfile.StackMapTable_attribute.same_frame_extended;
+import com.sun.tools.classfile.StackMapTable_attribute.same_locals_1_stack_item_frame;
+import com.sun.tools.classfile.StackMapTable_attribute.same_locals_1_stack_item_frame_extended;
 import com.sun.tools.classfile.StackMap_attribute;
 import com.sun.tools.classfile.Synthetic_attribute;
+import com.sun.tools.classfile.TargetPlatform_attribute;
 import com.sun.tools.classfile.TypeAnnotation;
 import com.sun.tools.classfile.TypeAnnotation.Position;
 import static com.sun.tools.classfile.TypeAnnotation.TargetType.THROWS;
+import com.sun.tools.classfile.Version_attribute;
+import java.io.*;
 import java.util.*;
-import java.io.*;
 import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
 import xmlkit.XMLKit.Element;
@@ -383,7 +418,9 @@
         AccessFlags af = new AccessFlags(c.access_flags.flags);
         klass.setAttr("flags", flagString(af, klass));
         if (!"java/lang/Object".equals(thisk)) {
-            klass.setAttr("super", c.getSuperclassName());
+            if (c.super_class != 0) {
+                klass.setAttr("super", c.getSuperclassName());
+            }
         }
         for (int i : c.interfaces) {
             klass.add(new Element("Interface", "name", getCpString(i)));
@@ -854,7 +891,6 @@
     }
 }
 
-
 class AttributeVisitor implements Attribute.Visitor<Element, Element> {
     final ClassFile cf;
     final ClassReader x;
@@ -981,6 +1017,21 @@
     }
 
     @Override
+    public Element visitConcealedPackages(ConcealedPackages_attribute attr, Element p) {
+        Element e = new Element(x.getCpString(attr.attribute_name_index));
+        for (int i : attr.packages_index) {
+            Element ee = new Element("Package");
+            String pkg = x.getCpString(i);
+            ee.setAttr("package", pkg);
+            e.add(ee);
+        }
+        e.trimToSize();
+        e.sort();
+        p.add(e);
+        return null;
+    }
+
+    @Override
     public Element visitConstantValue(ConstantValue_attribute cv, Element p) {
         Element e = new Element(x.getCpString(cv.attribute_name_index));
         e.add(x.getCpString(cv.constantvalue_index));
@@ -1063,6 +1114,52 @@
         return null; // already added to parent
     }
 
+    private void parseModuleRequires(RequiresEntry[] res, Element p) {
+        for (RequiresEntry re : res) {
+            Element er = new Element("Requires");
+            er.setAttr("module", x.getCpString(re.requires_index));
+            er.setAttr("flags", Integer.toString(re.requires_flags));
+            p.add(er);
+        }
+    }
+
+    private void parseModuleExports(ExportsEntry[] exports, Element p) {
+        Element ex = new Element("Exports");
+        for (ExportsEntry export : exports) {
+            Element exto = new Element("exports");
+            exto.setAttr("package", x.getCpString(export.exports_index));
+            for ( int idx : export.exports_to_index) {
+                exto.setAttr("module", x.getCpString(idx));
+            }
+            ex.add(exto);
+        }
+        p.add(ex);
+    }
+
+    private void parseModuleProvides(ProvidesEntry[] provides, Element p) {
+        Element ex = new Element("Provides");
+        for (ProvidesEntry provide : provides) {
+            ex.setAttr("provides", x.getCpString(provide.provides_index));
+            ex.setAttr("with", x.getCpString(provide.with_index));
+        }
+        p.add(ex);
+    }
+
+    @Override
+    public Element visitModule(Module_attribute m, Element p) {
+        Element e = new Element(x.getCpString(m.attribute_name_index));
+        parseModuleRequires(m.requires, e);
+        parseModuleExports(m.exports, e);
+        for (int idx : m.uses_index) {
+            Element ei = new Element("Uses");
+            ei.setAttr("used_class", x.getCpString(idx));
+            e.add(ei);
+        }
+        parseModuleProvides(m.provides, e);
+        p.add(e);
+        return null;
+    }
+
     @Override
     public Element visitLocalVariableTypeTable(LocalVariableTypeTable_attribute lvtt,
                                                     Element p) {
@@ -1362,6 +1459,52 @@
         p.add(e);
         return null;
     }
+
+    @Override
+    public Element visitHashes(Hashes_attribute attr, Element p) {
+        Element e = new Element(x.getCpString(attr.attribute_name_index));
+        e.setAttr("Algorithm", x.getCpString(attr.algorithm_index));
+        for (Entry entry : attr.hashes_table) {
+            Element ee = new Element("Entry");
+            String requires = x.getCpString(entry.requires_index);
+            String hashValue = x.getCpString(entry.hash_index);
+            ee.setAttr(requires, hashValue);
+            e.add(ee);
+        }
+        e.trimToSize();
+        e.sort();
+        p.add(e);
+        return null;
+    }
+
+    @Override
+    public Element visitMainClass(MainClass_attribute attr, Element p) {
+        Element e = new Element(x.getCpString(attr.attribute_name_index));
+        e.add(x.getCpString(attr.main_class_index));
+        e.trimToSize();
+        p.add(e);
+        return null;
+    }
+
+    @Override
+    public Element visitTargetPlatform(TargetPlatform_attribute attr, Element p) {
+        Element e = new Element(x.getCpString(attr.attribute_name_index));
+        e.add(x.getCpString(attr.os_name_index));
+        e.add(x.getCpString(attr.os_arch_index));
+        e.add(x.getCpString(attr.os_version_index));
+        e.trimToSize();
+        p.add(e);
+        return null;
+    }
+
+    @Override
+    public Element visitVersion(Version_attribute attr, Element p) {
+        Element e = new Element(x.getCpString(attr.attribute_name_index));
+        e.add(x.getCpString(attr.version_index));
+        e.trimToSize();
+        p.add(e);
+        return null;
+    }
 }
 
 class StackMapVisitor implements StackMapTable_attribute.stack_map_frame.Visitor<Element, Void> {